parametric 0.2.10 → 0.2.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f629915e6b2fee5ae5fcb9c63e340cd19880a72a3b53e06e33d3daff39ffa6a
4
- data.tar.gz: c3fd0ec0a51e954fccd021c62098192b52913d44e1f0c35299cc77c56e428f57
3
+ metadata.gz: c773dd859f56f8d526384567daf66c1c259a7e5d859c9fe40ecc620c0ee73253
4
+ data.tar.gz: 9b056fd197e9fe84a2b14b16134d860ae3a7c49313f370fd9de82fb918c7bc3b
5
5
  SHA512:
6
- metadata.gz: 9b46933db3b2bddd50ea66ec5e03faeb637248382e9a6fab81b2c539e201f148dc88ddc49e77f467974813a0c30a9c5196d48c3eef69f324ac47b15f39cd3d9e
7
- data.tar.gz: 14ce2da62e976fa4c234d25087cfa9abeff2b4d4a077dbeab2a85654cbcc641f33fadcd9f42c76f02cf21321468d971e754e9ed4ff76ee0c314c1382d0201770
6
+ metadata.gz: 9d068ab0c811e30db11d3b6eea2e38937557d2abb36df07623f419b669e7186a86af8de645575cacdb5efe7a51c0dbbe40048aa3fe5417296ee3c5810fd477bf
7
+ data.tar.gz: da9c1a990c6a0c2b85cf27d3f8ea7dd78e9b2e031548e240a79a43b85de9538e496ed491f3a5ef023ae6939d0f706b74274dd0519a7ae48d6452db65eed0d3ce
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in parametric.gemspec
4
4
  gemspec
5
+
6
+ group :development do
7
+ gem 'benchmark-ips'
8
+ end
data/README.md CHANGED
@@ -849,6 +849,130 @@ results.errors["$.Weight"] # => ["is required and value must be present"]
849
849
 
850
850
  NOTES: dynamically expanded field names are not included in `Schema#structure` metadata, and they are only processes if fields with the given expressions are present in the payload. This means that validations applied to those fields only run if keys are present in the first place.
851
851
 
