reform 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGES.md +415 -0
  5. data/Gemfile +19 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +339 -0
  8. data/Rakefile +15 -0
  9. data/TODO.md +45 -0
  10. data/gemfiles/Gemfile.disposable-0.3 +6 -0
  11. data/lib/reform.rb +8 -0
  12. data/lib/reform/contract.rb +77 -0
  13. data/lib/reform/contract/errors.rb +43 -0
  14. data/lib/reform/contract/validate.rb +33 -0
  15. data/lib/reform/form.rb +94 -0
  16. data/lib/reform/form/call.rb +23 -0
  17. data/lib/reform/form/coercion.rb +3 -0
  18. data/lib/reform/form/composition.rb +34 -0
  19. data/lib/reform/form/dry.rb +67 -0
  20. data/lib/reform/form/module.rb +27 -0
  21. data/lib/reform/form/mongoid.rb +37 -0
  22. data/lib/reform/form/orm.rb +26 -0
  23. data/lib/reform/form/populator.rb +123 -0
  24. data/lib/reform/form/prepopulate.rb +24 -0
  25. data/lib/reform/form/validate.rb +60 -0
  26. data/lib/reform/mongoid.rb +4 -0
  27. data/lib/reform/validation.rb +40 -0
  28. data/lib/reform/validation/groups.rb +73 -0
  29. data/lib/reform/version.rb +3 -0
  30. data/reform.gemspec +29 -0
  31. data/test/benchmarking.rb +26 -0
  32. data/test/call_test.rb +23 -0
  33. data/test/changed_test.rb +41 -0
  34. data/test/coercion_test.rb +66 -0
  35. data/test/composition_test.rb +149 -0
  36. data/test/contract_test.rb +77 -0
  37. data/test/default_test.rb +22 -0
  38. data/test/deprecation_test.rb +27 -0
  39. data/test/deserialize_test.rb +104 -0
  40. data/test/errors_test.rb +165 -0
  41. data/test/feature_test.rb +65 -0
  42. data/test/fixtures/dry_error_messages.yml +44 -0
  43. data/test/form_option_test.rb +24 -0
  44. data/test/form_test.rb +57 -0
  45. data/test/from_test.rb +75 -0
  46. data/test/inherit_test.rb +119 -0
  47. data/test/module_test.rb +142 -0
  48. data/test/parse_pipeline_test.rb +15 -0
  49. data/test/populate_test.rb +270 -0
  50. data/test/populator_skip_test.rb +28 -0
  51. data/test/prepopulator_test.rb +112 -0
  52. data/test/read_only_test.rb +3 -0
  53. data/test/readable_test.rb +30 -0
  54. data/test/readonly_test.rb +14 -0
  55. data/test/reform_test.rb +223 -0
  56. data/test/save_test.rb +89 -0
  57. data/test/setup_test.rb +48 -0
  58. data/test/skip_if_test.rb +74 -0
  59. data/test/skip_setter_and_getter_test.rb +54 -0
  60. data/test/test_helper.rb +49 -0
  61. data/test/validate_test.rb +420 -0
  62. data/test/validation/dry_test.rb +60 -0
  63. data/test/validation/dry_validation_test.rb +352 -0
  64. data/test/validation/errors.yml +4 -0
  65. data/test/virtual_test.rb +24 -0
  66. data/test/writeable_test.rb +29 -0
  67. metadata +265 -0
@@ -0,0 +1,60 @@
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
+ # # }
@@ -0,0 +1,352 @@
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
@@ -0,0 +1,4 @@
1
+ en:
2
+ errors:
3
+ music_taste_ok?: "You are a bad person"
4
+
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class VirtualTest < MiniTest::Spec
4
+ class CreditCardForm < Reform::Form
5
+ property :credit_card_number, virtual: true # no read, no write, it's virtual.
6
+ end
7
+
8
+ let (:form) { CreditCardForm.new(Object.new) }
9
+
10
+ it {
11
+ form.validate("credit_card_number" => "123")
12
+
13
+ form.credit_card_number.must_equal "123" # this is still readable in the UI.
14
+
15
+ form.sync
16
+
17
+ hash = {}
18
+ form.save do |nested|
19
+ hash = nested
20
+ end
21
+
22
+ hash.must_equal("credit_card_number"=> "123")
23
+ }
24
+ end
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class WriteableTest < MiniTest::Spec
4
+ Location = Struct.new(:country)
5
+
6
+ class LocationForm < Reform::Form
7
+ property :country, writeable: false
8
+ end
9
+
10
+ let (:loc) { Location.new("Australia") }
11
+ let (:form) { LocationForm.new(loc) }
12
+
13
+ it do
14
+ form.country.must_equal "Australia"
15
+
16
+ form.validate("country" => "Germany") # this usually won't change when submitting.
17
+ form.country.must_equal "Germany"
18
+
19
+ form.sync
20
+ loc.country.must_equal "Australia" # the writer wasn't called.
21
+
22
+ hash = {}
23
+ form.save do |nested|
24
+ hash = nested
25
+ end
26
+
27
+ hash.must_equal("country"=> "Germany")
28
+ end
29
+ end