reform 2.0.0.beta2 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +1 -0
- data/Gemfile +1 -1
- data/README.md +3 -0
- data/Rakefile +19 -18
- data/database.sqlite3 +0 -0
- data/lib/reform/contract.rb +0 -16
- data/lib/reform/form.rb +0 -4
- data/lib/reform/form/active_record.rb +1 -1
- data/lib/reform/form/model_reflections.rb +1 -1
- data/lib/reform/form/module.rb +2 -1
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +1 -1
- data/test/active_record_test.rb +3 -37
- data/test/inherit_test.rb +1 -130
- data/test/module_test.rb +130 -0
- data/test/populate_test.rb +2 -1
- data/test/reform_test.rb +1 -30
- data/test/twin_test.rb +28 -13
- metadata +6 -12
- data/test/fields_test.rb +0 -14
- data/test/representer_test.rb +0 -47
- data/test/scalar_test.rb +0 -167
- data/test/skip_unchanged_test.rb +0 -86
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 981ddfe5d276177430c4441c81e38f8d1bc89166
|
4
|
+
data.tar.gz: 269eeca94c1c7636e4ff8fd73df5e2c6bccc459c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 165337839adaf02e97f805f05974a2ce9b8b1950f848493a1feabbb5ce708c3877e7bb6f59c7d0f5ab088f36ddfc10c3b4069cbed2ada2ba95909a360c0d705d
|
7
|
+
data.tar.gz: c7cf74f86eebc98c0810299fbaa179715b2bf92ba02d666f8658a116323d8b3b637fb9cf36361612f673abe1e5aa9541d04b1606d674f758fcc264d165d0f23c
|
data/CHANGES.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
## 2.0.0
|
2
2
|
|
3
3
|
* The `::reform_2_0!` is no longer there. Guess why.
|
4
|
+
* Again: `:empty` doesn't exist anymore. You can choose from `:readable`, `:writeable` and `:virtual`.
|
4
5
|
* :populator => lambda { |fragment, index, args|
|
5
6
|
# songs[index] or songs[index] = args.binding[:form].new(Song.new)
|
6
7
|
# }
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -10,6 +10,7 @@ Although reform can be used in any Ruby framework, it comes with [Rails support]
|
|
10
10
|
|
11
11
|
Temporary note: This is the README and API for Reform 2. On the public API, only a few tiny things have changed. When in trouble, join us on the IRC (Freenode) #trailblazer channel.
|
12
12
|
|
13
|
+
[Full documentation for Reform](http://trailblazerb.org/gems/reform) is available online, or support us and grab the [Trailblazer book](https://leanpub.com/trailblazer).
|
13
14
|
|
14
15
|
## Disposable
|
15
16
|
|
@@ -527,6 +528,8 @@ end
|
|
527
528
|
|
528
529
|
Note that you can also override properties [using inheritance](#inheritance) in Reform.
|
529
530
|
|
531
|
+
When using coercion, make sure the including form already contains the `Coercion` module.
|
532
|
+
|
530
533
|
|
531
534
|
## Inheritance
|
532
535
|
|
data/Rakefile
CHANGED
@@ -6,31 +6,32 @@ Rake::TestTask.new(:test) do |test|
|
|
6
6
|
test.libs << 'test'
|
7
7
|
test.test_files = FileList['test/*_test.rb']
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# test.test_files = ["test/changed_test.rb",
|
10
|
+
# "test/coercion_test.rb",
|
11
|
+
# "test/feature_test.rb",
|
12
12
|
|
13
|
-
|
13
|
+
# "test/contract_test.rb",
|
14
14
|
|
15
|
-
|
15
|
+
# "test/populate_test.rb", "test/prepopulator_test.rb",
|
16
16
|
|
17
|
-
|
17
|
+
# "test/readable_test.rb","test/setup_test.rb","test/skip_if_test.rb",
|
18
18
|
|
19
|
-
|
19
|
+
# "test/validate_test.rb", "test/save_test.rb",
|
20
20
|
|
21
|
-
|
21
|
+
# "test/writeable_test.rb","test/virtual_test.rb",
|
22
22
|
|
23
|
-
|
23
|
+
# "test/form_builder_test.rb", "test/active_model_test.rb",
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
# "test/readonly_test.rb",
|
26
|
+
# "test/inherit_test.rb",
|
27
|
+
# "test/uniqueness_test.rb",
|
28
|
+
# "test/from_test.rb",
|
29
|
+
# "test/composition_test.rb",
|
30
|
+
# "test/form_option_test.rb",
|
31
|
+
# "test/form_test.rb",
|
32
|
+
# "test/deserialize_test.rb",
|
33
|
+
# "test/module_test.rb"
|
34
|
+
# ]
|
34
35
|
|
35
36
|
|
36
37
|
|
data/database.sqlite3
CHANGED
Binary file
|
data/lib/reform/contract.rb
CHANGED
@@ -91,22 +91,6 @@ module Reform
|
|
91
91
|
require "reform/schema"
|
92
92
|
extend Reform::Schema
|
93
93
|
end
|
94
|
-
|
95
|
-
class Contract_ # DISCUSS: make class?
|
96
|
-
# allows including representers from Representable, Roar or disposable.
|
97
|
-
def self.inherit_module!(representer) # called from Representable::included.
|
98
|
-
# representer_class.inherit_module!(representer)
|
99
|
-
representer.representable_attrs.each do |dfn|
|
100
|
-
next if dfn.name == "links" # wait a second # FIXME what is that?
|
101
|
-
|
102
|
-
# TODO: remove manifesting and do that in representable, too!
|
103
|
-
args = [dfn.name, dfn.instance_variable_get(:@options)] # TODO: dfn.to_args (inluding &block)
|
104
|
-
|
105
|
-
property(*args) and next unless dfn.representer_module
|
106
|
-
property(*args) { include dfn.representer_module } # nested.
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
94
|
end
|
111
95
|
|
112
96
|
require 'reform/contract/errors'
|
data/lib/reform/form.rb
CHANGED
@@ -16,10 +16,6 @@ module Reform
|
|
16
16
|
module Property
|
17
17
|
# add macro logic, e.g. for :populator.
|
18
18
|
def property(name, options={}, &block)
|
19
|
-
if options.delete(:virtual)
|
20
|
-
options[:writeable] = options[:readable] = false # DISCUSS: isn't that like an #option in Twin?
|
21
|
-
end
|
22
|
-
|
23
19
|
if deserializer = options[:deserializer] # this means someone is explicitly specifying :deserializer.
|
24
20
|
options[:deserializer] = Representable::Cloneable::Hash[deserializer]
|
25
21
|
end
|
@@ -39,7 +39,7 @@ module Reform::Form::ActiveRecord
|
|
39
39
|
def model_for_property(name)
|
40
40
|
return model unless is_a?(Reform::Form::Composition) # i am too lazy for proper inheritance. there should be a ActiveRecord::Composition that handles this.
|
41
41
|
|
42
|
-
model_name =
|
42
|
+
model_name = schema.representable_attrs.get(name)[:on]
|
43
43
|
model[model_name]
|
44
44
|
end
|
45
45
|
end
|
@@ -30,7 +30,7 @@ module Reform::Form::ModelReflections
|
|
30
30
|
def defined_enums
|
31
31
|
return model.defined_enums unless is_a?(Reform::Form::Composition)
|
32
32
|
|
33
|
-
|
33
|
+
mapper.each.with_object({}) { |m,h| h.merge! m.defined_enums }
|
34
34
|
end
|
35
35
|
|
36
36
|
# this should also contain to_param and friends as this is used by the form helpers.
|
data/lib/reform/form/module.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Include this in every module that gets further included.
|
2
|
-
|
2
|
+
# TODO: this could be implemented in Declarable, as we can use that everywhere.
|
3
|
+
module Reform::Form::Module
|
3
4
|
def self.included(base)
|
4
5
|
base.extend ClassMethods
|
5
6
|
base.extend Included
|
data/lib/reform/version.rb
CHANGED
data/reform.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_dependency "representable", ">= 2.2.2"
|
21
|
-
spec.add_dependency "disposable", "~> 0.1.
|
21
|
+
spec.add_dependency "disposable", "~> 0.1.5"
|
22
22
|
spec.add_dependency "uber", "~> 0.0.11"
|
23
23
|
spec.add_dependency "activemodel"
|
24
24
|
|
data/test/active_record_test.rb
CHANGED
@@ -205,7 +205,7 @@ class PopulateWithActiveRecordTest < MiniTest::Spec
|
|
205
205
|
let (:album) { Album.create(:title => 'Greatest Hits') }
|
206
206
|
let (:form) { ActiveModelAlbumForm.new(album) }
|
207
207
|
|
208
|
-
it do
|
208
|
+
it "xxx"do
|
209
209
|
form.validate('songs_attributes' => {'0' => {'title' => 'Tango'}})
|
210
210
|
|
211
211
|
# form populated.
|
@@ -229,6 +229,8 @@ class PopulateWithActiveRecordTest < MiniTest::Spec
|
|
229
229
|
album.songs.size.must_equal 1
|
230
230
|
album.songs[0].title.must_equal 'Tango'
|
231
231
|
|
232
|
+
# DISCUSS: IfEmpty uses twin.original[index] for syncing. in our case, this is empty, so it will add Tango again.
|
233
|
+
form = ActiveModelAlbumForm.new(album)
|
232
234
|
form.validate('songs_attributes' => {'0' => {'id' => first_song.id, 'title' => 'Tango nuevo'}, '1' => {'title' => 'Waltz'}})
|
233
235
|
|
234
236
|
# form populated.
|
@@ -257,42 +259,6 @@ class PopulateWithActiveRecordTest < MiniTest::Spec
|
|
257
259
|
end
|
258
260
|
end
|
259
261
|
end
|
260
|
-
|
261
|
-
# it do
|
262
|
-
# a=Album.new
|
263
|
-
# a.songs << Song.new(title: "Old What's His Name") # Song does not get persisted.
|
264
|
-
|
265
|
-
# a.songs[1] = Song.new(title: "Permanent Rust")
|
266
|
-
|
267
|
-
# puts "@@@"
|
268
|
-
# puts a.songs.inspect
|
269
|
-
|
270
|
-
# puts "---"
|
271
|
-
# a.save
|
272
|
-
# puts a.songs.inspect
|
273
|
-
|
274
|
-
# b = a.songs.first
|
275
|
-
|
276
|
-
# a.songs = [Song.new(title:"Biomag")]
|
277
|
-
# puts "\\\\"
|
278
|
-
# a.save
|
279
|
-
# a.reload
|
280
|
-
# puts a.songs.inspect
|
281
|
-
|
282
|
-
# b.reload
|
283
|
-
# puts "#{b.inspect}, #{b.persisted?}"
|
284
|
-
|
285
|
-
|
286
|
-
# a.songs = [a.songs.first, Song.new(title: "Count Down")]
|
287
|
-
# b = a.songs.first
|
288
|
-
# puts ":::::"
|
289
|
-
# a.save
|
290
|
-
# a.reload
|
291
|
-
# puts a.songs.inspect
|
292
|
-
|
293
|
-
# b.reload
|
294
|
-
# puts "#{b.inspect}, #{b.persisted?}"
|
295
|
-
# end
|
296
262
|
end
|
297
263
|
|
298
264
|
|
data/test/inherit_test.rb
CHANGED
@@ -104,133 +104,4 @@ require "pp"
|
|
104
104
|
AlbumForm.new(OpenStruct.new(artist: OpenStruct.new)).artist.artist_id.must_equal 1
|
105
105
|
CompilationForm.new(OpenStruct.new(artist: OpenStruct.new)).artist.artist_id.must_equal 1
|
106
106
|
end
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
# require 'reform/form/coercion'
|
111
|
-
# class ModuleInclusionTest < MiniTest::Spec
|
112
|
-
# module BandPropertyForm
|
113
|
-
# include Reform::Form::Module
|
114
|
-
|
115
|
-
# property :band do
|
116
|
-
# property :title
|
117
|
-
|
118
|
-
# validates :title, :presence => true
|
119
|
-
|
120
|
-
# def id # gets mixed into Form, too.
|
121
|
-
# 2
|
122
|
-
# end
|
123
|
-
# end
|
124
|
-
|
125
|
-
# def id # gets mixed into Form, too.
|
126
|
-
# 1
|
127
|
-
# end
|
128
|
-
|
129
|
-
# validates :band, :presence => true
|
130
|
-
|
131
|
-
# property :cool, type: Virtus::Attribute::Boolean # test coercion.
|
132
|
-
# end
|
133
|
-
|
134
|
-
# # TODO: test if works, move stuff into inherit_schema!
|
135
|
-
# module AirplaysPropertyForm
|
136
|
-
# include Reform::Form::Module
|
137
|
-
|
138
|
-
# collection :airplays do
|
139
|
-
# property :station
|
140
|
-
# validates :station, :presence => true
|
141
|
-
# end
|
142
|
-
# validates :airplays, :presence => true
|
143
|
-
# end
|
144
|
-
|
145
|
-
|
146
|
-
# # test:
|
147
|
-
# # by including BandPropertyForm into multiple classes we assure that options hashes don't get messed up by AM:V.
|
148
|
-
# class HitForm < Reform::Form
|
149
|
-
# include BandPropertyForm
|
150
|
-
# end
|
151
|
-
|
152
|
-
# class SongForm < Reform::Form
|
153
|
-
# property :title
|
154
|
-
|
155
|
-
# include BandPropertyForm
|
156
|
-
# end
|
157
|
-
|
158
|
-
|
159
|
-
# let (:song) { OpenStruct.new(:band => OpenStruct.new(:title => "Time Again")) }
|
160
|
-
|
161
|
-
# # nested form from module is present and creates accessor.
|
162
|
-
# it { SongForm.new(song).band.title.must_equal "Time Again" }
|
163
|
-
|
164
|
-
# # methods from module get included.
|
165
|
-
# it { SongForm.new(song).id.must_equal 1 }
|
166
|
-
# it { SongForm.new(song).band.id.must_equal 2 }
|
167
|
-
|
168
|
-
# # validators get inherited.
|
169
|
-
# it do
|
170
|
-
# form = SongForm.new(OpenStruct.new)
|
171
|
-
# form.validate({})
|
172
|
-
# form.errors.messages.must_equal({:band=>["can't be blank"]})
|
173
|
-
# end
|
174
|
-
|
175
|
-
# # coercion works
|
176
|
-
# it do
|
177
|
-
# form = SongForm.new(OpenStruct.new)
|
178
|
-
# form.validate({:cool => "1"})
|
179
|
-
# form.cool.must_equal true
|
180
|
-
# end
|
181
|
-
|
182
|
-
|
183
|
-
# # include a module into a module into a class :)
|
184
|
-
# module AlbumFormModule
|
185
|
-
# include Reform::Form::Module
|
186
|
-
# include BandPropertyForm
|
187
|
-
|
188
|
-
# property :name
|
189
|
-
# validates :name, :presence => true
|
190
|
-
# end
|
191
|
-
|
192
|
-
# class AlbumForm < Reform::Form
|
193
|
-
# include AlbumFormModule
|
194
|
-
|
195
|
-
# property :band, :inherit => true do
|
196
|
-
# property :label
|
197
|
-
# validates :label, :presence => true
|
198
|
-
# end
|
199
|
-
# end
|
200
|
-
# # puts "......"+ AlbumForm.representer_class.representable_attrs.get(:band).inspect
|
201
|
-
|
202
|
-
# it do
|
203
|
-
# form = AlbumForm.new(OpenStruct.new(:band => OpenStruct.new))
|
204
|
-
# form.validate({"band" => {}})
|
205
|
-
# form.errors.messages.must_equal({:"band.title"=>["can't be blank"], :"band.label"=>["can't be blank"], :name=>["can't be blank"]})
|
206
|
-
# end
|
207
|
-
|
208
|
-
|
209
|
-
# # including representer into form
|
210
|
-
# module GenericRepresenter
|
211
|
-
# include Representable
|
212
|
-
|
213
|
-
# property :title
|
214
|
-
# property :manager do
|
215
|
-
# property :title
|
216
|
-
# end
|
217
|
-
# end
|
218
|
-
|
219
|
-
# class LabelForm < Reform::Form
|
220
|
-
# property :location
|
221
|
-
|
222
|
-
# include GenericRepresenter
|
223
|
-
# validates :title, :presence => true
|
224
|
-
# property :manager, :inherit => true do
|
225
|
-
# validates :title, :presence => true
|
226
|
-
# end
|
227
|
-
# end
|
228
|
-
# puts "......"+ LabelForm.representer_class.representable_attrs.get(:title).inspect
|
229
|
-
|
230
|
-
|
231
|
-
# it do
|
232
|
-
# form = LabelForm.new(OpenStruct.new(:manager => OpenStruct.new))
|
233
|
-
# form.validate({"manager" => {}, "title"=>""}) # it's important to pass both nested and scalar here!
|
234
|
-
# form.errors.messages.must_equal(:title=>["can't be blank"], :"manager.title"=>["can't be blank"], )
|
235
|
-
# end
|
236
|
-
# end
|
107
|
+
end
|
data/test/module_test.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require 'reform/form/coercion'
|
3
|
+
|
4
|
+
class ModuleInclusionTest < MiniTest::Spec
|
5
|
+
module BandPropertyForm
|
6
|
+
include Reform::Form::Module
|
7
|
+
|
8
|
+
property :band do
|
9
|
+
property :title
|
10
|
+
|
11
|
+
validates :title, presence: true
|
12
|
+
|
13
|
+
def id # gets mixed into Form, too.
|
14
|
+
2
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def id # gets mixed into Form, too.
|
19
|
+
1
|
20
|
+
end
|
21
|
+
|
22
|
+
validates :band, presence: true
|
23
|
+
|
24
|
+
property :cool, type: Virtus::Attribute::Boolean # test coercion.
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO: test if works, move stuff into inherit_schema!
|
28
|
+
module AirplaysPropertyForm
|
29
|
+
include Reform::Form::Module
|
30
|
+
|
31
|
+
collection :airplays do
|
32
|
+
property :station
|
33
|
+
validates :station, presence: true
|
34
|
+
end
|
35
|
+
validates :airplays, presence: true
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# test:
|
40
|
+
# by including BandPropertyForm into multiple classes we assure that options hashes don't get messed up by AM:V.
|
41
|
+
class HitForm < Reform::Form
|
42
|
+
include BandPropertyForm
|
43
|
+
end
|
44
|
+
|
45
|
+
class SongForm < Reform::Form
|
46
|
+
include Coercion
|
47
|
+
property :title
|
48
|
+
|
49
|
+
include BandPropertyForm
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
let (:song) { OpenStruct.new(:band => OpenStruct.new(:title => "Time Again")) }
|
54
|
+
|
55
|
+
# nested form from module is present and creates accessor.
|
56
|
+
it { SongForm.new(song).band.title.must_equal "Time Again" }
|
57
|
+
|
58
|
+
# methods from module get included.
|
59
|
+
it { SongForm.new(song).id.must_equal 1 }
|
60
|
+
it { SongForm.new(song).band.id.must_equal 2 }
|
61
|
+
|
62
|
+
# validators get inherited.
|
63
|
+
it do
|
64
|
+
form = SongForm.new(OpenStruct.new)
|
65
|
+
form.validate({})
|
66
|
+
form.errors.messages.must_equal({:band=>["can't be blank"]})
|
67
|
+
end
|
68
|
+
|
69
|
+
# coercion works
|
70
|
+
it do
|
71
|
+
form = SongForm.new(OpenStruct.new)
|
72
|
+
form.validate({cool: "1"})
|
73
|
+
form.cool.must_equal true
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# include a module into a module into a class :)
|
78
|
+
module AlbumFormModule
|
79
|
+
include Reform::Form::Module
|
80
|
+
include BandPropertyForm
|
81
|
+
|
82
|
+
property :name
|
83
|
+
validates :name, :presence => true
|
84
|
+
end
|
85
|
+
|
86
|
+
class AlbumForm < Reform::Form
|
87
|
+
include AlbumFormModule
|
88
|
+
|
89
|
+
property :band, :inherit => true do
|
90
|
+
property :label
|
91
|
+
validates :label, :presence => true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
# puts "......"+ AlbumForm.representer_class.representable_attrs.get(:band).inspect
|
95
|
+
|
96
|
+
it do
|
97
|
+
form = AlbumForm.new(OpenStruct.new(:band => OpenStruct.new))
|
98
|
+
form.validate({"band" => {}})
|
99
|
+
form.errors.messages.must_equal({:"band.title"=>["can't be blank"], :"band.label"=>["can't be blank"], :name=>["can't be blank"]})
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# # including representer into form
|
104
|
+
# module GenericRepresenter
|
105
|
+
# include Representable
|
106
|
+
|
107
|
+
# property :title
|
108
|
+
# property :manager do
|
109
|
+
# property :title
|
110
|
+
# end
|
111
|
+
# end
|
112
|
+
|
113
|
+
# class LabelForm < Reform::Form
|
114
|
+
# property :location
|
115
|
+
|
116
|
+
# include GenericRepresenter
|
117
|
+
# validates :title, :presence => true
|
118
|
+
# property :manager, :inherit => true do
|
119
|
+
# validates :title, :presence => true
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
# puts "......"+ LabelForm.representer_class.representable_attrs.get(:title).inspect
|
123
|
+
|
124
|
+
|
125
|
+
# it do
|
126
|
+
# form = LabelForm.new(OpenStruct.new(:manager => OpenStruct.new))
|
127
|
+
# form.validate({"manager" => {}, "title"=>""}) # it's important to pass both nested and scalar here!
|
128
|
+
# form.errors.messages.must_equal(:title=>["can't be blank"], :"manager.title"=>["can't be blank"], )
|
129
|
+
# end
|
130
|
+
end
|
data/test/populate_test.rb
CHANGED
@@ -138,6 +138,8 @@ class PopulateIfEmptyTest < MiniTest::Spec
|
|
138
138
|
let (:form) { AlbumForm.new(album) }
|
139
139
|
|
140
140
|
it do
|
141
|
+
form.songs.size.must_equal 2
|
142
|
+
|
141
143
|
form.validate(
|
142
144
|
"songs" => [{"title" => "Fallout"}, {"title" => "Roxanne"},
|
143
145
|
{"title" => "Rime Of The Ancient Mariner"}, # new song.
|
@@ -181,7 +183,6 @@ class PopulateIfEmptyTest < MiniTest::Spec
|
|
181
183
|
|
182
184
|
album.artist.must_equal nil
|
183
185
|
end
|
184
|
-
|
185
186
|
end
|
186
187
|
|
187
188
|
|
data/test/reform_test.rb
CHANGED
@@ -1,40 +1,11 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
+
# TODO: this test should be removed.
|
3
4
|
class ReformTest < ReformSpec
|
4
5
|
let (:comp) { OpenStruct.new(:name => "Duran Duran", :title => "Rio") }
|
5
6
|
|
6
7
|
let (:form) { SongForm.new(comp) }
|
7
8
|
|
8
|
-
|
9
|
-
describe "::property" do
|
10
|
-
it "doesn't allow reserved names" do
|
11
|
-
assert_raises RuntimeError do
|
12
|
-
Class.new(Reform::Form) do
|
13
|
-
property :model
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
describe "::properties" do
|
21
|
-
let (:options) { {:type => String} }
|
22
|
-
|
23
|
-
subject do
|
24
|
-
opts = options
|
25
|
-
Class.new(Reform::Form) do
|
26
|
-
properties :name, :title, opts
|
27
|
-
properties :created_at
|
28
|
-
end.new(comp)
|
29
|
-
end
|
30
|
-
|
31
|
-
it { subject.name.must_equal "Duran Duran" }
|
32
|
-
it { subject.title.must_equal "Rio" }
|
33
|
-
it { subject.created_at.must_equal nil }
|
34
|
-
# don't overwrite options.
|
35
|
-
it { subject; options.must_equal({:type => String}) }
|
36
|
-
end
|
37
|
-
|
38
9
|
class SongForm < Reform::Form
|
39
10
|
property :name
|
40
11
|
property :title
|
data/test/twin_test.rb
CHANGED
@@ -3,21 +3,36 @@ require 'test_helper'
|
|
3
3
|
require 'test_helper'
|
4
4
|
require 'reform/twin'
|
5
5
|
|
6
|
+
# class TwinTest < MiniTest::Spec
|
7
|
+
# class SongForm < Reform::Form
|
8
|
+
# class Twin < Disposable::Twin
|
9
|
+
# property :title
|
10
|
+
# option :is_online # TODO: this should make it read-only in reform!
|
11
|
+
# end
|
12
|
+
|
13
|
+
# # include Reform::Twin
|
14
|
+
# # twin Twin
|
15
|
+
# end
|
16
|
+
|
17
|
+
# let (:model) { OpenStruct.new(title: "Kenny") }
|
18
|
+
|
19
|
+
# let (:form) { SongForm.new(model, is_online: true) }
|
20
|
+
|
21
|
+
# it { form.title.must_equal "Kenny" }
|
22
|
+
# it { form.is_online.must_equal true }
|
23
|
+
# end
|
6
24
|
class TwinTest < MiniTest::Spec
|
7
|
-
|
8
|
-
class Twin < Disposable::Twin
|
9
|
-
property :title
|
10
|
-
option :is_online # TODO: this should make it read-only in reform!
|
11
|
-
end
|
25
|
+
Song = Struct.new(:name)
|
12
26
|
|
13
|
-
|
14
|
-
|
27
|
+
class SongForm < Reform::Form
|
28
|
+
property :name
|
29
|
+
property :is_online, virtual: true
|
15
30
|
end
|
16
31
|
|
17
|
-
let (:
|
32
|
+
let (:form) { SongForm.new(Song.new("Kenny"), is_online: true) }
|
18
33
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
34
|
+
it do
|
35
|
+
form.name.must_equal "Kenny"
|
36
|
+
form.is_online.must_equal true
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-07-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: representable
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - "~>"
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.1.
|
34
|
+
version: 0.1.5
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - "~>"
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.1.
|
41
|
+
version: 0.1.5
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: uber
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -261,7 +261,6 @@ files:
|
|
261
261
|
- test/dummy/log/server.log
|
262
262
|
- test/errors_test.rb
|
263
263
|
- test/feature_test.rb
|
264
|
-
- test/fields_test.rb
|
265
264
|
- test/form_builder_test.rb
|
266
265
|
- test/form_option_test.rb
|
267
266
|
- test/form_test.rb
|
@@ -269,6 +268,7 @@ files:
|
|
269
268
|
- test/inherit_test.rb
|
270
269
|
- test/model_reflections_test.rb
|
271
270
|
- test/model_validations_test.rb
|
271
|
+
- test/module_test.rb
|
272
272
|
- test/populate_test.rb
|
273
273
|
- test/prepopulator_test.rb
|
274
274
|
- test/rails/integration_test.rb
|
@@ -276,13 +276,10 @@ files:
|
|
276
276
|
- test/readable_test.rb
|
277
277
|
- test/readonly_test.rb
|
278
278
|
- test/reform_test.rb
|
279
|
-
- test/representer_test.rb
|
280
279
|
- test/save_test.rb
|
281
|
-
- test/scalar_test.rb
|
282
280
|
- test/setup_test.rb
|
283
281
|
- test/skip_if_test.rb
|
284
282
|
- test/skip_setter_and_getter_test.rb
|
285
|
-
- test/skip_unchanged_test.rb
|
286
283
|
- test/test_helper.rb
|
287
284
|
- test/twin_test.rb
|
288
285
|
- test/uniqueness_test.rb
|
@@ -349,7 +346,6 @@ test_files:
|
|
349
346
|
- test/dummy/log/server.log
|
350
347
|
- test/errors_test.rb
|
351
348
|
- test/feature_test.rb
|
352
|
-
- test/fields_test.rb
|
353
349
|
- test/form_builder_test.rb
|
354
350
|
- test/form_option_test.rb
|
355
351
|
- test/form_test.rb
|
@@ -357,6 +353,7 @@ test_files:
|
|
357
353
|
- test/inherit_test.rb
|
358
354
|
- test/model_reflections_test.rb
|
359
355
|
- test/model_validations_test.rb
|
356
|
+
- test/module_test.rb
|
360
357
|
- test/populate_test.rb
|
361
358
|
- test/prepopulator_test.rb
|
362
359
|
- test/rails/integration_test.rb
|
@@ -364,13 +361,10 @@ test_files:
|
|
364
361
|
- test/readable_test.rb
|
365
362
|
- test/readonly_test.rb
|
366
363
|
- test/reform_test.rb
|
367
|
-
- test/representer_test.rb
|
368
364
|
- test/save_test.rb
|
369
|
-
- test/scalar_test.rb
|
370
365
|
- test/setup_test.rb
|
371
366
|
- test/skip_if_test.rb
|
372
367
|
- test/skip_setter_and_getter_test.rb
|
373
|
-
- test/skip_unchanged_test.rb
|
374
368
|
- test/test_helper.rb
|
375
369
|
- test/twin_test.rb
|
376
370
|
- test/uniqueness_test.rb
|
data/test/fields_test.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class FieldsTest < MiniTest::Spec
|
4
|
-
describe "#new" do
|
5
|
-
it "accepts list of properties" do
|
6
|
-
fields = Reform::Contract::Fields.new([:name, :title])
|
7
|
-
fields.name.must_equal nil
|
8
|
-
fields.title.must_equal nil
|
9
|
-
|
10
|
-
fields.title= "Planet X"
|
11
|
-
fields.title.must_equal "Planet X"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/test/representer_test.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class RepresenterOptionsTest < MiniTest::Spec
|
4
|
-
subject { Reform::Representer::Options[] }
|
5
|
-
|
6
|
-
# don't maintain empty excludes until fixed in representable.
|
7
|
-
it { subject.exclude!([]).must_equal({:exclude=>[]}) }
|
8
|
-
it { subject.include!([]).must_equal({:include=>[]}) }
|
9
|
-
|
10
|
-
it { subject.exclude!([:title, :id]).must_equal({exclude: [:title, :id]}) }
|
11
|
-
it { subject.include!([:title, :id]).must_equal({include: [:title, :id]}) }
|
12
|
-
|
13
|
-
|
14
|
-
module Representer
|
15
|
-
include Representable::Hash
|
16
|
-
property :title
|
17
|
-
property :genre
|
18
|
-
property :id
|
19
|
-
end
|
20
|
-
|
21
|
-
it "representable" do
|
22
|
-
song = OpenStruct.new(title: "Title", genre: "Punk", id: 1)
|
23
|
-
puts Representer.prepare(song).to_hash(include: [:genre, :id], exclude: [:id]).inspect
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
class RepresenterTest < MiniTest::Spec
|
29
|
-
class SongRepresenter < Reform::Representer
|
30
|
-
property :title
|
31
|
-
property :name
|
32
|
-
property :genre
|
33
|
-
end
|
34
|
-
|
35
|
-
subject { SongRepresenter.new(Object.new) }
|
36
|
-
|
37
|
-
describe "#fields" do
|
38
|
-
it "returns all properties as strings" do
|
39
|
-
SongRepresenter.fields.must_equal(["title", "name", "genre"])
|
40
|
-
end
|
41
|
-
|
42
|
-
# allows block.
|
43
|
-
it do
|
44
|
-
SongRepresenter.fields { |dfn| dfn.name =~ /n/ }.must_equal ["name", "genre"]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
data/test/scalar_test.rb
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
|
4
|
-
class SelfNestedTest < BaseTest
|
5
|
-
class Form < Reform::Form
|
6
|
-
property :title do
|
7
|
-
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
let (:song) { Song.new("Crash And Burn") }
|
12
|
-
it do
|
13
|
-
Form.new(song)
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
it do
|
18
|
-
form = Form.new(song)
|
19
|
-
|
20
|
-
form.title = Class.new(Reform::Form) do
|
21
|
-
@form_name = "ficken"
|
22
|
-
def self.name # needed by ActiveModel::Validation and I18N.
|
23
|
-
@form_name
|
24
|
-
end
|
25
|
-
|
26
|
-
validates :model, :length => {:minimum => 10}
|
27
|
-
|
28
|
-
|
29
|
-
def update!(object)
|
30
|
-
model.replace(object)
|
31
|
-
end
|
32
|
-
|
33
|
-
end.new("Crash And Burn") # gets initialized with string (or image object, or whatever).
|
34
|
-
|
35
|
-
form.validate({"title" => "Teaser"})
|
36
|
-
|
37
|
-
form.errors.messages.must_equal({:"title.model"=>["is too short (minimum is 10 characters)"]})
|
38
|
-
|
39
|
-
|
40
|
-
# validation only kicks in when value present
|
41
|
-
form = Form.new(song)
|
42
|
-
form.validate({})
|
43
|
-
form.errors.messages.must_equal({})
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
class ImageForm < Reform::Form
|
48
|
-
# property :image, populate_if_empty: lambda { |object, args| object } do
|
49
|
-
property :image, :scalar => true do
|
50
|
-
validates :size, numericality: { less_than: 10 }
|
51
|
-
validates :length, numericality: { greater_than: 1 } # TODO: make better validators and remove AM::Validators at some point.
|
52
|
-
|
53
|
-
# FIXME: does that only work with representable 2.0?
|
54
|
-
# def size; model.size; end
|
55
|
-
# def type; model.class.to_s; end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
AlbumCover = Struct.new(:image) do
|
60
|
-
include Saveable
|
61
|
-
end
|
62
|
-
|
63
|
-
# no image in params AND model.
|
64
|
-
it do
|
65
|
-
form = ImageForm.new(AlbumCover.new(nil))
|
66
|
-
|
67
|
-
|
68
|
-
form.validate({})
|
69
|
-
form.errors.messages.must_equal({})
|
70
|
-
end
|
71
|
-
|
72
|
-
# no image in params but in model.
|
73
|
-
it do
|
74
|
-
skip
|
75
|
-
|
76
|
-
# TODO: implement validations that only run when requested (only_validate_params: true)
|
77
|
-
form = ImageForm.new(AlbumCover.new("i don't know how i got here but i'm invalid"))
|
78
|
-
|
79
|
-
|
80
|
-
form.validate({})
|
81
|
-
form.errors.messages.must_equal({})
|
82
|
-
end
|
83
|
-
|
84
|
-
# image in params but NOT in model.
|
85
|
-
it do
|
86
|
-
form = ImageForm.new(AlbumCover.new(nil))
|
87
|
-
|
88
|
-
form.validate({"image" => "I'm OK!"})
|
89
|
-
puts form.inspect
|
90
|
-
form.errors.messages.must_equal({})
|
91
|
-
form.image.scalar.must_equal "I'm OK!"
|
92
|
-
end
|
93
|
-
|
94
|
-
# OK image, image existent.
|
95
|
-
it "hello" do
|
96
|
-
form = ImageForm.new(AlbumCover.new("nil"))
|
97
|
-
|
98
|
-
form.image.model.must_equal "nil"
|
99
|
-
|
100
|
-
form.validate({"image" => "I'm OK!"})
|
101
|
-
form.errors.messages.must_equal({})
|
102
|
-
end
|
103
|
-
|
104
|
-
# invalid image, image existent.
|
105
|
-
it "xx"do
|
106
|
-
form = ImageForm.new(AlbumCover.new("nil"))
|
107
|
-
|
108
|
-
form.validate({"image" => "I'm too long, is that a problem?"})
|
109
|
-
form.errors.messages.must_equal({:"image.size"=>["must be less than 10"]})
|
110
|
-
end
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
# validate string only if it's in params.
|
115
|
-
class StringForm < Reform::Form
|
116
|
-
property :image, :scalar => true do # creates "empty" form
|
117
|
-
validates :length => {:minimum => 10}
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
|
-
# validates when present.
|
123
|
-
# invalid
|
124
|
-
it do
|
125
|
-
form = StringForm.new(AlbumCover.new(nil))
|
126
|
-
form.validate("image" => "0x123").must_equal false
|
127
|
-
form.image.scalar.must_equal("0x123")
|
128
|
-
# TODO: errors, save
|
129
|
-
|
130
|
-
form.errors.messages.must_equal({:"image.scalar"=>["is too short (minimum is 10 characters)"]})
|
131
|
-
end
|
132
|
-
|
133
|
-
# valid
|
134
|
-
it "xxx" do
|
135
|
-
cover = AlbumCover.new(nil)
|
136
|
-
|
137
|
-
form = StringForm.new(cover)
|
138
|
-
form.validate("image" => "0x123456789").must_equal true
|
139
|
-
|
140
|
-
form.image.scalar.must_equal("0x123456789")
|
141
|
-
cover.image.must_equal nil
|
142
|
-
|
143
|
-
# errors
|
144
|
-
form.errors.messages.must_equal({})
|
145
|
-
|
146
|
-
# sync
|
147
|
-
form.sync
|
148
|
-
form.image.scalar.must_equal("0x123456789")
|
149
|
-
cover.image.must_equal "0x123456789" # that already writes it back.
|
150
|
-
|
151
|
-
# save
|
152
|
-
form.save
|
153
|
-
cover.image.must_equal "0x123456789" # #save writes back to model.
|
154
|
-
|
155
|
-
form.save do |hash|
|
156
|
-
hash.must_equal("image"=>"0x123456789")
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
# does not validate when absent (that's the whole point of this directive).
|
161
|
-
it do
|
162
|
-
form = StringForm.new(AlbumCover.new(nil))
|
163
|
-
form.validate({}).must_equal true
|
164
|
-
end
|
165
|
-
|
166
|
-
# DISCUSS: when AlbumCover.new("Hello").validate({}), does that fail?
|
167
|
-
end
|
data/test/skip_unchanged_test.rb
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class SkipUnchangedTest < MiniTest::Spec
|
4
|
-
class SongForm < Reform::Form
|
5
|
-
include Sync::SkipUnchanged
|
6
|
-
register_feature Sync::SkipUnchanged
|
7
|
-
|
8
|
-
property :id
|
9
|
-
property :title
|
10
|
-
property :image, sync: lambda { |value, *| model.image = "processed via :sync: #{value}" }#, virtual: true
|
11
|
-
property :band do
|
12
|
-
property :name, sync: lambda { |value, *| model.name = "band, processed: #{value}" }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
Song = Struct.new(:id, :title, :image, :band) do
|
17
|
-
def id=(v); raise "never call me #{v.inspect}"; end
|
18
|
-
end
|
19
|
-
Band = Struct.new(:name)
|
20
|
-
|
21
|
-
let (:song) { Song.new(1, "Injection", Object, Band.new("Rise Against")) }
|
22
|
-
|
23
|
-
# skips when not present in hash + SkipUnchanged.
|
24
|
-
it("zhz") do
|
25
|
-
form = SongForm.new(song)
|
26
|
-
|
27
|
-
form.validate("title" => "Ready To Fall").must_equal true
|
28
|
-
form.sync
|
29
|
-
|
30
|
-
song.id.must_equal 1 # old
|
31
|
-
song.title.must_equal "Ready To Fall" # new!
|
32
|
-
song.image.must_equal Object # old
|
33
|
-
song.band.name.must_equal "Rise Against" # old
|
34
|
-
end
|
35
|
-
|
36
|
-
# uses :sync when present in params hash.
|
37
|
-
it do
|
38
|
-
form = SongForm.new(song)
|
39
|
-
|
40
|
-
form.validate("title" => "Ready To Fall", "image" => Module, "band" => {"name" => Class})
|
41
|
-
form.sync
|
42
|
-
|
43
|
-
song.id.must_equal 1
|
44
|
-
song.image.must_equal "processed via :sync: Module"
|
45
|
-
# nested works.
|
46
|
-
song.band.name.must_equal "band, processed: Class"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
# :virtual is considered with SkipUnchanged
|
52
|
-
class SkipUnchangedWithVirtualTest < MiniTest::Spec
|
53
|
-
Song = Struct.new(:title, :image, :band) do
|
54
|
-
def image=(v)
|
55
|
-
raise "i should not be called: #{v}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
Band = Struct.new(:name) do
|
59
|
-
def name=(v)
|
60
|
-
raise "i should not be called: #{v}"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
let (:form) { HitForm.new(song) }
|
65
|
-
let (:song) { Song.new(nil, nil, Band.new) }
|
66
|
-
|
67
|
-
class HitForm < Reform::Form
|
68
|
-
include Sync::SkipUnchanged
|
69
|
-
register_feature Sync::SkipUnchanged
|
70
|
-
|
71
|
-
property :title
|
72
|
-
property :image, virtual: true
|
73
|
-
property :band do
|
74
|
-
property :name, virtual: true
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
it "hhy" do
|
79
|
-
form.validate("title" => "Full Throttle", "image" => "Funny photo of Steve Harris", "band" => {"name" => "Iron Maiden"}).must_equal true
|
80
|
-
|
81
|
-
form.sync
|
82
|
-
song.title.must_equal "Full Throttle"
|
83
|
-
song.image.must_equal nil
|
84
|
-
song.band.name.must_equal nil
|
85
|
-
end
|
86
|
-
end
|