reform 2.2.4 → 2.3.0.rc1

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 (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