reform 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,28 +1,32 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class FormCompositionTest < MiniTest::Spec
4
- Song = Struct.new(:id, :title)
4
+ Song = Struct.new(:id, :title, :band)
5
5
  Requester = Struct.new(:id, :name, :requester)
6
+ Band = Struct.new(:title)
6
7
 
7
8
  class RequestForm < Reform::Form
8
9
  include Composition
9
10
 
10
- # TODO: remove skip_accessors in 1.1.
11
- property :name, :on => :requester, :skip_accessors => true
12
- property :requester_id, :on => :requester, :as => :id, :skip_accessors => true
11
+ property :name, :on => :requester
12
+ property :requester_id, :on => :requester, :as => :id
13
13
  properties [:title, :id], :on => :song
14
14
  # property :channel # FIXME: what about the "main model"?
15
15
  property :channel, :empty => true, :on => :song
16
- property :requester, :on => :requester, :skip_accessors => true
16
+ property :requester, :on => :requester
17
17
  property :captcha, :on => :song, :empty => true
18
18
 
19
19
  validates :name, :title, :channel, :presence => true
20
- end
21
20
 
22
- let (:form) { RequestForm.new(:song => song, :requester => requester) }
23
- let (:song) { Song.new(1, "Rio") }
24
- let (:requester) { Requester.new(2, "Duran Duran", "MCP") }
21
+ property :band, :on => :song do
22
+ property :title
23
+ end
24
+ end
25
25
 
26
+ let (:form) { RequestForm.new(:song => song, :requester => requester) }
27
+ let (:song) { Song.new(1, "Rio", band) }
28
+ let (:requester) { Requester.new(2, "Duran Duran", "MCP") }
29
+ let (:band) { Band.new("Duran^2") }
26
30
 
27
31
  # delegation form -> composition works
28
32
  it { form.id.must_equal 1 }
@@ -33,11 +37,6 @@ class FormCompositionTest < MiniTest::Spec
33
37
  it { form.requester.must_equal "MCP" } # same name as composed model.
34
38
  it { form.captcha.must_equal nil }
35
39
 
36
- # [DEPRECATED] # TODO: remove in 1.2.
37
- # delegation form -> composed models (e.g. when saving this can be handy)
38
- it { form.song.must_equal song }
39
-
40
-
41
40
  # #model just returns <Composition>.
42
41
  it { form.model.must_be_kind_of Reform::Composition }
43
42
 
@@ -51,12 +50,13 @@ class FormCompositionTest < MiniTest::Spec
51
50
  end
52
51
 
53
52
  describe "#save" do
54
- it "provides data block argument" do
53
+ # #save with {}
54
+ it do
55
55
  hash = {}
56
56
 
57
- form.save do |data, map|
58
- hash[:name] = data.name
59
- hash[:title] = data.title
57
+ form.save do |map|
58
+ hash[:name] = form.name
59
+ hash[:title] = form.title
60
60
  end
61
61
 
62
62
  hash.must_equal({:name=>"Duran Duran", :title=>"Rio"})
@@ -65,21 +65,23 @@ class FormCompositionTest < MiniTest::Spec
65
65
  it "provides nested symbolized hash as second block argument" do
66
66
  form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb", "channel" => "JJJ", "captcha" => "wonderful")
67
67
 
68
- hash = {}
68
+ hash = nil
69
69
 
70
- form.save do |data, map|
70
+ form.save do |map|
71
71
  hash = map
72
72
  end
73
73
 
74
74
  hash.must_equal({
75
- :song=>{:title=>"Greyhound", :id=>1, :channel => "JJJ", :captcha=>"wonderful"},
76
- :requester=>{:name=>"Frenzal Rhomb", :id=>2, :requester => "MCP"}}
75
+ :song=>{:title=>"Greyhound", :id=>1, :channel => "JJJ", :captcha=>"wonderful", :band=>{"title"=>"Duran^2"}},
76
+ :requester=>{:name=>"Frenzal Rhomb", :id=>2, :requester => "MCP"}
77
+ }
77
78
  )
78
79
  end
79
80
 
80
81
  it "pushes data to models and calls #save when no block passed" do
81
82
  song.extend(Saveable)
82
83
  requester.extend(Saveable)
84
+ band.extend(Saveable)
83
85
 
84
86
  form.validate("title" => "Greyhound", "name" => "Frenzal Rhomb", "captcha" => "1337")
85
87
  form.captcha.must_equal "1337" # TODO: move to separate test.