852
+ ## Before and after resolve hooks
853
+
854
+ `Schema#before_resolve` can be used to register blocks to modify the entire input payload _before_ individual fields are validated and coerced.
855
+ This can be useful when you need to pre-populate fields relative to other fields' values, or fetch extra data from other sources.
856
+
857
+ ```ruby
858
+ # This example computes the value of the :slug field based on :name
859
+ schema = Parametric::Schema.new do
860
+ # Note1: These blocks run before field validations, so :name might be blank or invalid at this point.
861
+ # Note2: Before hooks _must_ return a payload hash.
862
+ before_resolve do |payload, context|
863
+ payload.merge(
864
+ slug: payload[:name].to_s.downcase.gsub(/\s+/, '-')
865
+ )
866
+ end
867
+
868
+ # You still need to define the fields you want
869
+ field(:name).type(:string).present
870
+ field(:slug).type(:string).present
871
+ end
872
+
873
+ result = schema.resolve( name: 'Joe Bloggs' )
874
+ result.output # => { name: 'Joe Bloggs', slug: 'joe-bloggs' }
875
+ ```
876
+
877
+ Before hooks can be added to nested schemas, too:
878
+
879
+ ```ruby
880
+ schema = Parametric::Schema.new do
881
+ field(:friends).type(:array).schema do
882
+ before_resolve do |friend_payload, context|
883
+ friend_payload.merge(title: "Mr/Ms #{friend_payload[:name]}")
884
+ end
885
+
886
+ field(:name).type(:string)
887
+ field(:title).type(:string)
888
+ end
889
+ end
890
+ ```
891
+
892
+ You can use inline blocks, but anything that responds to `#call(payload, context)` will work, too:
893
+
894
+ ```ruby
895
+ class SlugMaker
896
+ def initialize(slug_field, from:)
897
+ @slug_field, @from = slug_field, from
898
+ end
899
+
900
+ def call(payload, context)
901
+ payload.merge(
902
+ @slug_field => payload[@from].to_s.downcase.gsub(/\s+/, '-')
903
+ )
904
+ end
905
+ end
906
+
907
+ schema = Parametric::Schema.new do
908
+ before_resolve SlugMaker.new(:slug, from: :name)
909
+
910
+ field(:name).type(:string)
911
+ field(:slug).type(:slug)
912
+ end
913
+ ```
914
+
915
+ The `context` argument can be used to add custom validation errors in a before hook block.
916
+
917
+ ```ruby
918
+ schema = Parametric::Schema.new do
919
+ before_resolve do |payload, context|
920
+ # validate that there's no duplicate friend names
921
+ friends = payload[:friends] || []
922
+ if friends.any? && friends.map{ |fr| fr[:name] }.uniq.size < friends.size
923
+ context.add_error 'friend names must be unique'
924
+ end
925
+
926
+ # don't forget to return the payload
927
+ payload
928
+ end
929
+
930
+ field(:friends).type(:array).schema do
931
+ field(:name).type(:string)
932
+ end
933
+ end
934
+
935
+ result = schema.resolve(
936
+ friends: [
937
+ {name: 'Joe Bloggs'},
938
+ {name: 'Joan Bloggs'},
939
+ {name: 'Joe Bloggs'}
940
+ ]
941
+ )
942
+
943
+ result.valid? # => false
944
+ result.errors # => {'$' => ['friend names must be unique']}
945
+ ```
946
+
947
+ In most cases you should be validating individual fields using field policies. Only validate in before hooks in cases you have dependencies between fields.
948
+
949
+ `Schema#after_resolve` takes the sanitized input hash, and can be used to further validate fields that depend on eachother.
950
+
951
+ ```ruby
952
+ schema = Parametric::Schema.new do
953
+ after_resolve do |payload, ctx|
954
+ # Add a top level error using an arbitrary key name
955
+ ctx.add_base_error('deposit', 'cannot be greater than house price') if payload[:deposit] > payload[:house_price]
956
+ # Or add an error keyed after the current position in the schema
957
+ # ctx.add_error('some error') if some_condition
958
+ # after_resolve hooks must also return the payload, or a modified copy of it
959
+ # note that any changes added here won't be validated.
960
+ payload.merge(desc: 'hello')
961
+ end
962
+
963
+ field(:deposit).policy(:integer).present
964
+ field(:house_price).policy(:integer).present
965
+ field(:desc).policy(:string)
966
+ end
967
+
968
+ result = schema.resolve({ deposit: 1100, house_price: 1000 })
969
+ result.valid? # false
970
+ result.errors[:deposit] # ['cannot be greater than house price']
971
+ result.output[:deposit] # 1100
972
+ result.output[:house_price] # 1000
973
+ result.output[:desc] # 'hello'
974
+ ```
975
+
852
976
  ## Structs
853
977
 
854
978
  Structs turn schema definitions into objects graphs with attribute readers.
