phlexi-form 0.7.1 → 0.8.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/components/concerns/accepts_choices.rb +35 -5
 - data/lib/phlexi/form/components/file_input.rb +2 -0
 - data/lib/phlexi/form/components/select.rb +12 -2
 - data/lib/phlexi/form/grouped_choices_mapper.rb +62 -0
 - data/lib/phlexi/form/{choices_mapper.rb → simple_choices_mapper.rb} +9 -9
 - data/lib/phlexi/form/version.rb +1 -1
 - metadata +4 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 8747d53fec5851c3ad3f78d2c60fecfea530de3b033eb074ee5f4ce41bcd3181
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 51c02f430a3a81a4ee05197463a14aa9b00804c0a5b3a1837f36533b006d9860
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 7434f1529fda38b7e02318c01be2fba09a97de755c874d2319730e4118d747a20bac457e7421bb34f0280f7e405079717df55e3d5ba3f32934f51deb1ebf43d7
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 7457a359784b5404fee4a86ecdce99769f7899e080b7148aaff045719d536499efb4c6103c04334675258af94b74dbd10a9acacb7f327fb3a0f5f1508223f5bd
         
     | 
| 
         @@ -9,27 +9,57 @@ module Phlexi 
     | 
|
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
                      def build_attributes
         
     | 
| 
       11 
11 
     | 
    
         
             
                        super
         
     | 
| 
       12 
     | 
    
         
            -
                        @choice_collection = attributes.delete(:choices) || field.choices
         
     | 
| 
       13 
12 
     | 
    
         
             
                        @label_method = attributes.delete(:label_method)
         
     | 
| 
       14 
13 
     | 
    
         
             
                        @value_method = attributes.delete(:value_method)
         
     | 
| 
      
 14 
     | 
    
         
            +
                        @group_method = attributes.delete(:group_method)
         
     | 
| 
      
 15 
     | 
    
         
            +
                        @group_label_method = attributes.delete(:group_label_method)
         
     | 
| 
       15 
16 
     | 
    
         
             
                      end
         
     | 
| 
       16 
17 
     | 
    
         | 
| 
       17 
18 
     | 
    
         
             
                      def choices
         
     | 
| 
       18 
     | 
    
         
            -
                        @choices ||=  
     | 
| 
      
 19 
     | 
    
         
            +
                        @choices ||= begin
         
     | 
| 
      
 20 
     | 
    
         
            +
                          collection = attributes.delete(:choices) || field.choices
         
     | 
| 
      
 21 
     | 
    
         
            +
                          build_choice_mapper(collection)
         
     | 
| 
      
 22 
     | 
    
         
            +
                        end
         
     | 
| 
       19 
23 
     | 
    
         
             
                      end
         
     | 
| 
       20 
24 
     | 
    
         | 
| 
       21 
25 
     | 
    
         
             
                      def selected?(option)
         
     | 
| 
       22 
26 
     | 
    
         
             
                        if attributes[:multiple]
         
     | 
| 
       23 
     | 
    
         
            -
                           
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
                          field_value.any? { |item| item.to_s == option.to_s }
         
     | 
| 
      
 28 
     | 
    
         
            +
                        else
         
     | 
| 
      
 29 
     | 
    
         
            +
                          field_value.to_s == option.to_s
         
     | 
| 
      
 30 
     | 
    
         
            +
                        end
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                      def field_value
         
     | 
| 
      
 34 
     | 
    
         
            +
                        if attributes[:multiple]
         
     | 
| 
      
 35 
     | 
    
         
            +
                          Array(field.value)
         
     | 
| 
       25 
36 
     | 
    
         
             
                        else
         
     | 
| 
       26 
     | 
    
         
            -
                          field.value 
     | 
| 
      
 37 
     | 
    
         
            +
                          field.value
         
     | 
| 
       27 
38 
     | 
    
         
             
                        end
         
     | 
| 
       28 
39 
     | 
    
         
             
                      end
         
     | 
| 
       29 
40 
     | 
    
         | 
| 
       30 
41 
     | 
    
         
             
                      def normalize_simple_input(input_value)
         
     | 
| 
      
 42 
     | 
    
         
            +
                        # ensure that choice is in the list
         
     | 
| 
       31 
43 
     | 
    
         
             
                        ([super] & choices.values)[0]
         
     | 
| 
       32 
44 
     | 
    
         
             
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                      def build_choice_mapper(collection)
         
     | 
| 
      
 47 
     | 
    
         
            +
                        if @group_method
         
     | 