@@ -90,6 +92,32 @@ class FormCompositionTest < MiniTest::Spec
90
92
  requester.saved?.must_equal true
91
93
  song.title.must_equal "Greyhound"
92
94
  song.saved?.must_equal true
95
+ song.band.title.must_equal "Duran^2"
96
+ song.band.saved?.must_equal true
93
97
  end
94
98
  end
95
99
  end
100
+
101
+
102
+ class FormCompositionCollectionTest < MiniTest::Spec
103
+ Book = Struct.new(:id, :name)
104
+ Library = Struct.new(:id) do
105
+ def books
106
+ [Book.new(1,"My book")]
107
+ end
108
+ end
109
+
110
+ class LibraryForm < Reform::Form
111
+ include Reform::Form::Composition
112
+
113
+ collection :books, on: :library do
114
+ property :id
115
+ property :name
116
+ end
117
+ end
118
+
119
+ let (:form) { LibraryForm.new(library: library) }
120
+ let (:library) { Library.new(2) }
121
+
122
+ it { form.save do |hash| hash.must_equal({:library=>{:books=>[{"id"=>1, "name"=>"My book"}]}}) end }
123
+ end
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+ require 'representable/json'
3
+
4
+ class InheritTest < BaseTest
5
+ class CompilationForm < AlbumForm
6
+
7
+ property :hit, :inherit => true do
8
+ property :rating
9
+ validates :title, :rating, :presence => true
10
+ end
11
+
12
+ # puts representer_class.representable_attrs.
13
+ # get(:hit)[:extend].evaluate(nil).new(OpenStruct.new).rating
14
+ end
15
+
16
+ let (:album) { Album.new(nil, OpenStruct.new(:hit => OpenStruct.new()) ) }
17
+ subject { CompilationForm.new(album) }
18
+
19
+
20
+ # valid.
21
+ it {
22
+ subject.validate("hit" => {"title" => "LA Drone", "rating" => 10})
23
+ subject.hit.title.must_equal "LA Drone"
24
+ subject.hit.rating.must_equal 10
25
+ subject.errors.messages.must_equal({})
26
+ }
27
+
28
+ it do
29
+ subject.validate({})
30
+ subject.hit.title.must_equal nil
31
+ subject.hit.rating.must_equal nil
32
+ subject.errors.messages.must_equal({:"hit.title"=>["can't be blank"], :"hit.rating"=>["can't be blank"]})
33
+ end
34
+ end
35
+
36
+
37
+ class ModuleInclusionTest < MiniTest::Spec
38
+ module BandPropertyForm
39
+ include Reform::Form::Module
40
+
41
+ property :band do
42
+ property :title
43
+
44
+ validates :title, :presence => true
45
+
46
+ def id # gets mixed into Form, too.
47
+ 2
48
+ end
49
+ end
50
+
51
+ def id # gets mixed into Form, too.
52
+ 1
53
+ end
54
+
55
+ validates :band, :presence => true
56
+ end
57
+
58
+
59
+ class SongForm < Reform::Form
60
+ property :title
61
+
62
+ include BandPropertyForm
63
+ end
64
+
65
+ let (:song) { OpenStruct.new(:band => OpenStruct.new(:title => "Time Again")) }
66
+
67
+ # nested form from module is present and creates accessor.
68
+ it { SongForm.new(song).band.title.must_equal "Time Again" }
69
+
70
+ # methods from module get included.
71
+ it { SongForm.new(song).id.must_equal 1 }
72
+ it { SongForm.new(song).band.id.must_equal 2 }
73
+
74
+ it do
75
+ form = SongForm.new(OpenStruct.new())
76
+ form.validate({})
77
+ form.errors.messages.must_equal({:band=>["can't be blank"]})
78
+ end
79
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ class ModelValidationsTest < MiniTest::Spec
4
+
5
+ class Album
6
+ include ActiveModel::Validations
7
+ attr_accessor :title, :artist, :other_attribute
8
+
9
+ validates :title, :artist, presence: true
10
+ validates :other_attribute, presence: true
11
+ end
12
+
13
+ class AlbumRating
14
+ include ActiveModel::Validations
15
+
16
+ attr_accessor :rating
17
+
18
+ validates :rating, numericality: { greater_than_or_equal_to: 0 }
19
+
20
+ end
21
+
22
+ class AlbumForm < Reform::Form
23
+ extend ActiveModel::ModelValidations
24
+
25
+ property :title
26
+ property :artist_name, as: :artist
27
+ copy_validations_from Album
28
+ end
29
+
30
+ class CompositeForm < Reform::Form
31
+ include Composition
32
+ extend ActiveModel::ModelValidations
33
+
34
+ model :album
35
+
36
+ property :title, on: :album
37
+ property :artist_name, as: :artist, on: :album
38
+ property :rating, on: :album_rating
39
+
40
+ copy_validations_from album: Album, album_rating: AlbumRating
41
+ end
42
+
43
+ let(:album) { Album.new }
44
+
45
+ describe 'non-composite form' do
46
+
47
+ let(:album_form) { AlbumForm.new(album) }
48
+
49
+ it 'is not valid when title is not present' do
50
+ album_form.validate(artist_name: 'test', title: nil).must_equal false
51
+ end
52
+
53
+ it 'is not valid when artist_name is not present' do
54
+ album_form.validate(artist_name: nil, title: 'test').must_equal false
55
+ end
56
+
57
+ it 'is valid when title and artist_name is present' do
58
+ album_form.validate(artist_name: 'test', title: 'test').must_equal true
59
+ end
60
+
61
+ end
62
+
63
+ describe 'composite form' do
64
+
65
+ let(:album_rating) { AlbumRating.new }
66
+ let(:composite_form) { CompositeForm.new(album: album, album_rating: album_rating) }
67
+
68
+ it 'is valid when all attributes are correct' do
69
+ composite_form.validate(artist_name: 'test', title: 'test', rating: 1).must_equal true
70
+ end
71
+
72
+ it 'is invalid when rating is below 0' do
73
+ composite_form.validate(artist_name: 'test', title: 'test', rating: -1).must_equal false
74
+ end
75
+
76
+ it 'is invalid when artist_name is missing' do
77
+ composite_form.validate(artist_name: nil, title: 'test', rating: 1).must_equal false
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -39,7 +39,7 @@ class NestedFormTest < MiniTest::Spec
39
39
 
