reform 2.3.0.rc1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +5 -1
  3. data/.travis.yml +7 -11
  4. data/CHANGES.md +43 -3
  5. data/Gemfile +2 -5
  6. data/ISSUE_TEMPLATE.md +1 -1
  7. data/LICENSE.txt +1 -1
  8. data/README.md +7 -9
  9. data/Rakefile +6 -10
  10. data/lib/reform/contract.rb +7 -7
  11. data/lib/reform/contract/custom_error.rb +41 -0
  12. data/lib/reform/contract/validate.rb +10 -6
  13. data/lib/reform/errors.rb +27 -15
  14. data/lib/reform/form.rb +22 -11
  15. data/lib/reform/form/call.rb +1 -1
  16. data/lib/reform/form/composition.rb +2 -2
  17. data/lib/reform/form/dry.rb +22 -60
  18. data/lib/reform/form/dry/input_hash.rb +37 -0
  19. data/lib/reform/form/populator.rb +9 -11
  20. data/lib/reform/form/prepopulate.rb +3 -2
  21. data/lib/reform/form/validate.rb +19 -12
  22. data/lib/reform/result.rb +36 -9
  23. data/lib/reform/validation.rb +10 -8
  24. data/lib/reform/validation/groups.rb +2 -4
  25. data/lib/reform/version.rb +1 -1
  26. data/reform.gemspec +9 -9
  27. data/test/benchmarking.rb +10 -11
  28. data/test/call_test.rb +8 -8
  29. data/test/changed_test.rb +13 -13
  30. data/test/coercion_test.rb +56 -24
  31. data/test/composition_test.rb +49 -51
  32. data/test/contract/custom_error_test.rb +55 -0
  33. data/test/contract_test.rb +18 -18
  34. data/test/default_test.rb +3 -3
  35. data/test/deserialize_test.rb +14 -17
  36. data/test/docs/validation_test.rb +134 -0
  37. data/test/errors_test.rb +131 -86
  38. data/test/feature_test.rb +9 -11
  39. data/test/fixtures/dry_error_messages.yml +65 -52
  40. data/test/form_option_test.rb +3 -3
  41. data/test/form_test.rb +6 -6
  42. data/test/from_test.rb +17 -21
  43. data/test/inherit_test.rb +28 -35
  44. data/test/module_test.rb +23 -28
  45. data/test/parse_option_test.rb +12 -12
  46. data/test/parse_pipeline_test.rb +3 -3
  47. data/test/populate_test.rb +146 -93
  48. data/test/populator_skip_test.rb +3 -4
  49. data/test/prepopulator_test.rb +20 -21
  50. data/test/read_only_test.rb +12 -1
  51. data/test/readable_test.rb +7 -7
  52. data/test/reform_test.rb +38 -42
  53. data/test/save_test.rb +16 -19
  54. data/test/setup_test.rb +15 -15
  55. data/test/skip_if_test.rb +30 -19
  56. data/test/skip_setter_and_getter_test.rb +8 -9
  57. data/test/test_helper.rb +12 -5
  58. data/test/validate_test.rb +160 -140
  59. data/test/validation/dry_validation_test.rb +407 -236
  60. data/test/validation/result_test.rb +29 -31
  61. data/test/validation_library_provided_test.rb +3 -3
  62. data/test/virtual_test.rb +46 -6
  63. data/test/writeable_test.rb +13 -13
  64. metadata +32 -29
  65. data/test/readonly_test.rb +0 -14
@@ -4,7 +4,6 @@ class PopulatorSkipTest < MiniTest::Spec
4
4
  Album = Struct.new(:songs)
5
5
  Song = Struct.new(:title)
6
6
 
7
-
8
7
  class AlbumForm < TestForm
9
8
  collection :songs, populator: :my_populator do
10
9
  property :title
@@ -22,8 +21,8 @@ class PopulatorSkipTest < MiniTest::Spec
22
21
 
23
22
  form.validate(hash)
24
23
 
25
- form.songs.size.must_equal 2
24
+ assert_equal form.songs.size, 2
26
25
  assert_nil form.songs[0].title
27
- form.songs[1].title.must_equal "Bad"
26
+ assert_equal form.songs[1].title, "Bad"
28
27
  end
