reform 2.2.4 → 2.6.2

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 (76) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +17 -0
  3. data/.gitignore +5 -1
  4. data/CHANGES.md +80 -4
  5. data/CONTRIBUTING.md +31 -0
  6. data/Gemfile +2 -16
  7. data/ISSUE_TEMPLATE.md +25 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.md +10 -12
  10. data/Rakefile +6 -10
  11. data/lib/reform/contract/custom_error.rb +41 -0
  12. data/lib/reform/contract/validate.rb +53 -23
  13. data/lib/reform/contract.rb +7 -17
  14. data/lib/reform/errors.rb +61 -0
  15. data/lib/reform/form/call.rb +1 -1
  16. data/lib/reform/form/composition.rb +2 -2
  17. data/lib/reform/form/dry/input_hash.rb +37 -0
  18. data/lib/reform/form/dry.rb +25 -35
  19. data/lib/reform/form/populator.rb +20 -26
  20. data/lib/reform/form/prepopulate.rb +5 -4
  21. data/lib/reform/form/validate.rb +29 -14
  22. data/lib/reform/form.rb +36 -10
  23. data/lib/reform/result.rb +90 -0
  24. data/lib/reform/validation/groups.rb +12 -28
  25. data/lib/reform/validation.rb +19 -11
  26. data/lib/reform/version.rb +1 -1
  27. data/lib/reform.rb +1 -0
  28. data/reform.gemspec +13 -13
  29. data/test/benchmarking.rb +39 -6
  30. data/test/call_test.rb +9 -9
  31. data/test/changed_test.rb +14 -14
  32. data/test/coercion_test.rb +57 -25
  33. data/test/composition_test.rb +85 -49
  34. data/test/contract/custom_error_test.rb +55 -0
  35. data/test/contract_test.rb +20 -20
  36. data/test/default_test.rb +4 -4
  37. data/test/deserialize_test.rb +17 -20
  38. data/test/docs/validation_test.rb +134 -0
  39. data/test/errors_test.rb +142 -82
  40. data/test/feature_test.rb +10 -12
  41. data/test/fixtures/dry_error_messages.yml +83 -23
  42. data/test/form_option_test.rb +5 -5
  43. data/test/form_test.rb +8 -8
  44. data/test/from_test.rb +18 -22
  45. data/test/inherit_test.rb +54 -68
  46. data/test/module_test.rb +27 -32
  47. data/test/parse_option_test.rb +40 -0
  48. data/test/parse_pipeline_test.rb +4 -4
  49. data/test/populate_test.rb +217 -100
  50. data/test/populator_skip_test.rb +11 -11
  51. data/test/prepopulator_test.rb +24 -25
  52. data/test/read_only_test.rb +12 -1
  53. data/test/readable_test.rb +9 -9
  54. data/test/reform_test.rb +47 -66
  55. data/test/save_test.rb +35 -23
  56. data/test/setup_test.rb +17 -17
  57. data/test/skip_if_test.rb +33 -22
  58. data/test/skip_setter_and_getter_test.rb +9 -10
  59. data/test/test_helper.rb +23 -14
  60. data/test/validate_test.rb +165 -145
  61. data/test/validation/dry_validation_test.rb +630 -146
  62. data/test/validation/result_test.rb +77 -0
  63. data/test/validation_library_provided_test.rb +16 -0
  64. data/test/virtual_test.rb +47 -7
  65. data/test/writeable_test.rb +38 -9
  66. metadata +46 -38
  67. data/.travis.yml +0 -11
  68. data/gemfiles/Gemfile.disposable-0.3 +0 -6
  69. data/lib/reform/contract/errors.rb +0 -43
  70. data/lib/reform/form/mongoid.rb +0 -37
  71. data/lib/reform/form/orm.rb +0 -26
  72. data/lib/reform/mongoid.rb +0 -4
  73. data/test/deprecation_test.rb +0 -27
  74. data/test/readonly_test.rb +0 -14
  75. data/test/validation/dry_test.rb +0 -60
  76. data/test/validation/errors.yml +0 -4
data/test/benchmarking.rb CHANGED
@@ -1,15 +1,48 @@
1
- require 'reform'
2
- require 'ostruct'
3
- require 'benchmark'
1
+ require "reform"
2
+ require "benchmark/ips"
3
+ require "reform/form/dry"
4
4
 
5
5
  class BandForm < Reform::Form
