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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1656561190a1c9784f1e2463e6c4e2c558bb78d0
4
- data.tar.gz: 236cc4811f68a6e6e6e7a9e0a31d11a4afbe955d
3
+ metadata.gz: 247ffc53838f5e69a71f4ab5d066572b05308003
4
+ data.tar.gz: f6162c6a018e02ad2f9c487441dcea08623b960a
5
5
  SHA512:
6
- metadata.gz: 2aa18198338829e843a002d940dfb60d0f4d318662637d064f01a668f30fd59bf20fa3fe11dd25b7a5534e93b986aabc54d19cf2f01e3e42f02c81273fe7601a
7
- data.tar.gz: 4d9cea3a1c22769400c48164b2a907e0b8f713a82b2cb9e11fb0fb97bbc963f3a5445da828b4b899b2dd4b420416fb7b7d94f1f6c400378e47210c64028d99f5
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
- * :populator => lambda { |fragment, index, args|
6
- # songs[index] or songs[index] = args.binding[:form].new(Song.new)
7
- # }
8
- is now :populator => lambda { |fragment, index, args|
9
- # songs[index] or songs.insert(index) = Song.new
10
- # }
11
- you don't need to know about forms anymore, the twin handles that using #insert.
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 doesn't do anything but provide you with a nested hash with all the validated input. This allows you to implement the saving yourself.
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.
Binary file
@@ -4,13 +4,13 @@ module Reform
4
4
  end
5
5
  end
6
6
 
7
- require 'reform/contract'
8
- require 'reform/form'
9
- require 'reform/form/composition'
10
- require 'reform/form/active_model'
11
- require 'reform/form/module'
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) # DISCUSS: is everyone ok with this?
15
- require 'reform/rails'
14
+ if defined?(Rails)
15
+ require "reform/rails"
16
16
  end
@@ -1,4 +1,4 @@
1
- require 'reform/form/active_model'
2
- require 'reform/form/orm'
3
- require 'reform/form/active_record'
4
- require 'reform/form/model_reflections' # only load this in AR context as simple_form currently is bound to AR.
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.
@@ -1,19 +1,18 @@
1
- require 'forwardable'
2
- require 'uber/inheritable_attr'
3
- require 'uber/delegates'
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
- # Gives you a DSL for defining the object structure and its validations.
7
- require "disposable/twin"
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
- def name # this adds Form::name for AM::Validations and I18N. i know it's retarded.
61
- # something weird happens here: somewhere in Rails, this creates a constant (e.g. User). if this name doesn't represent a valid
62
- # constant, the reloading in dev will fail with weird messages. i'm not sure if we should just get rid of Rails validations etc.
63
- # or if i should look into this?
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
@@ -12,7 +12,7 @@ module Reform::Contract::Validate
12
12
  valid? # calls AM/Lotus validators and invokes self.errors=.
13
13
 
14
14
  errors.merge!(self.errors, prefix) # local errors.
15
- errors.merge!(nested_errors, []) #
15
+ errors.merge!(nested_errors, [])
16
16
  end
17
17
 
18
18
  def errors
@@ -9,12 +9,13 @@ module Reform
9
9
  end
10
10
 
11
11
  require "reform/form/validate"
12
- include Validate # extend Contract#validate with additional behaviour.
12
+ include Validate # override Contract#validate with additional behaviour.
13
13
 
14
14
  require "reform/form/populator"
15
15
 
16
16
  module Property
17
- # add macro logic, e.g. for :populator.
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}) #if options[:collection] # collections don't need to get re-assigned, they don't change.
38
+ deserializer_options.merge!({setter: nil})
45
39
  end
46
40
 
47
41
 
@@ -1,55 +1,14 @@
1
- require 'reform/form/active_model/model_validations'
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.
@@ -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/contract/errors"
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
 
@@ -1,5 +1,3 @@
1
1
  require "disposable/twin/coercion"
2
2
 
3
- Reform::Form.class_eval do
4
- Coercion = Disposable::Twin::Coercion
5
- end
3
+ Reform::Form::Coercion = Disposable::Twin::Coercion
@@ -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 = schema.representable_attrs.get(name)[:on]
5
+ model_name = options_for(name)[:on]
6
6
  model[model_name]
7
7
  end
8
8
 
@@ -1,5 +1,3 @@
1
- # TODO: move somewhere else!
2
- # TODO: make inheritable? and also, there's a lot of noise. shorten.
3
1
  # Implements the :populator option.
4
2
  #
5
3
  # populator: -> (fragment, twin, options)
@@ -5,8 +5,7 @@ module Reform::Form::Validate
5
5
  include Uber::Callable
6
6
 
7
7
  def call(form, params, options)
8
- # TODO: hahahahahaha.
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 #present! or pre-populator."
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|
@@ -1,3 +1,3 @@
1
1
  module Reform
2
- VERSION = "2.0.0.rc3"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -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.5"
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
@@ -1,5 +1,4 @@
1
1
  require 'test_helper'
2
- require 'reform/form/json'
3
2
 
4
3
  class DeserializeTest < MiniTest::Spec
5
4
  Song = Struct.new(:title, :album, :composer)
@@ -4,7 +4,7 @@ require 'test_helper'
4
4
  class ModelReflectionTest < MiniTest::Spec
5
5
  class SongForm < Reform::Form
6
6
  include Reform::Form::ActiveRecord
7
- include Reform::Form::ModelReflections
7
+ include Reform::Form::ActiveModel::ModelReflections
8
8
 
9
9
  model :song
10
10
 
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.rc3
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-08 00:00:00.000000000 Z
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.5
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.5
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: 1.3.1
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
@@ -1,13 +0,0 @@
1
- require 'representable/json'
2
-
3
- module Reform
4
- module Form::JSON
5
- def self.included(base)
6
- base.representer_class.send :include, Representable::JSON
7
- end
8
-
9
- def deserialize_method
10
- :from_json
11
- end
12
- end
13
- end
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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