reform 2.2.4 → 2.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +5 -1
  3. data/.travis.yml +11 -6
  4. data/Appraisals +8 -0
  5. data/CHANGES.md +57 -4
  6. data/CONTRIBUTING.md +31 -0
  7. data/Gemfile +2 -16
  8. data/ISSUE_TEMPLATE.md +25 -0
  9. data/LICENSE.txt +1 -1
  10. data/README.md +5 -7
  11. data/Rakefile +16 -9
  12. data/gemfiles/0.13.0.gemfile +8 -0
  13. data/gemfiles/1.5.0.gemfile +9 -0
  14. data/lib/reform.rb +1 -0
  15. data/lib/reform/contract.rb +7 -17
  16. data/lib/reform/contract/custom_error.rb +41 -0
  17. data/lib/reform/contract/validate.rb +53 -23
  18. data/lib/reform/errors.rb +61 -0
  19. data/lib/reform/form.rb +36 -10
  20. data/lib/reform/form/call.rb +1 -1
  21. data/lib/reform/form/composition.rb +2 -2
  22. data/lib/reform/form/dry.rb +10 -58
  23. data/lib/reform/form/dry/input_hash.rb +37 -0
  24. data/lib/reform/form/dry/new_api.rb +45 -0
  25. data/lib/reform/form/dry/old_api.rb +61 -0
  26. data/lib/reform/form/populator.rb +11 -27
  27. data/lib/reform/form/prepopulate.rb +4 -3
  28. data/lib/reform/form/validate.rb +28 -13
  29. data/lib/reform/result.rb +90 -0
  30. data/lib/reform/validation.rb +19 -11
  31. data/lib/reform/validation/groups.rb +12 -27
  32. data/lib/reform/version.rb +1 -1
  33. data/reform.gemspec +14 -13
  34. data/test/benchmarking.rb +39 -6
  35. data/test/call_new_api.rb +23 -0
  36. data/test/call_old_api.rb +23 -0
  37. data/test/changed_test.rb +14 -14
  38. data/test/coercion_test.rb +57 -25
  39. data/test/composition_new_api.rb +186 -0
  40. data/test/composition_old_api.rb +184 -0
  41. data/test/contract/custom_error_test.rb +55 -0
  42. data/test/contract_new_api.rb +77 -0
  43. data/test/contract_old_api.rb +77 -0
  44. data/test/default_test.rb +4 -4
  45. data/test/deserialize_test.rb +17 -20
  46. data/test/errors_new_api.rb +225 -0
  47. data/test/errors_old_api.rb +230 -0
  48. data/test/feature_test.rb +10 -12
  49. data/test/fixtures/dry_error_messages.yml +73 -23
  50. data/test/fixtures/dry_new_api_error_messages.yml +104 -0
  51. data/test/form_new_api.rb +57 -0
  52. data/test/{form_test.rb → form_old_api.rb} +8 -8
  53. data/test/form_option_new_api.rb +24 -0
  54. data/test/{form_option_test.rb → form_option_old_api.rb} +5 -5
  55. data/test/from_test.rb +18 -22
  56. data/test/inherit_new_api.rb +105 -0
  57. data/test/inherit_old_api.rb +105 -0
  58. data/test/{module_test.rb → module_new_api.rb} +26 -31
  59. data/test/module_old_api.rb +146 -0
  60. data/test/parse_option_test.rb +40 -0
  61. data/test/parse_pipeline_test.rb +4 -4
  62. data/test/populate_new_api.rb +304 -0
  63. data/test/populate_old_api.rb +304 -0
  64. data/test/populator_skip_test.rb +11 -11
  65. data/test/prepopulator_test.rb +23 -24
  66. data/test/read_only_test.rb +12 -1
  67. data/test/readable_test.rb +9 -9
  68. data/test/reform_new_api.rb +204 -0
  69. data/test/{reform_test.rb → reform_old_api.rb} +44 -65
  70. data/test/save_new_api.rb +101 -0
  71. data/test/save_old_api.rb +101 -0
  72. data/test/setup_test.rb +17 -17
  73. data/test/skip_if_new_api.rb +85 -0
  74. data/test/skip_if_old_api.rb +92 -0
  75. data/test/skip_setter_and_getter_test.rb +9 -10
  76. data/test/test_helper.rb +25 -14
  77. data/test/validate_new_api.rb +453 -0
  78. data/test/{validate_test.rb → validate_old_api.rb} +121 -131
  79. data/test/validation/dry_validation_new_api.rb +835 -0
  80. data/test/validation/dry_validation_old_api.rb +772 -0
  81. data/test/validation/result_test.rb +77 -0
  82. data/test/validation_library_provided_test.rb +16 -0
  83. data/test/virtual_test.rb +47 -7
  84. data/test/writeable_test.rb +38 -9
  85. metadata +111 -56
  86. data/gemfiles/Gemfile.disposable-0.3 +0 -6
  87. data/lib/reform/contract/errors.rb +0 -43
  88. data/lib/reform/form/mongoid.rb +0 -37
  89. data/lib/reform/form/orm.rb +0 -26
  90. data/lib/reform/mongoid.rb +0 -4
  91. data/test/call_test.rb +0 -23
  92. data/test/composition_test.rb +0 -149
  93. data/test/contract_test.rb +0 -77
  94. data/test/deprecation_test.rb +0 -27
  95. data/test/errors_test.rb +0 -165
  96. data/test/inherit_test.rb +0 -119
  97. data/test/populate_test.rb +0 -270
  98. data/test/readonly_test.rb +0 -14
  99. data/test/save_test.rb +0 -89
  100. data/test/skip_if_test.rb +0 -74
  101. data/test/validation/dry_test.rb +0 -60
  102. data/test/validation/dry_validation_test.rb +0 -352
  103. data/test/validation/errors.yml +0 -4
