reform 2.3.0.rc1 → 2.3.0.rc2

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +30 -0
  4. data/.rubocop_todo.yml +460 -0
  5. data/.travis.yml +26 -11
  6. data/CHANGES.md +25 -2
  7. data/Gemfile +6 -3
  8. data/ISSUE_TEMPLATE.md +1 -1
  9. data/README.md +2 -4
  10. data/Rakefile +18 -9
  11. data/lib/reform/contract.rb +7 -7
  12. data/lib/reform/contract/custom_error.rb +41 -0
  13. data/lib/reform/contract/validate.rb +9 -5
  14. data/lib/reform/errors.rb +27 -15
  15. data/lib/reform/form.rb +22 -11
  16. data/lib/reform/form/call.rb +1 -1
  17. data/lib/reform/form/composition.rb +2 -2
  18. data/lib/reform/form/dry.rb +10 -86
  19. data/lib/reform/form/dry/input_hash.rb +37 -0
  20. data/lib/reform/form/dry/new_api.rb +58 -0
  21. data/lib/reform/form/dry/old_api.rb +61 -0
  22. data/lib/reform/form/populator.rb +9 -11
  23. data/lib/reform/form/prepopulate.rb +3 -2
  24. data/lib/reform/form/validate.rb +19 -12
  25. data/lib/reform/result.rb +36 -9
  26. data/lib/reform/validation.rb +10 -8
  27. data/lib/reform/validation/groups.rb +2 -3
  28. data/lib/reform/version.rb +1 -1
  29. data/reform.gemspec +10 -9
  30. data/test/benchmarking.rb +10 -11
  31. data/test/call_new_api.rb +23 -0
  32. data/test/{call_test.rb → call_old_api.rb} +3 -3
  33. data/test/changed_test.rb +7 -7
  34. data/test/coercion_test.rb +50 -18
  35. data/test/composition_new_api.rb +186 -0
  36. data/test/{composition_test.rb → composition_old_api.rb} +23 -26
  37. data/test/contract/custom_error_test.rb +55 -0
  38. data/test/contract_new_api.rb +77 -0
  39. data/test/{contract_test.rb → contract_old_api.rb} +8 -8
  40. data/test/default_test.rb +1 -1
  41. data/test/deserialize_test.rb +8 -11
  42. data/test/errors_new_api.rb +225 -0
  43. data/test/errors_old_api.rb +230 -0
  44. data/test/feature_test.rb +7 -9
  45. data/test/fixtures/dry_error_messages.yml +5 -2
  46. data/test/fixtures/dry_new_api_error_messages.yml +104 -0
  47. data/test/form_new_api.rb +57 -0
  48. data/test/{form_test.rb → form_old_api.rb} +2 -2
  49. data/test/form_option_new_api.rb +24 -0
  50. data/test/{form_option_test.rb → form_option_old_api.rb} +1 -1
  51. data/test/from_test.rb +8 -12
  52. data/test/inherit_new_api.rb +105 -0
  53. data/test/{inherit_test.rb → inherit_old_api.rb} +10 -17
  54. data/test/module_new_api.rb +137 -0
  55. data/test/{module_test.rb → module_old_api.rb} +19 -15
  56. data/test/parse_option_test.rb +5 -5
  57. data/test/parse_pipeline_test.rb +2 -2
  58. data/test/populate_new_api.rb +304 -0
  59. data/test/{populate_test.rb → populate_old_api.rb} +28 -34
  60. data/test/populator_skip_test.rb +1 -2
  61. data/test/prepopulator_test.rb +5 -6
  62. data/test/read_only_test.rb +12 -1
  63. data/test/readable_test.rb +5 -5
  64. data/test/reform_new_api.rb +204 -0
  65. data/test/{reform_test.rb → reform_old_api.rb} +17 -23
  66. data/test/save_new_api.rb +101 -0
  67. data/test/{save_test.rb → save_old_api.rb} +10 -13
  68. data/test/setup_test.rb +6 -6
  69. data/test/{skip_if_test.rb → skip_if_new_api.rb} +20 -9
  70. data/test/skip_if_old_api.rb +92 -0
  71. data/test/skip_setter_and_getter_test.rb +2 -3
  72. data/test/test_helper.rb +13 -5
  73. data/test/validate_new_api.rb +408 -0
  74. data/test/{validate_test.rb → validate_old_api.rb} +43 -53
  75. data/test/validation/dry_validation_new_api.rb +826 -0
  76. data/test/validation/{dry_validation_test.rb → dry_validation_old_api.rb} +223 -116
  77. data/test/validation/result_test.rb +20 -22
  78. data/test/validation_library_provided_test.rb +3 -3
  79. data/test/virtual_test.rb +46 -6
  80. data/test/writeable_test.rb +7 -7
  81. metadata +101 -51
  82. data/test/errors_test.rb +0 -180
  83. data/test/readonly_test.rb +0 -14
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require "test_helper"
2
2
 