6
- property :name, validates: {presence: true}
6
+ feature Reform::Form::Dry
7
+ property :name #, validates: {presence: true}
8
+ collection :songs do
9
+ property :title #, validates: {presence: true}
10
+ end
11
+ end
7
12
 
13
+ class OptimizedBandForm < Reform::Form
14
+ feature Reform::Form::Dry
15
+ property :name #, validates: {presence: true}
8
16
  collection :songs do
9
- property :title, validates: {presence: true}
17
+ property :title #, validates: {presence: true}
18
+
19
+ def deserializer(*args)
20
+ # DISCUSS: should we simply delegate to class and sort out memoizing there?
21
+ self.class.deserializer_class || self.class.deserializer_class = deserializer!(*args)
22
+ end
23
+ end
24
+
25
+ def deserializer(*args)
26
+ # DISCUSS: should we simply delegate to class and sort out memoizing there?
27
+ self.class.deserializer_class || self.class.deserializer_class = deserializer!(*args)
10
28
  end
11
29
  end
12
30
 
31
+ songs = 10.times.collect { OpenStruct.new(title: "Be Stag") }
32
+ band = OpenStruct.new(name: "Teenage Bottlerock", songs: songs)
33
+
34
+ unoptimized_form = BandForm.new(band)
35
+ optimized_form = OptimizedBandForm.new(band)
36
+
37
+ songs_params = songs_params = 10.times.collect { {title: "Commando"} }
38
+
39
+ Benchmark.ips do |x|
40
+ x.report("2.2") { BandForm.new(band).validate("name" => "Ramones", "songs" => songs_params) }
41
+ x.report("2.3") { OptimizedBandForm.new(band).validate("name" => "Ramones", "songs" => songs_params) }
42
+ end
43
+
44
+ exit
45
+
13
46
  songs = 50.times.collect { OpenStruct.new(title: "Be Stag") }
14
47
  band = OpenStruct.new(name: "Teenage Bottlerock", songs: songs)
15
48
 
@@ -23,4 +56,4 @@ time = Benchmark.measure do
23
56
  end
24
57
  end
25
58
 
26
- puts time
59
+ puts time
data/test/call_test.rb CHANGED
@@ -3,21 +3,21 @@ require "test_helper"
3
3
  class CallTest < Minitest::Spec
4
4
  Song = Struct.new(:title)
5
5
 
6
- class SongForm < Reform::Form
6
+ class SongForm < TestForm
7
7
  property :title
8
8
 
9
9
  validation do
10
- key(:title).required
10
+ params { required(:title).filled }
11
11
  end
12
12
  end
13
13
 
14
- let (:form) { SongForm.new(Song.new) }
14
+ let(:form) { SongForm.new(Song.new) }
15
15
 
16
- it { form.(title: "True North").success?.must_equal true }
17
- it { form.(title: "True North").failure?.must_equal false }
18
- it { form.(title: "").success?.must_equal false }
19
- it { form.(title: "").failure?.must_equal true }
16
+ it { assert form.(title: "True North").success? }
17
+ it { refute form.(title: "True North").failure? }
18
+ it { refute form.(title: "").success? }
19
+ it { assert form.(title: "").failure? }
20
20
 
21
- it { form.(title: "True North").errors.messages.must_equal({}) }
22
- it { form.(title: "").errors.messages.must_equal({:title=>["must be filled"]}) }
21
+ it { assert_equal form.(title: "True North").errors.messages, {} }
22
+ it { assert_equal form.(title: "").errors.messages, title: ["must be filled"] }
23
23
  end
data/test/changed_test.rb CHANGED
@@ -1,12 +1,12 @@
1
- require 'test_helper'
2
- require 'reform/form/coercion'
1
+ require "test_helper"
2
+ require "reform/form/coercion"
3
3
 
4
4
  class ChangedTest < MiniTest::Spec
5
5
  Song = Struct.new(:title, :album, :composer)
6
6
  Album = Struct.new(:name, :songs, :artist)
7
7
  Artist = Struct.new(:name)
8
8
 
9
- class AlbumForm < Reform::Form
9
+ class AlbumForm < TestForm
10
10
  property :name
11
11
 
12
12
  collection :songs do
@@ -18,24 +18,24 @@ class ChangedTest < MiniTest::Spec
18
18
  end
19
19
  end
20
20
 
