From 890b549269cd71485d7302c68203c1126c22e9db Mon Sep 17 00:00:00 2001 From: David Harsha Date: Wed, 26 Oct 2022 18:42:52 -0700 Subject: [PATCH] Add named regexp resolvers `ecma` maintains the current behavior of rewriting Ruby's `\A` and `\z` anchors. `ruby` uses Ruby's `Regexp` directly. In the future, I think it may make sense to switch the default to `ruby` since it's the least surprising behavior. That way people could opt in to expression rewrites and the rewrites could be more aggressive. --- README.md | 3 ++- lib/json_schemer/schema/base.rb | 13 ++++++++++--- test/json_schemer_test.rb | 12 ++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 42a30753..8891ef47 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,8 @@ JSONSchemer.schema( ref_resolver: 'net/http', # use different method to match regexes - # Proc/lambda/respond_to?(:call) + # 'ecma'/'ruby'/proc/lambda/respond_to?(:call) + # default: 'ecma' regexp_resolver: proc do |pattern| RE2::Regexp.new(pattern) end diff --git a/lib/json_schemer/schema/base.rb b/lib/json_schemer/schema/base.rb index dbc1b19a..a947289c 100644 --- a/lib/json_schemer/schema/base.rb +++ b/lib/json_schemer/schema/base.rb @@ -30,7 +30,7 @@ def merge( :eol => '\z' }.freeze - DEFAULT_REGEXP_RESOLVER = proc do |pattern| + ECMA_262_REGEXP_RESOLVER = proc do |pattern| Regexp.new( Regexp::Scanner.scan(pattern).map do |type, token, text| type == :anchor ? RUBY_REGEX_ANCHORS_TO_ECMA_262.fetch(token, text) : text @@ -53,7 +53,7 @@ def initialize( formats: nil, keywords: nil, ref_resolver: DEFAULT_REF_RESOLVER, - regexp_resolver: CachedResolver.new(&DEFAULT_REGEXP_RESOLVER) + regexp_resolver: 'ecma' ) raise InvalidSymbolKey, 'schemas must use string keys' if schema.is_a?(Hash) && !schema.empty? && !schema.first.first.is_a?(String) @root = schema @@ -64,7 +64,14 @@ def initialize( @formats = formats @keywords = keywords @ref_resolver = ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : ref_resolver - @regexp_resolver = regexp_resolver + @regexp_resolver = case regexp_resolver + when 'ecma' + CachedResolver.new(&ECMA_262_REGEXP_RESOLVER) + when 'ruby' + CachedResolver.new(&Regexp.method(:new)) + else + regexp_resolver + end end def valid?(data) diff --git a/test/json_schemer_test.rb b/test/json_schemer_test.rb index e8e98473..0111974d 100644 --- a/test/json_schemer_test.rb +++ b/test/json_schemer_test.rb @@ -933,6 +933,18 @@ def initialize(*args) assert_equal(1, new_regexp_class.counts) end + def test_it_allows_named_regexp_resolvers + schema = JSONSchemer.schema({ 'pattern' => '^test$' }) + assert(schema.valid?("test")) + refute(schema.valid?("\ntest\n")) + schema = JSONSchemer.schema({ 'pattern' => '^test$' }, :regexp_resolver => 'ecma') + assert(schema.valid?("test")) + refute(schema.valid?("\ntest\n")) + schema = JSONSchemer.schema({ 'pattern' => '^test$' }, :regexp_resolver => 'ruby') + assert(schema.valid?("test")) + assert(schema.valid?("\ntest\n")) + end + def test_it_raises_for_invalid_regexp_resolution schema = JSONSchemer.schema( { 'pattern' => 'whatever' },