3
3
  class ParseOptionTest < MiniTest::Spec
4
4
  Comment = Struct.new(:content, :user)
@@ -9,8 +9,8 @@ class ParseOptionTest < MiniTest::Spec
9
9
  property :user, parse: false
10
10
  end
11
11
 
12
- let (:current_user) { User.new("Peter") }
13
- let (:form) { CommentForm.new(Comment.new, user: current_user) }
12
+ let(:current_user) { User.new("Peter") }
13
+ let(:form) { CommentForm.new(Comment.new, user: current_user) }
14
14
 
15
15
  it do
16
16
  form.user.must_equal current_user
@@ -25,8 +25,8 @@ class ParseOptionTest < MiniTest::Spec
25
25
  describe "using ':parse' option doesn't override other ':deserialize' options" do
26
26
  class ArticleCommentForm < TestForm
27
27
  property :content
28
- property :article, deserializer: { instance: "Instance" }
29
- property :user, parse: false, deserializer: { instance: "Instance" }
28
+ property :article, deserializer: {instance: "Instance"}
29
+ property :user, parse: false, deserializer: {instance: "Instance"}
30
30
  end
31
31
 
32
32
  it do
@@ -4,7 +4,7 @@ class ParsePipelineTest < MiniTest::Spec
4
4
  Album = Struct.new(:name)
5
5
 
6
6
  class AlbumForm < TestForm
7
- property :name, deserializer: { parse_pipeline: ->(input, options) { Representable::Pipeline[->(ipt, opts) { opts[:represented].name = ipt.inspect }] } }
7
+ property :name, deserializer: {parse_pipeline: ->(input, options) { Representable::Pipeline[->(ipt, opts) { opts[:represented].name = ipt.inspect }] }}
8
8
  end
9
9
 
10
10
  it "allows passing :parse_pipeline directly" do
@@ -12,4 +12,4 @@ class ParsePipelineTest < MiniTest::Spec
12
12
  form.validate("name" => "Greatest Hits")
13
13
  form.name.must_equal "{\"name\"=>\"Greatest Hits\"}"
14
14
  end