21
- let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
22
- let (:composer) { Artist.new("Greg Graffin") }
23
- let (:album) { Album.new("The Dissent Of Man", [song_with_composer]) }
21
+ let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
22
+ let(:composer) { Artist.new("Greg Graffin") }
23
+ let(:album) { Album.new("The Dissent Of Man", [song_with_composer]) }
24
24
 
25
- let (:form) { AlbumForm.new(album) }
25
+ let(:form) { AlbumForm.new(album) }
26
26
 
27
27
  # nothing changed after setup.
28
28
  it do
29
- form.changed?(:name).must_equal false
30
- form.songs[0].changed?(:title).must_equal false
31
- form.songs[0].composer.changed?(:name).must_equal false
29
+ refute form.changed?(:name)
30
+ refute form.songs[0].changed?(:title)
31
+ refute form.songs[0].composer.changed?(:name)
32
32
  end
33
33
 
34
34
  # after validate, things might have changed.
35
35
  it do
36
36
  form.validate("name" => "Out Of Bounds", "songs" => [{"composer" => {"name" => "Ingemar Jansson & Mikael Danielsson"}}])
37
- form.changed?(:name).must_equal true
38
- form.songs[0].changed?(:title).must_equal false
39
- form.songs[0].composer.changed?(:name).must_equal true
37
+ assert form.changed?(:name)
38
+ refute form.songs[0].changed?(:title)
39
+ assert form.songs[0].composer.changed?(:name)
40
40
  end
41
- end
41
+ end
@@ -1,21 +1,23 @@
1
1
  require "test_helper"
2
2
  require "reform/form/coercion"
3
+ require "disposable/twin/property/hash"
3
4
 
4
5
  class CoercionTest < BaseTest
5
6
  class Irreversible
6
7
  def self.call(value)
7
- value*2
8
+ value * 2
8
9
  end
9
10
  end
10
11
 
11
- class Form < Reform::Form
12
+ class Form < TestForm
12
13
  feature Coercion
14
+ include Disposable::Twin::Property::Hash
13
15
 
14
- property :released_at, type: Types::Form::DateTime
16
+ property :released_at, type: Types::Params::DateTime
15
17
 
16
18
  property :hit do
17
- property :length, type: Types::Form::Int
18
- property :good, type: Types::Form::Bool
19
+ property :length, type: Types::Params::Integer
20
+ property :good, type: Types::Params::Bool
19
21
  end
20
22
 
21
23
  property :band do
@@ -23,44 +25,74 @@ class CoercionTest < BaseTest
23
25
  property :value, type: Irreversible
24
26
  end
25
27
  end
28
+
29
+ property :metadata, field: :hash do
30
+ property :publication_settings do
31
+ property :featured, type: Types::Params::Bool
32
+ end
33
+ end
26
34
  end
27
35
 
28
36
  subject do
29
37
  Form.new(album)
30
38
  end
31
39
 
32
- let (:album) {
40
+ let(:album) do
33
41
  OpenStruct.new(
34
- :released_at => "31/03/1981",
35
- :hit => OpenStruct.new(:length => "312"),
36
- :band => Band.new(OpenStruct.new(:value => "9999.99"))
42
+ released_at: "31/03/1981",
43
+ hit: OpenStruct.new(length: "312"),
44
+ band: Band.new(OpenStruct.new(value: "9999.99")),
45
+ metadata: {}
37
46
  )
38
- }
47
+ end
39
48
 
40
49
  # it { subject.released_at.must_be_kind_of DateTime }
41
- it { subject.released_at.must_equal "31/03/1981" } # NO coercion in setup.
42
- it { subject.hit.length.must_equal "312" }
43
- it { subject.band.label.value.must_equal "9999.99" }
44
-
50
+ it { assert_equal subject.released_at, "31/03/1981" } # NO coercion in setup.
51
+ it { assert_equal subject.hit.length, "312" }
52
+ it { assert_equal subject.band.label.value, "9999.99" }
45
53
 
46
- let (:params) {
54
+ let(:params) do
47
55
  {
48
- :released_at => "30/03/1981",
49
- :hit => {:length => "312"},
50
- :band => {:label => {:value => "9999.99"}}
56
+ released_at: "30/03/1981",
57
+ hit: {
58
+ length: "312",
59
+ good: "0",
60
+ },
61
+ band: {
62
+ label: {
63
+ value: "9999.99"
64
+ }
65
+ },
66
+ metadata: {
67
+ publication_settings: {
68
+ featured: "0"
69
+ }
70
+ }
51
71
  }
52
- }
53
-
72
+ end
54
73
 