40
40
  it "responds to #save" do
41
41
  hsh = nil
42
- form.save do |f, nested|
42
+ form.save do |nested|
43
43
  hsh = nested
44
44
  end
45
45
  hsh.must_equal({"hit"=>{"title"=>"Downtown"}, "title" => "Blackhawks Over Los Angeles", "songs"=>[{"title"=>"Calling"}]})
@@ -103,21 +103,10 @@ class NestedFormTest < MiniTest::Spec
103
103
  data.must_equal(:title=>"Second Heat", :hit_title => "Sacrifice", :first_title => "Scarified")
104
104
  end
105
105
 
106
- it "passes form instances in first argument" do
107
- frm = nil
108
-
109
- form.save { |f, hsh| frm = f }
110
-
111
- frm.must_equal form
112
- frm.title.must_be_kind_of String
113
- frm.hit.must_be_kind_of Reform::Form
114
- frm.songs.first.must_be_kind_of Reform::Form
115
- end
116
-
117
106
  it "returns nested hash with indifferent access" do
118
107
  nested = nil
119
108
 
120
- form.save do |hash, nested_hash|
109
+ form.save do |nested_hash|
121
110
  nested = nested_hash
122
111
  end
123
112
 
@@ -204,7 +204,7 @@ class ReformTest < ReformSpec
204
204
  end
205
205
 
206
206
  describe "#save with block" do
207
- it "provides data block argument" do
207
+ it "Deprecated: provides data block argument" do # TODO: remove in 1.1.
208
208
  hash = {}
209
209
 
210
210
  form.save do |data, map|
@@ -215,7 +215,7 @@ class ReformTest < ReformSpec
215
215
  hash.must_equal({:name=>"Diesel Boy", :title=>nil})
216
216
  end
217
217
 
218
- it "provides nested symbolized hash as second block argument" do
218
+ it "Deprecated: provides nested symbolized hash as second block argument" do # TODO: remove in 1.1.
219
219
  hash = {}
220
220
 
221
221
  form.save do |data, map|
@@ -224,6 +224,16 @@ class ReformTest < ReformSpec
224
224
 
225
225
  hash.must_equal({"name"=>"Diesel Boy"})
226
226
  end
227
+
228
+ it do
229
+ hash = {}
230
+
231
+ form.save do |map|
232
+ hash = map
233
+ end
234
+
235
+ hash.must_equal({"name"=>"Diesel Boy"})
236
+ end
227
237
  end
228
238
  end
229
239
 
@@ -239,7 +249,7 @@ class ReformTest < ReformSpec
239
249
  validates :position, :presence => true
240
250
  end
241
251
 
242
- let (:form) { HitForm.new(OpenStruct.new) }
252
+ let (:form) { HitForm.new(OpenStruct.new()) }
243
253
  it do
