reform 2.2.4 → 2.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -7
  3. data/CHANGES.md +26 -4
  4. data/CONTRIBUTING.md +31 -0
  5. data/Gemfile +1 -12
  6. data/ISSUE_TEMPLATE.md +25 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +3 -3
  9. data/lib/reform.rb +1 -0
  10. data/lib/reform/contract.rb +1 -11
  11. data/lib/reform/contract/validate.rb +49 -23
  12. data/lib/reform/errors.rb +49 -0
  13. data/lib/reform/form.rb +20 -5
  14. data/lib/reform/form/dry.rb +57 -29
  15. data/lib/reform/form/populator.rb +2 -16
  16. data/lib/reform/form/prepopulate.rb +1 -1
  17. data/lib/reform/form/validate.rb +10 -2
  18. data/lib/reform/result.rb +63 -0
  19. data/lib/reform/validation.rb +19 -13
  20. data/lib/reform/validation/groups.rb +11 -25
  21. data/lib/reform/version.rb +1 -1
  22. data/reform.gemspec +7 -6
  23. data/test/benchmarking.rb +39 -5
  24. data/test/call_test.rb +1 -1
  25. data/test/changed_test.rb +1 -1
  26. data/test/coercion_test.rb +2 -2
  27. data/test/composition_test.rb +47 -9
  28. data/test/contract_test.rb +5 -5
  29. data/test/default_test.rb +1 -1
  30. data/test/deserialize_test.rb +3 -3
  31. data/test/errors_test.rb +36 -21
  32. data/test/feature_test.rb +1 -1
  33. data/test/fixtures/dry_error_messages.yml +70 -23
  34. data/test/form_option_test.rb +3 -3
  35. data/test/form_test.rb +3 -3
  36. data/test/from_test.rb +2 -2
  37. data/test/inherit_test.rb +44 -51
  38. data/test/module_test.rb +12 -12
  39. data/test/parse_option_test.rb +40 -0
  40. data/test/parse_pipeline_test.rb +2 -2
  41. data/test/populate_test.rb +59 -19
  42. data/test/populator_skip_test.rb +9 -8
  43. data/test/prepopulator_test.rb +3 -3
  44. data/test/readable_test.rb +2 -2
  45. data/test/readonly_test.rb +1 -1
  46. data/test/reform_test.rb +16 -31
  47. data/test/save_test.rb +23 -8
  48. data/test/setup_test.rb +2 -2
  49. data/test/skip_if_test.rb +4 -4
  50. data/test/skip_setter_and_getter_test.rb +1 -1
  51. data/test/test_helper.rb +13 -10
  52. data/test/validate_test.rb +18 -18
  53. data/test/validation/dry_validation_test.rb +430 -117
  54. data/test/validation/result_test.rb +79 -0
  55. data/test/validation_library_provided_test.rb +16 -0
  56. data/test/virtual_test.rb +1 -1
  57. data/test/writeable_test.rb +31 -2
  58. metadata +42 -23
  59. data/gemfiles/Gemfile.disposable-0.3 +0 -6
  60. data/lib/reform/contract/errors.rb +0 -43
  61. data/lib/reform/form/mongoid.rb +0 -37
  62. data/lib/reform/form/orm.rb +0 -26
  63. data/lib/reform/mongoid.rb +0 -4
  64. data/test/deprecation_test.rb +0 -27
  65. data/test/validation/dry_test.rb +0 -60
  66. data/test/validation/errors.yml +0 -4
