reform 2.0.0.rc3 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +15 -8
- data/README.md +2 -2
- data/database.sqlite3 +0 -0
- data/lib/reform.rb +7 -7
- data/lib/reform/active_record.rb +4 -4
- data/lib/reform/contract.rb +13 -12
- data/lib/reform/contract/validate.rb +1 -1
- data/lib/reform/form.rb +4 -10
- data/lib/reform/form/active_model.rb +4 -45
- data/lib/reform/{contract → form/active_model}/errors.rb +0 -0
- data/lib/reform/form/active_model/form_builder_methods.rb +47 -0
- data/lib/reform/form/active_model/model_reflections.rb +41 -0
- data/lib/reform/form/active_model/validations.rb +4 -1
- data/lib/reform/form/coercion.rb +1 -3
- data/lib/reform/form/orm.rb +1 -1
- data/lib/reform/form/populator.rb +0 -2
- data/lib/reform/form/validate.rb +2 -4
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +1 -1
- data/test/default_test.rb +22 -0
- data/test/deserialize_test.rb +0 -1
- data/test/model_reflections_test.rb +1 -1
- metadata +11 -14
- data/lib/reform/form/json.rb +0 -13
- data/lib/reform/form/model_reflections.rb +0 -37
- data/lib/reform/form/save.rb +0 -66
- data/lib/reform/form/scalar.rb +0 -54
- data/lib/reform/twin.rb +0 -20
- data/test/twin_test.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 247ffc53838f5e69a71f4ab5d066572b05308003
|
4
|
+
data.tar.gz: f6162c6a018e02ad2f9c487441dcea08623b960a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31ee6b2d4656b94ced0c7790832e8b6be84ea2b8218866c5cb9e75c6b3099710e9e2a52a24cd54b9c40ba0ead9a9712e7e961ac4b463f48bb34131b305c22246
|
7
|
+
data.tar.gz: d8954f5806cdbbd701b4e8352d930f2b1bd3aef5a36d5621ef154a0132e6e46481137b5f1d9208932a0377805f81cac75ee066885cf73b2ea4778957e8c1192b
|
data/CHANGES.md
CHANGED
@@ -2,18 +2,25 @@
|
|
2
2
|
|
3
3
|
* The `::reform_2_0!` is no longer there. Guess why.
|
4
4
|
* Again: `:empty` doesn't exist anymore. You can choose from `:readable`, `:writeable` and `:virtual`.
|
5
|
-
*
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
* When using `:populator` the API to work against the form has changed.
|
6
|
+
```ruby
|
7
|
+
populator: lambda { |fragment, index, args|
|
8
|
+
songs[index] or songs[index] = args.binding[:form].new(Song.new)
|
9
|
+
}
|
10
|
+
```
|
11
|
+
|
12
|
+
is now
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
populator: lambda { |fragment, index, args|
|
16
|
+
songs[index] or songs.insert(index) = Song.new
|
17
|
+
}
|
18
|
+
```
|
19
|
+
You don't need to know about forms anymore, the twin handles that using the [Twin](https://github.com/apotonick/disposable) API..
|
12
20
|
|
13
21
|
* `:as` option removed. Use `:from`.
|
14
22
|
* With `Composition` included, `Form#model` would give you a composition object. You can grab that using `Form#mapper` now.
|
15
23
|
* `Form#update!` is deprecated. It still works but will remind you to override `#present!` or use pre-populators as [described here](http://trailblazerb.org/gems/reform/prepopulator.html) and in the Trailblazer book, chapter "Nested Forms".
|
16
|
-
|
17
24
|
* Forms do not `include ActiveModel::Validations` anymore. This has polluted the entire gem and is not encapsulated in `Validator`. Consider using Lotus Validations instead.
|
18
25
|
* Validation inheritance with `ActiveModel::Validations` is broken with Rails 3.2 and 4.0. Update Rails or use the `Lotus` validations.
|
19
26
|
|
data/README.md
CHANGED
@@ -123,7 +123,7 @@ Sometimes, you need to do saving manually.
|
|
123
123
|
|
124
124
|
## Saving Forms Manually
|
125
125
|
|
126
|
-
Calling `#save` with a block
|
126
|
+
Calling `#save` with a block will provide a nested hash of the form's properties and values. This does **not call `#save` on the models** and allows you to implement the saving yourself.
|
127
127
|
|
128
128
|
The block parameter is a nested hash of the form input.
|
129
129
|
|
@@ -830,7 +830,7 @@ If you want full support for `simple_form` do as follows.
|
|
830
830
|
|
831
831
|
```ruby
|
832
832
|
class SongForm < Reform::Form
|
833
|
-
include ModelReflections
|
833
|
+
include ActiveModel::ModelReflections
|
834
834
|
```
|
835
835
|
|
836
836
|
Including this module will add `#column_for_attribute` and other methods need by form builders to automatically guess the type of a property.
|
data/database.sqlite3
CHANGED
Binary file
|
data/lib/reform.rb
CHANGED
@@ -4,13 +4,13 @@ module Reform
|
|
4
4
|
end
|
5
5
|
end
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
7
|
+
require "reform/contract"
|
8
|
+
require "reform/form"
|
9
|
+
require "reform/form/composition"
|
10
|
+
require "reform/form/active_model"
|
11
|
+
require "reform/form/module"
|
12
12
|
|
13
13
|
|
14
|
-
if defined?(Rails)
|
15
|
-
require
|
14
|
+
if defined?(Rails)
|
15
|
+
require "reform/rails"
|
16
16
|
end
|
data/lib/reform/active_record.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require "reform/form/active_model"
|
2
|
+
require "reform/form/orm"
|
3
|
+
require "reform/form/active_record"
|
4
|
+
require "reform/form/active_model/model_reflections" # only load this in AR context as simple_form currently is bound to AR.
|
data/lib/reform/contract.rb
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "uber/inheritable_attr"
|
2
|
+
require "disposable/twin"
|
3
|
+
require "disposable/twin/setup"
|
4
|
+
require "disposable/twin/default"
|
4
5
|
|
5
6
|
module Reform
|
6
|
-
#
|
7
|
-
|
8
|
-
require "disposable/twin/setup"
|
7
|
+
# Define your form structure and its validations. Instantiate it with a model,
|
8
|
+
# and then +validate+ this object graph.
|
9
9
|
class Contract < Disposable::Twin
|
10
10
|
require "disposable/twin/composition" # Expose.
|
11
11
|
include Expose
|
12
12
|
|
13
13
|
feature Setup
|
14
14
|
feature Setup::SkipSetter
|
15
|
-
|
16
|
-
extend Uber::Delegates
|
15
|
+
feature Default
|
17
16
|
|
18
17
|
representer_class.instance_eval do
|
19
18
|
def default_inline_class
|
@@ -57,10 +56,11 @@ module Reform
|
|
57
56
|
_name = definition.name
|
58
57
|
mod.instance_eval do
|
59
58
|
@_name = _name.singularize.camelize
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
# this adds Form::name for AM::Validations and I18N.
|
60
|
+
# i have a feeling that this is also needed for Rails autoloader, which is scary.
|
61
|
+
# beside that, it is a nice way for debugging to find out which anonymous form class you're working on:
|
62
|
+
# anonymous_nested_form.class.name
|
63
|
+
def name
|
64
64
|
@_name
|
65
65
|
end
|
66
66
|
end
|
@@ -76,6 +76,7 @@ module Reform
|
|
76
76
|
self.class.options_for(name)
|
77
77
|
end
|
78
78
|
end
|
79
|
+
|
79
80
|
def self.options_for(name)
|
80
81
|
representer_class.representable_attrs.get(name)
|
81
82
|
end
|
data/lib/reform/form.rb
CHANGED
@@ -9,12 +9,13 @@ module Reform
|
|
9
9
|
end
|
10
10
|
|
11
11
|
require "reform/form/validate"
|
12
|
-
include Validate #
|
12
|
+
include Validate # override Contract#validate with additional behaviour.
|
13
13
|
|
14
14
|
require "reform/form/populator"
|
15
15
|
|
16
16
|
module Property
|
17
|
-
#
|
17
|
+
# Add macro logic, e.g. for :populator.
|
18
|
+
# TODO: This will be re-structured once Declarative allows it.
|
18
19
|
def property(name, options={}, &block)
|
19
20
|
if deserializer = options[:deserializer] # this means someone is explicitly specifying :deserializer.
|
20
21
|
options[:deserializer] = Representable::Cloneable::Hash[deserializer]
|
@@ -23,25 +24,18 @@ module Reform
|
|
23
24
|
definition = super # let representable sort out inheriting of properties, and so on.
|
24
25
|
definition.merge!(deserializer: Representable::Cloneable::Hash.new) unless definition[:deserializer] # always keep :deserializer per property.
|
25
26
|
|
26
|
-
|
27
27
|
deserializer_options = definition[:deserializer]
|
28
28
|
|
29
|
-
# TODO: make this pluggable.
|
30
|
-
# DISCUSS: Populators should be a representable concept?
|
31
|
-
|
32
29
|
# Populators
|
33
30
|
# * they assign created data, no :setter (hence the name).
|
34
31
|
# * they (ab)use :instance, this is why they need to return a twin form.
|
35
32
|
# * they are only used in the deserializer.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
33
|
if populator = options.delete(:populate_if_empty)
|
40
34
|
deserializer_options.merge!({instance: Populator::IfEmpty.new(populator)})
|
41
35
|
deserializer_options.merge!({setter: nil})
|
42
36
|
elsif populator = options.delete(:populator)
|
43
37
|
deserializer_options.merge!({instance: Populator.new(populator)})
|
44
|
-
deserializer_options.merge!({setter: nil})
|
38
|
+
deserializer_options.merge!({setter: nil})
|
45
39
|
end
|
46
40
|
|
47
41
|
|
@@ -1,55 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require "reform/form/active_model/model_validations"
|
2
|
+
require "reform/form/active_model/form_builder_methods"
|
3
|
+
require "uber/delegates"
|
2
4
|
|
3
5
|
module Reform::Form::ActiveModel
|
4
|
-
module FormBuilderMethods # TODO: rename to FormBuilderCompat.
|
5
|
-
def self.included(base)
|
6
|
-
base.extend ClassMethods # ::model_name
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
private
|
11
|
-
|
12
|
-
# TODO: add that shit in Form#present, not by overriding ::property.
|
13
|
-
def property(name, options={}, &block)
|
14
|
-
super.tap do |definition|
|
15
|
-
add_nested_attribute_compat(name) if definition[:twin] # TODO: fix that in Rails FB#1832 work.
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# The Rails FormBuilder "detects" nested attributes (which is what we want) by checking existance of a setter method.
|
20
|
-
def add_nested_attribute_compat(name)
|
21
|
-
define_method("#{name}_attributes=") {} # this is why i hate respond_to? in Rails.
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Modify the incoming Rails params hash to be representable compliant.
|
26
|
-
def deserialize!(params)
|
27
|
-
# this only happens in a Hash environment. other engines have to overwrite this method.
|
28
|
-
schema.each do |dfn|
|
29
|
-
rename_nested_param_for!(params, dfn)
|
30
|
-
end
|
31
|
-
|
32
|
-
super(params)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
def rename_nested_param_for!(params, dfn)
|
37
|
-
nested_name = "#{dfn.name}_attributes"
|
38
|
-
return unless params.has_key?(nested_name)
|
39
|
-
|
40
|
-
value = params["#{dfn.name}_attributes"]
|
41
|
-
value = value.values if dfn[:collection]
|
42
|
-
|
43
|
-
params[dfn.name] = value
|
44
|
-
end
|
45
|
-
end # FormBuilderMethods
|
46
|
-
|
47
|
-
|
48
6
|
def self.included(base)
|
49
7
|
base.class_eval do
|
50
8
|
extend ClassMethods
|
51
9
|
register_feature ActiveModel
|
52
10
|
|
11
|
+
extend Uber::Delegates
|
53
12
|
delegates :model, *[:persisted?, :to_key, :to_param, :id] # Uber::Delegates
|
54
13
|
|
55
14
|
def to_model # this is called somewhere in FormBuilder and ActionController.
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Reform::Form::ActiveModel
|
2
|
+
# Including FormBuilderMethods will allow using form instances with form_for, simple_form, etc.
|
3
|
+
# in Rails. It will further try to translate Rails' suboptimal songs_attributes weirdness
|
4
|
+
# back to normal `songs: ` naming in +#valiate+.
|
5
|
+
module FormBuilderMethods
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods # ::model_name
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
private
|
12
|
+
|
13
|
+
# TODO: add that shit in Form#present, not by overriding ::property.
|
14
|
+
def property(name, options={}, &block)
|
15
|
+
super.tap do |definition|
|
16
|
+
add_nested_attribute_compat(name) if definition[:twin] # TODO: fix that in Rails FB#1832 work.
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# The Rails FormBuilder "detects" nested attributes (which is what we want) by checking existance of a setter method.
|
21
|
+
def add_nested_attribute_compat(name)
|
22
|
+
define_method("#{name}_attributes=") {} # this is why i hate respond_to? in Rails.
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Modify the incoming Rails params hash to be representable compliant.
|
27
|
+
def deserialize!(params)
|
28
|
+
# this only happens in a Hash environment. other engines have to overwrite this method.
|
29
|
+
schema.each do |dfn|
|
30
|
+
rename_nested_param_for!(params, dfn)
|
31
|
+
end
|
32
|
+
|
33
|
+
super(params)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def rename_nested_param_for!(params, dfn)
|
38
|
+
nested_name = "#{dfn.name}_attributes"
|
39
|
+
return unless params.has_key?(nested_name)
|
40
|
+
|
41
|
+
value = params["#{dfn.name}_attributes"]
|
42
|
+
value = value.values if dfn[:collection]
|
43
|
+
|
44
|
+
params[dfn.name] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# ModelReflections will be the interface between the form object and form builders like simple_form.
|
2
|
+
#
|
3
|
+
# This module is meant to collect all dependencies simple_form needs in addition to the ActiveModel ones.
|
4
|
+
# Goal is to collect all methods and define a reflection API so simple_form works with all ORMs and Reform
|
5
|
+
# doesn't have to "guess" what simple_form and other form helpers need.
|
6
|
+
class Reform::Form < Reform::Contract
|
7
|
+
module ActiveModel::ModelReflections
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
base.register_feature self # makes it work in nested forms.
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Delegate reflect_on_association to the model class to support simple_form's
|
15
|
+
# association input.
|
16
|
+
def reflect_on_association(*args)
|
17
|
+
model_name.to_s.constantize.reflect_on_association(*args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Delegate column for attribute to the model to support simple_form's
|
22
|
+
# attribute type interrogation.
|
23
|
+
def column_for_attribute(name)
|
24
|
+
model_for_property(name).column_for_attribute(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_attribute?(name)
|
28
|
+
model_for_property(name).has_attribute?(name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def defined_enums
|
32
|
+
return model.defined_enums unless is_a?(Reform::Form::Composition)
|
33
|
+
|
34
|
+
mapper.each.with_object({}) { |m,h| h.merge! m.defined_enums }
|
35
|
+
end
|
36
|
+
|
37
|
+
# this should also contain to_param and friends as this is used by the form helpers.
|
38
|
+
end
|
39
|
+
|
40
|
+
ModelReflections = ActiveModel::ModelReflections
|
41
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "active_model"
|
2
|
-
require "reform/
|
2
|
+
require "reform/form/active_model/errors"
|
3
|
+
require "uber/delegates"
|
3
4
|
|
4
5
|
module Reform::Form::ActiveModel
|
5
6
|
# AM::Validations for your form.
|
@@ -30,6 +31,8 @@ module Reform::Form::ActiveModel
|
|
30
31
|
# Validators is the validatable object. On the class level, we define validations,
|
31
32
|
# on instance, it exposes #valid?.
|
32
33
|
class Validator
|
34
|
+
# current i18n scope: :activemodel.
|
35
|
+
|
33
36
|
include ActiveModel::Validations
|
34
37
|
# extend ActiveModel::Naming
|
35
38
|
|
data/lib/reform/form/coercion.rb
CHANGED
data/lib/reform/form/orm.rb
CHANGED
@@ -2,7 +2,7 @@ module Reform::Form::ORM
|
|
2
2
|
def model_for_property(name)
|
3
3
|
return model unless is_a?(Reform::Form::Composition) # i am too lazy for proper inheritance. there should be a ActiveRecord::Composition that handles this.
|
4
4
|
|
5
|
-
model_name =
|
5
|
+
model_name = options_for(name)[:on]
|
6
6
|
model[model_name]
|
7
7
|
end
|
8
8
|
|
data/lib/reform/form/validate.rb
CHANGED
@@ -5,8 +5,7 @@ module Reform::Form::Validate
|
|
5
5
|
include Uber::Callable
|
6
6
|
|
7
7
|
def call(form, params, options)
|
8
|
-
# TODO:
|
9
|
-
# FIXME: this is a bit ridiculous.
|
8
|
+
# TODO: Schema should provide property names as plain list.
|
10
9
|
properties = options.binding[:twin].representer_class.representable_attrs[:definitions].keys
|
11
10
|
|
12
11
|
properties.each { |name| params[name].present? and return false }
|
@@ -46,7 +45,7 @@ private
|
|
46
45
|
# DISCUSS: this is only called once, on the top-level form.
|
47
46
|
def deprecate_update!(params)
|
48
47
|
return unless self.class.instance_methods(false).include?(:update!)
|
49
|
-
warn "[Reform] Form#update! is deprecated and will be removed in Reform 2.1. Please use #
|
48
|
+
warn "[Reform] Form#update! is deprecated and will be removed in Reform 2.1. Please use #prepopulate!"
|
50
49
|
update!(params)
|
51
50
|
end
|
52
51
|
|
@@ -68,7 +67,6 @@ private
|
|
68
67
|
|
69
68
|
deserializer.apply do |dfn|
|
70
69
|
next unless dfn[:twin]
|
71
|
-
|
72
70
|
# Representer#each and #apply have to be unified.
|
73
71
|
dfn.merge!(
|
74
72
|
deserialize: lambda { |decorator, params, options|
|
data/lib/reform/version.rb
CHANGED
data/reform.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.add_dependency "disposable", "~> 0.1.
|
20
|
+
spec.add_dependency "disposable", "~> 0.1.7"
|
21
21
|
spec.add_dependency "uber", "~> 0.0.11"
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class DefaultTest < 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, default: "Wrong"
|
10
|
+
|
11
|
+
collection :songs do
|
12
|
+
property :title, default: "It's Catching Up"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it do
|
17
|
+
form = AlbumForm.new(Album.new(nil, [Song.new]))
|
18
|
+
|
19
|
+
form.name.must_equal "Wrong"
|
20
|
+
form.songs[0].title.must_equal "It's Catching Up"
|
21
|
+
end
|
22
|
+
end
|
data/test/deserialize_test.rb
CHANGED
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
|
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-07-
|
12
|
+
date: 2015-07-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: disposable
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 0.1.
|
20
|
+
version: 0.1.7
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 0.1.
|
27
|
+
version: 0.1.7
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: uber
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -205,32 +205,29 @@ files:
|
|
205
205
|
- lib/reform.rb
|
206
206
|
- lib/reform/active_record.rb
|
207
207
|
- lib/reform/contract.rb
|
208
|
-
- lib/reform/contract/errors.rb
|
209
208
|
- lib/reform/contract/validate.rb
|
210
209
|
- lib/reform/form.rb
|
211
210
|
- lib/reform/form/active_model.rb
|
211
|
+
- lib/reform/form/active_model/errors.rb
|
212
|
+
- lib/reform/form/active_model/form_builder_methods.rb
|
213
|
+
- lib/reform/form/active_model/model_reflections.rb
|
212
214
|
- lib/reform/form/active_model/model_validations.rb
|
213
215
|
- lib/reform/form/active_model/validations.rb
|
214
216
|
- lib/reform/form/active_record.rb
|
215
217
|
- lib/reform/form/coercion.rb
|
216
218
|
- lib/reform/form/composition.rb
|
217
|
-
- lib/reform/form/json.rb
|
218
219
|
- lib/reform/form/lotus.rb
|
219
|
-
- lib/reform/form/model_reflections.rb
|
220
220
|
- lib/reform/form/module.rb
|
221
221
|
- lib/reform/form/mongoid.rb
|
222
222
|
- lib/reform/form/multi_parameter_attributes.rb
|
223
223
|
- lib/reform/form/orm.rb
|
224
224
|
- lib/reform/form/populator.rb
|
225
225
|
- lib/reform/form/prepopulate.rb
|
226
|
-
- lib/reform/form/save.rb
|
227
|
-
- lib/reform/form/scalar.rb
|
228
226
|
- lib/reform/form/validate.rb
|
229
227
|
- lib/reform/form/validation/unique_validator.rb
|
230
228
|
- lib/reform/mongoid.rb
|
231
229
|
- lib/reform/rails.rb
|
232
230
|
- lib/reform/schema.rb
|
233
|
-
- lib/reform/twin.rb
|
234
231
|
- lib/reform/version.rb
|
235
232
|
- reform.gemspec
|
236
233
|
- test/active_model_test.rb
|
@@ -242,6 +239,7 @@ files:
|
|
242
239
|
- test/composition_test.rb
|
243
240
|
- test/contract_test.rb
|
244
241
|
- test/custom_validation_test.rb
|
242
|
+
- test/default_test.rb
|
245
243
|
- test/deserialize_test.rb
|
246
244
|
- test/dummy/Rakefile
|
247
245
|
- test/dummy/app/controllers/albums_controller.rb
|
@@ -292,7 +290,6 @@ files:
|
|
292
290
|
- test/skip_if_test.rb
|
293
291
|
- test/skip_setter_and_getter_test.rb
|
294
292
|
- test/test_helper.rb
|
295
|
-
- test/twin_test.rb
|
296
293
|
- test/unique_test.rb
|
297
294
|
- test/validate_test.rb
|
298
295
|
- test/virtual_test.rb
|
@@ -312,9 +309,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
312
309
|
version: '0'
|
313
310
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
314
311
|
requirements:
|
315
|
-
- - "
|
312
|
+
- - ">="
|
316
313
|
- !ruby/object:Gem::Version
|
317
|
-
version:
|
314
|
+
version: '0'
|
318
315
|
requirements: []
|
319
316
|
rubyforge_project:
|
320
317
|
rubygems_version: 2.4.8
|
@@ -331,6 +328,7 @@ test_files:
|
|
331
328
|
- test/composition_test.rb
|
332
329
|
- test/contract_test.rb
|
333
330
|
- test/custom_validation_test.rb
|
331
|
+
- test/default_test.rb
|
334
332
|
- test/deserialize_test.rb
|
335
333
|
- test/dummy/Rakefile
|
336
334
|
- test/dummy/app/controllers/albums_controller.rb
|
@@ -381,7 +379,6 @@ test_files:
|
|
381
379
|
- test/skip_if_test.rb
|
382
380
|
- test/skip_setter_and_getter_test.rb
|
383
381
|
- test/test_helper.rb
|
384
|
-
- test/twin_test.rb
|
385
382
|
- test/unique_test.rb
|
386
383
|
- test/validate_test.rb
|
387
384
|
- test/virtual_test.rb
|
data/lib/reform/form/json.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# ModelReflections will be the interface between the form object and form builders like simple_form.
|
2
|
-
#
|
3
|
-
# This module is meant to collect all dependencies simple_form needs in addition to the ActiveModel ones.
|
4
|
-
# Goal is to collect all methods and define a reflection API so simple_form works with all ORMs and Reform
|
5
|
-
# doesn't have to "guess" what simple_form and other form helpers need.
|
6
|
-
module Reform::Form::ModelReflections
|
7
|
-
def self.included(base)
|
8
|
-
base.extend ClassMethods
|
9
|
-
base.register_feature self # makes it work in nested forms.
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
# Delegate reflect_on_association to the model class to support simple_form's
|
14
|
-
# association input.
|
15
|
-
def reflect_on_association(*args)
|
16
|
-
model_name.to_s.constantize.reflect_on_association(*args)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Delegate column for attribute to the model to support simple_form's
|
21
|
-
# attribute type interrogation.
|
22
|
-
def column_for_attribute(name)
|
23
|
-
model_for_property(name).column_for_attribute(name)
|
24
|
-
end
|
25
|
-
|
26
|
-
def has_attribute?(name)
|
27
|
-
model_for_property(name).has_attribute?(name)
|
28
|
-
end
|
29
|
-
|
30
|
-
def defined_enums
|
31
|
-
return model.defined_enums unless is_a?(Reform::Form::Composition)
|
32
|
-
|
33
|
-
mapper.each.with_object({}) { |m,h| h.merge! m.defined_enums }
|
34
|
-
end
|
35
|
-
|
36
|
-
# this should also contain to_param and friends as this is used by the form helpers.
|
37
|
-
end
|
data/lib/reform/form/save.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
module Reform::Form::Save
|
2
|
-
# Returns the result of that save invocation on the model.
|
3
|
-
def save(options={}, &block)
|
4
|
-
# DISCUSS: we should never hit @mapper here (which writes to the models) when a block is passed.
|
5
|
-
return yield to_nested_hash if block_given?
|
6
|
-
|
7
|
-
sync_models # recursion
|
8
|
-
save!(options)
|
9
|
-
end
|
10
|
-
|
11
|
-
def save!(options={}) # FIXME.
|
12
|
-
result = save_model
|
13
|
-
|
14
|
-
save_representer.new(fields).to_hash # save! on all nested forms.
|
15
|
-
|
16
|
-
dynamic_save!(options)
|
17
|
-
|
18
|
-
result
|
19
|
-
end
|
20
|
-
|
21
|
-
def save_model
|
22
|
-
model.save # TODO: implement nested (that should really be done by Twin/AR).
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
require "active_support/hash_with_indifferent_access" # DISCUSS: replace?
|
27
|
-
def to_nested_hash(*)
|
28
|
-
ActiveSupport::HashWithIndifferentAccess.new(nested_hash_representer.new(fields).to_hash)
|
29
|
-
end
|
30
|
-
alias_method :to_hash, :to_nested_hash
|
31
|
-
# NOTE: it is not recommended using #to_hash and #to_nested_hash in your code, consider them private.
|
32
|
-
|
33
|
-
private
|
34
|
-
def save_representer
|
35
|
-
self.class.representer(:save) do |dfn|
|
36
|
-
dfn.merge!(
|
37
|
-
:instance => lambda { |form, *| form },
|
38
|
-
:serialize => lambda { |form, args| form.save! unless args.binding[:save] === false }
|
39
|
-
)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def nested_hash_representer
|
44
|
-
self.class.representer(:nested_hash, :all => true) do |dfn|
|
45
|
-
dfn.merge!(:serialize => lambda { |form, args| form.to_nested_hash }) if dfn[:form]
|
46
|
-
|
47
|
-
dfn.merge!(:as => dfn[:private_name] || dfn.name)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def dynamic_save!(options)
|
52
|
-
names = options.keys & changed.keys.map(&:to_sym)
|
53
|
-
return if names.size == 0
|
54
|
-
|
55
|
-
dynamic_save_representer.new(fields).to_hash(options.merge(:include => names))
|
56
|
-
end
|
57
|
-
|
58
|
-
def dynamic_save_representer
|
59
|
-
self.class.representer(:dynamic_save, :all => true) do |dfn|
|
60
|
-
dfn.merge!(
|
61
|
-
:serialize => lambda { |object, options| options.user_options[options.binding.name.to_sym].call(object, options) },
|
62
|
-
:representable => true
|
63
|
-
)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
data/lib/reform/form/scalar.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
module Reform::Form::Scalar
|
2
|
-
# IDEA: what if every "leaf" property would be represented by a Scalar form?
|
3
|
-
def self.included(base)
|
4
|
-
base.extend ClassMethods
|
5
|
-
base.extend Forwardable
|
6
|
-
end
|
7
|
-
|
8
|
-
def update!(object)
|
9
|
-
@fields = object # @scalar is "I came from the outside." or <ArbitraryObject>.
|
10
|
-
end
|
11
|
-
|
12
|
-
def scalar
|
13
|
-
fields
|
14
|
-
end
|
15
|
-
|
16
|
-
def save!
|
17
|
-
end
|
18
|
-
|
19
|
-
def sync!(*)
|
20
|
-
model.replace(fields)
|
21
|
-
# FIXME: how to sync that, if it's not responds to replace? or what if we don't want to write (e.g. image with paperdragon)?
|
22
|
-
end
|
23
|
-
|
24
|
-
def to_nested_hash
|
25
|
-
scalar
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
module ClassMethods
|
30
|
-
def validates(name, options={})
|
31
|
-
if name.is_a?(Hash)
|
32
|
-
name, options = :scalar, name # per default, validate #scalar (e.g. "Hello").
|
33
|
-
else
|
34
|
-
def_delegator :scalar, name
|
35
|
-
end
|
36
|
-
|
37
|
-
super(name, options)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
# TODO: change the way i hook into ::property.
|
43
|
-
module Property
|
44
|
-
private
|
45
|
-
|
46
|
-
def property(name, options={}, &block)
|
47
|
-
if options[:scalar]
|
48
|
-
options.merge!(:features => [Reform::Form::Scalar], populate_if_empty: String)
|
49
|
-
end
|
50
|
-
|
51
|
-
super
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
data/lib/reform/twin.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'disposable/twin'
|
2
|
-
|
3
|
-
module Reform
|
4
|
-
module Twin
|
5
|
-
def self.included(base)
|
6
|
-
base.send :include, Disposable::Twin::Builder
|
7
|
-
base.extend ClassMethods
|
8
|
-
end
|
9
|
-
|
10
|
-
module ClassMethods
|
11
|
-
def twin(twin_class)
|
12
|
-
super(twin_class) { |dfn| property dfn.name } # create readers to twin model.
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def initialize(model, options={})
|
17
|
-
super(build_twin(model, options))
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/test/twin_test.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
require 'reform/twin'
|
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
|
24
|
-
class TwinTest < MiniTest::Spec
|
25
|
-
Song = Struct.new(:name)
|
26
|
-
|
27
|
-
class SongForm < Reform::Form
|
28
|
-
property :name
|
29
|
-
property :is_online, virtual: true
|
30
|
-
end
|
31
|
-
|
32
|
-
let (:form) { SongForm.new(Song.new("Kenny"), is_online: true) }
|
33
|
-
|
34
|
-
it do
|
35
|
-
form.name.must_equal "Kenny"
|
36
|
-
form.is_online.must_equal true
|
37
|
-
end
|
38
|
-
end
|