phlexi-form 0.4.7 → 0.5.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/lib/phlexi/form/builder.rb +1 -1
- data/lib/phlexi/form/{option_mapper.rb → choices_mapper.rb} +32 -32
- data/lib/phlexi/form/components/collection_checkboxes.rb +3 -3
- data/lib/phlexi/form/components/collection_radio_buttons.rb +3 -3
- data/lib/phlexi/form/components/concerns/{has_options.rb → accepts_choices.rb} +5 -5
- data/lib/phlexi/form/components/select.rb +2 -2
- data/lib/phlexi/form/options/{collection.rb → choices.rb} +9 -9
- data/lib/phlexi/form/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 454cb0f7804d3a7c10a6afdb3fe9bb7342e63bc76ee02750ea4a65f95e853449
|
4
|
+
data.tar.gz: 97c56aabb6e2c6b3b83f0c4782ac8724427fd93d211f5ac16f1dd42a4f1c1ac0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46350c1288b35d787080eff648bf86b23a55a1a122d234dfe2611cf91133d922f0e0747826cbf5a3980af7ebad55c07947953432bc3c700456871e7ab99ccb00
|
7
|
+
data.tar.gz: 31936b709b68353f3c855ec809e582f1d43a2c5669bcadec9499a0ea315ed66c9cf74038176b9106d4f316953a8111669aeaa63bc44f1fe48c92d746b86fcb8c
|
data/lib/phlexi/form/builder.rb
CHANGED
@@ -2,58 +2,58 @@
|
|
2
2
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
|
-
#
|
5
|
+
# ChoicesMapper is responsible for converting a collection of objects into a hash of options
|
6
6
|
# suitable for form controls, such as `select > options`.
|
7
7
|
# Both values and labels are converted to strings.
|
8
8
|
#
|
9
9
|
# @example Basic usage
|
10
10
|
# collection = [["First", 1], ["Second", 2]]
|
11
|
-
# mapper =
|
11
|
+
# mapper = ChoicesMapper.new(collection)
|
12
12
|
# mapper.each { |value, label| puts "#{value}: #{label}" }
|
13
13
|
#
|
14
14
|
# @example Using with ActiveRecord objects
|
15
15
|
# users = User.all
|
16
|
-
# mapper =
|
16
|
+
# mapper = ChoicesMapper.new(users)
|
17
17
|
# mapper.each { |id, name| puts "#{id}: #{name}" }
|
18
18
|
#
|
19
19
|
# @example Array access with different value types
|
20
|
-
# mapper =
|
20
|
+
# mapper = ChoicesMapper.new([["Integer", 1], ["String", "2"], ["Symbol", :three]])
|
21
21
|
# puts mapper["1"] # Output: "Integer"
|
22
22
|
# puts mapper["2"] # Output: "String"
|
23
23
|
# puts mapper["three"] # Output: "Symbol"
|
24
24
|
#
|
25
25
|
# @note This class is thread-safe as it doesn't maintain mutable state.
|
26
|
-
class
|
26
|
+
class ChoicesMapper
|
27
27
|
include Enumerable
|
28
28
|
|
29
|
-
# Initializes a new
|
29
|
+
# Initializes a new ChoicesMapper instance.
|
30
30
|
#
|
31
31
|
# @param collection [#call, #to_a] The collection to be mapped.
|
32
32
|
# @param label_method [Symbol, nil] The method to call on each object to get the label.
|
33
33
|
# @param value_method [Symbol, nil] The method to call on each object to get the value.
|
34
34
|
def initialize(collection, label_method: nil, value_method: nil)
|
35
|
-
@
|
35
|
+
@collection = collection
|
36
36
|
@label_method = label_method
|
37
37
|
@value_method = value_method
|
38
38
|
end
|
39
39
|
|
40
|
-
# Iterates over the
|
40
|
+
# Iterates over the choices, yielding value-label pairs.
|
41
41
|
#
|
42
|
-
# @yieldparam value [String] The string value for the current
|
43
|
-
# @yieldparam label [String] The string label for the current
|
42
|
+
# @yieldparam value [String] The string value for the current choice.
|
43
|
+
# @yieldparam label [String] The string label for the current choice.
|
44
44
|
# @return [Enumerator] If no block is given.
|
45
45
|
def each(&)
|
46
|
-
|
46
|
+
choices.each(&)
|
47
47
|
end
|
48
48
|
|
49
|
-
# @return [Array<String>] An array of all labels
|
49
|
+
# @return [Array<String>] An array of all choice labels.
|
50
50
|
def labels
|
51
|
-
|
51
|
+
choices.values
|
52
52
|
end
|
53
53
|
|
54
|
-
# @return [Array<String>] An array of all values
|
54
|
+
# @return [Array<String>] An array of all choice values.
|
55
55
|
def values
|
56
|
-
|
56
|
+
choices.keys
|
57
57
|
end
|
58
58
|
|
59
59
|
# Retrieves the label for a given value.
|
@@ -61,22 +61,22 @@ module Phlexi
|
|
61
61
|
# @param value [#to_s] The value to look up.
|
62
62
|
# @return [String, nil] The label corresponding to the value, or nil if not found.
|
63
63
|
def [](value)
|
64
|
-
|
64
|
+
choices[value.to_s]
|
65
65
|
end
|
66
66
|
|
67
67
|
private
|
68
68
|
|
69
|
-
# @return [Hash<String, String>] The
|
70
|
-
def
|
71
|
-
@
|
69
|
+
# @return [Hash<String, String>] The choices as a hash of {"string value" => "string label"}.
|
70
|
+
def choices
|
71
|
+
@choices ||= materialize_choices(@collection)
|
72
72
|
end
|
73
73
|
|
74
|
-
# Converts
|
74
|
+
# Converts a collection into a materialized hash of choices.
|
75
75
|
#
|
76
76
|
# @param collection [#call, #to_a] The collection to be materialized.
|
77
|
-
# @return [Hash<String, String>] The materialized
|
77
|
+
# @return [Hash<String, String>] The materialized choices as a hash of {"string value" => "string label"}.
|
78
78
|
# @raise [ArgumentError] If the collection cannot be materialized into an enumerable.
|
79
|
-
def
|
79
|
+
def materialize_choices(collection)
|
80
80
|
case collection
|
81
81
|
in Hash => hash
|
82
82
|
hash.transform_keys(&:to_s).transform_values(&:to_s)
|
@@ -85,7 +85,7 @@ module Phlexi
|
|
85
85
|
in Range => range
|
86
86
|
range_to_hash(range)
|
87
87
|
in Proc => proc
|
88
|
-
|
88
|
+
materialize_choices(proc.call)
|
89
89
|
in Symbol
|
90
90
|
raise ArgumentError, "Symbol collections are not supported in this context"
|
91
91
|
in Set => set
|
@@ -94,7 +94,7 @@ module Phlexi
|
|
94
94
|
array_to_hash(Array(collection))
|
95
95
|
end
|
96
96
|
rescue ArgumentError
|
97
|
-
# Rails.logger.warn("Unhandled inclusion collection type: #{e}")
|
97
|
+
# Rails.logger.warn("Unhandled inclusion collection type: #{e}")TODO
|
98
98
|
{}
|
99
99
|
end
|
100
100
|
|
@@ -134,20 +134,20 @@ module Phlexi
|
|
134
134
|
{value: :last, label: :first}
|
135
135
|
else
|
136
136
|
{
|
137
|
-
value: @value_method ||
|
138
|
-
label: @label_method ||
|
137
|
+
value: @value_method || choice_value_methods.find { |m| sample.respond_to?(m) },
|
138
|
+
label: @label_method || choice_label_methods.find { |m| sample.respond_to?(m) }
|
139
139
|
}
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
|
-
# @return [Array<Symbol>] An array of method names to try for
|
144
|
-
def
|
145
|
-
@
|
143
|
+
# @return [Array<Symbol>] An array of method names to try for choice values.
|
144
|
+
def choice_value_methods
|
145
|
+
@choice_value_methods ||= %i[to_value id to_s].freeze
|
146
146
|
end
|
147
147
|
|
148
|
-
# @return [Array<Symbol>] An array of method names to try for
|
149
|
-
def
|
150
|
-
@
|
148
|
+
# @return [Array<Symbol>] An array of method names to try for choice labels.
|
149
|
+
def choice_label_methods
|
150
|
+
@choice_label_methods ||= %i[to_label name title to_s].freeze
|
151
151
|
end
|
152
152
|
end
|
153
153
|
end
|
@@ -6,15 +6,15 @@ module Phlexi
|
|
6
6
|
class CollectionCheckboxes < Base
|
7
7
|
include Concerns::HandlesInput
|
8
8
|
include Concerns::HandlesArrayInput
|
9
|
-
include Concerns::
|
9
|
+
include Concerns::AcceptsChoices
|
10
10
|
|
11
11
|
def view_template
|
12
12
|
div(**attributes.slice(:id, :class)) do
|
13
|
-
field.repeated(
|
13
|
+
field.repeated(choices.values) do |builder|
|
14
14
|
render builder.hidden_field_tag if builder.index == 0
|
15
15
|
|
16
16
|
field = builder.field(
|
17
|
-
label:
|
17
|
+
label: choices[builder.key],
|
18
18
|
# We set the attributes here so they are applied to all input components even if the user decides to use a block
|
19
19
|
input_attributes: {
|
20
20
|
checked_value: builder.key,
|
@@ -5,15 +5,15 @@ module Phlexi
|
|
5
5
|
module Components
|
6
6
|
class CollectionRadioButtons < Base
|
7
7
|
include Concerns::HandlesInput
|
8
|
-
include Concerns::
|
8
|
+
include Concerns::AcceptsChoices
|
9
9
|
|
10
10
|
def view_template
|
11
11
|
div(**attributes.slice(:id, :class)) do
|
12
|
-
field.repeated(
|
12
|
+
field.repeated(choices.values) do |builder|
|
13
13
|
render builder.hidden_field_tag if builder.index == 0
|
14
14
|
|
15
15
|
field = builder.field(
|
16
|
-
label:
|
16
|
+
label: choices[builder.key],
|
17
17
|
# We set the attributes here so they are applied to all input components even if the user decides to use a block
|
18
18
|
input_attributes: {
|
19
19
|
checked_value: builder.key,
|
@@ -4,18 +4,18 @@ module Phlexi
|
|
4
4
|
module Form
|
5
5
|
module Components
|
6
6
|
module Concerns
|
7
|
-
module
|
7
|
+
module AcceptsChoices
|
8
8
|
protected
|
9
9
|
|
10
10
|
def build_attributes
|
11
11
|
super
|
12
|
-
@
|
12
|
+
@choice_collection = attributes.delete(:choices) || field.choices
|
13
13
|
@label_method = attributes.delete(:label_method)
|
14
14
|
@value_method = attributes.delete(:value_method)
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
@
|
17
|
+
def choices
|
18
|
+
@choices ||= ChoicesMapper.new(@choice_collection, label_method: @label_method, value_method: @value_method)
|
19
19
|
end
|
20
20
|
|
21
21
|
def selected?(option)
|
@@ -28,7 +28,7 @@ module Phlexi
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def normalize_simple_input(input_value)
|
31
|
-
([super] &
|
31
|
+
([super] & choices.values)[0]
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -6,7 +6,7 @@ module Phlexi
|
|
6
6
|
class Select < Base
|
7
7
|
include Concerns::HandlesInput
|
8
8
|
include Concerns::HandlesArrayInput
|
9
|
-
include Concerns::
|
9
|
+
include Concerns::AcceptsChoices
|
10
10
|
|
11
11
|
def view_template
|
12
12
|
input(type: :hidden, name: attributes[:name], value: "", autocomplete: "off", hidden: true) if include_hidden?
|
@@ -19,7 +19,7 @@ module Phlexi
|
|
19
19
|
protected
|
20
20
|
|
21
21
|
def options
|
22
|
-
|
22
|
+
choices.each do |value, label|
|
23
23
|
option(selected: selected?(value), value: value) { label }
|
24
24
|
end
|
25
25
|
end
|
@@ -3,27 +3,27 @@
|
|
3
3
|
module Phlexi
|
4
4
|
module Form
|
5
5
|
module Options
|
6
|
-
module
|
7
|
-
def
|
8
|
-
if
|
9
|
-
options.fetch(:
|
6
|
+
module Choices
|
7
|
+
def choices(choices = nil)
|
8
|
+
if choices.nil?
|
9
|
+
options.fetch(:choices) { options[:choices] = infer_choices }
|
10
10
|
else
|
11
|
-
options[:
|
11
|
+
options[:choices] = choices
|
12
12
|
self
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
17
17
|
|
18
|
-
def
|
18
|
+
def infer_choices
|
19
19
|
if object.class.respond_to?(:defined_enums)
|
20
20
|
return object.class.defined_enums.fetch(key.to_s).keys if object.class.defined_enums.key?(key.to_s)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
choices_from_association || choices_from_validator
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
26
|
+
def choices_from_association
|
27
27
|
return unless association_reflection
|
28
28
|
|
29
29
|
relation = association_reflection.klass.all
|
@@ -46,7 +46,7 @@ module Phlexi
|
|
46
46
|
relation
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
49
|
+
def choices_from_validator
|
50
50
|
return unless has_validators?
|
51
51
|
|
52
52
|
inclusion_validator = find_validator(:inclusion)
|
data/lib/phlexi/form/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phlexi-form
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Froelich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: phlex
|
@@ -205,14 +205,15 @@ files:
|
|
205
205
|
- lib/phlexi/form.rb
|
206
206
|
- lib/phlexi/form/base.rb
|
207
207
|
- lib/phlexi/form/builder.rb
|
208
|
+
- lib/phlexi/form/choices_mapper.rb
|
208
209
|
- lib/phlexi/form/components/base.rb
|
209
210
|
- lib/phlexi/form/components/checkbox.rb
|
210
211
|
- lib/phlexi/form/components/collection_checkboxes.rb
|
211
212
|
- lib/phlexi/form/components/collection_radio_buttons.rb
|
213
|
+
- lib/phlexi/form/components/concerns/accepts_choices.rb
|
212
214
|
- lib/phlexi/form/components/concerns/extracts_input.rb
|
213
215
|
- lib/phlexi/form/components/concerns/handles_array_input.rb
|
214
216
|
- lib/phlexi/form/components/concerns/handles_input.rb
|
215
|
-
- lib/phlexi/form/components/concerns/has_options.rb
|
216
217
|
- lib/phlexi/form/components/concerns/submits_form.rb
|
217
218
|
- lib/phlexi/form/components/error.rb
|
218
219
|
- lib/phlexi/form/components/file_input.rb
|
@@ -228,9 +229,8 @@ files:
|
|
228
229
|
- lib/phlexi/form/components/textarea.rb
|
229
230
|
- lib/phlexi/form/components/wrapper.rb
|
230
231
|
- lib/phlexi/form/html.rb
|
231
|
-
- lib/phlexi/form/option_mapper.rb
|
232
232
|
- lib/phlexi/form/options/autofocus.rb
|
233
|
-
- lib/phlexi/form/options/
|
233
|
+
- lib/phlexi/form/options/choices.rb
|
234
234
|
- lib/phlexi/form/options/disabled.rb
|
235
235
|
- lib/phlexi/form/options/errors.rb
|
236
236
|
- lib/phlexi/form/options/hints.rb
|