55
74
  # validate
56
75
  describe "#validate" do
57
76
  before { subject.validate(params) }
58
77
 
59
- it { subject.released_at.must_equal DateTime.parse("30/03/1981") }
60
- it { subject.hit.length.must_equal 312 }
61
- it { subject.hit.good.must_equal nil }
62
- it { subject.band.label.value.must_equal "9999.999999.99" } # coercion happened once.
78
+ it { assert_equal subject.released_at, DateTime.parse("30/03/1981") }
79
+ it { assert_equal subject.hit.length, 312 }
80
+ it { assert_equal subject.hit.good, false }
81
+ it { assert_equal subject.band.label.value, "9999.999999.99" } # coercion happened once.
82
+ it { assert_equal subject.metadata.publication_settings.featured, false }
63
83
  end
64
84
 
65
- # save
85
+ # sync
86
+ describe "#sync" do
87
+ before do
88
+ assert subject.validate(params)
89
+ subject.sync
90
+ end
91
+
92
+ it { assert_equal album.released_at, DateTime.parse("30/03/1981") }
93
+ it { assert_equal album.hit.length, 312 }
94
+ it { assert_equal album.hit.good, false }
95
+ it { assert_nil album.metadata[:publication_settings] }
96
+ it { assert_equal album.metadata["publication_settings"]["featured"], false }
97
+ end
66
98
  end
@@ -1,56 +1,94 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
+
3
+ class FormCompositionInheritanceTest < MiniTest::Spec
4
+ module SizePrice
5
+ include Reform::Form::Module
6
+
7
+ property :price
8
+ property :size
9
+
10
+ module InstanceMethods
11
+ def price(for_size: size)
12
+ case for_size.to_sym
13
+ when :s then super() * 1
14
+ when :m then super() * 2
15
+ when :l then super() * 3
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ class OutfitForm < TestForm
22
+ include Reform::Form::Composition
23
+ include SizePrice
24
+
25
+ property :price, inherit: true, on: :tshirt
26
+ property :size, inherit: true, on: :measurement
27
+ end
28
+
29
+ let(:measurement) { Measurement.new(:l) }
30
+ let(:tshirt) { Tshirt.new(2, :m) }
31
+ let(:form) { OutfitForm.new(tshirt: tshirt, measurement: measurement) }
32
+
33
+ Tshirt = Struct.new(:price, :size)
34
+ Measurement = Struct.new(:size)
35
+
36
+ it { assert_equal form.price, 6 }
37
+ it { assert_equal form.price(for_size: :s), 2 }
38
+ end
2
39
 
3
40
  class FormCompositionTest < MiniTest::Spec
4
41
  Song = Struct.new(:id, :title, :band)
5
42
  Requester = Struct.new(:id, :name, :requester)
6
43
  Band = Struct.new(:title)
7
44
 
8
- class RequestForm < Reform::Form
45
+ class RequestForm < TestForm
9
46
  include Composition
10
47
 
11
- property :name, :on => :requester
12
- property :requester_id, :on => :requester, :from => :id
13
- properties :title, :id, :on => :song
48
+ property :name, on: :requester
49
+ property :requester_id, on: :requester, from: :id
50
+ properties :title, :id, on: :song
14
51
  # property :channel # FIXME: what about the "main model"?
15
- property :channel, :virtual => true, :on => :song
16
- property :requester, :on => :requester
17
- property :captcha, :on => :song, :virtual => true
52
+ property :channel, virtual: true, on: :song
53
+ property :requester, on: :requester
54
+ property :captcha, on: :song, virtual: true
18
55
 
19
56
  validation do
20
- key(:name).required
21
- key(:name).required
22
- key(:title).required
57
+ params do
58
+ required(:name).filled
59
+ required(:title).filled
60
+ end
23
61
  end
24
62
 
25
- property :band, :on => :song do
63
+ property :band, on: :song do
26
64
  property :title
27
65
  end
28
66
  end
29
67
 
