reform 2.2.4 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +5 -1
  3. data/.rubocop.yml +30 -0
  4. data/.rubocop_todo.yml +460 -0
  5. data/.travis.yml +11 -6
  6. data/Appraisals +8 -0
  7. data/CHANGES.md +54 -4
  8. data/CONTRIBUTING.md +31 -0
  9. data/Gemfile +2 -16
  10. data/ISSUE_TEMPLATE.md +25 -0
  11. data/LICENSE.txt +1 -1
  12. data/README.md +5 -7
  13. data/Rakefile +18 -9
  14. data/gemfiles/0.13.0.gemfile +8 -0
  15. data/gemfiles/1.5.0.gemfile +9 -0
  16. data/lib/reform.rb +1 -0
  17. data/lib/reform/contract.rb +7 -17
  18. data/lib/reform/contract/custom_error.rb +41 -0
  19. data/lib/reform/contract/validate.rb +53 -23
  20. data/lib/reform/errors.rb +61 -0
  21. data/lib/reform/form.rb +36 -10
  22. data/lib/reform/form/call.rb +1 -1
  23. data/lib/reform/form/composition.rb +2 -2
  24. data/lib/reform/form/dry.rb +10 -58
  25. data/lib/reform/form/dry/input_hash.rb +37 -0
  26. data/lib/reform/form/dry/new_api.rb +46 -0
  27. data/lib/reform/form/dry/old_api.rb +61 -0
  28. data/lib/reform/form/populator.rb +11 -27
  29. data/lib/reform/form/prepopulate.rb +4 -3
  30. data/lib/reform/form/validate.rb +28 -13
  31. data/lib/reform/result.rb +90 -0
  32. data/lib/reform/validation.rb +19 -11
  33. data/lib/reform/validation/groups.rb +12 -27
  34. data/lib/reform/version.rb +1 -1
  35. data/reform.gemspec +15 -13
  36. data/test/benchmarking.rb +39 -6
  37. data/test/call_new_api.rb +23 -0
  38. data/test/{call_test.rb → call_old_api.rb} +4 -4
  39. data/test/changed_test.rb +8 -8
  40. data/test/coercion_test.rb +51 -19
  41. data/test/composition_new_api.rb +186 -0
  42. data/test/{composition_test.rb → composition_old_api.rb} +66 -31
  43. data/test/contract/custom_error_test.rb +55 -0
  44. data/test/contract_new_api.rb +77 -0
  45. data/test/{contract_test.rb → contract_old_api.rb} +13 -13
  46. data/test/default_test.rb +2 -2
  47. data/test/deserialize_test.rb +11 -14
  48. data/test/errors_new_api.rb +225 -0
  49. data/test/errors_old_api.rb +230 -0
  50. data/test/feature_test.rb +8 -10
  51. data/test/fixtures/dry_error_messages.yml +73 -23
  52. data/test/fixtures/dry_new_api_error_messages.yml +104 -0
  53. data/test/form_new_api.rb +57 -0
  54. data/test/{form_test.rb → form_old_api.rb} +5 -5
  55. data/test/form_option_new_api.rb +24 -0
  56. data/test/{form_option_test.rb → form_option_old_api.rb} +4 -4
  57. data/test/from_test.rb +9 -13
  58. data/test/inherit_new_api.rb +105 -0
  59. data/test/inherit_old_api.rb +105 -0
  60. data/test/{module_test.rb → module_new_api.rb} +20 -25
  61. data/test/module_old_api.rb +146 -0
  62. data/test/parse_option_test.rb +40 -0
  63. data/test/parse_pipeline_test.rb +3 -3
  64. data/test/populate_new_api.rb +304 -0
  65. data/test/{populate_test.rb → populate_old_api.rb} +83 -49
  66. data/test/populator_skip_test.rb +9 -9
  67. data/test/prepopulator_test.rb +8 -9
  68. data/test/read_only_test.rb +12 -1
  69. data/test/readable_test.rb +7 -7
  70. data/test/reform_new_api.rb +204 -0
  71. data/test/{reform_test.rb → reform_old_api.rb} +30 -51
  72. data/test/save_new_api.rb +101 -0
  73. data/test/{save_test.rb → save_old_api.rb} +32 -20
  74. data/test/setup_test.rb +8 -8
  75. data/test/{skip_if_test.rb → skip_if_new_api.rb} +23 -12
  76. data/test/skip_if_old_api.rb +92 -0
  77. data/test/skip_setter_and_getter_test.rb +3 -4
  78. data/test/test_helper.rb +25 -14
  79. data/test/validate_new_api.rb +408 -0
  80. data/test/{validate_test.rb → validate_old_api.rb} +59 -69
  81. data/test/validation/dry_validation_new_api.rb +836 -0
  82. data/test/validation/dry_validation_old_api.rb +772 -0
  83. data/test/validation/result_test.rb +77 -0
  84. data/test/validation_library_provided_test.rb +16 -0
  85. data/test/virtual_test.rb +47 -7
  86. data/test/writeable_test.rb +35 -6
  87. metadata +127 -56
  88. data/gemfiles/Gemfile.disposable-0.3 +0 -6
  89. data/lib/reform/contract/errors.rb +0 -43
  90. data/lib/reform/form/mongoid.rb +0 -37
  91. data/lib/reform/form/orm.rb +0 -26
  92. data/lib/reform/mongoid.rb +0 -4
  93. data/test/deprecation_test.rb +0 -27
  94. data/test/errors_test.rb +0 -165
  95. data/test/inherit_test.rb +0 -119
  96. data/test/readonly_test.rb +0 -14
  97. data/test/validation/dry_test.rb +0 -60
  98. data/test/validation/dry_validation_test.rb +0 -352
  99. data/test/validation/errors.yml +0 -4