@@ -0,0 +1,79 @@
1
+ require "test_helper"
2
+
3
+ class ErrorsResultTest < Minitest::Spec
4
+ MyResult = Struct.new(:success?, :errors) do
5
+ def failure?; !success? end
6
+ end
7
+
8
+ # TODO: errors(args) not tested.
9
+
10
+ describe "Contract::Result#success?" do
11
+ let (:failed) { MyResult.new(false) }
12
+ let (:succeeded) { MyResult.new(true) }
13
+
14
+ it { Reform::Contract::Result.new([failed, failed]).success?.must_equal false }
15
+ it { Reform::Contract::Result.new([succeeded, failed]).success?.must_equal false }
16
+ it { Reform::Contract::Result.new([failed, succeeded]).success?.must_equal false }
17
+ it { Reform::Contract::Result.new([succeeded, succeeded]).success?.must_equal true }
18
+ end
19
+
20
+ describe "Contract::Result#errors" do
21
+ let (:results) {
22
+ [
23
+ MyResult.new(false, { title: ["must be filled"], nested: { something: [] } }),
24
+ MyResult.new(false, { length: ["no Int"] })
25
+ ]
26
+ }
27
+
28
+ it { Reform::Contract::Result.new(results).errors.must_equal({:title=>["must be filled"], :length=>["no Int"]}) }
29
+ end
30
+
31
+ describe "Result::Pointer" do
32
+ let (:errors) do # dry result #errors format.
33
+ {
34
+ title: ["ignore"],
35
+ artist: { age: ["too old"],
36
+ bands: {
37
+ 0 => { name: "too new school" },
38
+ 1 => { name: "too boring" },
39
+ }
40
+ }
41
+ }
42
+ end
43
+
44
+ let (:top) { Reform::Contract::Result::Pointer.new(MyResult.new(false, errors), []) }
45
+ it { top.success?.must_equal false }
46
+ it { top.errors.must_equal errors }
47
+
48
+ let (:artist) { Reform::Contract::Result::Pointer.new(MyResult.new(false, errors), [:artist]) }
49
+ it { artist.success?.must_equal false }
50
+ it { artist.errors.must_equal({:age=>["too old"], :bands=>{0=>{:name=>"too new school"}, 1=>{:name=>"too boring"}}}) }
51
+
52
+ let (:band) { Reform::Contract::Result::Pointer.new(MyResult.new(false, errors), [:artist, :bands, 1]) }
53
+ it { band.success?.must_equal false }
54
+ it { band.errors.must_equal({:name=>"too boring"}) }
55
+
56
+ describe "advance" do
57
+ let(:advanced) { artist.advance(:bands, 1) }
58
+
59
+ it { advanced.success?.must_equal false }
60
+ it { advanced.errors.must_equal({:name=>"too boring"}) }
61
+
62
+ it { artist.advance([:absolute, :nonsense]).must_equal nil }
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ # validation group:
69
+
70
+ # form.errors/messages/hint(*args) ==> {:title: [..]}
71
+ # @call_result.errors/messages/hint(*args) }
72
+
73
+
74
+
75
+ # # result = Result(original_result => [:band, :label], my_local_result => [] )
76
+ # # result.messages(locale: :en) merges original_result and my_local_result
77
+
78
+ # form.errors => Result(fetch tree of all nested forms.messages(*args))
79
+
@@ -0,0 +1,16 @@
1
+ require 'reform'
2
+ require 'minitest/autorun'
3
+
4
+ class ValidationLibraryProvidedTest < MiniTest::Spec
5
+ it 'no validation library loaded' do
6
+ assert_raises Reform::Validation::NoValidationLibraryError do
7
+ class PersonForm < Reform::Form
8
+ property :name
9
+
10
+ validation do
11
+ required(:name).maybe(:str?)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class VirtualTest < MiniTest::Spec
4
- class CreditCardForm < Reform::Form
4
+ class CreditCardForm < TestForm
5
5
  property :credit_card_number, virtual: true # no read, no write, it's virtual.
6
6
  end
7
7
 
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  class WriteableTest < MiniTest::Spec
4
4
  Location = Struct.new(:country)
5
5
 
6
- class LocationForm < Reform::Form
6
+ class LocationForm < TestForm
7
7
  property :country, writeable: false
8
8
  end
9
9
 
@@ -26,4 +26,33 @@ class WriteableTest < MiniTest::Spec
26
26
 
27
27
  hash.must_equal("country"=> "Germany")
28
28
  end
29
- end
29
+ end
30
+
31
+ # writable option is alias of writeable option.
32
+ class WritableTest < MiniTest::Spec
33
+ Location = Struct.new(:country)
34
+
35
+ class LocationForm < TestForm
36
+ property :country, writable: false
37
+ end
38
+
39
+ let (:loc) { Location.new("Australia") }
40
+ let (:form) { LocationForm.new(loc) }
41
+
42
+ it do
43
+ form.country.must_equal "Australia"
44
+
45
+ form.validate("country" => "Germany") # this usually won't change when submitting.
46
+ form.country.must_equal "Germany"
47
+
48
+ form.sync
49
+ loc.country.must_equal "Australia" # the writer wasn't called.
50
+
51
+ hash = {}
52
+ form.save do |nested|
53
+ hash = nested
54
+ end
55
+
56
+ hash.must_equal("country"=> "Germany")
57
+ end
58
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reform
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.4
4
+ version: 2.3.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
- - Garrett Heinlen
8
+ - Fran Worley
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-01-31 00:00:00.000000000 Z
12
+ date: 2017-02-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: disposable
@@ -17,14 +17,34 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 0.4.1
20
+ version: 0.4.2
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.5.0
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
28
  - - ">="
26
29
  - !ruby/object:Gem::Version
