reform 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
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