244
254
  form.validate({"title" => "The Body"})
245
255
  form.title.must_equal "The Body"
@@ -247,8 +257,73 @@ class ReformTest < ReformSpec
247
257
  form.errors.messages.must_equal({:name=>["can't be blank"], :position=>["can't be blank"]})
248
258
  end
249
259
  end
260
+
261
+ describe "#column_for_attribute" do
262
+ let (:model) { Artist.new }
263
+ let (:klass) do
264
+ require 'reform/active_record'
265
+
266
+ Class.new Reform::Form do
267
+ include Reform::Form::ActiveRecord
268
+
269
+ model :artist
270
+
271
+ property :name
272
+ end
273
+ end
274
+ let (:form) { klass.new(model) }
275
+
276
+ it 'should delegate to the model' do
277
+ Calls = []
278
+
279
+ def model.column_for_attribute(*args)
280
+ Calls << [:column_for_attribute, *args]
281
+ end
282
+
283
+ form.column_for_attribute(:name)
284
+ Calls.must_include [:column_for_attribute, :name]
285
+ end
286
+ end
287
+
288
+ describe "#column_for_attribute with composition" do
289
+ let (:artist_model) { Artist.new }
290
+ let (:song_model) { Song.new }
291
+ let (:form_klass) do
292
+ require 'reform/active_record'
293
+
294
+ Class.new Reform::Form do
295
+ include Reform::Form::ActiveRecord
296
+ include Reform::Form::Composition
297
+
298
+ model :artist
299
+
300
+ property :name, on: :artist
301
+ property :title, on: :song
302
+ end
303
+ end
304
+ let (:form) { form_klass.new(artist: artist_model, song: song_model) }
305
+
306
+ it 'should delegate to the model' do
307
+ ArtistCalls, SongCalls = [], []
308
+
309
+ def artist_model.column_for_attribute(*args)
310
+ ArtistCalls << [:column_for_attribute, *args]
311
+ end
312
+
313
+ def song_model.column_for_attribute(*args)
314
+ SongCalls << [:column_for_attribute, *args]
315
+ end
316
+
317
+ form.column_for_attribute(:name)
318
+ ArtistCalls.must_include [:column_for_attribute, :name]
319
+
320
+ form.column_for_attribute(:title)
321
+ SongCalls.must_include [:column_for_attribute, :title]
322
+ end
323
+ end
250
324
  end
251
325
 
326
+
252
327
  class EmptyAttributesTest < MiniTest::Spec
253
328
  Credentials = Struct.new(:password)
254
329
 
@@ -270,7 +345,7 @@ class EmptyAttributesTest < MiniTest::Spec
270
345
  cred.password.must_equal "123"
271
346
 
272
347
  hash = {}
273
- form.save do |f, nested|
348
+ form.save do |nested|
274
349
  hash = nested
275
350
  end
276
351
 
@@ -298,7 +373,7 @@ class ReadonlyAttributesTest < MiniTest::Spec
298
373
  loc.country.must_equal "Australia" # the writer wasn't called.
299
374
 
300
375
  hash = {}
301
- form.save do |f, nested|
376
+ form.save do |nested|
302
377
  hash = nested
303
378
  end
304
379
 
@@ -335,7 +410,7 @@ class OverridingAccessorsTest < BaseTest
335
410
 
336
411
  # the reader is not used when saving/syncing.
337
412
  it do
338
- subject.save do |f, hash|
413
+ subject.save do |hash|
339
414
  hash["title"].must_equal "Hey Little WorldHey Little World"
340
415
  end
341
416
  end
@@ -347,4 +422,28 @@ class OverridingAccessorsTest < BaseTest
347
422
  song.title.must_equal "Hey Little WorldHey Little World"
348
423
  end
349
424
  end
350
- end
425
+ end
426
+
427
+
428
+ class MethodInFormTest < MiniTest::Spec
429
+ class AlbumForm < Reform::Form
430
+ property :title
431
+
432
+ def title
433
+ "The Suffer And The Witness"
434
+ end
435
+
436
+ property :hit do
437
+ property :title
438
+
439
+ def title
440
+ "Drones"
441
+ end
442
+ end
443
+ end
444
+
445
+ # methods can be used instead of created accessors.
446
+ subject { AlbumForm.new(OpenStruct.new(:hit => OpenStruct.new)) }
447
+ it { subject.title.must_equal "The Suffer And The Witness" }
448
+ it { subject.hit.title.must_equal "Drones" }
449
+ end