phlexi-form 0.3.0.rc1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -8
- data/gemfiles/default.gemfile.lock +34 -32
- data/gemfiles/rails_7.gemfile.lock +16 -18
- data/lib/phlexi/form/base.rb +42 -41
- data/lib/phlexi/form/builder.rb +297 -0
- data/lib/phlexi/form/components/base.rb +3 -3
- data/lib/phlexi/form/components/collection_checkboxes.rb +1 -1
- data/lib/phlexi/form/components/collection_radio_buttons.rb +1 -1
- data/lib/phlexi/form/components/concerns/extracts_input.rb +53 -0
- data/lib/phlexi/form/components/concerns/handles_input.rb +4 -34
- data/lib/phlexi/form/components/concerns/submits_form.rb +8 -0
- data/lib/phlexi/form/components/error.rb +1 -1
- data/lib/phlexi/form/components/file_input.rb +1 -0
- data/lib/phlexi/form/components/hint.rb +1 -1
- data/lib/phlexi/form/components/input.rb +16 -6
- data/lib/phlexi/form/components/input_array.rb +1 -1
- data/lib/phlexi/form/components/select.rb +4 -3
- data/lib/phlexi/form/components/textarea.rb +2 -3
- data/lib/phlexi/form/html.rb +18 -0
- data/lib/phlexi/form/{field_options → options}/autofocus.rb +1 -1
- data/lib/phlexi/form/{field_options → options}/collection.rb +14 -10
- data/lib/phlexi/form/{field_options → options}/disabled.rb +1 -1
- data/lib/phlexi/form/{field_options → options}/errors.rb +18 -14
- data/lib/phlexi/form/options/hints.rb +13 -0
- data/lib/phlexi/form/options/inferred_types.rb +32 -0
- data/lib/phlexi/form/{field_options → options}/length.rb +3 -3
- data/lib/phlexi/form/{field_options → options}/limit.rb +2 -2
- data/lib/phlexi/form/options/max.rb +55 -0
- data/lib/phlexi/form/options/min.rb +55 -0
- data/lib/phlexi/form/{field_options → options}/pattern.rb +2 -2
- data/lib/phlexi/form/{field_options → options}/readonly.rb +1 -1
- data/lib/phlexi/form/{field_options → options}/required.rb +3 -3
- data/lib/phlexi/form/options/step.rb +39 -0
- data/lib/phlexi/form/options/validators.rb +24 -0
- data/lib/phlexi/form/structure/field_collection.rb +12 -27
- data/lib/phlexi/form/structure/namespace.rb +4 -111
- data/lib/phlexi/form/structure/namespace_collection.rb +1 -32
- data/lib/phlexi/form/theme.rb +160 -0
- data/lib/phlexi/form/version.rb +1 -1
- data/lib/phlexi/form.rb +3 -6
- metadata +36 -24
- data/lib/phlexi/form/field_options/associations.rb +0 -21
- data/lib/phlexi/form/field_options/hints.rb +0 -22
- data/lib/phlexi/form/field_options/inferred_types.rb +0 -155
- data/lib/phlexi/form/field_options/labels.rb +0 -28
- data/lib/phlexi/form/field_options/min_max.rb +0 -92
- data/lib/phlexi/form/field_options/multiple.rb +0 -65
- data/lib/phlexi/form/field_options/placeholder.rb +0 -18
- data/lib/phlexi/form/field_options/themes.rb +0 -207
- data/lib/phlexi/form/field_options/validators.rb +0 -48
- data/lib/phlexi/form/structure/dom.rb +0 -62
- data/lib/phlexi/form/structure/field_builder.rb +0 -236
- data/lib/phlexi/form/structure/node.rb +0 -18
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
|
-
module
|
5
|
+
module Options
|
6
6
|
module Errors
|
7
7
|
def custom_error(error)
|
8
8
|
options[:error] = error
|
@@ -21,14 +21,28 @@ module Phlexi
|
|
21
21
|
object_with_errors? || !object && has_custom_error?
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
24
|
+
def can_show_errors?
|
25
25
|
options[:error] != false
|
26
26
|
end
|
27
27
|
|
28
|
+
def show_errors?
|
29
|
+
can_show_errors? && has_errors?
|
30
|
+
end
|
31
|
+
|
28
32
|
def valid?
|
29
33
|
!has_errors? && has_value?
|
30
34
|
end
|
31
35
|
|
36
|
+
# Determines if the associated object is in a valid state
|
37
|
+
#
|
38
|
+
# An object is considered valid if it is persisted and has no errors.
|
39
|
+
#
|
40
|
+
# @return [Boolean] true if the object is persisted and has no errors, false otherwise
|
41
|
+
def object_valid?
|
42
|
+
object.respond_to?(:persisted?) && object.persisted? &&
|
43
|
+
object.respond_to?(:errors) && !object.errors.empty?
|
44
|
+
end
|
45
|
+
|
32
46
|
protected
|
33
47
|
|
34
48
|
def error_text
|
@@ -66,26 +80,16 @@ module Phlexi
|
|
66
80
|
end
|
67
81
|
|
68
82
|
def errors_on_association
|
69
|
-
|
83
|
+
association_reflection ? object.errors[association_reflection.name] : []
|
70
84
|
end
|
71
85
|
|
72
86
|
def full_errors_on_association
|
73
|
-
|
87
|
+
association_reflection ? object.errors.full_messages_for(association_reflection.name) : []
|
74
88
|
end
|
75
89
|
|
76
90
|
def has_custom_error?
|
77
91
|
options[:error].is_a?(String)
|
78
92
|
end
|
79
|
-
|
80
|
-
# Determines if the associated object is in a valid state
|
81
|
-
#
|
82
|
-
# An object is considered valid if it is persisted and has no errors.
|
83
|
-
#
|
84
|
-
# @return [Boolean] true if the object is persisted and has no errors, false otherwise
|
85
|
-
def object_valid?
|
86
|
-
object.respond_to?(:persisted?) && object.persisted? &&
|
87
|
-
object.respond_to?(:errors) && !object.errors.empty?
|
88
|
-
end
|
89
93
|
end
|
90
94
|
end
|
91
95
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Options
|
6
|
+
module InferredTypes
|
7
|
+
private
|
8
|
+
|
9
|
+
def infer_field_component
|
10
|
+
case inferred_field_type
|
11
|
+
when :string, :text
|
12
|
+
infer_string_field_type || inferred_field_type
|
13
|
+
when :integer, :float, :decimal
|
14
|
+
:number
|
15
|
+
when :json, :jsonb
|
16
|
+
:text
|
17
|
+
when :enum
|
18
|
+
:select
|
19
|
+
when :association
|
20
|
+
association_reflection.polymorphic? ? :"polymorphic_#{association_reflection.macro}" : association_reflection.macro
|
21
|
+
when :attachment, :binary
|
22
|
+
:file
|
23
|
+
when :date, :time, :datetime, :boolean, :hstore
|
24
|
+
inferred_field_type
|
25
|
+
else
|
26
|
+
:string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
|
-
module
|
5
|
+
module Options
|
6
6
|
module Length
|
7
7
|
def minlength(minlength = nil)
|
8
8
|
if minlength.nil?
|
9
|
-
options
|
9
|
+
options.fetch(:minlength) { options[:minlength] = calculate_minlength }
|
10
10
|
else
|
11
11
|
options[:minlength] = minlength
|
12
12
|
self
|
@@ -15,7 +15,7 @@ module Phlexi
|
|
15
15
|
|
16
16
|
def maxlength(maxlength = nil)
|
17
17
|
if maxlength.nil?
|
18
|
-
options
|
18
|
+
options.fetch(:maxlength) { options[:maxlength] = calculate_maxlength }
|
19
19
|
else
|
20
20
|
options[:maxlength] = maxlength
|
21
21
|
self
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
|
-
module
|
5
|
+
module Options
|
6
6
|
module Limit
|
7
7
|
def limit(limit = nil)
|
8
8
|
if limit.nil?
|
9
|
-
options
|
9
|
+
options.fetch(:limit) { options[:limit] = calculate_limit }
|
10
10
|
else
|
11
11
|
options[:limit] = limit
|
12
12
|
self
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Options
|
6
|
+
module Max
|
7
|
+
def max(max_value = nil)
|
8
|
+
if max_value.nil?
|
9
|
+
options.fetch(:max) { options[:max] = calculate_max }
|
10
|
+
else
|
11
|
+
options[:max] = max_value
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def calculate_max
|
19
|
+
if (numericality_validator = find_numericality_validator)
|
20
|
+
get_max_from_validator(numericality_validator)
|
21
|
+
elsif (max = get_max_from_attribute(key))
|
22
|
+
max
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_max_from_validator(validator)
|
27
|
+
options = validator.options
|
28
|
+
max = if options.key?(:less_than)
|
29
|
+
{value: options[:less_than], exclusive: true}
|
30
|
+
elsif options.key?(:less_than_or_equal_to)
|
31
|
+
{value: options[:less_than_or_equal_to], exclusive: false}
|
32
|
+
end
|
33
|
+
evaluate_and_adjust_max(max)
|
34
|
+
end
|
35
|
+
|
36
|
+
def evaluate_and_adjust_max(max)
|
37
|
+
return nil unless max
|
38
|
+
|
39
|
+
value = evaluate_numericality_validator_option(max[:value])
|
40
|
+
max[:exclusive] ? value - 1 : value
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_max_from_attribute(attribute)
|
44
|
+
if object.class.respond_to?(:attribute_types) && (attribute_type = object.class.attribute_types[attribute.to_s])
|
45
|
+
if (range = attribute_type.instance_variable_get(:@range))
|
46
|
+
range.max
|
47
|
+
elsif attribute_type.respond_to?(:precision) && (precision = attribute_type.precision)
|
48
|
+
(precision**8) - ((step && step != "any") ? step : 0.000001)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Options
|
6
|
+
module Min
|
7
|
+
def min(min_value = nil)
|
8
|
+
if min_value.nil?
|
9
|
+
options.fetch(:min) { options[:min] = calculate_min }
|
10
|
+
else
|
11
|
+
options[:min] = min_value
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def calculate_min
|
19
|
+
if (numericality_validator = find_numericality_validator)
|
20
|
+
get_min_from_validator(numericality_validator)
|
21
|
+
elsif (min = get_min_from_attribute(key))
|
22
|
+
min
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_min_from_validator(validator)
|
27
|
+
options = validator.options
|
28
|
+
min = if options.key?(:greater_than)
|
29
|
+
{value: options[:greater_than], exclusive: true}
|
30
|
+
elsif options.key?(:greater_than_or_equal_to)
|
31
|
+
{value: options[:greater_than_or_equal_to], exclusive: false}
|
32
|
+
end
|
33
|
+
evaluate_and_adjust_min(min)
|
34
|
+
end
|
35
|
+
|
36
|
+
def evaluate_and_adjust_min(min)
|
37
|
+
return nil unless min
|
38
|
+
|
39
|
+
value = evaluate_numericality_validator_option(min[:value])
|
40
|
+
min[:exclusive] ? value + 1 : value
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_min_from_attribute(attribute)
|
44
|
+
if object.class.respond_to?(:attribute_types) && (attribute_type = object.class.attribute_types[attribute.to_s])
|
45
|
+
if (range = attribute_type.instance_variable_get(:@range))
|
46
|
+
range.min
|
47
|
+
elsif attribute_type.respond_to?(:precision) && (precision = attribute_type.precision)
|
48
|
+
-((precision**8) - ((step && step != "any") ? step : 0.000001))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
|
-
module
|
5
|
+
module Options
|
6
6
|
module Pattern
|
7
7
|
def pattern(pattern = nil)
|
8
8
|
if pattern.nil?
|
9
|
-
options
|
9
|
+
options.fetch(:pattern) { options[:pattern] = calculate_pattern }
|
10
10
|
else
|
11
11
|
options[:pattern] = pattern
|
12
12
|
self
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
|
-
module
|
5
|
+
module Options
|
6
6
|
module Required
|
7
7
|
def required?
|
8
|
-
options
|
8
|
+
options.fetch(:required) { options[:required] = calculate_required }
|
9
9
|
end
|
10
10
|
|
11
11
|
def required!(required = true)
|
@@ -24,7 +24,7 @@ module Phlexi
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def required_by_validators?
|
27
|
-
(attribute_validators +
|
27
|
+
(attribute_validators + association_reflection_validators).any? { |v| v.kind == :presence && valid_validator?(v) }
|
28
28
|
end
|
29
29
|
|
30
30
|
def required_by_default?
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Options
|
6
|
+
module Step
|
7
|
+
def step(value = nil)
|
8
|
+
if value.nil?
|
9
|
+
options.fetch(:step) { options[:step] = calculate_step }
|
10
|
+
else
|
11
|
+
options[:step] = value
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def calculate_step
|
19
|
+
if (scale = get_scale_from_attribute(key))
|
20
|
+
return 1.fdiv(10**scale)
|
21
|
+
end
|
22
|
+
|
23
|
+
case inferred_field_type
|
24
|
+
when :integer
|
25
|
+
1
|
26
|
+
when :decimal, :float
|
27
|
+
"any"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_scale_from_attribute(attribute)
|
32
|
+
if object.class.respond_to?(:attribute_types) && (attribute_type = object.class.attribute_types[attribute.to_s])
|
33
|
+
attribute_type.scale if attribute_type.respond_to?(:scale)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Phlexi
|
4
|
+
module Form
|
5
|
+
module Options
|
6
|
+
module Validators
|
7
|
+
private
|
8
|
+
|
9
|
+
def find_numericality_validator
|
10
|
+
find_validator(:numericality)
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate_numericality_validator_option(option)
|
14
|
+
case option
|
15
|
+
when Proc
|
16
|
+
option.arity.zero? ? option.call : option.call(object)
|
17
|
+
else
|
18
|
+
option
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -3,20 +3,11 @@
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
5
|
module Structure
|
6
|
-
class FieldCollection
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(key, field, index)
|
13
|
-
@key = key.to_s
|
14
|
-
@field = field
|
15
|
-
@index = index
|
16
|
-
end
|
17
|
-
|
18
|
-
def field(**)
|
19
|
-
@field.class.new(key, input_attributes: @field.input_attributes, **, parent: @field).tap do |field|
|
6
|
+
class FieldCollection < Phlexi::Field::Structure::FieldCollection
|
7
|
+
class Builder < Builder
|
8
|
+
def field(**options)
|
9
|
+
options = mix({input_attributes: @field.input_attributes}, options)
|
10
|
+
@field.class.new(key, **options, parent: @field).tap do |field|
|
20
11
|
yield field if block_given?
|
21
12
|
end
|
22
13
|
end
|
@@ -30,22 +21,16 @@ module Phlexi
|
|
30
21
|
end
|
31
22
|
end
|
32
23
|
|
33
|
-
|
34
|
-
|
35
|
-
|
24
|
+
private
|
25
|
+
|
26
|
+
def build_collection(collection)
|
27
|
+
case collection
|
36
28
|
when Range, Array
|
37
|
-
|
29
|
+
collection
|
38
30
|
when Integer
|
39
|
-
1..
|
31
|
+
1..collection
|
40
32
|
else
|
41
|
-
|
42
|
-
end
|
43
|
-
each(&) if block_given?
|
44
|
-
end
|
45
|
-
|
46
|
-
def each(&)
|
47
|
-
@range.each.with_index do |key, index|
|
48
|
-
yield Builder.new(key, @field, index)
|
33
|
+
collection.to_a
|
49
34
|
end
|
50
35
|
end
|
51
36
|
end
|
@@ -3,74 +3,11 @@
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
5
|
module Structure
|
6
|
-
|
7
|
-
|
8
|
-
# To access the values on a Namespace, the `field` can be called for single values.
|
9
|
-
#
|
10
|
-
# Additionally, to access namespaces within a namespace, such as if a `User has_many :addresses` in
|
11
|
-
# ActiveRecord, the `namespace` method can be called which will return another Namespace object and
|
12
|
-
# set the current Namespace as the parent.
|
13
|
-
class Namespace < Structure::Node
|
14
|
-
include Enumerable
|
6
|
+
class Namespace < Phlexi::Field::Structure::Namespace
|
7
|
+
class NamespaceCollection < Phlexi::Form::Structure::NamespaceCollection; end
|
15
8
|
|
16
|
-
|
17
|
-
|
18
|
-
def initialize(key, parent:, builder_klass:, object: nil)
|
19
|
-
super(key, parent: parent)
|
20
|
-
@builder_klass = builder_klass
|
21
|
-
@object = object
|
22
|
-
@children = {}
|
23
|
-
yield self if block_given?
|
24
|
-
end
|
25
|
-
|
26
|
-
def field(key, **attributes)
|
27
|
-
create_child(key, attributes.delete(:builder_klass) || builder_klass, object: object, **attributes).tap do |field|
|
28
|
-
yield field if block_given?
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def submit_button(key = nil, **attributes, &)
|
33
|
-
field(key || SecureRandom.hex).submit_button_tag(**attributes, &)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Creates a `Namespace` child instance with the parent set to the current instance, adds to
|
37
|
-
# the `@children` Hash to ensure duplicate child namespaces aren't created, then calls the
|
38
|
-
# method on the `@object` to get the child object to pass into that namespace.
|
39
|
-
#
|
40
|
-
# For example, if a `User#permission` returns a `Permission` object, we could map that to a
|
41
|
-
# form like this:
|
42
|
-
#
|
43
|
-
# ```ruby
|
44
|
-
# Superform :user, object: User.new do |form|
|
45
|
-
# form.nest_one :permission do |permission|
|
46
|
-
# form.field :role
|
47
|
-
# end
|
48
|
-
# end
|
49
|
-
# ```
|
50
|
-
def nest_one(key, object: nil, &)
|
51
|
-
object ||= object_value_for(key: key)
|
52
|
-
create_child(key, self.class, object:, builder_klass:, &)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Wraps an array of objects in Namespace classes. For example, if `User#addresses` returns
|
56
|
-
# an enumerable or array of `Address` classes:
|
57
|
-
#
|
58
|
-
# ```ruby
|
59
|
-
# Phlexi::Form.new User.new do |form|
|
60
|
-
# render form.field(:email).input_tag
|
61
|
-
# render form.field(:name).input_tag
|
62
|
-
# form.nest_many :addresses do |address|
|
63
|
-
# render address.field(:street).input_tag
|
64
|
-
# render address.field(:state).input_tag
|
65
|
-
# render address.field(:zip).input_tag
|
66
|
-
# end
|
67
|
-
# end
|
68
|
-
# ```
|
69
|
-
# The object within the block is a `Namespace` object that maps each object within the enumerable
|
70
|
-
# to another `Namespace` or `Field`.
|
71
|
-
def nest_many(key, collection: nil, &)
|
72
|
-
collection ||= Array(object_value_for(key: key))
|
73
|
-
create_child(key, NamespaceCollection, collection:, &)
|
9
|
+
def submit_button(key = :submit_button, **, &)
|
10
|
+
field(key).submit_button_tag(**, &)
|
74
11
|
end
|
75
12
|
|
76
13
|
def extract_input(params)
|
@@ -85,50 +22,6 @@ module Phlexi
|
|
85
22
|
{key => input}
|
86
23
|
end
|
87
24
|
end
|
88
|
-
|
89
|
-
# Iterates through the children of the current namespace, which could be `Namespace` or `Field`
|
90
|
-
# objects.
|
91
|
-
def each(&)
|
92
|
-
@children.values.each(&)
|
93
|
-
end
|
94
|
-
|
95
|
-
def dom_id
|
96
|
-
@dom_id ||= begin
|
97
|
-
id = if object.nil?
|
98
|
-
nil
|
99
|
-
elsif object.class.respond_to?(:primary_key)
|
100
|
-
object.public_send(object.class.primary_key) || :new
|
101
|
-
elsif object.respond_to?(:id)
|
102
|
-
object.id || :new
|
103
|
-
end
|
104
|
-
[key, id].compact.join("_").underscore
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Creates a root Namespace, which is essentially a form.
|
109
|
-
def self.root(*, builder_klass:, **, &)
|
110
|
-
new(*, parent: nil, builder_klass:, **, &)
|
111
|
-
end
|
112
|
-
|
113
|
-
protected
|
114
|
-
|
115
|
-
# Calls the corresponding method on the object for the `key` name, if it exists. For example
|
116
|
-
# if the `key` is `email` on `User`, this method would call `User#email` if the method is
|
117
|
-
# present.
|
118
|
-
#
|
119
|
-
# This method could be overwritten if the mapping between the `@object` and `key` name is not
|
120
|
-
# a method call. For example, a `Hash` would be accessed via `user[:email]` instead of `user.send(:email)`
|
121
|
-
def object_value_for(key:)
|
122
|
-
@object.send(key) if @object.respond_to? key
|
123
|
-
end
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
# Checks if the child exists. If it does then it returns that. If it doesn't, it will
|
128
|
-
# build the child.
|
129
|
-
def create_child(key, child_class, **kwargs, &block)
|
130
|
-
@children.fetch(key) { @children[key] = child_class.new(key, parent: self, **kwargs, &block) }
|
131
|
-
end
|
132
25
|
end
|
133
26
|
end
|
134
27
|
end
|
@@ -3,19 +3,7 @@
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
5
|
module Structure
|
6
|
-
class NamespaceCollection <
|
7
|
-
include Enumerable
|
8
|
-
|
9
|
-
def initialize(key, parent:, collection: nil, &block)
|
10
|
-
raise ArgumentError, "block is required" unless block.present?
|
11
|
-
|
12
|
-
super(key, parent: parent)
|
13
|
-
|
14
|
-
@collection = collection
|
15
|
-
@block = block
|
16
|
-
each(&block)
|
17
|
-
end
|
18
|
-
|
6
|
+
class NamespaceCollection < Phlexi::Field::Structure::NamespaceCollection
|
19
7
|
def extract_input(params)
|
20
8
|
namespace = build_namespace(0)
|
21
9
|
@block.call(namespace)
|
@@ -23,25 +11,6 @@ module Phlexi
|
|
23
11
|
inputs = params[key].map { |param| namespace.extract_input([param]) }
|
24
12
|
{key => inputs}
|
25
13
|
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def each(&)
|
30
|
-
namespaces.each(&)
|
31
|
-
end
|
32
|
-
|
33
|
-
# Builds and memoizes namespaces for the collection.
|
34
|
-
#
|
35
|
-
# @return [Array<Hash>] An array of namespace hashes.
|
36
|
-
def namespaces
|
37
|
-
@namespaces ||= @collection.map.with_index do |object, key|
|
38
|
-
build_namespace(key, object: object)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def build_namespace(index, **)
|
43
|
-
parent.class.new(index, parent: self, builder_klass: parent.builder_klass, **)
|
44
|
-
end
|
45
14
|
end
|
46
15
|
end
|
47
16
|
end
|