29
- end
28
+ end
@@ -1,17 +1,17 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class PrepopulatorTest < MiniTest::Spec
4
4
  Song = Struct.new(:title, :band, :length)
5
5
  Band = Struct.new(:name)
6
6
 
7
7
  class AlbumForm < TestForm
8
- property :title, prepopulator: ->(*){ self.title = "Another Day At Work" } # normal assignment.
8
+ property :title, prepopulator: ->(*) { self.title = "Another Day At Work" } # normal assignment.
9
9
  property :length
10
10
 
11
11
  property :hit, prepopulator: ->(options) { self.hit = Song.new(options[:title]) } do # use user options.
12
12
  property :title
13
13
 
14
- property :band, prepopulator: ->(options){ self.band = my_band(options[:title]) } do # invoke your own code.
14
+ property :band, prepopulator: ->(options) { self.band = my_band(options[:title]) } do # invoke your own code.
15
15
  property :name
16
16
  end
17
17
 
@@ -24,7 +24,7 @@ class PrepopulatorTest < MiniTest::Spec
24
24
  property :title
25
25
  end
26
26
 
27
- private
27
+ private
28
28
  def prepopulate_songs!(options)
29
29
  if songs == nil
30
30
  self.songs = [Song.new, Song.new]
@@ -37,25 +37,25 @@ class PrepopulatorTest < MiniTest::Spec
37
37
  it do
38
38
  form = AlbumForm.new(OpenStruct.new(length: 1)).prepopulate!(title: "Potemkin City Limits")
39
39
 
40
- form.length.must_equal 1
41
- form.title.must_equal "Another Day At Work"
42
- form.hit.model.must_equal Song.new("Potemkin City Limits")
43
- form.songs.size.must_equal 2
44
- form.songs[0].model.must_equal Song.new
45
- form.songs[1].model.must_equal Song.new
46
- form.songs[1].model.must_equal Song.new
40
+ assert_equal form.length, 1
41
+ assert_equal form.title, "Another Day At Work"
42
+ assert_equal form.hit.model, Song.new("Potemkin City Limits")
43
+ assert_equal form.songs.size, 2
44
+ assert_equal form.songs[0].model, Song.new
45
+ assert_equal form.songs[1].model, Song.new
46
+ assert_equal form.songs[1].model, Song.new
47
47
  # prepopulate works more than 1 level, recursive.
48
48
  # it also passes options properly down there.
49
- form.hit.band.model.must_equal Band.new("Potemkin City Limits")
49
+ assert_equal form.hit.band.model, Band.new("Potemkin City Limits")
50
50
  end
51
51
 
52
52
  # add to existing collection.
53
53
  it do
54
54
  form = AlbumForm.new(OpenStruct.new(songs: [Song.new])).prepopulate!
55
55
 
56
- form.songs.size.must_equal 2
57
- form.songs[0].model.must_equal Song.new
58
- form.songs[1].model.must_equal Song.new
56
+ assert_equal form.songs.size, 2
57
+ assert_equal form.songs[0].model, Song.new
58
+ assert_equal form.songs[1].model, Song.new
59
59
  end
60
60
  end
61
61
 
@@ -75,10 +75,9 @@ class PrepopulateWithoutConfiguration < MiniTest::Spec
75
75
 
76
76
  subject { AlbumForm.new(OpenStruct.new(songs: [], hit: nil)).prepopulate! }
77
77
 
78
- it { subject.songs.size.must_equal 0 }
78
+ it { assert_equal subject.songs.size, 0 }
79
79
  end
80
80
 
81
-
82
81
  class ManualPrepopulatorOverridingTest < MiniTest::Spec
83
82
  Song = Struct.new(:title, :band, :length)
84
83
  Band = Struct.new(:name)
@@ -105,8 +104,8 @@ class ManualPrepopulatorOverridingTest < MiniTest::Spec
105
104
  it do
106
105
  form = AlbumForm.new(OpenStruct.new(length: 1)).prepopulate!(title: "Potemkin City Limits")
107
106
 
108
- form.length.must_equal 1
109
- form.hit.model.must_equal Song.new("Potemkin City Limits")
110
- form.hit.title.must_equal "Potemkin City Limits"
107
+ assert_equal form.length, 1
108
+ assert_equal form.hit.model, Song.new("Potemkin City Limits")
109
+ assert_equal form.hit.title, "Potemkin City Limits"
111
110
  end
