Skip to content

Commit

Permalink
Fix regular expression parsing
Browse files Browse the repository at this point in the history
This allows us to write regular expression in YAML files as if they were
a supported thing, and without any of the weird Rubyisms. YAML files
with weird Rubyisms will continue to work, though!

This was valuable, we may have found a fix for a bug in Psych, Ruby's
YAML parser.
  • Loading branch information
mamhoff committed Feb 4, 2025
1 parent 8404402 commit 4ac4ea8
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 8 deletions.
22 changes: 20 additions & 2 deletions lib/alchemy/configuration/regexp_option.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,26 @@ module RegexpOption
private

def validate_regexp(value, option_name)
raise TypeError, "#{option_name} must be set as a Regexp, given #{value.inspect}" unless value.is_a?(Regexp)
value
raise TypeError, "#{option_name} must be set as a String or a regular expression, given #{value.inspect}" unless value.is_a?(String) || value.is_a?(Regexp)
if value.is_a?(String)
matches = /^\/(?<string>.*)\/(?<options>[mixn]*)$/m.match(value)
source = matches[:string].gsub('\/', '/')
options = 0
lang = nil
matches[:options].each_char do |option|
case option
when 'x' then options |= Regexp::EXTENDED
when 'i' then options |= Regexp::IGNORECASE
when 'm' then options |= Regexp::MULTILINE
when 'n' then options |= Regexp::NOENCODING
else lang = option
end
end
Regexp.new(*[source, options, lang].compact)
else
# It's already a regex
value
end
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions lib/generators/alchemy/install/files/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ link_target_options: [blank]
# validates_format_of :url, with: Alchemy.config.get('format_matchers')['url']
#
format_matchers:
email: !ruby/regexp '/\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/'
url: !ruby/regexp '/\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix'
link_url: !ruby/regexp '/^(tel:|mailto:|\/|[a-z]+:\/\/)/'
email: /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
url: /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix
link_url: /^(tel:|mailto:|/|[a-z]+://)/

# The layout used for rendering the +alchemy/admin/pages#show+ action.
admin_page_preview_layout: application
Expand Down
12 changes: 9 additions & 3 deletions spec/libraries/alchemy/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,16 @@
expect(configuration.email).to eq(/\A.*\z/)
end

it "can only be set with a regexp" do
it "can be set with a regexp" do
expect do
configuration.email = '/\A.*\z/'
end.to raise_exception(TypeError, /email must be set as a Regexp, given .*/)
configuration.email = /\A.+\z/
end.to change(configuration, :email).to(/\A.+\z/)
end

it "can be set with a string" do
expect do
configuration.email = '/\A\/+\z/i'
end.to change(configuration, :email).to(/\A\/+\z/i)
end
end

Expand Down
11 changes: 11 additions & 0 deletions spec/libraries/alchemy/configurations/main_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,15 @@
end.to change { subject.output_image_quality }.from(85).to(90)
end
end

describe "generated config.yml" do
let(:config_template) { Alchemy::Engine.root.join("lib", "generators", "alchemy", "install", "files", "config.yml") }
let(:default_config) { Alchemy::Configurations::Main.new }

it "does not change the defaults" do
expect do
default_config.set_from_yaml(config_template)
end.not_to change { default_config.to_h }
end
end
end

0 comments on commit 4ac4ea8

Please sign in to comment.