@@ -0,0 +1,53 @@
1
+ require 'benchmark/ips'
2
+ require 'parametric/struct'
3
+
4
+ StructAccount = Struct.new(:id, :email, keyword_init: true)
5
+ StructFriend = Struct.new(:name, keyword_init: true)
6
+ StructUser = Struct.new(:name, :age, :friends, :account, keyword_init: true)
7
+
8
+ class ParametricAccount
9
+ include Parametric::Struct
10
+ schema do
11
+ field(:id).type(:integer).present
12
+ field(:email).type(:string)
13
+ end
14
+ end
15
+
16
+ class ParametricUser
17
+ include Parametric::Struct
18
+ schema do
19
+ field(:name).type(:string).present
20
+ field(:age).type(:integer).default(42)
21
+ field(:friends).type(:array).schema do
22
+ field(:name).type(:string).present
23
+ end
24
+ field(:account).type(:object).schema ParametricAccount
25
+ end
26
+ end
27
+
28
+ Benchmark.ips do |x|
29
+ x.report("Struct") {
30
+ StructUser.new(
31
+ name: 'Ismael',
32
+ age: 42,
33
+ friends: [
34
+ StructFriend.new(name: 'Joe'),
35
+ StructFriend.new(name: 'Joan'),
36
+ ],
37
+ account: StructAccount.new(id: 123, email: 'my@account.com')
38
+ )
39
+ }
40
+ x.report("Parametric::Struct") {
41
+ ParametricUser.new!(
42
+ name: 'Ismael',
43
+ age: 42,
44
+ friends: [
45
+ { name: 'Joe' },
46
+ { name: 'Joan' }
47
+ ],
48
+ account: { id: 123, email: 'my@account.com' }
49
+ )
50
+ }
51
+ x.compare!
52
+ end
53
+
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Parametric
2
4
  class BlockValidator
3
5
  def self.build(meth, &block)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Parametric
2
4
  class Top
3
5
  attr_reader :errors
@@ -26,6 +28,10 @@ module Parametric
26
28
  top.add_error(string_path, msg)
27
29
  end
28
30
 
31
+ def add_base_error(key, msg)
32
+ top.add_error(key, msg)
33
+ end
34
+
29
35
  def sub(key)
30
36
  self.class.new(path + [key], top)
31
37
  end
@@ -40,5 +46,4 @@ module Parametric
40
46
  end.join
41
47
  end
42
48
  end
43
-
44
49
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "date"
2
4
 
3
5
  module Parametric
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "parametric"
2
4
 
3
5
  module Parametric
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "parametric/field_dsl"
2
4
 
3
5
  module Parametric
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Parametric
2
4
  # Field DSL
3
5
  # host instance must implement:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Parametric
2
4
  module Policies
3
5
  class Format
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'parametric/block_validator'
2
4
 
3
5
  module Parametric
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Parametric
2
4
  class Results
3
5
  attr_reader :output, :errors
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "parametric/context"
2
4
  require "parametric/results"
3
5
  require "parametric/field"
@@ -12,6 +14,8 @@ module Parametric
12
14
  @default_field_policies = []
13
15
  @ignored_field_keys = []
14
16
  @expansions = {}
17
+ @before_hooks = []
18
+ @after_hooks = []
15
19
  end
16
20
 
17
21
  def schema
@@ -90,6 +94,20 @@ module Parametric
90
94
  end
91
95
  end
92
96
 
97
+ def before_resolve(klass = nil, &block)
98
+ raise ArgumentError, '#before_resolve expects a callable object, or a block' if !klass && !block_given?
99
+ callable = klass || block
100
+ before_hooks << callable
101
+ self
102
+ end
103
+
104
+ def after_resolve(klass = nil, &block)
105
+ raise ArgumentError, '#after_resolve expects a callable object, or a block' if !klass && !block_given?
106
+ callable = klass || block
107
+ after_hooks << callable
108
+ self
109
+ end
110
+
93
111
  def expand(exp, &block)
94
112
  expansions[exp] = block
95
113
  self
@@ -139,19 +157,35 @@ module Parametric
139
157
 
140
158
  protected
141
159
 
142
- attr_reader :definitions, :options
160
+ attr_reader :definitions, :options, :before_hooks, :after_hooks
143
161
 
144
162
  private
145
163
 
146
164
  attr_reader :default_field_policies, :ignored_field_keys, :expansions
147
165
 
148
166
  def coerce_one(val, context, flds: fields)
149
- flds.each_with_object({}) do |(_, field), m|
167
+ val = run_before_hooks(val, context)
168
+
169
+ out = flds.each_with_object({}) do |(_, field), m|
150
170
  r = field.resolve(val, context.sub(field.key))
151
171
  if r.eligible?
152
172
  m[field.key] = r.value
153
173
  end
154
174
  end