| 
      
 48 
     | 
    
         
            +
                          GroupedChoicesMapper.new(
         
     | 
| 
      
 49 
     | 
    
         
            +
                            collection,
         
     | 
| 
      
 50 
     | 
    
         
            +
                            group_method: @group_method,
         
     | 
| 
      
 51 
     | 
    
         
            +
                            group_label_method: @group_label_method,
         
     | 
| 
      
 52 
     | 
    
         
            +
                            label_method: @label_method,
         
     | 
| 
      
 53 
     | 
    
         
            +
                            value_method: @value_method
         
     | 
| 
      
 54 
     | 
    
         
            +
                          )
         
     | 
| 
      
 55 
     | 
    
         
            +
                        else
         
     | 
| 
      
 56 
     | 
    
         
            +
                          SimpleChoicesMapper.new(
         
     | 
| 
      
 57 
     | 
    
         
            +
                            collection,
         
     | 
| 
      
 58 
     | 
    
         
            +
                            label_method: @label_method,
         
     | 
| 
      
 59 
     | 
    
         
            +
                            value_method: @value_method
         
     | 
| 
      
 60 
     | 
    
         
            +
                          )
         
     | 
| 
      
 61 
     | 
    
         
            +
                        end
         
     | 
| 
      
 62 
     | 
    
         
            +
                      end
         
     | 
| 
       33 
63 
     | 
    
         
             
                    end
         
     | 
| 
       34 
64 
     | 
    
         
             
                  end
         
     | 
| 
       35 
65 
     | 
    
         
             
                end
         
     | 
| 
         @@ -19,8 +19,18 @@ module Phlexi 
     | 
|
| 
       19 
19 
     | 
    
         
             
                    protected
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                    def options
         
     | 
| 
       22 
     | 
    
         
            -
                      choices. 
     | 
| 
       23 
     | 
    
         
            -
                         
     | 
| 
      
 22 
     | 
    
         
            +
                      if choices.is_a?(GroupedChoicesMapper)
         
     | 
| 
      
 23 
     | 
    
         
            +
                        choices.each do |group_label, group_choices|
         
     | 
| 
      
 24 
     | 
    
         
            +
                          optgroup(label: group_label) do
         
     | 
| 
      
 25 
     | 
    
         
            +
                            group_choices.each do |value, label|
         
     | 
| 
      
 26 
     | 
    
         
            +
                              option(selected: selected?(value), value: value) { label }
         
     | 
| 
      
 27 
     | 
    
         
            +
                            end
         
     | 
| 
      
 28 
     | 
    
         
            +
                          end
         
     | 
| 
      
 29 
     | 
    
         
            +
                        end
         
     | 
| 
      
 30 
     | 
    
         
            +
                      else
         
     | 
| 
      
 31 
     | 
    
         
            +
                        choices.each do |value, label|
         
     | 
| 
      
 32 
     | 
    
         
            +
                          option(selected: selected?(value), value: value) { label }
         
     | 
| 
      
 33 
     | 
    
         
            +
                        end
         
     | 
| 
       24 
34 
     | 
    
         
             
                      end
         
     | 
| 
       25 
35 
     | 
    
         
             
                    end
         
     | 
| 
       26 
36 
     | 
    
         | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Phlexi
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Form
         
     | 
| 
      
 5 
     | 
    
         
            +
                class GroupedChoicesMapper
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include Enumerable
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(collection, group_method:, group_label_method: :to_s, label_method: nil, value_method: nil)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @collection = collection
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @group_method = group_method
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @group_label_method = group_label_method
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @label_method = label_method
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @value_method = value_method
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def each(&)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    grouped_choices.each(&)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def grouped_choices
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @grouped_choices ||= materialize_grouped_choices(@collection)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def materialize_grouped_choices(collection)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    case collection
         
     | 
| 
      
 26 
     | 
    
         
            +
                    in Hash => hash
         
     | 
| 
      
 27 
     | 
    
         
            +
                      hash.transform_values { |items| to_choices_mapper(items) }
         
     | 
| 
      
 28 
     | 
    
         
            +
                    in Array => arr
         
     | 
| 
      
 29 
     | 
    
         
            +
                      array_to_grouped_hash(arr)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    in Proc => proc
         
     | 
| 
      
 31 
     | 
    
         
            +
                      materialize_grouped_choices(proc.call)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    else
         
     | 
| 
      
 33 
     | 
    
         
            +
                      record_collection_to_hash
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  private
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def array_to_grouped_hash(array)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    sample = array.first
         
     | 
| 
      
 41 
     | 
    
         
            +
                    if group_method == :last && sample.is_a?(Array) && sample.size == 2
         
     | 
| 
      
 42 
     | 
    
         
            +
                      array.each_with_object({}) do |(label, items), hash|
         
     | 
| 
      
 43 
     | 
    
         
            +
                        hash[label.to_s] = to_choices_mapper(items)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    else
         
     | 