@@ -1,34 +1,33 @@
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
- class SongForm < Reform::Form
8
+ class SongForm < TestForm
10
9
  property :name
11
10
  property :title
12
11
 
13
12
  validation do
14
- key(:name).required
13
+ 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
- form.title.must_equal nil
23
- form.name.must_equal nil
21
+ assert_nil form.title
22
+ form.name.must_be_nil
24
23
  end
25
24
 
26
25
  describe "and submitted values" do
27
26
  it "returns filled-out fields" do
28
27
  form.validate("name" => "Duran Duran")
29
28
 
30
- form.title.must_equal nil
31
- form.name.must_equal "Duran Duran"
29
+ assert_nil form.title
30
+ form.name.must_equal "Duran Duran"
32
31
  end
33
32
  end
34
33
  end
@@ -41,7 +40,7 @@ class ReformTest < Minitest::Spec
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")
@@ -63,21 +62,21 @@ class ReformTest < Minitest::Spec
63
62
  it "doesn't change model properties" do
64
63
  form.validate("name" => "Duran Duran")
65
64
 
66
- comp.name.must_equal nil # don't touch model, yet.
65
+ assert_nil comp.name # don't touch model, yet.
67
66
  end
68
67
 
69
68
  # TODO: test errors. test valid.
70
69
  describe "invalid input" do
71
- class ValidatingForm < Reform::Form
70
+ class ValidatingForm < TestForm
72
71
  property :name
73
72
  property :title
74
73
 
75
74
  validation do
76
- key(:name).required
77
- key(:title).required
75
+ required(:name).filled
76
+ required(:title).filled
78
77
  end
79
78
  end
80
- let (:form) { ValidatingForm.new(comp) }
79
+ let(:form) { ValidatingForm.new(comp) }
81
80
 
82
81
  it "returns false when invalid" do
83
82
  form.validate({}).must_equal false
@@ -85,29 +84,14 @@ class ReformTest < Minitest::Spec
85
84
 
86
85
  it "populates errors" do
87
86
  form.validate({})
88
- form.errors.messages.must_equal({:name=>["is missing"], :title=>["is missing"]})
87
+ form.errors.messages.must_equal({name: ["must be filled"], title: ["must be filled"]})
89
88
  end
90
89
  end
91
90
  end
92
91
 
93
- # FIXME: add this test to reform-rails.
94
- describe "#errors" do
95
- before { form.validate({})}
96
-
97
- it { form.errors.must_be_kind_of Reform::Contract::Errors }
98
-
99
- it { form.errors.messages.must_equal({}) }
100
-
101
- it do
102
- form.validate({"name"=>""})
103
- form.errors.messages.must_equal({:name=>["must be filled"]})
104
- end
105
- end
106
-
107
-
108
92
  describe "#save" do
109
- let (:comp) { OpenStruct.new }
110
- let (:form) { SongForm.new(comp) }
93
+ let(:comp) { OpenStruct.new }
94
+ let(:form) { SongForm.new(comp) }
111
95
 
112
96
  before { form.validate("name" => "Diesel Boy") }
113
97
 
@@ -115,7 +99,7 @@ class ReformTest < Minitest::Spec
115
99
  form.save
116
100
 
117
101
  comp.name.must_equal "Diesel Boy"
118
- comp.title.must_equal nil
102
+ assert_nil comp.title
119
103
  end
120
104
 
121
105
  describe "#save with block" do
@@ -126,42 +110,39 @@ class ReformTest < Minitest::Spec
126
110
  hash = map
127
111
  end
128
112
 
129
- hash.must_equal({"name"=>"Diesel Boy"})
113
+ hash.must_equal({"name" => "Diesel Boy", "title" => nil})
130
114
  end
131
115
  end
132
116
  end
133
117
 
134
-
135
118
  describe "#model" do