112
- end
111
+ end
@@ -1,3 +1,14 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
+ class ReadonlyTest < MiniTest::Spec
4
+ class SongForm < TestForm
5
+ property :artist
6
+ property :title, writeable: false
7
+ # TODO: what to do with virtual values?
8
+ end
3
9
 
10
+ let(:form) { SongForm.new(OpenStruct.new) }
11
+
12
+ it { refute form.readonly?(:artist) }
13
+ it { assert form.readonly?(:title) }
14
+ end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ReadableTest < MiniTest::Spec
4
4
  Credentials = Struct.new(:password)
@@ -7,24 +7,24 @@ class ReadableTest < MiniTest::Spec
7
7
  property :password, readable: false
8
8
  end
9
9
 
10
- let (:cred) { Credentials.new }
11
- let (:form) { PasswordForm.new(cred) }
10
+ let(:cred) { Credentials.new }
11
+ let(:form) { PasswordForm.new(cred) }
12
12
 
13
13
  it {
14
14
  assert_nil form.password # password not read.
15
15
 
16
16
  form.validate("password" => "123")
17
17
 
18
- form.password.must_equal "123"
18
+ assert_equal form.password, "123"
19
19
 
20
20
  form.sync
21
- cred.password.must_equal "123" # password written.
21
+ assert_equal cred.password, "123" # password written.
22
22
 
23
23
  hash = {}
24
24
  form.save do |nested|
25
25
  hash = nested
26
26
  end
27
27
 
28
- hash.must_equal("password"=> "123")
28
+ assert_equal hash, "password" => "123"
29
29
  }
30
- end
30
+ end
data/test/reform_test.rb CHANGED
@@ -1,26 +1,25 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
- # TODO: this test should be removed.
4
3
  class ReformTest < Minitest::Spec
5
- let (:comp) { OpenStruct.new(:name => "Duran Duran", :title => "Rio") }
4
+ let(:comp) { OpenStruct.new(name: "Duran Duran", title: "Rio") }
6
5
 
7
- let (:form) { SongForm.new(comp) }
6
+ let(:form) { SongForm.new(comp) }
8
7
 
9
8
  class SongForm < TestForm
10
9
  property :name
11
10
  property :title
12
11
 
13
12
  validation do
14
- required(:name).filled
13
+ params { required(:name).filled }
15
14
  end
16
15
  end
17
16
 
18
17
  describe "(new) form with empty models" do
19
- let (:comp) { OpenStruct.new }
18
+ let(:comp) { OpenStruct.new }
20
19
 
21
20
  it "returns empty fields" do
22
21
  assert_nil form.title
23
- form.name.must_equal nil
22
+ assert_nil form.name
24
23
  end
25
24
 
26
25
  describe "and submitted values" do
@@ -28,20 +27,20 @@ class ReformTest < Minitest::Spec
28
27
  form.validate("name" => "Duran Duran")
29
28
 
30
29
  assert_nil form.title
31
- form.name.must_equal "Duran Duran"
30
+ assert_equal form.name, "Duran Duran"
32
31
  end
33
32
  end
34
33
  end
35
34
 
36
35
  describe "(edit) form with existing models" do
37
36
  it "returns filled-out fields" do
38
- form.name.must_equal "Duran Duran"
39
- form.title.must_equal "Rio"
37
+ assert_equal form.name, "Duran Duran"
38
+ assert_equal form.title, "Rio"
40
39
  end
41
40
  end
42
41
 
43
42
  describe "#validate" do
44
- let (:comp) { OpenStruct.new }
43
+ let(:comp) { OpenStruct.new }
45
44
 
46
45
  it "ignores unmapped fields in input" do
47
46
  form.validate("name" => "Duran Duran", :genre => "80s")
@@ -51,13 +50,13 @@ class ReformTest < Minitest::Spec
51
50
  end
52
51
 
53
52
  it "returns true when valid" do
54
- form.validate("name" => "Duran Duran").must_equal true
53
+ assert_equal form.validate("name" => "Duran Duran"), true
55
54
  end
56
55
 
57
56
  it "exposes input via property accessors" do
58
57
  form.validate("name" => "Duran Duran")
59
58
 
60
- form.name.must_equal "Duran Duran"
59
+ assert_equal form.name, "Duran Duran"
61
60
  end
