reform 0.2.4 → 0.2.5
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/CHANGES.md +5 -0
- data/README.md +14 -0
- data/database.sqlite3 +0 -0
- data/lib/reform/form.rb +8 -9
- data/lib/reform/form/active_model.rb +13 -3
- data/lib/reform/form/composition.rb +2 -1
- data/lib/reform/representer.rb +4 -0
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +2 -1
- data/test/active_model_test.rb +22 -1
- data/test/reform_test.rb +21 -3
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76401e86f77b8b06874c24e8257dc97e5d0e66c0
|
4
|
+
data.tar.gz: 37e55343b9fc0d9b7d7764c4988f01f22db0d4fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b7b1d9f9ed49bff28ac3bd83802b8d73d20005bd9126a1d25b6a342e031a0e44a5ed675686242468c29c2ac7bf7c5b71bb7bf40c53ec5811d26ba601c02ca97
|
7
|
+
data.tar.gz: 557e270fa0dfbaad214790f3aaa0bf579d90feeb4b70a5193fcd2bb526b4ada902d3308081ae67b0a6fdcd13b2048afd389b9625cf7c9a8819668a3c1f247095
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
## 0.2.5
|
2
|
+
|
3
|
+
* Allow proper form inheritance. When having `HitForm < SongForm < Reform::Form` the `HitForm` class will contain `SongForm`'s properties in addition to its own fields.
|
4
|
+
* `::model` is now inherited properly.
|
5
|
+
|
1
6
|
## 0.2.4
|
2
7
|
|
3
8
|
* Accessors for properties (e.g. `title` and `title=`) can now be overridden in the form *and* call `super`. This is extremely helpful if you wanna do "manual coercion" since the accessors are invoked in `#validate`. Thanks to @cj for requesting this.
|
data/README.md
CHANGED
@@ -271,12 +271,17 @@ class SongWithLabelForm < Reform::Form
|
|
271
271
|
property :title, on: :song
|
272
272
|
property :city, on: :label
|
273
273
|
|
274
|
+
model :song # only needed in ActiveModel context.
|
275
|
+
|
274
276
|
validates :title, :city, presence: true
|
275
277
|
end
|
276
278
|
```
|
277
279
|
|
278
280
|
Note that reform needs to know about the owner objects of properties. You can do so by using the `on:` option.
|
279
281
|
|
282
|
+
Also, the form needs to have a main object configured. This is where ActiveModel-methods like `#persisted?` or '#id' are delegated to. Use `::model` to define the main object.
|
283
|
+
|
284
|
+
|
280
285
|
### Composition: Setup
|
281
286
|
|
282
287
|
The constructor slightly differs.
|
@@ -415,6 +420,15 @@ Reform provides the following `ActiveRecord` specific features. They're mixed in
|
|
415
420
|
* Uniqueness validations. Use `validates_uniqueness_of` in your form.
|
416
421
|
* Calling `Form#save` will explicitely call `save` on your model (added in 0.2.1) which will usually trigger a database insertion or update.
|
417
422
|
|
423
|
+
As mentioned in the [Rails Integration](https://github.com/apotonick/reform#rails-integration) section some Rails 4 setups do not properly load.
|
424
|
+
|
425
|
+
You may want to include the module manually then.
|
426
|
+
|
427
|
+
```ruby
|
428
|
+
class SongForm < Reform::Form
|
429
|
+
include Reform::Form::ActiveRecord
|
430
|
+
```
|
431
|
+
|
418
432
|
|
419
433
|
## ActiveModel Compliance
|
420
434
|
|
data/database.sqlite3
CHANGED
Binary file
|
data/lib/reform/form.rb
CHANGED
@@ -4,15 +4,18 @@ require 'ostruct'
|
|
4
4
|
require 'reform/composition'
|
5
5
|
require 'reform/representer'
|
6
6
|
|
7
|
+
require 'uber/inheritable_attr'
|
8
|
+
|
9
|
+
|
7
10
|
module Reform
|
8
11
|
class Form
|
9
12
|
extend Forwardable
|
10
|
-
# reasons for delegation:
|
11
|
-
# presentation: this object is used in the presentation layer by #form_for.
|
12
|
-
# problem: #form_for uses respond_to?(:email_before_type_cast) which goes to an internal hash in the actual record.
|
13
|
-
# validation: this object also contains the validation rules itself, should be separated.
|
14
13
|
|
15
|
-
|
14
|
+
extend Uber::InheritableAttr
|
15
|
+
inheritable_attr :representer_class
|
16
|
+
self.representer_class = Class.new(Reform::Representer)
|
17
|
+
|
18
|
+
|
16
19
|
module PropertyMethods
|
17
20
|
extend Forwardable
|
18
21
|
|
@@ -43,10 +46,6 @@ module Reform
|
|
43
46
|
definition.options[:instance] = true # just to make typed? work
|
44
47
|
end
|
45
48
|
|
46
|
-
def representer_class
|
47
|
-
@representer_class ||= Class.new(Reform::Representer)
|
48
|
-
end
|
49
|
-
|
50
49
|
private
|
51
50
|
def create_accessor(name)
|
52
51
|
# Make a module that contains these very accessors, then include it
|
@@ -55,18 +55,28 @@ module Reform::Form::ActiveModel
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
|
58
59
|
module ClassMethods
|
60
|
+
# this module is only meant to extend (not include). # DISCUSS: is this a sustainable concept?
|
61
|
+
def self.extended(base)
|
62
|
+
base.class_eval do
|
63
|
+
extend Hooks::InheritableAttribute
|
64
|
+
inheritable_attr :model_options
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
59
69
|
# Set a model name for this form if the infered is wrong.
|
60
70
|
#
|
61
71
|
# class CoverSongForm < Reform::Form
|
62
72
|
# model :song
|
63
73
|
def model(main_model, options={})
|
64
|
-
|
74
|
+
self.model_options = [main_model, options]
|
65
75
|
end
|
66
76
|
|
67
77
|
def model_name
|
68
|
-
if
|
69
|
-
form_name =
|
78
|
+
if model_options
|
79
|
+
form_name = model_options.first.to_s.camelize
|
70
80
|
else
|
71
81
|
form_name = name.sub(/Form$/, "")
|
72
82
|
end
|
@@ -5,12 +5,13 @@ class Reform::Form
|
|
5
5
|
module Composition
|
6
6
|
def self.included(base)
|
7
7
|
base.class_eval do
|
8
|
+
extend Reform::Form::ActiveModel::ClassMethods # ::model.
|
8
9
|
extend ClassMethods
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
12
13
|
module ClassMethods
|
13
|
-
include Reform::Form::ActiveModel::ClassMethods # ::model.
|
14
|
+
#include Reform::Form::ActiveModel::ClassMethods # ::model.
|
14
15
|
|
15
16
|
def model_class # DISCUSS: needed?
|
16
17
|
rpr = representer_class
|
data/lib/reform/representer.rb
CHANGED
@@ -47,6 +47,10 @@ module Reform
|
|
47
47
|
each(&block)
|
48
48
|
end
|
49
49
|
|
50
|
+
def self.clone # called in inheritable_attr :representer_class.
|
51
|
+
Class.new(self) # By subclassing, representable_attrs.clone is called.
|
52
|
+
end
|
53
|
+
|
50
54
|
private
|
51
55
|
def clone_config!
|
52
56
|
# TODO: representable_attrs.clone! which does exactly what's done below.
|
data/lib/reform/version.rb
CHANGED
data/reform.gemspec
CHANGED
@@ -19,10 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "representable", ">= 1.7.5"
|
22
|
+
spec.add_dependency "uber", "~> 0.0.4"
|
22
23
|
spec.add_dependency "activemodel"
|
23
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
25
|
spec.add_development_dependency "rake", ">= 10.1.0"
|
25
|
-
spec.add_development_dependency "minitest"
|
26
|
+
spec.add_development_dependency "minitest", "4.2.0"
|
26
27
|
spec.add_development_dependency "activerecord"
|
27
28
|
spec.add_development_dependency "sqlite3"
|
28
29
|
spec.add_development_dependency "virtus"
|
data/test/active_model_test.rb
CHANGED
@@ -30,6 +30,15 @@ class NewActiveModelTest < MiniTest::Spec # TODO: move to test/rails/
|
|
30
30
|
|
31
31
|
it { class_with_model.model_name.must_be_kind_of ActiveModel::Name }
|
32
32
|
it { class_with_model.model_name.to_s.must_equal "Album" }
|
33
|
+
|
34
|
+
|
35
|
+
let (:subclass_of_class_with_model) {
|
36
|
+
Class.new(class_with_model)
|
37
|
+
}
|
38
|
+
|
39
|
+
it { subclass_of_class_with_model.model_name.must_be_kind_of ActiveModel::Name }
|
40
|
+
it { subclass_of_class_with_model.model_name.to_s.must_equal 'Album' }
|
41
|
+
|
33
42
|
|
34
43
|
describe "inline with model" do
|
35
44
|
let (:form_class) {
|
@@ -198,6 +207,18 @@ class ActiveModelWithCompositionTest < MiniTest::Spec
|
|
198
207
|
model :song
|
199
208
|
end.new(:song => rio, :artist => duran).song.must_equal rio
|
200
209
|
end
|
210
|
+
|
211
|
+
# it "delegates when you call ::model" do
|
212
|
+
# class SongOnlyForm < Reform::Form
|
213
|
+
# include Composition
|
214
|
+
# include Reform::Form::ActiveModel
|
215
|
+
|
216
|
+
# property :title, :on => :song
|
217
|
+
# model :song
|
218
|
+
|
219
|
+
# self
|
220
|
+
# end.new(:song => rio, :artist => duran).persisted?
|
221
|
+
# end
|
201
222
|
end
|
202
223
|
|
203
224
|
|
@@ -240,4 +261,4 @@ class ActiveModelWithCompositionTest < MiniTest::Spec
|
|
240
261
|
|
241
262
|
AnotherForm.new(:song => rio).song.must_equal rio
|
242
263
|
end
|
243
|
-
end
|
264
|
+
end
|
data/test/reform_test.rb
CHANGED
@@ -112,12 +112,14 @@ class ReformTest < ReformSpec
|
|
112
112
|
end
|
113
113
|
|
114
114
|
it "exposes input via property accessors" do
|
115
|
-
comp.name.must_equal nil
|
116
|
-
form.name.must_equal nil
|
117
|
-
|
118
115
|
form.validate("name" => "Duran Duran")
|
119
116
|
|
120
117
|
form.name.must_equal "Duran Duran"
|
118
|
+
end
|
119
|
+
|
120
|
+
it "doesn't change model properties" do
|
121
|
+
form.validate("name" => "Duran Duran")
|
122
|
+
|
121
123
|
comp.name.must_equal nil # don't touch model, yet.
|
122
124
|
end
|
123
125
|
|
@@ -213,6 +215,22 @@ class ReformTest < ReformSpec
|
|
213
215
|
describe "#model" do
|
214
216
|
it { form.model.must_equal comp }
|
215
217
|
end
|
218
|
+
|
219
|
+
|
220
|
+
describe "inheritance" do
|
221
|
+
class HitForm < SongForm
|
222
|
+
property :position
|
223
|
+
validates :position, :presence => true
|
224
|
+
end
|
225
|
+
|
226
|
+
let (:form) { HitForm.new(OpenStruct.new) }
|
227
|
+
it do
|
228
|
+
form.validate({"title" => "The Body"})
|
229
|
+
form.title.must_equal "The Body"
|
230
|
+
form.position.must_equal nil
|
231
|
+
form.errors.messages.must_equal({:name=>["can't be blank"], :position=>["can't be blank"]})
|
232
|
+
end
|
233
|
+
end
|
216
234
|
end
|
217
235
|
|
218
236
|
class EmptyAttributesTest < MiniTest::Spec
|
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: 0.2.
|
4
|
+
version: 0.2.5
|
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:
|
12
|
+
date: 2014-03-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: representable
|
@@ -25,6 +25,20 @@ dependencies:
|
|
25
25
|
- - '>='
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 1.7.5
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: uber
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.0.4
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.0.4
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: activemodel
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -71,16 +85,16 @@ dependencies:
|
|
71
85
|
name: minitest
|
72
86
|
requirement: !ruby/object:Gem::Requirement
|
73
87
|
requirements:
|
74
|
-
- - '
|
88
|
+
- - '='
|
75
89
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
90
|
+
version: 4.2.0
|
77
91
|
type: :development
|
78
92
|
prerelease: false
|
79
93
|
version_requirements: !ruby/object:Gem::Requirement
|
80
94
|
requirements:
|
81
|
-
- - '
|
95
|
+
- - '='
|
82
96
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
97
|
+
version: 4.2.0
|
84
98
|
- !ruby/object:Gem::Dependency
|
85
99
|
name: activerecord
|
86
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -225,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
239
|
version: '0'
|
226
240
|
requirements: []
|
227
241
|
rubyforge_project:
|
228
|
-
rubygems_version: 2.0.
|
242
|
+
rubygems_version: 2.0.2
|
229
243
|
signing_key:
|
230
244
|
specification_version: 4
|
231
245
|
summary: Decouples your models from form by giving you form objects with validation,
|