30
- let (:form) { RequestForm.new(:song => song, :requester => requester) }
31
- let (:song) { Song.new(1, "Rio", band) }
32
- let (:requester) { Requester.new(2, "Duran Duran", "MCP") }
33
- let (:band) { Band.new("Duran^2") }
68
+ let(:form) { RequestForm.new(song: song, requester: requester) }
69
+ let(:song) { Song.new(1, "Rio", band) }
70
+ let(:requester) { Requester.new(2, "Duran Duran", "MCP") }
71
+ let(:band) { Band.new("Duran^2") }
34
72
 
35
73
  # delegation form -> composition works
36
- it { form.id.must_equal 1 }
37
- it { form.title.must_equal "Rio" }
38
- it { form.name.must_equal "Duran Duran" }
39
- it { form.requester_id.must_equal 2 }
40
- it { form.channel.must_equal nil }
41
- it { form.requester.must_equal "MCP" } # same name as composed model.
42
- it { form.captcha.must_equal nil }
74
+ it { assert_equal form.id, 1 }
75
+ it { assert_equal form.title, "Rio" }
76
+ it { assert_equal form.name, "Duran Duran" }
77
+ it { assert_equal form.requester_id, 2 }
78
+ it { assert_nil form.channel }
79
+ it { assert_equal form.requester, "MCP" } # same name as composed model.
80
+ it { assert_nil form.captcha }
43
81
 
44
82
  # #model just returns <Composition>.
45
- it { form.mapper.must_be_kind_of Disposable::Composition }
83
+ it { assert form.mapper.is_a? Disposable::Composition }
46
84
 
47
85
  # #model[] -> composed models
48
- it { form.model[:requester].must_equal requester }
49
- it { form.model[:song].must_equal song }
50
-
86
+ it { assert_equal form.model[:requester], requester }
87
+ it { assert_equal form.model[:song], song }
51
88
 
52
89
  it "creates Composition for you" do
53
- form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb").must_equal false
90
+ assert_equal form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb"), true
91
+ assert_equal form.validate("title" => "", "name" => "Frenzal Rhomb"), false
54
92
  end
55
93
 
56
94
  describe "#save" do
@@ -63,7 +101,7 @@ class FormCompositionTest < MiniTest::Spec
63
101
  hash[:title] = form.title
64
102
  end
65
103
 
66
- hash.must_equal({:name=>"Duran Duran", :title=>"Rio"})
104
+ assert_equal hash, name: "Duran Duran", title: "Rio"
67
105
  end
68
106
 
69
107
  it "provides nested symbolized hash as second block argument" do
@@ -75,11 +113,10 @@ class FormCompositionTest < MiniTest::Spec
75
113
  hash = map
76
114
  end
77
115
 
78
- hash.must_equal({
79
- :song=>{"title"=>"Greyhound", "id"=>1, "channel" => "JJJ", "captcha"=>"wonderful", "band"=>{"title"=>"Duran^2"}},
80
- :requester=>{"name"=>"Frenzal Rhomb", "id"=>2, "requester" => "MCP"}
81
- }
82
- )
116
+ assert_equal hash, {
117
+ song: {"title" => "Greyhound", "id" => 1, "channel" => "JJJ", "captcha" => "wonderful", "band" => {"title" => "Duran^2"}},
118
+ requester: {"name" => "Frenzal Rhomb", "id" => 2, "requester" => "MCP"}
119
+ }
83
120
  end
84
121
 
85
122
  it "xxx pushes data to models and calls #save when no block passed" do
@@ -88,16 +125,16 @@ class FormCompositionTest < MiniTest::Spec
88
125
  band.extend(Saveable)
89
126
 
90
127
  form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb", "captcha" => "1337")
91
- form.captcha.must_equal "1337" # TODO: move to separate test.
128
+ assert_equal form.captcha, "1337" # TODO: move to separate test.
92
129
 
93
130
  form.save
94
131
 
95
- requester.name.must_equal "Frenzal Rhomb"
96
- requester.saved?.must_equal true
97
- song.title.must_equal "Greyhound"
98
- song.saved?.must_equal true
99
- song.band.title.must_equal "Duran^2"
100
- song.band.saved?.must_equal true
132
+ assert_equal requester.name, "Frenzal Rhomb"
133
+ assert_equal requester.saved?, true
134
+ assert_equal song.title, "Greyhound"
135
+ assert_equal song.saved?, true
136
+ assert_equal song.band.title, "Duran^2"
137
+ assert_equal song.band.saved?, true
101
138
  end
102
139
 
103
140
  it "returns true when models all save successfully" do
