reform 2.1.0 → 2.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +4 -12
  4. data/CHANGES.md +8 -0
  5. data/README.md +36 -743
  6. data/Rakefile +1 -31
  7. data/gemfiles/{Gemfile.rails-3.1 → Gemfile.disposable-0.3} +1 -2
  8. data/lib/reform.rb +0 -9
  9. data/lib/reform/contract.rb +5 -1
  10. data/lib/reform/form.rb +1 -4
  11. data/lib/reform/form/composition.rb +1 -2
  12. data/lib/reform/form/dry.rb +29 -16
  13. data/lib/reform/form/module.rb +15 -3
  14. data/lib/reform/form/validate.rb +1 -1
  15. data/lib/reform/validation.rb +3 -3
  16. data/lib/reform/version.rb +1 -1
  17. data/reform.gemspec +3 -10
  18. data/test/coercion_test.rb +7 -7
  19. data/test/composition_test.rb +5 -1
  20. data/test/contract_test.rb +10 -4
  21. data/test/deserialize_test.rb +3 -3
  22. data/test/errors_test.rb +48 -28
  23. data/test/form_option_test.rb +3 -1
  24. data/test/form_test.rb +19 -14
  25. data/test/module_test.rb +51 -11
  26. data/test/populate_test.rb +21 -7
  27. data/test/reform_test.rb +24 -20
  28. data/test/save_test.rb +10 -4
  29. data/test/skip_if_test.rb +5 -3
  30. data/test/test_helper.rb +3 -43
  31. data/test/validate_test.rb +34 -14
  32. data/test/validation/dry_test.rb +60 -0
  33. data/test/validation/dry_validation_test.rb +65 -43
  34. data/test/validation/errors.yml +4 -0
  35. metadata +16 -192
  36. data/database.sqlite3 +0 -0
  37. data/gemfiles/Gemfile.rails-3.2 +0 -7
  38. data/gemfiles/Gemfile.rails-4.0 +0 -8
  39. data/gemfiles/Gemfile.rails-4.1 +0 -8
  40. data/gemfiles/Gemfile.rails-4.2 +0 -8
  41. data/lib/reform/active_record.rb +0 -4
  42. data/lib/reform/form/active_model.rb +0 -87
  43. data/lib/reform/form/active_model/form_builder_methods.rb +0 -48
  44. data/lib/reform/form/active_model/model_reflections.rb +0 -46
  45. data/lib/reform/form/active_model/model_validations.rb +0 -110
  46. data/lib/reform/form/active_model/validations.rb +0 -107
  47. data/lib/reform/form/active_record.rb +0 -30
  48. data/lib/reform/form/lotus.rb +0 -59
  49. data/lib/reform/form/multi_parameter_attributes.rb +0 -48
  50. data/lib/reform/form/validation/unique_validator.rb +0 -54
  51. data/lib/reform/rails.rb +0 -13
  52. data/test/active_model_custom_validation_translations_test.rb +0 -75
  53. data/test/active_model_test.rb +0 -207
  54. data/test/active_model_validation_for_property_named_format_test.rb +0 -18
  55. data/test/active_record_test.rb +0 -273
  56. data/test/builder_test.rb +0 -32
  57. data/test/custom_validation_test.rb +0 -47
  58. data/test/dummy/Rakefile +0 -7
  59. data/test/dummy/app/controllers/albums_controller.rb +0 -18
  60. data/test/dummy/app/controllers/application_controller.rb +0 -4
  61. data/test/dummy/app/controllers/musician_controller.rb +0 -5
  62. data/test/dummy/app/forms/album_form.rb +0 -18
  63. data/test/dummy/app/helpers/application_helper.rb +0 -2
  64. data/test/dummy/app/models/album.rb +0 -4
  65. data/test/dummy/app/models/song.rb +0 -3
  66. data/test/dummy/app/views/albums/new.html.erb +0 -28
  67. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  68. data/test/dummy/config.ru +0 -4
  69. data/test/dummy/config/application.rb +0 -20
  70. data/test/dummy/config/boot.rb +0 -10
  71. data/test/dummy/config/database.yml +0 -22
  72. data/test/dummy/config/environment.rb +0 -5
  73. data/test/dummy/config/environments/development.rb +0 -16
  74. data/test/dummy/config/environments/production.rb +0 -46
  75. data/test/dummy/config/environments/test.rb +0 -33
  76. data/test/dummy/config/locales/en.yml +0 -14
  77. data/test/dummy/config/routes.rb +0 -4
  78. data/test/dummy/db/test.sqlite3 +0 -0
  79. data/test/form_builder_test.rb +0 -138
  80. data/test/lotus/Gemfile +0 -5
  81. data/test/lotus/lotus_test.rb +0 -31
  82. data/test/lotus_test.rb +0 -150
  83. data/test/model_reflections_test.rb +0 -138
  84. data/test/model_validations_test.rb +0 -82
  85. data/test/mongoid_test.rb +0 -313
  86. data/test/multi_parameter_attributes_test.rb +0 -50
  87. data/test/rails/integration_test.rb +0 -54
  88. data/test/unique_test.rb +0 -135
  89. data/test/validation/activemodel_validation_test.rb +0 -252