62
61
 
63
62
  it "doesn't change model properties" do
@@ -73,33 +72,35 @@ class ReformTest < Minitest::Spec
73
72
  property :title
74
73
 
75
74
  validation do
76
- required(:name).filled
77
- required(:title).filled
75
+ params do
76
+ required(:name).filled
77
+ required(:title).filled
78
+ end
78
79
  end
79
80
  end
80
- let (:form) { ValidatingForm.new(comp) }
81
+ let(:form) { ValidatingForm.new(comp) }
81
82
 
82
83
  it "returns false when invalid" do
83
- form.validate({}).must_equal false
84
+ assert_equal form.validate({}), false
84
85
  end
85
86
 
86
87
  it "populates errors" do
87
88
  form.validate({})
88
- form.errors.messages.must_equal({:name=>["must be filled"], :title=>["must be filled"]})
89
+ assert_equal form.errors.messages, name: ["must be filled"], title: ["must be filled"]
89
90
  end
90
91
  end
91
92
  end
92
93
 
93
94
  describe "#save" do
94
- let (:comp) { OpenStruct.new }
95
- let (:form) { SongForm.new(comp) }
95
+ let(:comp) { OpenStruct.new }
96
+ let(:form) { SongForm.new(comp) }
96
97
 
97
98
  before { form.validate("name" => "Diesel Boy") }
98
99
 
99
100
  it "xxpushes data to models" do
100
101
  form.save
101
102
 
102
- comp.name.must_equal "Diesel Boy"
103
+ assert_equal comp.name, "Diesel Boy"
103
104
  assert_nil comp.title
104
105
  end
105
106
 
@@ -111,42 +112,39 @@ class ReformTest < Minitest::Spec
111
112
  hash = map
112
113
  end
113
114
 
114
- hash.must_equal({"name"=>"Diesel Boy", "title" => nil})
115
+ assert_equal hash, "name" => "Diesel Boy", "title" => nil
115
116
  end
116
117
  end
117
118
  end
118
119
 
119
-
120
120
  describe "#model" do
121
- it { form.model.must_equal comp }
121
+ it { assert_equal form.model, comp }
122
122
  end
123
123
 
124
-
125
124
  describe "inheritance" do
126
125
  class HitForm < SongForm
127
126
  property :position
128
127
  validation do
129
- required(:position).filled
128
+ params { required(:position).filled }
130
129
  end
131
130
  end
132
131
 
133
- let (:form) { HitForm.new(OpenStruct.new()) }
132
+ let(:form) { HitForm.new(OpenStruct.new()) }
134
133
  it do
135
- form.validate({"title" => "The Body"})
136
- form.title.must_equal "The Body"
134
+ form.validate("title" => "The Body")
135
+ assert_equal form.title, "The Body"
137
136
  assert_nil form.position
138
- form.errors.messages.must_equal({:name=>["must be filled"], :position=>["must be filled"]})
137
+ assert_equal form.errors.messages, name: ["must be filled"], position: ["must be filled"]
139
138
  end
140
139
  end
141
140
  end
142
141
 
143
-
144
142
  class OverridingAccessorsTest < BaseTest
145
143
  class SongForm < TestForm
146
144
  property :title
147
145
 
148
146
  def title=(v) # used in #validate.
149
- super v*2
147
+ super v * 2
150
148
  end
151
149
 
152
150
  def title # used in #sync.
@@ -154,23 +152,22 @@ class OverridingAccessorsTest < BaseTest
154
152
  end
155
153
  end
156
154
 
157
- let (:song) { Song.new("Pray") }
155
+ let(:song) { Song.new("Pray") }
158
156
  subject { SongForm.new(song) }
159
157
 
160
158
  # override reader for presentation.
161
- it { subject.title.must_equal "pray" }
162
-
159
+ it { assert_equal subject.title, "pray" }
163
160
 
164
161
  describe "#save" do
165
162
  before { subject.validate("title" => "Hey Little World") }
166
163
 
167
164
  # reader always used
168
- it { subject.title.must_equal "hey little worldhey little world" }
165
+ it { assert_equal subject.title, "hey little worldhey little world" }
169
166
 
170
167
  # the reader is not used when saving/syncing.
171
168
  it do
172
169
  subject.save do |hash|