| 
      
 46 
     | 
    
         
            +
                      record_collection_to_hash
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  def record_collection_to_hash
         
     | 
| 
      
 51 
     | 
    
         
            +
                    @collection.group_by do |item|
         
     | 
| 
      
 52 
     | 
    
         
            +
                      group = item.public_send(@group_method)
         
     | 
| 
      
 53 
     | 
    
         
            +
                      group.public_send(@group_label_method).to_s
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end.transform_values { |items| to_choices_mapper(items) }
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def to_choices_mapper(items)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    SimpleChoicesMapper.new(items, label_method: @label_method, value_method: @value_method)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -2,31 +2,31 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Phlexi
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Form
         
     | 
| 
       5 
     | 
    
         
            -
                #  
     | 
| 
      
 5 
     | 
    
         
            +
                # SimpleChoicesMapper 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 = SimpleChoicesMapper.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 = SimpleChoicesMapper.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 = SimpleChoicesMapper.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 SimpleChoicesMapper
         
     | 
| 
       27 
27 
     | 
    
         
             
                  include Enumerable
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                  # Initializes a new  
     | 
| 
      
 29 
     | 
    
         
            +
                  # Initializes a new SimpleChoicesMapper 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.
         
     | 
| 
         @@ -93,9 +93,9 @@ module Phlexi 
     | 
|
| 
       93 
93 
     | 
    
         
             
                    else
         
     | 
| 
       94 
94 
     | 
    
         
             
                      array_to_hash(Array(collection))
         
     | 
| 
       95 
95 
     | 
    
         
             
                    end
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                    # Rails.logger.warn("Unhandled inclusion collection type: #{e}")TODO
         
     | 
| 
       98 
     | 
    
         
            -
                    {}
         
     | 
| 
      
 96 
     | 
    
         
            +
                    # rescue ArgumentError
         
     | 
| 
      
 97 
     | 
    
         
            +
                    #   # Rails.logger.warn("Unhandled inclusion collection type: #{e}")TODO
         
     | 
| 
      
 98 
     | 
    
         
            +
                    #   {}
         
     | 
| 
       99 
99 
     | 
    
         
             
                  end
         
     | 
| 
       100 
100 
     | 
    
         | 
| 
       101 
101 
     | 
    
         
             
                  # Converts an array to a hash using detected or specified methods.
         
     | 
    
        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.8.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:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2025-01-03 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: phlex
         
     | 
| 
         @@ -205,7 +205,6 @@ 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
         
     | 
| 
       209 
208 
     | 
    
         
             
            - lib/phlexi/form/components/base.rb
         
     | 
| 
       210 
209 
     | 
    
         
             
            - lib/phlexi/form/components/belongs_to.rb
         
     | 
| 
       211 
210 
     | 
    
         
             
            - lib/phlexi/form/components/checkbox.rb
         
     | 
| 
         @@ -231,6 +230,7 @@ files: 
     | 
|
| 
       231 
230 
     | 
    
         
             
            - lib/phlexi/form/components/submit_button.rb
         
     | 
| 
       232 
231 
     | 
    
         
             
            - lib/phlexi/form/components/textarea.rb
         
     | 
| 
       233 
232 
     | 
    
         
             
            - lib/phlexi/form/components/wrapper.rb
         
     | 
| 
      
 233 
     | 
    
         
            +
            - lib/phlexi/form/grouped_choices_mapper.rb
         
     | 
| 
       234 
234 
     | 
    
         
             
            - lib/phlexi/form/html.rb
         
     | 
| 
       235 
235 
     | 
    
         
             
            - lib/phlexi/form/options/autofocus.rb
         
     | 
| 
       236 
236 
     | 
    
         
             
            - lib/phlexi/form/options/choices.rb
         
     | 
| 
         @@ -247,6 +247,7 @@ files: 
     | 
|
| 
       247 
247 
     | 
    
         
             
            - lib/phlexi/form/options/required.rb
         
     | 
| 
       248 
248 
     | 
    
         
             
            - lib/phlexi/form/options/step.rb
         
     | 
| 
       249 
249 
     | 
    
         
             
            - lib/phlexi/form/options/validators.rb
         
     | 
| 
      
 250 
     | 
    
         
            +
            - lib/phlexi/form/simple_choices_mapper.rb
         
     | 
| 
       250 
251 
     | 
    
         
             
            - lib/phlexi/form/structure/field_collection.rb
         
     | 
| 
       251 
252 
     | 
    
         
             
            - lib/phlexi/form/structure/manages_fields.rb
         
     | 
| 
       252 
253 
     | 
    
         
             
            - lib/phlexi/form/structure/namespace.rb
         
     |