27
- version: 0.4.1
30
+ version: 0.4.2
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.0
34
+ - !ruby/object:Gem::Dependency
35
+ name: uber
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "<"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
28
48
  - !ruby/object:Gem::Dependency
29
49
  name: representable
30
50
  requirement: !ruby/object:Gem::Requirement
@@ -121,18 +141,18 @@ dependencies:
121
141
  requirements:
122
142
  - - ">="
123
143
  - !ruby/object:Gem::Version
124
- version: 0.10.0
144
+ version: 0.10.1
125
145
  type: :development
126
146
  prerelease: false
127
147
  version_requirements: !ruby/object:Gem::Requirement
128
148
  requirements:
129
149
  - - ">="
130
150
  - !ruby/object:Gem::Version
131
- version: 0.10.0
151
+ version: 0.10.1
132
152
  description: Form object decoupled from models.
133
153
  email:
134
154
  - apotonick@gmail.com
135
- - heinleng@gmail.com
155
+ - frances@safetytoolbox.co.uk
136
156
  executables: []
137
157
  extensions: []
138
158
  extra_rdoc_files: []
@@ -140,28 +160,27 @@ files:
140
160
  - ".gitignore"
141
161
  - ".travis.yml"
142
162
  - CHANGES.md
163
+ - CONTRIBUTING.md
143
164
  - Gemfile
165
+ - ISSUE_TEMPLATE.md
144
166
  - LICENSE.txt
145
167
  - README.md
146
168
  - Rakefile
147
169
  - TODO.md
148
- - gemfiles/Gemfile.disposable-0.3
149
170
  - lib/reform.rb
150
171
  - lib/reform/contract.rb
151
- - lib/reform/contract/errors.rb
152
172
  - lib/reform/contract/validate.rb
173
+ - lib/reform/errors.rb
153
174
  - lib/reform/form.rb
154
175
  - lib/reform/form/call.rb
155
176
  - lib/reform/form/coercion.rb
156
177
  - lib/reform/form/composition.rb
157
178
  - lib/reform/form/dry.rb
158
179
  - lib/reform/form/module.rb
159
- - lib/reform/form/mongoid.rb
160
- - lib/reform/form/orm.rb
161
180
  - lib/reform/form/populator.rb
162
181
  - lib/reform/form/prepopulate.rb
163
182
  - lib/reform/form/validate.rb
164
- - lib/reform/mongoid.rb
183
+ - lib/reform/result.rb
165
184
  - lib/reform/validation.rb
166
185
  - lib/reform/validation/groups.rb
167
186
  - lib/reform/version.rb
@@ -173,7 +192,6 @@ files:
173
192
  - test/composition_test.rb
174
193
  - test/contract_test.rb
175
194
  - test/default_test.rb
176
- - test/deprecation_test.rb
177
195
  - test/deserialize_test.rb
178
196
  - test/errors_test.rb
179
197
  - test/feature_test.rb
@@ -183,6 +201,7 @@ files:
183
201
  - test/from_test.rb
184
202
  - test/inherit_test.rb
185
203
  - test/module_test.rb
204
+ - test/parse_option_test.rb
186
205
  - test/parse_pipeline_test.rb
187
206
  - test/populate_test.rb
188
207
  - test/populator_skip_test.rb
@@ -197,12 +216,12 @@ files:
197
216
  - test/skip_setter_and_getter_test.rb
198
217
  - test/test_helper.rb
199
218
  - test/validate_test.rb
200
- - test/validation/dry_test.rb
201
219
  - test/validation/dry_validation_test.rb
202
- - test/validation/errors.yml
220
+ - test/validation/result_test.rb
221
+ - test/validation_library_provided_test.rb
203
222
  - test/virtual_test.rb
204
223
  - test/writeable_test.rb
205
- homepage: https://github.com/apotonick/reform
224
+ homepage: https://github.com/trailblazer/reform
206
225
  licenses:
207
226
  - MIT
208
227
  metadata: {}
@@ -217,12 +236,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
217
236
  version: '0'
218
237
  required_rubygems_version: !ruby/object:Gem::Requirement
219
238
  requirements:
220
- - - ">="
239
+ - - ">"
221
240
  - !ruby/object:Gem::Version
222
- version: '0'
241
+ version: 1.3.1
223
242
  requirements: []
224
243
  rubyforge_project:
225
- rubygems_version: 2.5.1
244
+ rubygems_version: 2.6.3
226
245
  signing_key:
227
246
  specification_version: 4
228
247
  summary: Form object decoupled from models with validation, population and presentation.
@@ -234,7 +253,6 @@ test_files:
234
253
  - test/composition_test.rb
235
254
  - test/contract_test.rb
236
255
  - test/default_test.rb