136
119
  it { form.model.must_equal comp }
137
120
  end
138
121
 
139
-
140
122
  describe "inheritance" do
141
123
  class HitForm < SongForm
142
124
  property :position
143
125
  validation do
144
- key(:position).required
126
+ required(:position).filled
145
127
  end
146
128
  end
147
129
 
148
- let (:form) { HitForm.new(OpenStruct.new()) }
130
+ let(:form) { HitForm.new(OpenStruct.new()) }
149
131
  it do
150
132
  form.validate({"title" => "The Body"})
151
133
  form.title.must_equal "The Body"
152
- form.position.must_equal nil
153
- form.errors.messages.must_equal({:name=>["is missing"], :position=>["is missing"]})
134
+ assert_nil form.position
135
+ form.errors.messages.must_equal({name: ["must be filled"], position: ["must be filled"]})
154
136
  end
155
137
  end
156
138
  end
157
139
 
158
-
159
140
  class OverridingAccessorsTest < BaseTest
160
- class SongForm < Reform::Form
141
+ class SongForm < TestForm
161
142
  property :title
162
143
 
163
144
  def title=(v) # used in #validate.
164
- super v*2
145
+ super v * 2
165
146
  end
166
147
 
167
148
  def title # used in #sync.
@@ -169,13 +150,12 @@ class OverridingAccessorsTest < BaseTest
169
150
  end
170
151
  end
171
152
 
172
- let (:song) { Song.new("Pray") }
153
+ let(:song) { Song.new("Pray") }
173
154
  subject { SongForm.new(song) }
174
155
 
175
156
  # override reader for presentation.
176
157
  it { subject.title.must_equal "pray" }
177
158
 
178
-
179
159
  describe "#save" do
180
160
  before { subject.validate("title" => "Hey Little World") }
181
161
 
@@ -198,9 +178,8 @@ class OverridingAccessorsTest < BaseTest
198
178
  end
199
179
  end
200
180
 
201
-
202
181
  class MethodInFormTest < MiniTest::Spec
203
- class AlbumForm < Reform::Form
182
+ class AlbumForm < TestForm
204
183
  property :title
205
184
 
206
185
  def title
@@ -217,7 +196,7 @@ class MethodInFormTest < MiniTest::Spec
217
196
  end
218
197
 
219
198
  # methods can be used instead of created accessors.
220
- subject { AlbumForm.new(OpenStruct.new(:hit => OpenStruct.new)) }
199
+ subject { AlbumForm.new(OpenStruct.new(hit: OpenStruct.new)) }
221
200
  it { subject.title.must_equal "The Suffer And The Witness" }
222
201
  it { subject.hit.title.must_equal "Drones" }
223
202
  end
@@ -0,0 +1,101 @@
1
+ require "test_helper"
2
+
3
+ class SaveTest < BaseTest
4
+ Song = Struct.new(:title, :album, :composer)
5
+ Album = Struct.new(:name, :songs, :artist)
6
+ Artist = Struct.new(:name)
7
+
8
+ class AlbumForm < TestForm
9
+ property :name
10
+ validation do
11
+ params { required(:name).filled }
12
+ end
13
+
14
+ collection :songs do
15
+ property :title
16
+ validation do
17
+ params { required(:title).filled }
18
+ end
19
+
20
+ property :composer do
21
+ property :name
22
+ validation do
23
+ params { required(:name).filled }
24
+ end
25
+ end
26
+ end
27
+
28
+ property :artist, save: false do
29
+ property :name
30
+ end
31
+ end
32
+
33
+ module Saveable
34
+ def save
35
+ @saved = true
36
+ end
37
+
38
+ def saved?
39
+ defined?(@saved) && @saved
40
+ end
41
+ end
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) }
48
+
49
+ let(:form) { AlbumForm.new(album) }
50
+
51
+ it do
52
+ form.validate("songs" => [{"title" => "Fixed"}])
53
+
54
+ form.save
55
+
56
+ album.saved?.must_equal true
57
+ album.songs[0].title.must_equal "Fixed"
58
+ album.songs[0].saved?.must_equal true
59
+ assert_nil album.artist.saved?
60
+ end
61
+
62
+ describe "#sync with block" do
63
+ it do
64
+ form = AlbumForm.new(Album.new("Greatest Hits"))
65
+
66
+ form.validate(name: nil) # nil-out the title.
67
+
68
+ nested_hash = nil
69
+ form.sync do |hash|
70
+ nested_hash = hash
71
+ end
72
+
73
+ nested_hash.must_equal({"name" => nil, "artist" => nil})
74
+ end
75
+ end
76
+ end
77
+
78
+ # class SaveWithDynamicOptionsTest < MiniTest::Spec
79
+ # Song = Struct.new(:id, :title, :length) do
80
+ # include Saveable
81
+ # end
82
+
83
+ # class SongForm < TestForm
84
+ # property :title#, save: false
85
+ # property :length, virtual: true
86
+ # end
87
+
88
+ # let(:song) { Song.new }
89
+ # let(:form) { SongForm.new(song) }
90
+
91
+ # # we have access to original input value and outside parameters.
92
+ # it "xxx" do
93
+ # form.validate("title" => "A Poor Man's Memory", "length" => 10)
94
+ # length_seconds = 120
95
+ # form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
96
+
97
+ # song.title.must_equal "A Poor Man's Memory"
98
+ # assert_nil song.length
99
+ # song.id.must_equal "10: 120"
100
+ # end
101
+ # end
@@ -1,26 +1,26 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class SaveTest < BaseTest
4
4
  Song = Struct.new(:title, :album, :composer)
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
10
10
  validation do