15
- end
15
+ end
@@ -0,0 +1,304 @@
1
+ require "test_helper"
2
+
3
+ class PopulatorTest < MiniTest::Spec
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, populator: ->(options) { self.name = options[:fragment].reverse }
10
+ validation do
11
+ params { required(:name).filled }
12
+ end
13
+
14
+ collection :songs,
15
+ populator: ->(fragment:, model:, index:, **) {
16
+ (item = model[index]) ? item : model.insert(index, Song.new)
17
+ } do
18
+ property :title
19
+ validation do
20
+ params { required(:title).filled }
21
+ end
22
+
23
+ property :composer, populator: ->(options) { options[:model] || self.composer = Artist.new } do
24
+ property :name
25
+ validation do
26
+ params { required(:name).filled }
27
+ end
28
+ end
29
+ end
30
+
31
+ # property :artist, populator: lambda { |fragment, options| (item = options.binding.get) ? item : Artist.new } do
32
+ # NOTE: we have to document that model here is the twin!
33
+ property :artist, populator: ->(options) { options[:model] || self.artist = Artist.new } do
34
+ property :name
35
+ end
36
+ end
37
+
38
+ let(:song) { Song.new("Broken") }
39
+ let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
40
+ let(:composer) { Artist.new("Greg Graffin") }
41
+ let(:artist) { Artist.new("Bad Religion") }
42
+ let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
43
+
44
+ let(:form) { AlbumForm.new(album) }
45
+
46
+ it "runs populator on scalar" do
47
+ form.validate(
48
+ "name" => "override me!"
49
+ )
50
+
51
+ form.name.must_equal "!em edirrevo"
52
+ end
53
+
54
+ # changing existing property :artist.
55
+ # TODO: check with artist==nil
56
+ it do
57
+ old_id = artist.object_id
58
+
59
+ form.validate(
60
+ "artist" => {"name" => "Marcus Miller"}
61
+ )
62
+
63
+ form.artist.model.object_id.must_equal old_id
64
+ end
65
+
66
+ # use populator for default value on scalars?
67
+
68
+ # adding to collection via :populator.
69
+ # valid.
70
+ it "yyy" do
71
+ form.validate(
72
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
73
+ {"title" => "Rime Of The Ancient Mariner"}, # new song.
74
+ {"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
75
+ ).must_equal true
76
+
77
+ form.errors.messages.inspect.must_equal "{}"
78
+
79
+ # form has updated.
80
+ form.name.must_equal "The Dissent Of Man"
81
+ form.songs[0].title.must_equal "Fallout"
82
+ form.songs[1].title.must_equal "Roxanne"
83
+ form.songs[1].composer.name.must_equal "Greg Graffin"
84
+
85
+ form.songs[1].composer.model.must_be_instance_of Artist
86
+
87
+ form.songs[1].title.must_equal "Roxanne"
88
+ form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
89
+ form.songs[3].title.must_equal "Re-Education"
90
+ form.songs[3].composer.name.must_equal "Rise Against"
91
+ form.songs.size.must_equal 4
92
+ form.artist.name.must_equal "Bad Religion"
93
+
94
+ # model has not changed, yet.
95
+ album.name.must_equal "The Dissent Of Man"
96
+ album.songs[0].title.must_equal "Broken"
97
+ album.songs[1].title.must_equal "Resist Stance"
98
+ album.songs[1].composer.name.must_equal "Greg Graffin"
99
+ album.songs.size.must_equal 2
100
+ album.artist.name.must_equal "Bad Religion"
101
+ end
102
+ end
103
+
104
+ class PopulateWithMethodTest < Minitest::Spec
105
+ Album = Struct.new(:title)
106
+
107
+ class AlbumForm < TestForm
108
+ property :title, populator: :title!
109
+
110
+ def title!(options)
111
+ self.title = options[:fragment].reverse
112
+ end
113
+ end
114
+
115
+ let(:form) { AlbumForm.new(Album.new) }
116
+
117
+ it "runs populator method" do
118
+ form.validate("title" => "override me!")
119
+
120
+ form.title.must_equal "!em edirrevo"
121
+ end
122
+ end
123
+
124
+ class PopulateWithCallableTest < Minitest::Spec
125
+ Album = Struct.new(:title)
126
+
127
+ class TitlePopulator
128
+ include Uber::Callable
129
+
130
+ def call(form, options)
131
+ form.title = options[:fragment].reverse
132
+ end
133
+ end
134
+
135
+ class AlbumForm < TestForm
136
+ property :title, populator: TitlePopulator.new
137
+ end
138
+
139
+ let(:form) { AlbumForm.new(Album.new) }
140
+
141
+ it "runs populator method" do
142
+ form.validate("title" => "override me!")
143
+
144
+ form.title.must_equal "!em edirrevo"
145
+ end
146
+ end
147
+
148
+ class PopulateWithProcTest < Minitest::Spec
149
+ Album = Struct.new(:title)
150
+
151
+ TitlePopulator = ->(options) do
152
+ options[:represented].title = options[:fragment].reverse
153
+ end
154
+
155
+ class AlbumForm < TestForm
156
+ property :title, populator: TitlePopulator
157
+ end
158
+
159
+ let(:form) { AlbumForm.new(Album.new) }
160
+
161
+ it "runs populator method" do
162
+ form.validate("title" => "override me!")
163
+
164
+ form.title.must_equal "!em edirrevo"
165
+ end
166
+ end
167
+
168
+ class PopulateIfEmptyTest < MiniTest::Spec
169
+ Song = Struct.new(:title, :album, :composer)
170
+ Album = Struct.new(:name, :songs, :artist)
171
+ Artist = Struct.new(:name)
172
+
173
+ let(:song) { Song.new("Broken") }
174
+ let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
175
+ let(:composer) { Artist.new("Greg Graffin") }
176
+ let(:artist) { Artist.new("Bad Religion") }
177
+ let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
178
+
179
+ class AlbumForm < TestForm
180
+ property :name
181
+
182
+ collection :songs,
183
+ populate_if_empty: Song do # class name works.
184
+
185
+ property :title
186
+ validation do
187
+ params { required(:title).filled }
188
+ end
189
+
190
+ property :composer, populate_if_empty: :populate_composer! do # lambda works, too. in form context.
191
+ property :name
192
+ validation do
193
+ params { required(:name).filled }
194
+ end
195
+ end
196
+
197
+ private
198
+ def populate_composer!(options)
199
+ Artist.new
200
+ end
201
+ end
202
+
203
+ property :artist, populate_if_empty: ->(args) { create_artist(args[:fragment], args[:user_options]) } do # methods work, too.
204
+ property :name
205
+ end
206
+
207
+ private
208
+ class Sting < Artist
209
+ attr_accessor :args
210
+ end
211
+ def create_artist(input, user_options)
212
+ Sting.new.tap { |artist| artist.args = ([input, user_options].to_s) }
213
+ end
214
+ end
215
+
216
+ let(:form) { AlbumForm.new(album) }
217
+
218
+ it do
219
+ form.songs.size.must_equal 2
220
+
221
+ form.validate(
222
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
223
+ {"title" => "Rime Of The Ancient Mariner"}, # new song.
224
+ {"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
225
+ ).must_equal true
226
+
227
+ form.errors.messages.inspect.must_equal "{}"
228
+
229
+ # form has updated.
230
+ form.name.must_equal "The Dissent Of Man"
231
+ form.songs[0].title.must_equal "Fallout"
232
+ form.songs[1].title.must_equal "Roxanne"
233
+ form.songs[1].composer.name.must_equal "Greg Graffin"
234
+ form.songs[1].title.must_equal "Roxanne"
235
+ form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
236
+ form.songs[3].title.must_equal "Re-Education"
237
+ form.songs[3].composer.name.must_equal "Rise Against"
238
+ form.songs.size.must_equal 4
239
+ form.artist.name.must_equal "Bad Religion"
240
+
241
+ # model has not changed, yet.
242
+ album.name.must_equal "The Dissent Of Man"
243
+ album.songs[0].title.must_equal "Broken"
244
+ album.songs[1].title.must_equal "Resist Stance"
245
+ album.songs[1].composer.name.must_equal "Greg Graffin"
246
+ album.songs.size.must_equal 2
247
+ album.artist.name.must_equal "Bad Religion"
248
+ end
249
+
250
+ # trigger artist populator. lambda calling form instance method.
251
+ it "xxxx" do
252
+ form = AlbumForm.new(album = Album.new)
253
+ form.validate("artist" => {"name" => "From Autumn To Ashes"})
254
+
255
+ form.artist.name.must_equal "From Autumn To Ashes"
256
+ # test lambda was executed in form context.
257
+ form.artist.model.must_be_instance_of AlbumForm::Sting
258
+ # test lambda block arguments.
259
+ form.artist.model.args.to_s.must_equal "[{\"name\"=>\"From Autumn To Ashes\"}, nil]"
260
+
261
+ assert_nil album.artist
262
+ end
263
+ end
264
+
265
+ # delete songs while deserializing.
266
+ class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
267
+ Song = Struct.new(:title, :album, :composer)
268
+ Album = Struct.new(:name, :songs, :artist)
269
+
270
+ let(:song) { Song.new("Broken") }
271
+ let(:song2) { Song.new("Resist Stance") }
272
+ let(:album) { Album.new("The Dissent Of Man", [song, song2]) }
273
+
274
+ class AlbumForm < TestForm
275
+ property :name
276
+
277
+ collection :songs,
278
+ populate_if_empty: Song, skip_if: :delete_song! do
279
+
280
+ property :title
281
+ validation do
282
+ params { required(:title).filled }
283
+ end
284
+ end
285
+
286
+ def delete_song!(options)
287
+ songs.delete(songs[0]) and return true if options[:fragment]["title"] == "Broken, delete me!"
288
+ false
289
+ end
290
+ end
291
+
292
+ let(:form) { AlbumForm.new(album) }
293
+
294
+ it do
295
+ form.validate(
296
+ "songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
297
+ ).must_equal true
298
+
299
+ form.errors.messages.inspect.must_equal "{}"
300
+
301
+ form.songs.size.must_equal 1
302
+ form.songs[0].title.must_equal "Roxanne"
303
+ end
304
+ end
@@ -12,15 +12,15 @@ class PopulatorTest < MiniTest::Spec
12
12
  end
13
13
 
14
14
  collection :songs,
15
- populator: ->(fragment:, model:, index:, **) {
16
- (item = model[index]) ? item : model.insert(index, Song.new) } do
17
-
15
+ populator: ->(fragment:, model:, index:, **) {
16
+ (item = model[index]) ? item : model.insert(index, Song.new)
17
+ } do
18
18
  property :title
19
19
  validation do
20
20
  required(:title).filled
21
21
  end
22
22
 
23
- property :composer, populator: ->(options) { options[:model] || self.composer= Artist.new } do
23
+ property :composer, populator: ->(options) { options[:model] || self.composer = Artist.new } do
24
24
  property :name
25
25
  validation do
26
26
  required(:name).filled
@@ -35,13 +35,13 @@ class PopulatorTest < MiniTest::Spec
35
35
  end
36
36
  end
37
37
 
38
- let (:song) { Song.new("Broken") }
39
- let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
40
- let (:composer) { Artist.new("Greg Graffin") }
41
- let (:artist) { Artist.new("Bad Religion") }
42
- let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
38
+ let(:song) { Song.new("Broken") }
39
+ let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
40
+ let(:composer) { Artist.new("Greg Graffin") }
41
+ let(:artist) { Artist.new("Bad Religion") }
42
+ let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
43
43
 
44
- let (:form) { AlbumForm.new(album) }
44
+ let(:form) { AlbumForm.new(album) }
45
45
 
46
46
  it "runs populator on scalar" do
47
47
  form.validate(
@@ -91,7 +91,6 @@ class PopulatorTest < MiniTest::Spec
91
91
  form.songs.size.must_equal 4
92
92
  form.artist.name.must_equal "Bad Religion"
93
93
 
94
-
95
94
  # model has not changed, yet.
96
95
  album.name.must_equal "The Dissent Of Man"
97
96
  album.songs[0].title.must_equal "Broken"
@@ -113,7 +112,7 @@ class PopulateWithMethodTest < Minitest::Spec
113
112
  end
114
113
  end
115
114
 
116
- let (:form) { AlbumForm.new(Album.new) }
115
+ let(:form) { AlbumForm.new(Album.new) }
117
116
 
118
117
  it "runs populator method" do
119
118
  form.validate("title" => "override me!")
@@ -137,7 +136,7 @@ class PopulateWithCallableTest < Minitest::Spec
137
136
  property :title, populator: TitlePopulator.new
138
137
  end
139
138
 
140
- let (:form) { AlbumForm.new(Album.new) }
139
+ let(:form) { AlbumForm.new(Album.new) }
141
140
 
142
141
  it "runs populator method" do
143
142
  form.validate("title" => "override me!")
@@ -157,7 +156,7 @@ class PopulateWithProcTest < Minitest::Spec
157
156
  property :title, populator: TitlePopulator
158
157
  end
159
158
 
160
- let (:form) { AlbumForm.new(Album.new) }
159
+ let(:form) { AlbumForm.new(Album.new) }
161
160
 
162
161
  it "runs populator method" do
163
162
  form.validate("title" => "override me!")
@@ -171,13 +170,11 @@ class PopulateIfEmptyTest < MiniTest::Spec
171
170
  Album = Struct.new(:name, :songs, :artist)
172
171
  Artist = Struct.new(:name)
173
172
 
174
- let (:song) { Song.new("Broken") }
175
- let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
176
- let (:composer) { Artist.new("Greg Graffin") }
177
- let (:artist) { Artist.new("Bad Religion") }
178
- let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
179
-
180
-
173
+ let(:song) { Song.new("Broken") }
174
+ let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
175
+ let(:composer) { Artist.new("Greg Graffin") }
176
+ let(:artist) { Artist.new("Bad Religion") }
177
+ let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
181
178
 
182
179
  class AlbumForm < TestForm
183
180
  property :name
@@ -203,26 +200,26 @@ class PopulateIfEmptyTest < MiniTest::Spec
203
200
  end
204
201
  end
205
202
 
206
- property :artist, populate_if_empty: lambda { |args| create_artist(args[:fragment], args[:user_options]) } do # methods work, too.
203
+ property :artist, populate_if_empty: ->(args) { create_artist(args[:fragment], args[:user_options]) } do # methods work, too.
207
204
  property :name
208
205
  end
209
206
 
210
- private
207
+ private
211
208
  class Sting < Artist
212
209
  attr_accessor :args
213
210
  end
214
211
  def create_artist(input, user_options)
215
- Sting.new.tap { |artist| artist.args=([input, user_options].to_s) }
212
+ Sting.new.tap { |artist| artist.args = ([input, user_options].to_s) }
216
213
  end
217
214
  end
218
215
 
219
- let (:form) { AlbumForm.new(album) }
216
+ let(:form) { AlbumForm.new(album) }
220
217
 
221
218
  it do
222
219
  form.songs.size.must_equal 2
223
220
 
224
221
  form.validate(
225
- "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
222
+ "songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
226
223
  {"title" => "Rime Of The Ancient Mariner"}, # new song.
227
224
  {"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
228
225
  ).must_equal true
@@ -241,7 +238,6 @@ class PopulateIfEmptyTest < MiniTest::Spec
241
238
  form.songs.size.must_equal 4
242
239
  form.artist.name.must_equal "Bad Religion"
243
240
 
244
-
245
241
  # model has not changed, yet.
246
242
  album.name.must_equal "The Dissent Of Man"
247
243
  album.songs[0].title.must_equal "Broken"
@@ -266,16 +262,14 @@ class PopulateIfEmptyTest < MiniTest::Spec
266
262
  end
267
263
  end
268
264
 
269
-
270
265
  # delete songs while deserializing.
271
266
  class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
272
267
  Song = Struct.new(:title, :album, :composer)
273
268
  Album = Struct.new(:name, :songs, :artist)
274
269
 
275
- let (:song) { Song.new("Broken") }
276
- let (:song2) { Song.new("Resist Stance") }
277
- let (:album) { Album.new("The Dissent Of Man", [song, song2]) }
278
-
270
+ let(:song) { Song.new("Broken") }
271
+ let(:song2) { Song.new("Resist Stance") }
272
+ let(:album) { Album.new("The Dissent Of Man", [song, song2]) }
279
273
 
280
274
  class AlbumForm < TestForm
281
275
  property :name
@@ -295,11 +289,11 @@ class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
295
289
  end
296
290
  end
297
291
 
298
- let (:form) { AlbumForm.new(album) }
292
+ let(:form) { AlbumForm.new(album) }
299
293
 
300
294
  it do
301
295
  form.validate(
302
- "songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
296
+ "songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
303
297
  ).must_equal true
304
298
 
305
299
  form.errors.messages.inspect.must_equal "{}"