@@ -1,74 +0,0 @@
1
- require 'test_helper'
2
-
3
- class SkipIfTest < BaseTest
4
-
5
- class AlbumForm < Reform::Form
6
- property :title
7
-
8
- property :hit, skip_if: lambda { |options| options[:fragment]["title"]=="" } do
9
- property :title
10
- validation do
11
- key(:title).required
12
- end
13
- end
14
-
15
- collection :songs, skip_if: :skip_song?, populate_if_empty: BaseTest::Song do
16
- property :title
17
- end
18
-
19
- def skip_song?(options)
20
- options[:fragment]["title"].nil?
21
- end
22
- end
23
-
24
-
25
- let (:hit) { Song.new }
26
- let (:album) { Album.new(nil, hit, [], nil) }
27
-
28
- # deserializes when present.
29
- it do
30
- form = AlbumForm.new(album)
31
- form.validate("hit" => {"title" => "Altar Of Sacrifice"}).must_equal true
32
- form.hit.title.must_equal "Altar Of Sacrifice"
33
- end
34
-
35
- # skips deserialization when not present.
36
- it do
37
- form = AlbumForm.new(Album.new)
38
- form.validate("hit" => {"title" => ""}).must_equal true
39
- form.hit.must_equal nil # hit hasn't been deserialised.
40
- end
41
-
42
- # skips deserialization when not present.
43
- it do
44
- form = AlbumForm.new(Album.new(nil, nil, []))
45
- form.validate("songs" => [{"title" => "Waste Of Breath"}, {"title" => nil}]).must_equal true
46
- form.songs.size.must_equal 1
47
- form.songs[0].title.must_equal "Waste Of Breath"
48
- end
49
- end
50
-
51
- class SkipIfAllBlankTest < BaseTest
52
- # skip_if: :all_blank"
53
- class AlbumForm < Reform::Form
54
- collection :songs, skip_if: :all_blank, populate_if_empty: BaseTest::Song do
55
- property :title
56
- property :length
57
- end
58
- end
59
-
60
- # create only one object.
61
- it do
62
- form = AlbumForm.new(OpenStruct.new(songs: []))
63
- form.validate("songs" => [{"title"=>"Apathy"}, {"title"=>"", "length" => ""}]).must_equal true
64
- form.songs.size.must_equal 1
65
- form.songs[0].title.must_equal "Apathy"
66
- end
67
-
68
- it do
69
- form = AlbumForm.new(OpenStruct.new(songs: []))
70
- form.validate("songs" => [{"title"=>"", "length" => ""}, {"title"=>"Apathy"}]).must_equal true
71
- form.songs.size.must_equal 1
72
- form.songs[0].title.must_equal "Apathy"
73
- end
74
- end
@@ -1,60 +0,0 @@
1
- # require "test_helper"
2
- # require "reform/form/dry"
3
-
4
- # class BlaTest < MiniTest::Spec
5
- # class CartForm < Reform::Form
6
- # include Reform::Form::Dry::Validations
7
-
8
- # property :user_id
9
-
10
- # collection :variants do
11
- # property :id
12
- # end
13
-
14
-
15
- # validation :default do
16
- # key(:user_id).required
17
-
18
- # key(:variants).schema do
19
- # each do
20
- # key(:id).required
21
- # end
22
- # end
23
-
24
- # configure do
25
- # config.messages_file = 'test/validation/errors.yml'
26
-
27
- # option :form
28
- # # message need to be defined on fixtures/dry_error_messages
29
- # # d-v expects you to define your custome messages on the .yml file
30
-
31
-
32
- # def form_access_validation?(value)
33
- # raise value.inspect
34
- # form.title == 'Reform'
35
- # end
36
- # end
37
-
38
- # rule(form_present: [:form]) do |form|
39
- # form.user_id == "hallo"
40
- # end
41
- # end
42
- # end
43
-
44
- # it do
45
- # cart = Struct.new(:user_id, :variants).new(1, [Struct.new(:id).new])
46
-
47
- # form = CartForm.new(cart)
48
- # form.validate(user_id: 2, variants: [{id: 3}])
49
- # puts form.errors.inspect
50
- # end
51
- # end
52
-
53
-
54
- # # current_id: BlaTest
55
- # # cart: {
56
- # # carts: {
57
- # # products: [{current_id}]
58
- # # }
59
-
60
- # # }
@@ -1,352 +0,0 @@
1
- require "test_helper"
2
- require "reform/form/dry"
3
-
4
- class DryValidationDefaultGroupTest < Minitest::Spec
5
- Session = Struct.new(:username, :email, :password, :confirm_password)
6
-
7
- class SessionForm < Reform::Form
8
- include Reform::Form::Dry
9
-
10
- property :username
11
- property :email
12
- property :password
13
- property :confirm_password
14
-
15
- validation do
16
- key(:username).required
17
- key(:email).required
18
- end
19
- end
20
-
21
- let (:form) { SessionForm.new(Session.new) }
22
-
23
- # valid.
24
- it do
25
- form.validate(username: "Helloween",
26
- email: "yep").must_equal true
27
- form.errors.messages.inspect.must_equal "{}"
28
- end
29
- end
30
-
31
- class ValidationGroupsTest < MiniTest::Spec
32
- describe "basic validations" do
33
- Session = Struct.new(:username, :email, :password, :confirm_password)
34
-
35
- class SessionForm < Reform::Form
36
- include Reform::Form::Dry::Validations
37
-
38
- property :username
39
- property :email
40
- property :password
41
- property :confirm_password
42
-
43
- validation :default do
44
- key(:username).required
45
- key(:email).required
46
- end
47
-
48
- validation :email, if: :default do
49
- key(:email).required(min_size?: 3)
50
- end
51
-
52
- validation :nested, if: :default do
53
- key(:password).required(min_size?: 2)
54
- end
55
-
56
- validation :confirm, if: :default, after: :email do
57
- key(:confirm_password).required(min_size?: 2)
58
- end
59
- end
60
-
61
- let (:form) { SessionForm.new(Session.new) }
62
-
63
- # valid.
64
- it do
65
- form.validate({ username: "Helloween",
66
- email: "yep",
67
- password: "99",
68
- confirm_password: "99" }).must_equal true
69
- form.errors.messages.inspect.must_equal "{}"
70
- end
71
-
72
- # invalid.
73
- it do
74
- form.validate({}).must_equal false
75
- form.errors.messages.inspect.must_equal "{:username=>[\"is missing\"], :email=>[\"is missing\"]}"
76
- end
77
-
78
- # partially invalid.
79
- # 2nd group fails.
80
- it do
81
- form.validate(username: "Helloween", email: "yo", confirm_password:"9").must_equal false
82
- form.errors.messages.inspect.must_equal "{:email=>[\"size cannot be less than 3\"], :confirm_password=>[\"size cannot be less than 2\"], :password=>[\"is missing\", \"size cannot be less than 2\"]}"
83
- end
84
- # 3rd group fails.
85
- it do
86
- form.validate(username: "Helloween", email: "yo!", confirm_password:"9").must_equal false
87
- form.errors.messages.inspect
88
- .must_equal "{:confirm_password=>[\"size cannot be less than 2\"], :password=>[\"is missing\", \"size cannot be less than 2\"]}"
89
- end
90
- # 4th group with after: fails.
91
- it do
92
- form.validate(username: "Helloween", email: "yo!", password: "", confirm_password: "9").must_equal false
93
- form.errors.messages.inspect.must_equal "{:confirm_password=>[\"size cannot be less than 2\"], :password=>[\"must be filled\", \"size cannot be less than 2\"]}"
94
- end
95
- end
96
-
97
- describe "Nested validations" do
98
- class AlbumForm < Reform::Form
99
- include Reform::Form::Dry::Validations
100
-
101
- property :title
102
-
103
- property :hit do
104
- property :title
105
-
106
- # FIX ME: this doesn't work now, @apotonick said he knows why
107
- # The error is that this validation block act as an AM:V instead of the Dry one.
108
- # validation :default do
109
- # key(:title, &:filled?)
110
- # end
111
- end
112
-
113
- collection :songs do
114
- property :title
115
- end
116
-
117
- property :band do
118
- property :name
119
- property :label do
120
- property :name
121
- end
122
- end
123
-
124
- validation :default do
125
-
126
- key(:title).required
127
-
128
- key(:band).schema do
129
- key(:name).required
130
- key(:label).schema do
131
- key(:name).required
132
- end
133
- end
134
-
135
- configure do
136
- option :form
137
- # message need to be defined on fixtures/dry_error_messages
138
- # d-v expects you to define your custome messages on the .yml file
139
- def good_musical_taste?(value)
140
- value != 'Nickelback'
141
- end
142
-
143
- def form_access_validation?(value)
144
- form.title == 'Reform'
145
- end
146
- end
147
-
148
- key(:title).required(:good_musical_taste?)
149
- key(:title).required(:form_access_validation?)
150
- end
151
- end
152
-
153
- let (:album) do
154
- OpenStruct.new(
155
- :title => "Blackhawks Over Los Angeles",
156
- :hit => song,
157
- :songs => songs,
158
- :band => Struct.new(:name, :label).new("Epitaph", OpenStruct.new),
159
- )
160
- end
161
- let (:song) { OpenStruct.new(:title => "Downtown") }
162
- let (:songs) { [ song = OpenStruct.new(:title => "Calling"), song ] }
163
- let (:form) { AlbumForm.new(album) }
164
-
165
- # correct #validate.
166
- it do
167
- result = form.validate(
168
- "title" => "Reform",
169
- "songs" => [
170
- {"title" => "Fallout"},
171
- {"title" => "Roxanne", "composer" => {"name" => "Sting"}}
172
- ],
173
- "band" => {"label" => {"name" => "Epitaph"}},
174
- )
175
-
176
- result.must_equal true
177
- form.errors.messages.inspect.must_equal "{}"
178
- end
179
- end
180
-
181
-
182
- describe "fails with :validate, :validates and :validates_with" do
183
-
184
- it "throws a goddamn error" do
185
- e = proc do
186
- class FailingForm < Reform::Form
187
- include Reform::Form::Dry::Validations
188
-
189
- property :username
190
-
191
- validation :email do
192
- validates(:email, &:filled?)
193
- end
194
- end
195
- end.must_raise(NoMethodError)
196
- # e.message.must_equal 'validates() is not supported by Dry Validation backend.'
197
-
198
- e = proc do
199
- class FailingForm < Reform::Form
200
- include Reform::Form::Dry::Validations
201
-
202
- property :username
203
-
204
- validation :email do
205
- validate(:email, &:filled?)
206
- end
207
- end
208
- end.must_raise(NoMethodError)
209
- # e.message.must_equal 'validate() is not supported by Dry Validation backend.'
210
-
211
- e = proc do
212
- class FailingForm < Reform::Form
213
- include Reform::Form::Dry::Validations
214
-
215
- property :username
216
-
217
- validation :email do
218
- validates_with(:email, &:filled?)
219
- end
220
- end
221
- end.must_raise(NoMethodError)
222
- # e.message.must_equal (NoMethodError)'validates_with() is not supported by Dry Validation backend.'
223
- end
224
- end
225
-
226
-
227
- # describe "same-named group" do
228
- # class OverwritingForm < Reform::Form
229
- # include Reform::Form::Dry::Validations
230
-
231
- # property :username
232
- # property :email
233
-
234
- # validation :email do # FIX ME: is this working for other validator or just bugging here?
235
- # key(:email, &:filled?) # it's not considered, overitten
236
- # end
237
-
238
- # validation :email do # just another group.
239
- # key(:username, &:filled?)
240
- # end
241
- # end
242
-
243
- # let (:form) { OverwritingForm.new(Session.new) }
244
-
245
- # # valid.
246
- # it do
247
- # form.validate({username: "Helloween"}).must_equal true
248
- # end
249
-
250
- # # invalid.
251
- # it "whoo" do
252
- # form.validate({}).must_equal false
253
- # form.errors.messages.inspect.must_equal "{:username=>[\"username can't be blank\"]}"
254
- # end
255
- # end
256
-
257
-
258
- describe "inherit: true in same group" do
259
- class InheritSameGroupForm < Reform::Form
260
- include Reform::Form::Dry::Validations
261
-
262
- property :username
263
- property :email
264
-
265
- validation :email do
266
- key(:email).required
267
- end
268
-
269
- validation :email, inherit: true do # extends the above.
270
- key(:username).required
271
- end
272
- end
273
-
274
- let (:form) { InheritSameGroupForm.new(Session.new) }
275
-
276
- # valid.
277
- it do
278
- form.validate({username: "Helloween", email: 9}).must_equal true
279
- end
280
-
281
- # invalid.
282
- it do
283
- form.validate({}).must_equal false
284
- form.errors.messages.inspect.must_equal "{:email=>[\"is missing\"], :username=>[\"is missing\"]}"
285
- end
286
- end
287
-
288
-
289
- describe "if: with lambda" do
290
- class IfWithLambdaForm < Reform::Form
291
- include Reform::Form::Dry::Validations # ::build_errors.
292
-
293
- property :username
294
- property :email
295
- property :password
296
-
297
- validation :email do
298
- key(:email).required
299
- end
300
-
301
- # run this is :email group is true.
302
- validation :after_email, if: lambda { |results| results[:email]==true } do # extends the above.
303
- key(:username).required
304
- end
305
-
306
- # block gets evaled in form instance context.
307
- validation :password, if: lambda { |results| email == "john@trb.org" } do
308
- key(:password).required
309
- end
310
- end
311
-
312
- let (:form) { IfWithLambdaForm.new(Session.new) }
313
-
314
- # valid.
315
- it do
316
- form.validate({username: "Strung Out", email: 9}).must_equal true
317
- end
318
-
319
- # invalid.
320
- it do
321
- form.validate({email: 9}).must_equal false
322
- form.errors.messages.inspect.must_equal "{:username=>[\"is missing\"]}"
323
- end
324
- end
325
-
326
-
327
- # Currenty dry-v don't support that option, it doesn't make sense
328
- # I've talked to @solnic and he plans to add a "hint" feature to show
329
- # more errors messages than only those that have failed.
330
- #
331
- # describe "multiple errors for property" do
332
- # class MultipleErrorsForPropertyForm < Reform::Form
333
- # include Reform::Form::Dry::Validations
334
-
335
- # property :username
336
-
337
- # validation :default do
338
- # key(:username) do |username|
339
- # username.filled? | (username.min_size?(2) & username.max_size?(3))
340
- # end
341
- # end
342
- # end
343
-
344
- # let (:form) { MultipleErrorsForPropertyForm.new(Session.new) }
345
-
346
- # # valid.
347
- # it do
348
- # form.validate({username: ""}).must_equal false
349
- # form.errors.messages.inspect.must_equal "{:username=>[\"username must be filled\", \"username is not proper size\"]}"
350
- # end
351
- # end
352
- end