reform 1.2.6 → 2.0.0.beta1
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.
- checksums.yaml +4 -4
- data/.travis.yml +6 -1
- data/CHANGES.md +14 -0
- data/Gemfile +3 -2
- data/README.md +225 -283
- data/Rakefile +27 -0
- data/TODO.md +12 -0
- data/database.sqlite3 +0 -0
- data/gemfiles/Gemfile.rails-3.0 +1 -0
- data/gemfiles/Gemfile.rails-3.1 +1 -0
- data/gemfiles/Gemfile.rails-3.2 +1 -0
- data/gemfiles/Gemfile.rails-4.0 +1 -0
- data/lib/reform.rb +0 -1
- data/lib/reform/contract.rb +64 -170
- data/lib/reform/contract/validate.rb +10 -13
- data/lib/reform/form.rb +74 -19
- data/lib/reform/form/active_model.rb +19 -14
- data/lib/reform/form/coercion.rb +1 -13
- data/lib/reform/form/composition.rb +2 -24
- data/lib/reform/form/multi_parameter_attributes.rb +43 -62
- data/lib/reform/form/populator.rb +85 -0
- data/lib/reform/form/prepopulate.rb +13 -43
- data/lib/reform/form/validate.rb +29 -90
- data/lib/reform/form/validation/unique_validator.rb +13 -0
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +7 -7
- data/test/active_model_test.rb +43 -0
- data/test/changed_test.rb +23 -51
- data/test/coercion_test.rb +1 -7
- data/test/composition_test.rb +128 -34
- data/test/contract_test.rb +27 -86
- data/test/feature_test.rb +43 -6
- data/test/fields_test.rb +2 -12
- data/test/form_builder_test.rb +28 -25
- data/test/form_option_test.rb +19 -0
- data/test/from_test.rb +0 -75
- data/test/inherit_test.rb +178 -117
- data/test/model_reflections_test.rb +1 -1
- data/test/populate_test.rb +226 -0
- data/test/prepopulator_test.rb +112 -0
- data/test/readable_test.rb +2 -4
- data/test/save_test.rb +56 -112
- data/test/setup_test.rb +48 -0
- data/test/skip_if_test.rb +5 -2
- data/test/skip_setter_and_getter_test.rb +54 -0
- data/test/test_helper.rb +3 -1
- data/test/uniqueness_test.rb +41 -0
- data/test/validate_test.rb +325 -289
- data/test/virtual_test.rb +1 -3
- data/test/writeable_test.rb +3 -4
- metadata +35 -39
- data/lib/reform/composition.rb +0 -63
- data/lib/reform/contract/setup.rb +0 -50
- data/lib/reform/form/changed.rb +0 -9
- data/lib/reform/form/sync.rb +0 -116
- data/lib/reform/representer.rb +0 -84
- data/test/empty_test.rb +0 -58
- data/test/form_composition_test.rb +0 -145
- data/test/nested_form_test.rb +0 -197
- data/test/prepopulate_test.rb +0 -85
- data/test/sync_option_test.rb +0 -83
- data/test/sync_test.rb +0 -56
@@ -85,7 +85,7 @@ class ModelReflectionTest < MiniTest::Spec
|
|
85
85
|
# delegate to model class.
|
86
86
|
it do
|
87
87
|
reflection = form.class.reflect_on_association(:artist)
|
88
|
-
reflection.
|
88
|
+
reflection.must_be_kind_of ActiveRecord::Reflection::AssociationReflection
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
@@ -0,0 +1,226 @@
|
|
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 < Reform::Form
|
9
|
+
property :name
|
10
|
+
validates :name, presence: true
|
11
|
+
|
12
|
+
collection :songs,
|
13
|
+
populator: lambda { |fragment, collection, index, options|
|
14
|
+
# collection = options.binding.get # we don't need this anymore as this comes in for free!
|
15
|
+
(item = collection[index]) ? item : collection.insert(index, Song.new) } do
|
16
|
+
|
17
|
+
property :title
|
18
|
+
validates :title, presence: true
|
19
|
+
|
20
|
+
property :composer, populator: lambda { |fragment, model, options| model || self.composer= Artist.new } do
|
21
|
+
property :name
|
22
|
+
validates :name, presence: true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# property :artist, populator: lambda { |fragment, options| (item = options.binding.get) ? item : Artist.new } do
|
27
|
+
# NOTE: we have to document that model here is the twin!
|
28
|
+
property :artist, populator: lambda { |fragment, twin, *| twin || self.artist = Artist.new } do
|
29
|
+
property :name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
let (:song) { Song.new("Broken") }
|
34
|
+
let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
|
35
|
+
let (:composer) { Artist.new("Greg Graffin") }
|
36
|
+
let (:artist) { Artist.new("Bad Religion") }
|
37
|
+
let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
|
38
|
+
|
39
|
+
let (:form) { AlbumForm.new(album) }
|
40
|
+
|
41
|
+
# changing existing property :artist.
|
42
|
+
# TODO: check with artist==nil
|
43
|
+
it do
|
44
|
+
old_id = artist.object_id
|
45
|
+
|
46
|
+
form.validate(
|
47
|
+
"artist" => {"name" => "Marcus Miller"}
|
48
|
+
)
|
49
|
+
|
50
|
+
form.artist.model.object_id.must_equal old_id
|
51
|
+
end
|
52
|
+
|
53
|
+
# use populator for default value on scalars?
|
54
|
+
|
55
|
+
# adding to collection via :populator.
|
56
|
+
# valid.
|
57
|
+
it "yyy" do
|
58
|
+
form.validate(
|
59
|
+
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
|
60
|
+
{"title" => "Rime Of The Ancient Mariner"}, # new song.
|
61
|
+
{"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
|
62
|
+
).must_equal true
|
63
|
+
|
64
|
+
form.errors.messages.inspect.must_equal "{}"
|
65
|
+
|
66
|
+
# form has updated.
|
67
|
+
form.name.must_equal "The Dissent Of Man"
|
68
|
+
form.songs[0].title.must_equal "Fallout"
|
69
|
+
form.songs[1].title.must_equal "Roxanne"
|
70
|
+
form.songs[1].composer.name.must_equal "Greg Graffin"
|
71
|
+
|
72
|
+
form.songs[1].composer.model.must_be_instance_of Artist
|
73
|
+
|
74
|
+
form.songs[1].title.must_equal "Roxanne"
|
75
|
+
form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
|
76
|
+
form.songs[3].title.must_equal "Re-Education"
|
77
|
+
form.songs[3].composer.name.must_equal "Rise Against"
|
78
|
+
form.songs.size.must_equal 4
|
79
|
+
form.artist.name.must_equal "Bad Religion"
|
80
|
+
|
81
|
+
|
82
|
+
# model has not changed, yet.
|
83
|
+
album.name.must_equal "The Dissent Of Man"
|
84
|
+
album.songs[0].title.must_equal "Broken"
|
85
|
+
album.songs[1].title.must_equal "Resist Stance"
|
86
|
+
album.songs[1].composer.name.must_equal "Greg Graffin"
|
87
|
+
album.songs.size.must_equal 2
|
88
|
+
album.artist.name.must_equal "Bad Religion"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class PopulateIfEmptyTest < MiniTest::Spec
|
93
|
+
Song = Struct.new(:title, :album, :composer)
|
94
|
+
Album = Struct.new(:name, :songs, :artist)
|
95
|
+
Artist = Struct.new(:name)
|
96
|
+
|
97
|
+
let (:song) { Song.new("Broken") }
|
98
|
+
let (:song_with_composer) { Song.new("Resist Stance", nil, composer) }
|
99
|
+
let (:composer) { Artist.new("Greg Graffin") }
|
100
|
+
let (:artist) { Artist.new("Bad Religion") }
|
101
|
+
let (:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
class AlbumForm < Reform::Form
|
106
|
+
property :name
|
107
|
+
|
108
|
+
collection :songs,
|
109
|
+
populate_if_empty: Song do # class name works.
|
110
|
+
|
111
|
+
property :title
|
112
|
+
validates :title, presence: true
|
113
|
+
|
114
|
+
property :composer, populate_if_empty: :populate_composer! do # lambda works, too. in form context.
|
115
|
+
property :name
|
116
|
+
validates :name, presence: true
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def populate_composer!(fragment, options)
|
121
|
+
Artist.new
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
property :artist, populate_if_empty: lambda { |*args| create_artist(args) } do # methods work, too.
|
126
|
+
property :name
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
class Sting < Artist
|
131
|
+
attr_accessor :args
|
132
|
+
end
|
133
|
+
def create_artist(args)
|
134
|
+
Sting.new.tap { |artist| artist.args=(args) }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
let (:form) { AlbumForm.new(album) }
|
139
|
+
|
140
|
+
it do
|
141
|
+
form.validate(
|
142
|
+
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
|
143
|
+
{"title" => "Rime Of The Ancient Mariner"}, # new song.
|
144
|
+
{"title" => "Re-Education", "composer" => {"name" => "Rise Against"}}], # new song with new composer.
|
145
|
+
).must_equal true
|
146
|
+
|
147
|
+
form.errors.messages.inspect.must_equal "{}"
|
148
|
+
|
149
|
+
# form has updated.
|
150
|
+
form.name.must_equal "The Dissent Of Man"
|
151
|
+
form.songs[0].title.must_equal "Fallout"
|
152
|
+
form.songs[1].title.must_equal "Roxanne"
|
153
|
+
form.songs[1].composer.name.must_equal "Greg Graffin"
|
154
|
+
form.songs[1].title.must_equal "Roxanne"
|
155
|
+
form.songs[2].title.must_equal "Rime Of The Ancient Mariner" # new song added.
|
156
|
+
form.songs[3].title.must_equal "Re-Education"
|
157
|
+
form.songs[3].composer.name.must_equal "Rise Against"
|
158
|
+
form.songs.size.must_equal 4
|
159
|
+
form.artist.name.must_equal "Bad Religion"
|
160
|
+
|
161
|
+
|
162
|
+
# model has not changed, yet.
|
163
|
+
album.name.must_equal "The Dissent Of Man"
|
164
|
+
album.songs[0].title.must_equal "Broken"
|
165
|
+
album.songs[1].title.must_equal "Resist Stance"
|
166
|
+
album.songs[1].composer.name.must_equal "Greg Graffin"
|
167
|
+
album.songs.size.must_equal 2
|
168
|
+
album.artist.name.must_equal "Bad Religion"
|
169
|
+
end
|
170
|
+
|
171
|
+
# trigger artist populator. lambda calling form instance method.
|
172
|
+
it do
|
173
|
+
form = AlbumForm.new(album = Album.new)
|
174
|
+
form.validate("artist" => {"name" => "From Autumn To Ashes"})
|
175
|
+
|
176
|
+
form.artist.name.must_equal "From Autumn To Ashes"
|
177
|
+
# test lambda was executed in form context.
|
178
|
+
form.artist.model.must_be_instance_of AlbumForm::Sting
|
179
|
+
# test lambda block arguments.
|
180
|
+
form.artist.model.args.to_s.must_equal "[{\"name\"=>\"From Autumn To Ashes\"}, {}]"
|
181
|
+
|
182
|
+
album.artist.must_equal nil
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
# delete songs while deserializing.
|
189
|
+
class PopulateIfEmptyWithDeletionTest < MiniTest::Spec
|
190
|
+
Song = Struct.new(:title, :album, :composer)
|
191
|
+
Album = Struct.new(:name, :songs, :artist)
|
192
|
+
|
193
|
+
let (:song) { Song.new("Broken") }
|
194
|
+
let (:song2) { Song.new("Resist Stance") }
|
195
|
+
let (:album) { Album.new("The Dissent Of Man", [song, song2]) }
|
196
|
+
|
197
|
+
|
198
|
+
class AlbumForm < Reform::Form
|
199
|
+
property :name
|
200
|
+
|
201
|
+
collection :songs,
|
202
|
+
populate_if_empty: Song, skip_if: :delete_song! do
|
203
|
+
|
204
|
+
property :title
|
205
|
+
validates :title, presence: true
|
206
|
+
end
|
207
|
+
|
208
|
+
def delete_song!(fragment, *)
|
209
|
+
songs.delete(songs[0]) and return true if fragment["title"] == "Broken, delete me!"
|
210
|
+
false
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
let (:form) { AlbumForm.new(album) }
|
215
|
+
|
216
|
+
it do
|
217
|
+
form.validate(
|
218
|
+
"songs" => [{"title" => "Broken, delete me!"}, {"title" => "Roxanne"}]
|
219
|
+
).must_equal true
|
220
|
+
|
221
|
+
form.errors.messages.inspect.must_equal "{}"
|
222
|
+
|
223
|
+
form.songs.size.must_equal 1
|
224
|
+
form.songs[0].title.must_equal "Roxanne"
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class PrepopulatorTest < MiniTest::Spec
|
4
|
+
Song = Struct.new(:title, :band, :length)
|
5
|
+
Band = Struct.new(:name)
|
6
|
+
|
7
|
+
class AlbumForm < Reform::Form
|
8
|
+
property :title, prepopulator: ->(*){ self.title = "Another Day At Work" } # normal assignment.
|
9
|
+
property :length
|
10
|
+
|
11
|
+
property :hit, prepopulator: ->(options) { self.hit = Song.new(options[:title]) } do # use user options.
|
12
|
+
property :title
|
13
|
+
|
14
|
+
property :band, prepopulator: ->(options){ self.band = my_band(options[:title]) } do # invoke your own code.
|
15
|
+
property :name
|
16
|
+
end
|
17
|
+
|
18
|
+
def my_band(name)
|
19
|
+
Band.new(title)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
collection :songs, prepopulator: :prepopulate_songs! do
|
24
|
+
property :title
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def prepopulate_songs!(options)
|
29
|
+
if songs == nil
|
30
|
+
self.songs = [Song.new, Song.new]
|
31
|
+
else
|
32
|
+
songs << Song.new # full Twin::Collection API available.
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it do
|
38
|
+
form = AlbumForm.new(OpenStruct.new(length: 1)).prepopulate!(title: "Potemkin City Limits")
|
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
|
47
|
+
# prepopulate works more than 1 level, recursive.
|
48
|
+
# it also passes options properly down there.
|
49
|
+
form.hit.band.model.must_equal Band.new("Potemkin City Limits")
|
50
|
+
end
|
51
|
+
|
52
|
+
# add to existing collection.
|
53
|
+
it do
|
54
|
+
form = AlbumForm.new(OpenStruct.new(songs: [Song.new])).prepopulate!
|
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
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# calling form.prepopulate! shouldn't crash.
|
63
|
+
class PrepopulateWithoutConfiguration < MiniTest::Spec
|
64
|
+
Song = Struct.new(:title)
|
65
|
+
|
66
|
+
class AlbumForm < Reform::Form
|
67
|
+
collection :songs do
|
68
|
+
property :title
|
69
|
+
end
|
70
|
+
|
71
|
+
property :hit do
|
72
|
+
property :title
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
subject { AlbumForm.new(OpenStruct.new(songs: [], hit: nil)).prepopulate! }
|
77
|
+
|
78
|
+
it { subject.songs.size.must_equal 0 }
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
class ManualPrepopulatorOverridingTest < MiniTest::Spec
|
83
|
+
Song = Struct.new(:title, :band, :length)
|
84
|
+
Band = Struct.new(:name)
|
85
|
+
|
86
|
+
class AlbumForm < Reform::Form
|
87
|
+
property :title
|
88
|
+
property :length
|
89
|
+
|
90
|
+
property :hit do
|
91
|
+
property :title
|
92
|
+
|
93
|
+
property :band do
|
94
|
+
property :name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def prepopulate!(options)
|
99
|
+
self.hit = Song.new(options[:title])
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# you can simply override Form#prepopulate!
|
105
|
+
it do
|
106
|
+
form = AlbumForm.new(OpenStruct.new(length: 1)).prepopulate!(title: "Potemkin City Limits")
|
107
|
+
|
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"
|
111
|
+
end
|
112
|
+
end
|
data/test/readable_test.rb
CHANGED
@@ -4,8 +4,6 @@ class ReadableTest < MiniTest::Spec
|
|
4
4
|
Credentials = Struct.new(:password)
|
5
5
|
|
6
6
|
class PasswordForm < Reform::Form
|
7
|
-
reform_2_0!
|
8
|
-
|
9
7
|
property :password, readable: false
|
10
8
|
end
|
11
9
|
|
@@ -13,14 +11,14 @@ class ReadableTest < MiniTest::Spec
|
|
13
11
|
let (:form) { PasswordForm.new(cred) }
|
14
12
|
|
15
13
|
it {
|
16
|
-
form.password.must_equal nil
|
14
|
+
form.password.must_equal nil # password not read.
|
17
15
|
|
18
16
|
form.validate("password" => "123")
|
19
17
|
|
20
18
|
form.password.must_equal "123"
|
21
19
|
|
22
20
|
form.sync
|
23
|
-
cred.password.must_equal "123"
|
21
|
+
cred.password.must_equal "123" # password written.
|
24
22
|
|
25
23
|
hash = {}
|
26
24
|
form.save do |nested|
|
data/test/save_test.rb
CHANGED
@@ -1,139 +1,83 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class SaveTest < BaseTest
|
4
|
-
|
5
|
-
|
4
|
+
Song = Struct.new(:title, :album, :composer)
|
5
|
+
Album = Struct.new(:name, :songs, :artist)
|
6
|
+
Artist = Struct.new(:name)
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
8
|
+
class AlbumForm < Reform::Form
|
9
|
+
property :name
|
10
|
+
validates :name, presence: true
|
11
11
|
|
12
12
|
collection :songs do
|
13
13
|
property :title
|
14
|
-
validates :title, :
|
15
|
-
end
|
14
|
+
validates :title, presence: true
|
16
15
|
|
17
|
-
|
18
|
-
property :label do
|
16
|
+
property :composer do
|
19
17
|
property :name
|
20
|
-
validates :name, :
|
18
|
+
validates :name, presence: true
|
21
19
|
end
|
22
|
-
# TODO: make band a required object.
|
23
20
|
end
|
24
21
|
|
25
|
-
|
22
|
+
property :artist, save: false do
|
23
|
+
property :name
|
24
|
+
end
|
26
25
|
end
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"}],
|
33
|
-
:band => {:label => {:name => "Polydor"}}
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
let (:album) { Album.new(nil, hit, [song1, song2], band) }
|
38
|
-
let (:hit) { Song.new }
|
39
|
-
let (:song1) { Song.new }
|
40
|
-
let (:song2) { Song.new }
|
41
|
-
let (:band) { Band.new(label) }
|
42
|
-
let (:label) { Label.new }
|
43
|
-
|
44
|
-
subject { AlbumForm.new(album) }
|
45
|
-
|
46
|
-
before do
|
47
|
-
[album, hit, song1, song2, band, label].each { |mdl| mdl.extend(Saveable) }
|
48
|
-
|
49
|
-
subject.validate(params)
|
50
|
-
subject.save
|
51
|
-
end
|
27
|
+
module Saveable
|
28
|
+
def save
|
29
|
+
@saved = true
|
30
|
+
end
|
52
31
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
it { song1.title.must_equal "Fallout" }
|
57
|
-
it { song2.title.must_equal "Roxanne" }
|
58
|
-
it { label.name.must_equal "Polydor" }
|
59
|
-
|
60
|
-
# saved?
|
61
|
-
it { album.saved?.must_equal true }
|
62
|
-
it { hit.saved?.must_equal true }
|
63
|
-
it { song1.saved?.must_equal true }
|
64
|
-
it { song1.saved?.must_equal true }
|
65
|
-
it { band.saved?.must_equal true }
|
66
|
-
it { label.saved?.must_equal true }
|
67
|
-
|
68
|
-
|
69
|
-
describe "save: false" do
|
70
|
-
let (:form) {
|
71
|
-
Class.new(Reform::Form) do
|
72
|
-
property :hit do
|
73
|
-
property :title
|
74
|
-
end
|
75
|
-
|
76
|
-
collection :songs, :save => false do
|
77
|
-
property :title
|
78
|
-
end
|
79
|
-
|
80
|
-
property :band do # yepp, people do crazy stuff like that.
|
81
|
-
property :label, :save => false do
|
82
|
-
property :name
|
83
|
-
end
|
84
|
-
# TODO: make band a required object.
|
85
|
-
end
|
86
|
-
end
|
87
|
-
}
|
88
|
-
|
89
|
-
subject { form.new(album) }
|
90
|
-
|
91
|
-
# synced?
|
92
|
-
it { hit.title.must_equal "Roxanne" }
|
93
|
-
it { song1.title.must_equal "Fallout" }
|
94
|
-
it { song2.title.must_equal "Roxanne" }
|
95
|
-
it { label.name.must_equal "Polydor" }
|
96
|
-
|
97
|
-
# saved?
|
98
|
-
it { album.saved?.must_equal true }
|
99
|
-
it { hit.saved?.must_equal true }
|
100
|
-
it { song1.saved?.must_equal nil }
|
101
|
-
it { song1.saved?.must_equal nil }
|
102
|
-
it { band.saved?.must_equal true }
|
103
|
-
it { label.saved?.must_equal nil }
|
32
|
+
def saved?
|
33
|
+
@saved
|
34
|
+
end
|
104
35
|
end
|
105
36
|
|
106
37
|
|
107
|
-
|
108
|
-
|
38
|
+
let (:song) { Song.new("Broken").extend(Saveable) }
|
39
|
+
# let (:song_with_composer) { Song.new("Resist Stance", nil, composer).extend(Saveable) }
|
40
|
+
let (:composer) { Artist.new("Greg Graffin").extend(Saveable) }
|
41
|
+
let (:artist) { Artist.new("Bad Religion").extend(Saveable).extend(Saveable) }
|
42
|
+
let (:album) { Album.new("The Dissent Of Man", [song], artist).extend(Saveable) }
|
43
|
+
|
44
|
+
let (:form) { AlbumForm.new(album) }
|
45
|
+
|
46
|
+
|
109
47
|
it do
|
110
|
-
|
111
|
-
|
48
|
+
form.validate("songs" => [{"title" => "Fixed"}])
|
49
|
+
|
50
|
+
form.save
|
51
|
+
|
52
|
+
album.saved?.must_equal true
|
53
|
+
album.songs[0].title.must_equal "Fixed"
|
54
|
+
album.songs[0].saved?.must_equal true
|
55
|
+
album.artist.saved?.must_equal nil
|
112
56
|
end
|
113
57
|
end
|
114
58
|
|
115
59
|
|
116
|
-
class SaveWithDynamicOptionsTest < MiniTest::Spec
|
117
|
-
|
118
|
-
|
119
|
-
|
60
|
+
# class SaveWithDynamicOptionsTest < MiniTest::Spec
|
61
|
+
# Song = Struct.new(:id, :title, :length) do
|
62
|
+
# include Saveable
|
63
|
+
# end
|
120
64
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
65
|
+
# class SongForm < Reform::Form
|
66
|
+
# property :title#, save: false
|
67
|
+
# property :length, virtual: true
|
68
|
+
# end
|
125
69
|
|
126
|
-
|
127
|
-
|
70
|
+
# let (:song) { Song.new }
|
71
|
+
# let (:form) { SongForm.new(song) }
|
128
72
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
73
|
+
# # we have access to original input value and outside parameters.
|
74
|
+
# it "xxx" do
|
75
|
+
# form.validate("title" => "A Poor Man's Memory", "length" => 10)
|
76
|
+
# length_seconds = 120
|
77
|
+
# form.save(length: lambda { |value, options| form.model.id = "#{value}: #{length_seconds}" })
|
134
78
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
79
|
+
# song.title.must_equal "A Poor Man's Memory"
|
80
|
+
# song.length.must_equal nil
|
81
|
+
# song.id.must_equal "10: 120"
|
82
|
+
# end
|
83
|
+
# end
|