173
- hash["title"].must_equal "Hey Little WorldHey Little World"
170
+ assert_equal hash["title"], "Hey Little WorldHey Little World"
174
171
  end
175
172
  end
176
173
 
@@ -178,12 +175,11 @@ class OverridingAccessorsTest < BaseTest
178
175
  it do
179
176
  song.extend(Saveable)
180
177
  subject.save
181
- song.title.must_equal "Hey Little WorldHey Little World"
178
+ assert_equal song.title, "Hey Little WorldHey Little World"
182
179
  end
183
180
  end
184
181
  end
185
182
 
186
-
187
183
  class MethodInFormTest < MiniTest::Spec
188
184
  class AlbumForm < TestForm
189
185
  property :title
@@ -202,7 +198,7 @@ class MethodInFormTest < MiniTest::Spec
202
198
  end
203
199
 
204
200
  # methods can be used instead of created accessors.
205
- subject { AlbumForm.new(OpenStruct.new(:hit => OpenStruct.new)) }
206
- it { subject.title.must_equal "The Suffer And The Witness" }
207
- it { subject.hit.title.must_equal "Drones" }
201
+ subject { AlbumForm.new(OpenStruct.new(hit: OpenStruct.new)) }
202
+ it { assert_equal subject.title, "The Suffer And The Witness" }
203
+ it { assert_equal subject.hit.title, "Drones" }
208
204
  end
data/test/save_test.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class SaveTest < BaseTest
4
4
  Song = Struct.new(:title, :album, :composer)
@@ -8,19 +8,19 @@ class SaveTest < BaseTest
8
8
  class AlbumForm < TestForm
9
9
  property :name
10
10
  validation do
11
- required(:name).filled
11
+ params { required(:name).filled }
12
12
  end
13
13
 
14
14
  collection :songs do
15
15
  property :title
16
16
  validation do
17
- required(:title).filled
17
+ params { required(:title).filled }
18
18
  end
19
19
 
20
20
  property :composer do
21
21
  property :name
22
22
  validation do
23
- required(:name).filled
23
+ params { required(:name).filled }
24
24
  end
25
25
  end
26
26
  end
@@ -40,24 +40,22 @@ class SaveTest < BaseTest
40
40
  end
41
41
  end
42
42
 
43
+ let(:song) { Song.new("Broken").extend(Saveable) }
44
+ # let(:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
45
+ let(:composer) { Artist.new("Greg Graffin").extend(Saveable) }
46
+ let(:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
47
+ let(:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
43
48
 
44
- let (:song) { Song.new("Broken").extend(Saveable) }
45
- # let (:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
46
- let (:composer) { Artist.new("Greg Graffin").extend(Saveable) }
47
- let (:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
48
- let (:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
49
-
50
- let (:form) { AlbumForm.new(album) }
51
-
49
+ let(:form) { AlbumForm.new(album) }
52
50
 
53
51
  it do
54
52
  form.validate("songs" => [{"title" => "Fixed"}])
55
53
 
56
54
  form.save
57
55
 
58
- album.saved?.must_equal true
59
- album.songs[0].title.must_equal "Fixed"
60
- album.songs[0].saved?.must_equal true
56
+ assert album.saved?
57
+ assert_equal album.songs[0].title, "Fixed"
58
+ assert album.songs[0].saved?
61
59
  assert_nil album.artist.saved?
62
60
  end
63
61
 
@@ -72,12 +70,11 @@ class SaveTest < BaseTest
72
70
  nested_hash = hash
73
71
  end
74
72
 
75
- nested_hash.must_equal({"name"=>nil, "artist"=>nil})
73
+ assert_equal nested_hash, "name" => nil, "artist" => nil
76
74
  end
77
75
  end
78
76
  end
79
77
 
80
-
81
78
  # class SaveWithDynamicOptionsTest < MiniTest::Spec
82
79
  # Song = Struct.new(:id, :title, :length) do
83
80
  # include Saveable
@@ -88,8 +85,8 @@ end
88
85
  # property :length, virtual: true
89
86
  # end
90
87
 
91
- # let (:song) { Song.new }
92
- # let (:form) { SongForm.new(song) }
88
+ # let(:song) { Song.new }
89
+ # let(:form) { SongForm.new(song) }
93
90
 
94
91
  # # we have access to original input value and outside parameters.
95
92
  # it "xxx" do