reform 2.2.3 → 2.3.2
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 +5 -5
- data/.gitignore +5 -1
- data/.travis.yml +11 -6
- data/Appraisals +8 -0
- data/CHANGES.md +56 -0
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +2 -16
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +5 -7
- data/Rakefile +16 -9
- data/gemfiles/0.13.0.gemfile +8 -0
- data/gemfiles/1.5.0.gemfile +9 -0
- data/lib/reform.rb +1 -0
- data/lib/reform/contract.rb +7 -17
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +53 -23
- data/lib/reform/errors.rb +61 -0
- data/lib/reform/form.rb +36 -10
- data/lib/reform/form/call.rb +1 -1
- data/lib/reform/form/composition.rb +2 -2
- data/lib/reform/form/dry.rb +10 -58
- data/lib/reform/form/dry/input_hash.rb +37 -0
- data/lib/reform/form/dry/new_api.rb +47 -0
- data/lib/reform/form/dry/old_api.rb +61 -0
- data/lib/reform/form/populator.rb +11 -29
- data/lib/reform/form/prepopulate.rb +5 -4
- data/lib/reform/form/validate.rb +28 -13
- data/lib/reform/result.rb +90 -0
- data/lib/reform/validation.rb +19 -11
- data/lib/reform/validation/groups.rb +12 -27
- data/lib/reform/version.rb +1 -1
- data/reform.gemspec +13 -13
- data/test/benchmarking.rb +39 -6
- data/test/call_new_api.rb +23 -0
- data/test/{call_test.rb → call_old_api.rb} +4 -4
- data/test/changed_test.rb +8 -8
- data/test/coercion_test.rb +51 -19
- data/test/composition_new_api.rb +186 -0
- data/test/{composition_test.rb → composition_old_api.rb} +66 -31
- data/test/contract/custom_error_test.rb +55 -0
- data/test/contract_new_api.rb +77 -0
- data/test/{contract_test.rb → contract_old_api.rb} +13 -13
- data/test/default_test.rb +2 -2
- data/test/deserialize_test.rb +11 -14
- data/test/errors_new_api.rb +225 -0
- data/test/errors_old_api.rb +230 -0
- data/test/feature_test.rb +8 -10
- data/test/fixtures/dry_error_messages.yml +73 -23
- data/test/fixtures/dry_new_api_error_messages.yml +104 -0
- data/test/form_new_api.rb +57 -0
- data/test/{form_test.rb → form_old_api.rb} +5 -5
- data/test/form_option_new_api.rb +24 -0
- data/test/{form_option_test.rb → form_option_old_api.rb} +4 -4
- data/test/from_test.rb +9 -13
- data/test/inherit_new_api.rb +105 -0
- data/test/inherit_old_api.rb +105 -0
- data/test/{module_test.rb → module_new_api.rb} +20 -25
- data/test/module_old_api.rb +146 -0
- data/test/parse_option_test.rb +40 -0
- data/test/parse_pipeline_test.rb +3 -3
- data/test/populate_new_api.rb +304 -0
- data/test/{populate_test.rb → populate_old_api.rb} +83 -49
- data/test/populator_skip_test.rb +9 -9
- data/test/prepopulator_test.rb +8 -9
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +7 -7
- data/test/reform_new_api.rb +204 -0
- data/test/{reform_test.rb → reform_old_api.rb} +30 -51
- data/test/save_new_api.rb +101 -0
- data/test/{save_test.rb → save_old_api.rb} +32 -20
- data/test/setup_test.rb +8 -8
- data/test/{skip_if_test.rb → skip_if_new_api.rb} +23 -12
- data/test/skip_if_old_api.rb +92 -0
- data/test/skip_setter_and_getter_test.rb +3 -4
- data/test/test_helper.rb +25 -14
- data/test/validate_new_api.rb +453 -0
- data/test/{validate_test.rb → validate_old_api.rb} +59 -69
- data/test/validation/dry_validation_new_api.rb +836 -0
- data/test/validation/dry_validation_old_api.rb +772 -0
- data/test/validation/result_test.rb +77 -0
- data/test/validation_library_provided_test.rb +16 -0
- data/test/virtual_test.rb +47 -7
- data/test/writeable_test.rb +35 -6
- metadata +101 -72
- data/gemfiles/Gemfile.disposable-0.3 +0 -6
- data/lib/reform/contract/errors.rb +0 -43
- data/lib/reform/form/mongoid.rb +0 -37
- data/lib/reform/form/orm.rb +0 -26
- data/lib/reform/mongoid.rb +0 -4
- data/test/deprecation_test.rb +0 -27
- data/test/errors_test.rb +0 -165
- data/test/inherit_test.rb +0 -119
- data/test/readonly_test.rb +0 -14
- data/test/validation/dry_test.rb +0 -60
- data/test/validation/dry_validation_test.rb +0 -352
- data/test/validation/errors.yml +0 -4
@@ -0,0 +1,61 @@
|
|
1
|
+
# Provides the old API for Rails and friends.
|
2
|
+
# Note that this might become an optional "deprecation" gem in Reform 3.
|
3
|
+
class Reform::Contract::Result::Errors
|
4
|
+
def initialize(result, form)
|
5
|
+
@result = result # DISCUSS: we don't use this ATM?
|
6
|
+
@form = form
|
7
|
+
@dotted_errors = {} # Reform does not endorse this style of error msgs.
|
8
|
+
|
9
|
+
DottedErrors.(@form, [], @dotted_errors)
|
10
|
+
end
|
11
|
+
|
12
|
+
# PROTOTYPING. THIS WILL GO TO A SEPARATE GEM IN REFORM 2.4/3.0.
|
13
|
+
DottedErrors = ->(form, prefix, hash) do
|
14
|
+
result = form.to_result
|
15
|
+
result.messages.collect { |k, v| hash[[*prefix, k].join(".").to_sym] = v }
|
16
|
+
|
17
|
+
form.schema.each(twin: true) do |dfn|
|
18
|
+
Disposable::Twin::PropertyProcessor.new(dfn, form).() do |frm, i|
|
19
|
+
form_obj = i ? form.send(dfn[:name])[i] : form.send(dfn[:name])
|
20
|
+
DottedErrors.(form_obj, [*prefix, dfn[:name]], hash)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def messages(*args)
|
26
|
+
@dotted_errors
|
27
|
+
end
|
28
|
+
|
29
|
+
def full_messages
|
30
|
+
@dotted_errors.collect { |path, errors|
|
31
|
+
human_field = path.to_s.gsub(/([\.\_])+/, " ").gsub(/(\b\w)+/) { |s| s.capitalize }
|
32
|
+
errors.collect { |message| "#{human_field} #{message}" }
|
33
|
+
}.flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
def [](name)
|
37
|
+
@dotted_errors[name] || []
|
38
|
+
end
|
39
|
+
|
40
|
+
def size
|
41
|
+
messages.size
|
42
|
+
end
|
43
|
+
|
44
|
+
# needed for rails form helpers
|
45
|
+
def empty?
|
46
|
+
messages.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
# we need to delegate adding error to result because every time we call form.errors
|
50
|
+
# a new instance of this class is created so we need to update the @results array
|
51
|
+
# to be able to add custom errors here.
|
52
|
+
# This method will actually work only AFTER a validate call has been made
|
53
|
+
def add(key, error_test)
|
54
|
+
@result.add_error(key, error_test)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Ensure that we can return Active Record compliant full messages when using dry
|
59
|
+
# we only want unique messages in our array
|
60
|
+
#
|
61
|
+
# @full_errors.add()
|
data/lib/reform/form.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Reform
|
2
2
|
class Form < Contract
|
3
|
+
class InvalidOptionsCombinationError < StandardError; end
|
4
|
+
|
3
5
|
def self.default_nested_class
|
4
6
|
Form
|
5
7
|
end
|
@@ -15,8 +17,32 @@ module Reform
|
|
15
17
|
|
16
18
|
module Property
|
17
19
|
# Add macro logic, e.g. for :populator.
|
18
|
-
|
19
|
-
|
20
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
21
|
+
def property(name, options = {}, &block)
|
22
|
+
if (options.keys & %i[skip_if populator]).size == 2
|
23
|
+
raise InvalidOptionsCombinationError.new(
|
24
|
+
"[Reform] #{self}:property:#{name} Do not use skip_if and populator together, use populator with skip! instead"
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
# if composition and inherited we also need this setting
|
29
|
+
# to correctly inherit modules
|
30
|
+
options[:_inherited] = options[:inherit] if options.key?(:on) && options.key?(:inherit)
|
31
|
+
|
32
|
+
if options.key?(:parse)
|
33
|
+
options[:deserializer] ||= {}
|
34
|
+
options[:deserializer][:writeable] = options.delete(:parse)
|
35
|
+
end
|
36
|
+
|
37
|
+
options[:writeable] ||= options.delete(:writable) if options.key?(:writable)
|
38
|
+
|
39
|
+
# for virtual collection we need at least to have the collection equal to [] to
|
40
|
+
# avoid issue when the populator
|
41
|
+
if (options.keys & %i[collection virtual]).size == 2
|
42
|
+
options = { default: [] }.merge(options)
|
43
|
+
end
|
44
|
+
|
45
|
+
definition = super # letdisposable and declarative gems sort out inheriting of properties, and so on.
|
20
46
|
definition.merge!(deserializer: {}) unless definition[:deserializer] # always keep :deserializer per property.
|
21
47
|
|
22
48
|
deserializer_options = definition[:deserializer]
|
@@ -33,10 +59,10 @@ module Reform
|
|
33
59
|
external_populator = Populator::External.new
|
34
60
|
|
35
61
|
# always compute a parse_pipeline for each property of the deserializer and inject it via :parse_pipeline.
|
36
|
-
# first,
|
62
|
+
# first, letrepresentable compute the pipeline functions by invoking #parse_functions.
|
37
63
|
if definition[:nested]
|
38
|
-
parse_pipeline = ->(input,
|
39
|
-
functions =
|
64
|
+
parse_pipeline = ->(input, opts) do
|
65
|
+
functions = opts[:binding].send(:parse_functions)
|
40
66
|
pipeline = Representable::Pipeline[*functions] # Pipeline[StopOnExcluded, AssignName, ReadFragment, StopOnNotFound, OverwriteOnNil, Collect[#<Representable::Function::CreateObject:0xa6148ec>, #<Representable::Function::Decorate:0xa6148b0>, Deserialize], Set]
|
41
67
|
|
42
68
|
pipeline = Representable::Pipeline::Insert.(pipeline, external_populator, replace: Representable::CreateObject::Instance)
|
@@ -45,12 +71,12 @@ module Reform
|
|
45
71
|
pipeline = Representable::Pipeline::Insert.(pipeline, Representable::SetValue, delete: true) # FIXME: only diff to options without :populator
|
46
72
|
end
|
47
73
|
else
|
48
|
-
parse_pipeline = ->(input,
|
49
|
-
functions =
|
74
|
+
parse_pipeline = ->(input, opts) do
|
75
|
+
functions = opts[:binding].send(:parse_functions)
|
50
76
|
pipeline = Representable::Pipeline[*functions] # Pipeline[StopOnExcluded, AssignName, ReadFragment, StopOnNotFound, OverwriteOnNil, Collect[#<Representable::Function::CreateObject:0xa6148ec>, #<Representable::Function::Decorate:0xa6148b0>, Deserialize], Set]
|
51
77
|
|
52
78
|
# FIXME: this won't work with property :name, inherit: true (where there is a populator set already).
|
53
|
-
pipeline = Representable::Pipeline::Insert.(pipeline, external_populator,
|
79
|
+
pipeline = Representable::Pipeline::Insert.(pipeline, external_populator, replace: Representable::SetValue) if definition[:populator] # FIXME: only diff to options without :populator
|
54
80
|
pipeline
|
55
81
|
end
|
56
82
|
end
|
@@ -62,12 +88,12 @@ module Reform
|
|
62
88
|
deserializer_options.merge!(skip_parse: proc) # TODO: same with skip_parse ==> External
|
63
89
|
end
|
64
90
|
|
65
|
-
|
66
91
|
# per default, everything should be writeable for the deserializer (we're only writing on the form). however, allow turning it off.
|
67
|
-
deserializer_options.merge!(writeable: true) unless deserializer_options.
|
92
|
+
deserializer_options.merge!(writeable: true) unless deserializer_options.key?(:writeable)
|
68
93
|
|
69
94
|
definition
|
70
95
|
end
|
96
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
71
97
|
end
|
72
98
|
extend Property
|
73
99
|
|
data/lib/reform/form/call.rb
CHANGED
@@ -16,13 +16,13 @@ module Reform::Form::Composition
|
|
16
16
|
#
|
17
17
|
# class CoverSongForm < Reform::Form
|
18
18
|
# model :song, on: :cover_song
|
19
|
-
def model(main_model, options={})
|
19
|
+
def model(main_model, options = {})
|
20
20
|
super
|
21
21
|
|
22
22
|
composition_model = options[:on] || main_model
|
23
23
|
|
24
24
|
# FIXME: this should just delegate to :model as in FB, and the comp would take care of it internally.
|
25
|
-
[
|
25
|
+
%i[persisted? to_key to_param].each do |method|
|
26
26
|
define_method method do
|
27
27
|
model[composition_model].send(method)
|
28
28
|
end
|
data/lib/reform/form/dry.rb
CHANGED
@@ -1,67 +1,19 @@
|
|
1
1
|
require "dry-validation"
|
2
|
-
require "dry/validation/
|
2
|
+
require "dry/validation/version"
|
3
3
|
require "reform/validation"
|
4
|
+
require "reform/form/dry/input_hash"
|
4
5
|
|
5
6
|
module Reform::Form::Dry
|
6
7
|
def self.included(includer)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
Reform::Contract::Errors.new(self)
|
14
|
-
end
|
15
|
-
|
16
|
-
module ClassMethods
|
17
|
-
def validation_group_class
|
18
|
-
Group
|
19
|
-
end
|
8
|
+
if Gem::Version.new(Dry::Validation::VERSION) > Gem::Version.new("0.13.3")
|
9
|
+
require "reform/form/dry/new_api"
|
10
|
+
validations = Reform::Form::Dry::NewApi::Validations
|
11
|
+
else
|
12
|
+
require "reform/form/dry/old_api"
|
13
|
+
validations = Reform::Form::Dry::OldApi::Validations
|
20
14
|
end
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
class Group
|
27
|
-
def initialize
|
28
|
-
@schemas = []
|
29
|
-
end
|
30
|
-
|
31
|
-
def instance_exec(&block)
|
32
|
-
@schemas << block
|
33
|
-
@validator = Builder.new(@schemas.dup).validation_graph
|
34
|
-
end
|
35
|
-
|
36
|
-
def call(fields, reform_errors, form)
|
37
|
-
# a message item looks like: {:confirm_password=>["confirm_password size cannot be less than 2"]}
|
38
|
-
@validator.with(form: form).call(fields).messages.each do |field, dry_error|
|
39
|
-
dry_error.each do |attr_error|
|
40
|
-
reform_errors.add(field, attr_error)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
class Builder < Array
|
46
|
-
def initialize(array)
|
47
|
-
super(array)
|
48
|
-
@validator = Dry::Validation.Form({}, &shift)
|
49
|
-
end
|
50
|
-
|
51
|
-
def validation_graph
|
52
|
-
build_graph(@validator)
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def build_graph(validator)
|
59
|
-
if empty?
|
60
|
-
return validator
|
61
|
-
end
|
62
|
-
build_graph(Dry::Validation.Schema(validator, {}, &shift))
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
16
|
+
includer.send :include, validations
|
17
|
+
includer.extend validations::ClassMethods
|
66
18
|
end
|
67
19
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Reform::Form::Dry
|
2
|
+
module InputHash
|
3
|
+
private
|
4
|
+
|
5
|
+
# if dry_error is a hash rather than an array then it contains
|
6
|
+
# the messages for a nested property
|
7
|
+
# these messages need to be added to the correct collection
|
8
|
+
# objects.
|
9
|
+
|
10
|
+
# collections:
|
11
|
+
# {0=>{:name=>["must be filled"]}, 1=>{:name=>["must be filled"]}}
|
12
|
+
|
13
|
+
# Objects:
|
14
|
+
# {:name=>["must be filled"]}
|
15
|
+
# simply load up the object and attach the message to it
|
16
|
+
|
17
|
+
# we can't use to_nested_hash as it get's messed up by composition.
|
18
|
+
def input_hash(form)
|
19
|
+
hash = form.class.nested_hash_representer.new(form).to_hash
|
20
|
+
symbolize_hash(hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
# dry-v needs symbolized keys
|
24
|
+
# TODO: Don't do this here... Representers??
|
25
|
+
def symbolize_hash(old_hash)
|
26
|
+
old_hash.each_with_object({}) do |(k, v), new_hash|
|
27
|
+
new_hash[k.to_sym] = if v.is_a?(Hash)
|
28
|
+
symbolize_hash(v)
|
29
|
+
elsif v.is_a?(Array)
|
30
|
+
v.map { |h| h.is_a?(Hash) ? symbolize_hash(h) : h }
|
31
|
+
else
|
32
|
+
v
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
::Dry::Validation.load_extensions(:hints)
|
2
|
+
|
3
|
+
module Reform::Form::Dry
|
4
|
+
module NewApi
|
5
|
+
|
6
|
+
class Contract < ::Dry::Validation::Contract
|
7
|
+
end
|
8
|
+
|
9
|
+
module Validations
|
10
|
+
module ClassMethods
|
11
|
+
def validation_group_class
|
12
|
+
Group
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.included(includer)
|
17
|
+
includer.extend(ClassMethods)
|
18
|
+
end
|
19
|
+
|
20
|
+
class Group
|
21
|
+
include InputHash
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
@validator = options.fetch(:schema, Contract)
|
25
|
+
@schema_inject_params = options.fetch(:with, {})
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :validator, :schema_inject_params, :block
|
29
|
+
|
30
|
+
def instance_exec(&block)
|
31
|
+
@block = block
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(form)
|
35
|
+
# when passing options[:schema] the class instance is already created so we just need to call
|
36
|
+
# "call"
|
37
|
+
return validator.call(input_hash(form)) unless validator.is_a?(Class) && @validator <= ::Dry::Validation::Contract
|
38
|
+
|
39
|
+
dynamic_options = { form: form }
|
40
|
+
inject_options = schema_inject_params.merge(dynamic_options)
|
41
|
+
|
42
|
+
validator.build(inject_options, &block).call(input_hash(form))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Reform::Form::Dry
|
2
|
+
module OldApi
|
3
|
+
class Schema < Dry::Validation::Schema
|
4
|
+
end
|
5
|
+
|
6
|
+
module Validations
|
7
|
+
module ClassMethods
|
8
|
+
def validation_group_class
|
9
|
+
Group
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(includer)
|
14
|
+
includer.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
class Group
|
18
|
+
include InputHash
|
19
|
+
|
20
|
+
def initialize(options = {})
|
21
|
+
options ||= {}
|
22
|
+
schema_class = options[:schema] || Reform::Form::Dry::OldApi::Schema
|
23
|
+
@validator = Dry::Validation.Schema(schema_class, build: false)
|
24
|
+
|
25
|
+
@schema_inject_params = options[:with] || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def instance_exec(&block)
|
29
|
+
@validator = Dry::Validation.Schema(@validator, build: false, &block)
|
30
|
+
# inject the keys into the configure block automatically
|
31
|
+
keys = @schema_inject_params.keys
|
32
|
+
@validator.class_eval do
|
33
|
+
configure do
|
34
|
+
keys.each { |k| option k }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def call(form)
|
40
|
+
dynamic_options = {}
|
41
|
+
dynamic_options[:form] = form if @schema_inject_params[:form]
|
42
|
+
inject_options = @schema_inject_params.merge(dynamic_options)
|
43
|
+
|
44
|
+
# TODO: only pass submitted values to Schema#call?
|
45
|
+
dry_result = call_schema(inject_options, input_hash(form))
|
46
|
+
# dry_messages = dry_result.messages
|
47
|
+
|
48
|
+
return dry_result
|
49
|
+
|
50
|
+
_reform_errors = Reform::Contract::Errors.new(dry_result) # TODO: dry should be merged here.
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def call_schema(inject_options, input)
|
56
|
+
@validator.new(@validator.rules, inject_options).(input)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -5,11 +5,9 @@
|
|
5
5
|
#
|
6
6
|
# For collections, the entire collection and the currently deserialised index is passed in.
|
7
7
|
class Reform::Form::Populator
|
8
|
-
include Uber::Callable
|
9
|
-
|
10
8
|
def initialize(user_proc)
|
11
9
|
@user_proc = user_proc # the actual `populator: ->{}` block from the user, via ::property.
|
12
|
-
@value =
|
10
|
+
@value = Declarative::Option(user_proc, instance_exec: true, callable: Object) # we can now process Callable, procs, :symbol.
|
13
11
|
end
|
14
12
|
|
15
13
|
def call(input, options)
|
@@ -28,13 +26,11 @@ class Reform::Form::Populator
|
|
28
26
|
twin
|
29
27
|
end
|
30
28
|
|
31
|
-
private
|
29
|
+
private
|
30
|
+
|
32
31
|
def call!(options)
|
33
32
|
form = options[:represented]
|
34
|
-
|
35
|
-
deprecate_positional_args(form, @user_proc, options) do
|
36
|
-
@value.(form, options)
|
37
|
-
end
|
33
|
+
@value.(form, options) # Declarative::Option call.
|
38
34
|
end
|
39
35
|
|
40
36
|
def handle_fail(twin, options)
|
@@ -42,20 +38,9 @@ private
|
|
42
38
|
end
|
43
39
|
|
44
40
|
def get(options)
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
def deprecate_positional_args(form, proc, options) # TODO: remove in 2.2.
|
49
|
-
arity = proc.is_a?(Symbol) ? form.method(proc).arity : proc.arity
|
50
|
-
return yield if arity == 1
|
51
|
-
warn "[Reform] Positional arguments for :populator and friends are deprecated. Please use ->(options) and enjoy the rest of your day. Learn more at http://trailblazerb.org/gems/reform/upgrading-guide.html#to-21"
|
52
|
-
args = []
|
53
|
-
args << options[:index] if options[:index]
|
54
|
-
args << options[:representable_options]
|
55
|
-
form.instance_exec(options[:fragment], options[:model], *args, &proc)
|
41
|
+
Representable::GetValue.(nil, options)
|
56
42
|
end
|
57
43
|
|
58
|
-
|
59
44
|
class IfEmpty < self # Populator
|
60
45
|
def call!(options)
|
61
46
|
binding, twin, index, fragment = options[:binding], options[:model], options[:index], options[:fragment] # TODO: remove once we drop 2.0.
|
@@ -75,7 +60,8 @@ private
|
|
75
60
|
end
|
76
61
|
end
|
77
62
|
|
78
|
-
|
63
|
+
private
|
64
|
+
|
79
65
|
def run!(form, fragment, options)
|
80
66
|
return @user_proc.new if @user_proc.is_a?(Class) # handle populate_if_empty: Class. this excludes using Callables, though.
|
81
67
|
|
@@ -91,18 +77,14 @@ private
|
|
91
77
|
|
92
78
|
@value.(form, options[:fragment], options[:user_options])
|
93
79
|
end
|
94
|
-
|
95
80
|
end
|
96
81
|
|
97
82
|
# Sync (default) blindly grabs the corresponding form twin and returns it. This might imply that nil is returned,
|
98
83
|
# and in turn #validate! is called on nil.
|
99
84
|
class Sync < self
|
100
85
|
def call!(options)
|
101
|
-
if options[:binding].array?
|
102
|
-
|
103
|
-
else
|
104
|
-
options[:model]
|
105
|
-
end
|
86
|
+
return options[:model][options[:index]] if options[:binding].array?
|
87
|
+
options[:model]
|
106
88
|
end
|
107
89
|
end
|
108
90
|
|
@@ -118,8 +100,8 @@ private
|
|
118
100
|
# (which population is) to the form.
|
119
101
|
class External
|
120
102
|
def call(input, options)
|
121
|
-
options[:represented].class.definitions
|
122
|
-
|
103
|
+
options[:represented].class.definitions
|
104
|
+
.get(options[:binding][:name])[:internal_populator].(input, options)
|
123
105
|
end
|
124
106
|
end
|
125
107
|
end
|