@@ -105,7 +142,7 @@ class FormCompositionTest < MiniTest::Spec
105
142
  requester.extend(Saveable)
106
143
  band.extend(Saveable)
107
144
 
108
- form.save.must_equal true
145
+ assert_equal form.save, true
109
146
  end
110
147
 
111
148
  it "returns false when one or more models don't save successfully" do
@@ -119,21 +156,20 @@ class FormCompositionTest < MiniTest::Spec
119
156
  requester.extend(Saveable)
120
157
  band.extend(Saveable)
121
158
 
122
- form.save.must_equal false
159
+ assert_equal form.save, false
123
160
  end
124
161
  end
125
162
  end
126
163
 
127
-
128
164
  class FormCompositionCollectionTest < MiniTest::Spec
129
165
  Book = Struct.new(:id, :name)
130
166
  Library = Struct.new(:id) do
131
167
  def books
132
- [Book.new(1,"My book")]
168
+ [Book.new(1, "My book")]
133
169
  end
134
170
  end
135
171
 
136
- class LibraryForm < Reform::Form
172
+ class LibraryForm < TestForm
137
173
  include Reform::Form::Composition
138
174
 
139
175
  collection :books, on: :library do
@@ -142,8 +178,8 @@ class FormCompositionCollectionTest < MiniTest::Spec
142
178
  end
143
179
  end
144
180
 
145
- let (:form) { LibraryForm.new(library: library) }
146
- let (:library) { Library.new(2) }
181
+ let(:form) { LibraryForm.new(library: library) }
182
+ let(:library) { Library.new(2) }
147
183
 
148
- it { form.save do |hash| hash.must_equal({:library=>{"books"=>[{"id"=>1, "name"=>"My book"}]}}) end }
184
+ it { form.save { |hash| assert_equal hash, { library: { "books" => [{ "id" => 1, "name" => "My book" }] } } } }
149
185
  end
@@ -0,0 +1,55 @@
1
+ require "test_helper"
2
+
3
+ class CustomerErrorTest < MiniTest::Spec
4
+ let(:key) { :name }
5
+ let(:error_text) { "text2" }
6
+ let(:starting_error) { [OpenStruct.new(errors: {title: ["text1"]})] }
7
+
8
+ let(:custom_error) { Reform::Contract::CustomError.new(key, error_text, @results) }
9
+
10
+ before { @results = starting_error }
11
+
12
+ it "base class structure" do
13
+ assert_equal custom_error.success?, false
14
+ assert_equal custom_error.failure?, true
15
+ assert_equal custom_error.errors, key => [error_text]
16
+ assert_equal custom_error.messages, key => [error_text]
17
+ assert_equal custom_error.hint, {}
18
+ end
19
+
20
+ describe "updates @results accordingly" do
21
+ it "add new key" do
22
+ custom_error
23
+
24
+ assert_equal @results.size, 2
25
+ errors = @results.map(&:errors)
26
+
27
+ assert_equal errors[0], starting_error.first.errors
28
+ assert_equal errors[1], custom_error.errors
29
+ end
30
+
31
+ describe "when key error already exists in @results" do
32
+ let(:key) { :title }
33
+
34
+ it "merge errors text" do
35
+ custom_error
36
+
37
+ assert_equal @results.size, 1
38
+
39
+ assert_equal @results.first.errors.values, [%w[text1 text2]]
40
+ end
41
+
42
+ describe "add error text is already" do
43
+ let(:error_text) { "text1" }
44
+
45
+ it 'does not create duplicates' do
46
+ custom_error
47
+
48
+ assert_equal @results.size, 1
49
+
50
+ assert_equal @results.first.errors.values, [%w[text1]]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,34 +1,34 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ContractTest < MiniTest::Spec
4
4
  Song = Struct.new(:title, :album, :composer)
5
5
  Album = Struct.new(:name, :duration, :songs, :artist)
6
6
  Artist = Struct.new(:name)
7
7
 
8
- class ArtistForm < Reform::Form
8
+ class ArtistForm < TestForm
9
9
  property :name
10
10
  end
11
11
 
12
- class AlbumForm < Reform::Contract
12
+ class AlbumForm < TestContract
13
13
  property :name
14
14
 
15
15
  properties :duration
16
16
  properties :year, :style, readable: false
17
17
 
18
18
  validation do