175
+
176
+ run_after_hooks(out, context)
177
+ end
178
+
179
+ def run_before_hooks(val, context)
180
+ before_hooks.reduce(val) do |value, callable|
181
+ callable.call(value, context)
182
+ end
183
+ end
184
+
185
+ def run_after_hooks(val, context)
186
+ after_hooks.reduce(val) do |value, callable|
187
+ callable.call(value, context)
188
+ end
155
189
  end
156
190
 
157
191
  class MatchContext
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'parametric/dsl'
2
4
 
3
5
  module Parametric
@@ -56,10 +58,24 @@ module Parametric
56
58
 
57
59
  # this hook is called after schema definition in DSL module
58
60
  def parametric_after_define_schema(schema)
59
- schema.fields.keys.each do |key|
60
- define_method key do
61
- _graph[key]
61
+ schema.fields.values.each do |field|
62
+ if field.meta_data[:schema]
63
+ if field.meta_data[:schema].is_a?(Parametric::Schema)
64
+ klass = Class.new do
65
+ include Struct
66
+ end
67
+ klass.schema = field.meta_data[:schema]
68
+ self.const_set(__class_name(field.key), klass)
69
+ klass.parametric_after_define_schema(field.meta_data[:schema])
70
+ else
71
+ self.const_set(__class_name(field.key), field.meta_data[:schema])
72
+ end
62
73
  end