Binary file
@@ -1,7 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in reform.gemspec
4
- gemspec :path => '../'
5
-
6
- gem 'railties', '~> 3.2.0'
7
- gem 'activerecord', '~> 3.2.0'
@@ -1,8 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in reform.gemspec
4
- gemspec :path => '../'
5
-
6
- gem 'railties', '~> 4.0.0'
7
- gem 'activerecord', '~> 4.0.0'
8
- gem 'minitest', '~> 4.2'
@@ -1,8 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in reform.gemspec
4
- gemspec :path => '../'
5
-
6
- gem 'railties', '~> 4.1.0'
7
- gem 'activerecord', '~> 4.1.0'
8
- gem 'minitest'
@@ -1,8 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in reform.gemspec
4
- gemspec :path => '../'
5
-
6
- gem 'railties', '~> 4.2.0'
7
- gem 'activerecord', '~> 4.2.0'
8
- gem 'minitest'
@@ -1,4 +0,0 @@
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,87 +0,0 @@
1
- require "reform/form/active_model/model_validations"
2
- require "reform/form/active_model/form_builder_methods"
3
- require "uber/delegates"
4
-
5
- module Reform::Form::ActiveModel
6
- def self.included(base)
7
- base.class_eval do
8
- extend ClassMethods
9
- register_feature ActiveModel
10
-
11
- extend Uber::Delegates
12
- delegates :model, *[:persisted?, :to_key, :to_param, :id] # Uber::Delegates
13
-
14
- def to_model # this is called somewhere in FormBuilder and ActionController.
15
- self
16
- end
17
- end
18
- end
19
-
20
-
21
- module ClassMethods
22
- # this module is only meant to extend (not include). # DISCUSS: is this a sustainable concept?
23
- def self.extended(base)
24
- base.class_eval do
25
- extend Uber::InheritableAttribute
26
- inheritable_attr :model_options
27
- end
28
- end
29
-
30
- # DISCUSS: can we achieve that somehow via features in build_inline?
31
- def property(*)
32
- super.tap do |dfn|
33
- return dfn unless dfn[:nested]
34
- _name = dfn[:name]
35
- dfn[:nested].instance_eval do
36
- @_name = _name.singularize.camelize
37
- # this adds Form::name for AM::Validations and I18N.
38
- def name
39
- @_name
40
- end
41
- end
42
- end
43
- end
44
-
45
-
46
- # Set a model name for this form if the infered is wrong.
47
- #
48
- # class CoverSongForm < Reform::Form
49
- # model :song
50
- #
51
- # or we can setup a isolated namespace model ( which defined in isolated rails egine )
52
- #
53
- # class CoverSongForm < Reform::Form
54
- # model "api/v1/song", namespace: "api"
55
- def model(main_model, options={})
56
- self.model_options = [main_model, options]
57
- end
58
-
59
- def model_name
60
- if model_options
61
- form_name = model_options.first.to_s.camelize
62
- namespace = model_options.last[:namespace].present? ? model_options.last[:namespace].to_s.camelize.constantize : nil
63
- else
64
- if name
65
- form_name = name.sub(/(::)?Form$/, "") # Song::Form => "Song"
66
- namespace = nil
67
- else # anonymous forms. let's drop AM and forget about all this.
68
- form_name = "reform"
69
- namespace = nil
70
- end
71
- end
72
-
73
- active_model_name_for(form_name, namespace)
74
- end
75
-
76
- private
77
- def active_model_name_for(string, namespace=nil)
78
- return ::ActiveModel::Name.new(OpenStruct.new(:name => string)) if Reform.rails3_0?
79
- ::ActiveModel::Name.new(self, namespace, string)
80
- end
81
- end # ClassMethods
82
-
83
-
84
- def model_name(*args)
85
- self.class.model_name(*args)
86
- end
87
- end
@@ -1,48 +0,0 @@
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[:nested] # 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
- name = dfn[:name]
39
- nested_name = "#{name}_attributes"
40
- return unless params.has_key?(nested_name)
41
-
42
- value = params["#{name}_attributes"]
43
- value = value.values if dfn[:collection]
44
-
45
- params[name] = value
46
- end
47
- end
48
- end
@@ -1,46 +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
- class Reform::Form < Reform::Contract
7
- module ActiveModel::ModelReflections
8
- def self.included(base)
9
- base.extend ClassMethods
10
- base.send :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
-
20
- # this is needed in simpleform to infer required fields.
21
- def validators_on(*args)
22
- validation_groups.collect { |k, group| group.instance_variable_get(:@validations).validators_on(*args) }.flatten
23
- end
24
- end
25
-
26
- # Delegate column for attribute to the model to support simple_form's
27
- # attribute type interrogation.
28
- def column_for_attribute(name)
29
- model_for_property(name).column_for_attribute(name)
30
- end
31
-
32
- def has_attribute?(name)
33
- model_for_property(name).has_attribute?(name)
34
- end
35
-
36
- def defined_enums
37
- return model.defined_enums unless is_a?(Reform::Form::Composition)
38
-
39
- mapper.each.with_object({}) { |m,h| h.merge! m.defined_enums }
40
- end
41
-
42
- # this should also contain to_param and friends as this is used by the form helpers.
43
- end
44
-
45
- ModelReflections = ActiveModel::ModelReflections
46
- end
@@ -1,110 +0,0 @@
1
- module Reform::Form::ActiveModel
2
- module ModelValidations
3
- # TODO: extract Composition behaviour.
4
- # reduce code in Mapping.
5
-
6
- class ValidationCopier
7
-
8
- def self.copy(form_class, mapping, models)
9
- if models.is_a?(Hash)
10
- models.each do |model_name, model|
11
- new(form_class, mapping, model, model_name).copy
12
- end
13
- else
14
- new(form_class, mapping, models).copy
15
- end
16
- end
17
-
18
- def initialize(form_class, mapping, model, model_name=nil)
19
- @form_class = form_class
20
- @mapping = mapping
21
- @model = model
22
- @model_name = model_name
23
- end
24
-
25
- def copy
26
- @model.validators.each(&method(:add_validator))
27
- end
28
-
29
- private
30
-
31
- def add_validator(validator)
32
- if validator.respond_to?(:attributes)
33
- add_native_validator validator
34
- else
35
- add_custom_validator validator
36
- end
37
- end
38
-
39
- def add_native_validator validator
40
- attributes = inverse_map_attributes(validator.attributes)
41
- if attributes.any?
42
- @form_class.validates(*attributes, {validator.kind => validator.options})
43
- end
44
- end
45
-
46
- def add_custom_validator validator
47
- @form_class.validates(nil, {validator.kind => validator.options})
48
- end
49
-
50
- def inverse_map_attributes(attributes)
51
- @mapping.inverse_image(create_attributes(attributes))
52
- end
53
-
54
- def create_attributes(attributes)
55
- attributes.map do |attribute|
56
- [@model_name, attribute].compact
57
- end
58
- end
59
-
60
- end
61
-
62
- class Mapping
63
- def self.from_representable_attrs(attrs)
64
- new.tap do |mapping|
65
- attrs.each do |dfn|
66
- from = dfn[:name].to_sym
67
- to = [dfn[:on], (dfn[:private_name] || dfn[:name])].compact.map(&:to_sym)
68
- mapping.add(from, to)
69
- end
70
- end
71
- end
72
-
73
- def initialize
74
- @forward_map = {}
75
- @inverse_map = {}
76
- end
77
-
78
- # from is a symbol attribute
79
- # to is an 1 or 2 element array, depending on whether the attribute is 'namespaced', as it is with composite forms.
80
- # eg, add(:phone_number, [:person, :phone])
81
- def add(from, to)
82
- raise 'Mapping is not one-to-one' if @forward_map.has_key?(from) || @inverse_map.has_key?(to)
83
- @forward_map[from] = to
84
- @inverse_map[to] = from
85
- end
86
-
87
- def forward_image(attrs)
88
- @forward_map.values_at(*attrs).compact
89
- end
90
-
91
- def forward(attr)
92
- @forward_map[attr]
93
- end
94
-
95
- def inverse_image(attrs)
96
- @inverse_map.values_at(*attrs).compact
97
- end
98
-
99
- def inverse(attr)
100
- @inverse_map[attr]
101
- end
102
-
103
- end
104
-
105
- def copy_validations_from(models)
106
- ValidationCopier.copy(self, Mapping.from_representable_attrs(definitions), models)
107
- end
108
-
109
- end
110
- end
@@ -1,107 +0,0 @@
1
- require "active_model"
2
- require "uber/delegates"
3
-
4
- module Reform::Form::ActiveModel
5
- # AM::Validations for your form.
6
- # Provides ::validates, ::validate, #validate, and #valid?.
7
- #
8
- # Most of this file contains unnecessary wiring to make ActiveModel's error message magic work.
9
- # Since Rails still thinks it's a good idea to do things like object.class.human_attribute_name,
10
- # we have some hacks in here to provide that. If it doesn't work for you, don't blame us.
11
- module Validations
12
- def self.included(includer)
13
- includer.instance_eval do
14
- include Reform::Form::ActiveModel
15
-
16
- class << self
17
- extend Uber::Delegates
18
- # # Hooray! Delegate translation back to Reform's Validator class which contains AM::Validations.
19
- delegates :active_model_really_sucks, :human_attribute_name, :lookup_ancestors, :i18n_scope # Rails 3.1.
20
-
21
- def validation_group_class
22
- Group
23
- end
24
-
25
- # this is to allow calls like Form::human_attribute_name (note that this is on the CLASS level) to be resolved.
26
- # those calls happen when adding errors in a custom validation method, which is defined on the form (as an instance method).
27
- def active_model_really_sucks
28
- Class.new(Validator).tap do |v|
29
- v.model_name = model_name
30
- end
31
- end
32
- end
33
- end # ::included
34
- end
35
-
36
- def build_errors
37
- Errors.new(self)
38
- end
39
-
40
- # The concept of "composition" has still not arrived in Rails core and they rely on 400 methods being
41
- # available in one object. This is why we need to provide parts of the I18N API in the form.
42
- def read_attribute_for_validation(name)
43
- send(name)
44
- end
45
-
46
- class Group
47
- def initialize
48
- @validations = Class.new(Reform::Form::ActiveModel::Validations::Validator)
49
- end
50
-
51
- extend Uber::Delegates
52
- delegates :@validations, :validates, :validate, :validates_with, :validate_with
53
-
54
- def call(fields, errors, form) # FIXME.
55
- validator = @validations.new(form)
56
- validator.valid?
57
-
58
- validator.errors.each do |name, error| # TODO: handle with proper merge, or something. validator.errors is ALWAYS AM::Errors.
59
- errors.add(name, error)
60
- end
61
- end
62
- end
63
-
64
-
65
- # Validator is the validatable object. On the class level, we define validations,
66
- # on instance, it exposes #valid?.
67
- require "delegate"
68
- class Validator < SimpleDelegator
69
- # current i18n scope: :activemodel.
70
- include ActiveModel::Validations
71
-
72
- class << self
73
- def model_name
74
- @_active_model_sucks ||= ActiveModel::Name.new(Reform::Form, nil, "Reform::Form")
75
- end
76
-
77
- def model_name=(name)
78
- @_active_model_sucks = name
79
- end
80
-
81
- def validates(*args, &block)
82
- super(*Declarative::DeepDup.(args), &block)
83
- end
84
-
85
- # Prevent AM:V from mutating the validator class
86
- def attr_reader(*)
87
- end
88
-
89
- def attr_writer(*)
90
- end
91
- end
92
-
93
- def initialize(form)
94
- super(form)
95
- self.class.model_name = form.model_name # one of the many reasons why i will drop support for AM::V in 2.1. or maybe a bit later.
96
- end
97
-
98
- def method_missing(m, *args, &block)
99
- __getobj__.send(m, *args, &block) # send all methods to the form, even privates.
100
- end
101
- end
102
- end
103
-
104
- class Errors < ActiveModel::Errors
105
- include Reform::Form::Errors::Merge
106
- end
107
- end