19
- key(:name).required
19
+ params { required(:name).filled }
20
20
  end
21
21
 
22
22
  collection :songs do
23
23
  property :title
24
24
  validation do
25
- key(:title).required
25
+ params { required(:title).filled }
26
26
  end
27
27
 
28
28
  property :composer do
29
29
  property :name
30
30
  validation do
31
- key(:name).required
31
+ params { required(:name).filled }
32
32
  end
33
33
  end
34
34
  end
@@ -36,42 +36,42 @@ class ContractTest < MiniTest::Spec
36
36
  property :artist, form: ArtistForm
37
37
  end
38
38
 
39
- let (:song) { Song.new("Broken") }
40
- let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
41
- let (:composer) { Artist.new("Greg Graffin") }
42
- let (:artist) { Artist.new("Bad Religion") }
43
- let (:album) { Album.new("The Dissent Of Man", 123, [song, song_with_composer], artist) }
39
+ let(:song) { Song.new("Broken") }
40
+ let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
41
+ let(:composer) { Artist.new("Greg Graffin") }
42
+ let(:artist) { Artist.new("Bad Religion") }
43
+ let(:album) { Album.new("The Dissent Of Man", 123, [song, song_with_composer], artist) }
44
44
 
45
- let (:form) { AlbumForm.new(album) }
45
+ let(:form) { AlbumForm.new(album) }
46
46
 
47
47
  # accept `property form: SongForm`.
48
48
  it do
49
- form.artist.must_be_instance_of ArtistForm
49
+ assert form.artist.is_a? ArtistForm
50
50
  end
51
51
 
52
52
  describe ".properties" do
53
53
  it "defines a property when called with one argument" do
54
- form.must_respond_to :duration
54
+ assert_respond_to form, :duration
55
55
  end
56
56
 
57
57
  it "defines several properties when called with multiple arguments" do
58
- form.must_respond_to :year
59
- form.must_respond_to :style
58
+ assert_respond_to form, :year
59
+ assert_respond_to form, :style
60
60
  end
61
61
 
62
62
  it "passes options to each property when options are provided" do
63
63
  readable = AlbumForm.new(album).options_for(:style)[:readable]
64
- readable.must_equal false
64
+ assert_equal readable, false
65
65
  end
66
66
 
67
67
  it "returns the list of defined properties" do
68
68
  returned_value = AlbumForm.properties(:hello, :world, virtual: true)
69
- returned_value.must_equal [:hello, :world]
69
+ assert_equal returned_value, %i[hello world]
70
70
  end
71
71
  end
72
72
 
73
73
  describe "#options_for" do
74
- it { AlbumForm.options_for(:name).extend(Declarative::Inspect).inspect.must_equal "#<Disposable::Twin::Definition: @options={:private_name=>:name, :name=>\"name\"}>" }
75
- it { AlbumForm.new(album).options_for(:name).extend(Declarative::Inspect).inspect.must_equal "#<Disposable::Twin::Definition: @options={:private_name=>:name, :name=>\"name\"}>" }
74
+ it { assert_equal AlbumForm.options_for(:name).extend(Declarative::Inspect).inspect, "#<Disposable::Twin::Definition: @options={:private_name=>:name, :name=>\"name\"}>" }
75
+ it { assert_equal AlbumForm.new(album).options_for(:name).extend(Declarative::Inspect).inspect, "#<Disposable::Twin::Definition: @options={:private_name=>:name, :name=>\"name\"}>" }
76
76
  end
77
77
  end
data/test/default_test.rb CHANGED
@@ -5,7 +5,7 @@ class DefaultTest < Minitest::Spec
5
5
  Album = Struct.new(:name, :songs, :artist)
6
6
  Artist = Struct.new(:name)
7
7
 
8
- class AlbumForm < Reform::Form
8
+ class AlbumForm < TestForm
9
9
  property :name, default: "Wrong"
10
10
 
11
11
  collection :songs do
@@ -16,7 +16,7 @@ class DefaultTest < Minitest::Spec
16
16
  it do
17
17
  form = AlbumForm.new(Album.new(nil, [Song.new]))
18
18
 
19
- form.name.must_equal "Wrong"
20
- form.songs[0].title.must_equal "It's Catching Up"
19
+ assert_equal form.name, "Wrong"
20
+ assert_equal form.songs[0].title, "It's Catching Up"
21
21
  end
22
- end
22
+ end