74
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
75
+ def #{field.key}
76
+ _graph[:#{field.key}]
77
+ end
78
+ RUBY
63
79
  end
64
80
  end
65
81
 
@@ -69,27 +85,11 @@ module Parametric
69
85
  end
70
86
  end
71
87
 
72
- def parametric_build_class_for_child(key, child_schema)
73
- klass = Class.new do
74
- include Struct
75
- end
76
- klass.schema = child_schema
77
- klass
78
- end
79
-
80
88
  def wrap(key, value)
81
- field = schema.fields[key]
82
- return value unless field
83
-
84
89
  case value
85
90
  when Hash
86
91
  # find constructor for field
87
- cons = field.meta_data[:schema]
88
- if cons.kind_of?(Parametric::Schema)
89
- klass = parametric_build_class_for_child(key, cons)
90
- klass.parametric_after_define_schema(cons)
91
- cons = klass
92
- end
92
+ cons = self.const_get(__class_name(key))
93
93
  cons ? cons.new(value) : value.freeze
94
94
  when Array
95
95
  value.map{|v| wrap(key, v) }.freeze
@@ -97,6 +97,12 @@ module Parametric
97
97
  value.freeze
98
98
  end
99
99
  end
100
+
101
+ PLURAL_END = /s$/.freeze
102
+
103
+ def __class_name(key)
104
+ key.to_s.split('_').map(&:capitalize).join.sub(PLURAL_END, '')
105
+ end
100
106
  end
101
107
  end
102
108
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Parametric
2
- VERSION = "0.2.10"
4
+ VERSION = "0.2.12"
3
5
  end
data/lib/parametric.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "parametric/version"
2
4
  require "parametric/registry"
3
5
  require "parametric/field"
data/parametric.gemspec CHANGED
@@ -17,7 +17,6 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_development_dependency "bundler", "~> 1.5"
21
20
  spec.add_development_dependency "rake"
22
21
  spec.add_development_dependency "rspec", '3.4.0'
23
22
  spec.add_development_dependency "byebug"
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe 'default coercions' do
4
4
  def test_coercion(key, value, expected)
5
- coercion = Parametric.registry.coercions[key]
5
+ coercion = Parametric.registry.policies[key]
6
6
  expect(coercion.new.coerce(value, nil, nil)).to eq expected
7
7
  end
8
8
 
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parametric::Schema do
4
+ describe '#before_resolve' do
5
+ it 'passes payload through before_resolve block, if defined' do
6
+ schema = described_class.new do
7
+ before_resolve do |payload, _context|
8
+ payload[:slug] = payload[:name].to_s.downcase.gsub(/\s+/, '-') unless payload[:slug]
9
+ payload
10
+ end
11
+
12
+ field(:name).policy(:string).present
13
+ field(:slug).policy(:string).present
14
+ field(:variants).policy(:array).schema do
15
+ before_resolve do |payload, _context|
16
+ payload[:slug] = "v: #{payload[:name].to_s.downcase}"
17
+ payload
18
+ end
19
+ field(:name).policy(:string).present
20
+ field(:slug).type(:string).present
21
+ end
22
+ end
23
+
24
+ result = schema.resolve({ name: 'A name', variants: [{ name: 'A variant' }] })
25
+ expect(result.valid?).to be true
26
+ expect(result.output[:slug]).to eq 'a-name'
27
+ expect(result.output[:variants].first[:slug]).to eq 'v: a variant'
28
+ end
29
+
30
+ it 'collects errors added in before_resolve blocks' do
31
+ schema = described_class.new do
32
+ field(:variants).type(:array).schema do
33
+ before_resolve do |payload, context|
34
+ context.add_error 'nope!' if payload[:name] == 'with errors'
35
+ payload
36
+ end
37
+ field(:name).type(:string)
38
+ end
39
+ end
40
+
41
+ results = schema.resolve({ variants: [ {name: 'no errors'}, {name: 'with errors'}]})
42
+ expect(results.valid?).to be false
43
+ expect(results.errors['$.variants[1]']).to eq ['nope!']
44
+ end
45
+
46
+ it 'copies before_resolve hooks to merged schemas' do
47
+ schema1 = described_class.new do
48
+ before_resolve do |payload, _context|
49
+ payload[:slug] = payload[:name].to_s.downcase.gsub(/\s+/, '-') unless payload[:slug]
50
+ payload
51
+ end
52
+ field(:name).present.type(:string)
53
+ field(:slug).present.type(:string)
54
+ end
55
+
56
+ schema2 = described_class.new do
57
+ before_resolve do |payload, _context|
58
+ payload[:slug] = "slug-#{payload[:slug]}" if payload[:slug]
59
+ payload
60
+ end
61
+
62
+ field(:age).type(:integer)
63
+ end
64
+
65
+ schema3 = schema1.merge(schema2)
66
+
67
+ results = schema3.resolve({ name: 'Ismael Celis', age: 41 })
68
+ expect(results.output[:slug]).to eq 'slug-ismael-celis'
69
+ end
70
+
71
+ it 'works with any callable' do
72
+ slug_maker = Class.new do
73
+ def initialize(slug_field, from:)
74
+ @slug_field, @from = slug_field, from
75
+ end
76
+
77
+ def call(payload, _context)
78
+ payload.merge(
79
+ @slug_field => payload[@from].to_s.downcase.gsub(/\s+/, '-')
80
+ )
81
+ end
82
+ end
83
+
84
+ schema = described_class.new do |sc, _opts|
85
+ sc.before_resolve slug_maker.new(:slug, from: :name)
86
+
87
+ sc.field(:name).type(:string)
88
+ sc.field(:slug).type(:string)
89
+ end
90
+
91
+ results = schema.resolve(name: 'Ismael Celis')
92
+ expect(results.output[:slug]).to eq 'ismael-celis'
93
+ end
94
+ end
95
+
96
+ describe '#after_resolve' do
97
+ let!(:schema) do
98
+ described_class.new do
99
+ after_resolve do |payload, ctx|
100
+ ctx.add_base_error('deposit', 'cannot be greater than house price') if payload[:deposit] > payload[:house_price]
101
+ payload.merge(desc: 'hello')
102
+ end
103
+
104
+ field(:deposit).policy(:integer).present
105
+ field(:house_price).policy(:integer).present
106
+ field(:desc).policy(:string)
107
+ end
108
+ end
109
+
110
+ it 'passes payload through after_resolve block, if defined' do
111
+ result = schema.resolve({ deposit: 1100, house_price: 1000 })
112
+ expect(result.valid?).to be false
113
+ expect(result.output[:deposit]).to eq 1100
114
+ expect(result.output[:house_price]).to eq 1000
115
+ expect(result.output[:desc]).to eq 'hello'
116
+ end
117
+
118
+ it 'copies after hooks when merging schemas' do
119
+ child_schema = described_class.new do
120
+ field(:name).type(:string)
121
+ end
122
+
123
+ union = schema.merge(child_schema)
124
+
125
+ result = union.resolve({ name: 'Joe', deposit: 1100, house_price: 1000 })
126
+ expect(result.valid?).to be false
127
+ expect(result.output[:deposit]).to eq 1100
128
+ expect(result.output[:house_price]).to eq 1000
129
+ expect(result.output[:desc]).to eq 'hello'
130
+ expect(result.output[:name]).to eq 'Joe'
131
+ end
132
+ end
133
+ end
data/spec/struct_spec.rb CHANGED
@@ -99,32 +99,6 @@ describe Parametric::Struct do
99
99
  expect(instance.friends.first.age).to eq 10
100
100
  end
101
101
 
102
- it 'wraps nested schemas in custom class' do
103
- klass = Class.new do
104
- include Parametric::Struct
105
-
106
- def self.parametric_build_class_for_child(key, child_schema)
107
- Class.new do
108
- include Parametric::Struct
109
- schema child_schema
110
- def salutation
111
- "my age is #{age}"
112
- end
113
- end
114
- end
115
-
116
- schema do
117
- field(:name).type(:string).present
118
- field(:friends).type(:array).schema do
119
- field(:age).type(:integer)
120
- end
121
- end
122
- end
123
-
124
- user = klass.new(name: 'Ismael', friends: [{age: 43}])
125
- expect(user.friends.first.salutation).to eq 'my age is 43'
126
- end
127
-
128
102
  it "wraps regular schemas in structs" do
129
103
  friend_schema = Parametric::Schema.new do
130
104
  field(:name)
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parametric
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.10
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Celis
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-26 00:00:00.000000000 Z
11
+ date: 2020-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.5'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.5'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rake
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -81,6 +67,7 @@ files:
81
67
  - LICENSE.txt
82
68
  - README.md
83
69
  - Rakefile
70
+ - bench/struct_bench.rb
84
71
  - bin/console
85
72
  - lib/parametric.rb
86
73
  - lib/parametric/block_validator.rb
@@ -101,6 +88,7 @@ files:
101
88
  - spec/expand_spec.rb
102
89
  - spec/field_spec.rb
103
90
  - spec/policies_spec.rb
91
+ - spec/schema_lifecycle_hooks_spec.rb
104
92
  - spec/schema_spec.rb
105
93
  - spec/schema_walk_spec.rb
106
94
  - spec/spec_helper.rb
@@ -110,7 +98,7 @@ homepage: ''
110
98
  licenses:
111
99
  - MIT
112
100
  metadata: {}
113
- post_install_message:
101
+ post_install_message:
114
102
  rdoc_options: []
115
103
  require_paths:
116
104
  - lib
@@ -125,9 +113,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
113
  - !ruby/object:Gem::Version
126
114
  version: '0'
127
115
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 2.7.7
130
- signing_key:
116
+ rubygems_version: 3.0.3
117
+ signing_key:
131
118
  specification_version: 4
132
119
  summary: DSL for declaring allowed parameters with options, regexp patern and default
133
120
  values.
@@ -137,6 +124,7 @@ test_files:
137
124
  - spec/expand_spec.rb
138
125
  - spec/field_spec.rb
139
126
  - spec/policies_spec.rb
127
+ - spec/schema_lifecycle_hooks_spec.rb
140
128
  - spec/schema_spec.rb
141
129
  - spec/schema_walk_spec.rb
142
130
  - spec/spec_helper.rb