237
- - test/deprecation_test.rb
238
256
  - test/deserialize_test.rb
239
257
  - test/errors_test.rb
240
258
  - test/feature_test.rb
@@ -244,6 +262,7 @@ test_files:
244
262
  - test/from_test.rb
245
263
  - test/inherit_test.rb
246
264
  - test/module_test.rb
265
+ - test/parse_option_test.rb
247
266
  - test/parse_pipeline_test.rb
248
267
  - test/populate_test.rb
249
268
  - test/populator_skip_test.rb
@@ -258,8 +277,8 @@ test_files:
258
277
  - test/skip_setter_and_getter_test.rb
259
278
  - test/test_helper.rb
260
279
  - test/validate_test.rb
261
- - test/validation/dry_test.rb
262
280
  - test/validation/dry_validation_test.rb
263
- - test/validation/errors.yml
281
+ - test/validation/result_test.rb
282
+ - test/validation_library_provided_test.rb
264
283
  - test/virtual_test.rb
265
284
  - test/writeable_test.rb
@@ -1,6 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in reform.gemspec
4
- gemspec :path => '../'
5
-
6
- gem 'minitest'
@@ -1,43 +0,0 @@
1
- class Reform::Contract::Errors
2
- def initialize(*)
3
- @errors = {}
4
- end
5
-
6
- module Merge
7
- def merge!(errors, prefix)
8
- errors.messages.each do |field, msgs|
9
- unless field.to_sym == :base
10
- field = (prefix+[field]).join(".").to_sym # TODO: why is that a symbol in Rails?
11
- end
12
-
13
- msgs.each do |msg|
14
- next if messages[field] and messages[field].include?(msg)
15
- add(field, msg)
16
- end # Forms now contains a plain errors hash. the errors for each item are still available in item.errors.
17
- end
18
- end
19
-
20
- def to_s
21
- messages.inspect
22
- end
23
- end
24
- include Merge
25
-
26
- def add(field, message)
27
- @errors[field] ||= []
28
- @errors[field] << message
29
- end
30
-
31
- def messages
32
- @errors
33
- end
34
-
35
- def empty?
36
- @errors.empty?
37
- end
38
-
39
- # needed by Rails form builder.
40
- def [](name)
41
- @errors[name] || []
42
- end
43
- end
@@ -1,37 +0,0 @@
1
- module Reform::Form::Mongoid
2
- def self.included(base)
3
- base.class_eval do
4
- register_feature Reform::Form::Mongoid
5
- include Reform::Form::ActiveModel
6
- include Reform::Form::ORM
7
- extend ClassMethods
8
- end
9
- end
10
-
11
- module ClassMethods
12
- def validates_uniqueness_of(attribute, options={})
13
- options = options.merge(:attributes => [attribute])
14
- validates_with(UniquenessValidator, options)
15
- end
16
- def i18n_scope
17
- :mongoid
18
- end
19
- end
20
-
21
-
22
- def self.mongoid_namespace
23
- if mongoid_is_4_or_more?
24
- 'Validatable'
25
- else
26
- 'Validations'
27
- end
28
- end
29
-
30
- def self.mongoid_is_4_or_more?
31
- Mongoid::VERSION.split('.').first.to_i >= 4
32
- end
33
-
34
- UniquenessValidator = Class.new("::Mongoid::#{mongoid_namespace}::UniquenessValidator".constantize) do
35
- include Reform::Form::ORM::UniquenessValidator
36
- end
37
- end
@@ -1,26 +0,0 @@
1
- module Reform::Form::ORM
2
- def model_for_property(name)
3
- return model unless is_a?(Reform::Form::Composition) # i am too lazy for proper inheritance. there should be a ActiveRecord::Composition that handles this.
4
-
5
- model_name = options_for(name)[:on]
6
- model[model_name]
7
- end
8
-
9
- module UniquenessValidator
10
- # when calling validates it should create the Vali instance already and set @klass there! # TODO: fix this in AM.
11
- def validate(form)
12
- property = attributes.first
13
-
14
- # here is the thing: why does AM::UniquenessValidator require a filled-out record to work properly? also, why do we need to set
15
- # the class? it would be way easier to pass #validate a hash of attributes and get back an errors hash.
16
- # the class for the finder could either be infered from the record or set in the validator instance itself in the call to ::validates.
17
- record = form.model_for_property(property)
18
- record.send("#{property}=", form.send(property))
19
-
20
- @klass = record.class # this is usually done in the super-sucky #setup method.
21
- super(record).tap do |res|
22
- form.errors.add(property, record.errors.first.last) if record.errors.present?
23
- end
24
- end
25
- end
26
- end