11
- key(:name).required
11
+ required(:name).filled
12
12
  end
13
13
 
14
14
  collection :songs do
15
15
  property :title
16
16
  validation do
17
- key(:title).required
17
+ required(:title).filled
18
18
  end
19
19
 
20
20
  property :composer do
21
21
  property :name
22
22
  validation do
23
- key(:name).required
23
+ required(:name).filled
24
24
  end
25
25
  end
26
26
  end
@@ -36,19 +36,17 @@ class SaveTest < BaseTest
36
36
  end
37
37
 
38
38
  def saved?
39
- @saved
39
+ defined?(@saved) && @saved
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"}])
@@ -58,23 +56,37 @@ class SaveTest < BaseTest
58
56
  album.saved?.must_equal true
59
57
  album.songs[0].title.must_equal "Fixed"
60
58
  album.songs[0].saved?.must_equal true
61
- album.artist.saved?.must_equal nil
59
+ assert_nil album.artist.saved?
62
60
  end
63
- end
64
61
 
62
+ describe "#sync with block" do
63
+ it do
64
+ form = AlbumForm.new(Album.new("Greatest Hits"))
65
+
66
+ form.validate(name: nil) # nil-out the title.
67
+
68
+ nested_hash = nil
69
+ form.sync do |hash|
70
+ nested_hash = hash
71
+ end
72
+
73
+ nested_hash.must_equal({"name" => nil, "artist" => nil})
74
+ end
75
+ end
76
+ end
65
77
 
66
78
  # class SaveWithDynamicOptionsTest < MiniTest::Spec
67
79
  # Song = Struct.new(:id, :title, :length) do
68
80
  # include Saveable
69
81
  # end
70
82
 
71
- # class SongForm < Reform::Form
83
+ # class SongForm < TestForm
72
84
  # property :title#, save: false
73
85
  # property :length, virtual: true
74
86
  # end
75
87
 
76
- # let (:song) { Song.new }
77
- # let (:form) { SongForm.new(song) }
88
+ # let(:song) { Song.new }
89
+ # let(:form) { SongForm.new(song) }
78
90
 
79
91
  # # we have access to original input value and outside parameters.
80
92
  # it "xxx" do
@@ -83,7 +95,7 @@ end
83
95
  # form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
84
96
 
85
97
  # song.title.must_equal "A Poor Man's Memory"
86
- # song.length.must_equal nil
98
+ # assert_nil song.length
87
99
  # song.id.must_equal "10: 120"
88
100
  # end
89
101
  # end
@@ -5,7 +5,7 @@ class SetupTest < 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
10
10
  collection :songs do
11
11
  property :title
@@ -20,20 +20,20 @@ class SetupTest < MiniTest::Spec
20
20
  end
21
21
  end
22
22
 
23
- let (:song) { Song.new("Broken") }
24
- let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
25
- let (:composer) { Artist.new("Greg Graffin") }
26
- let (:artist) { Artist.new("Bad Religion") }
23
+ let(:song) { Song.new("Broken") }
24
+ let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
25
+ let(:composer) { Artist.new("Greg Graffin") }
26
+ let(:artist) { Artist.new("Bad Religion") }
27
27
 
28
28
  describe "with nested objects" do
29
- let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
29
+ let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
30
30
 
31
31
  it do
32
32
  form = AlbumForm.new(album)
33
33
 
34
34
  form.name.must_equal "The Dissent Of Man"
35
35
  form.songs[0].title.must_equal "Broken"
36
- form.songs[0].composer.must_equal nil
36
+ assert_nil form.songs[0].composer
37
37
  form.songs[1].title.must_equal "Resist Stance"
38
38
  form.songs[1].composer.name.must_equal "Greg Graffin"
39
39
  form.artist.name.must_equal "Bad Religion"
@@ -45,4 +45,4 @@ class SetupTest < MiniTest::Spec
45
45
  form.artist.must_be_kind_of Reform::Form
46
46
  end
47
47
  end
48
- end
48
+ end