Class: Attrify::Parser

Inherits:
Object
  • Object
show all
Extended by:
Helpers
Defined in:
lib/attrify/parser.rb

Constant Summary collapse

OPERATIONS =
[:append, :prepend, :remove, :set].freeze
ALLOWED_NESTED_FIELDS =
[:data, :aria].freeze

Class Method Summary collapse

Methods included from Helpers

compute_attributes, deep_merge_hashes, deep_merge_hashes!, execute_operation

Class Method Details

.parse_attribute(key, value) ⇒ Object



124
125
126
127
128
129
130
131
132
133
# File 'lib/attrify/parser.rb', line 124

def parse_attribute(key, value)
  unless valid_attribute?(key, value)
    raise ArgumentError, "Invalid attributes list: invalid attribute #{key}"
  end
  unless key.is_a?(Symbol)
    raise ArgumentError, "Attribute: Key must be a symbol #{key}"
  end

  parse_operations(value)
end

.parse_attributes(attributes) ⇒ Object

class: [%w[bg-blue-500 text-white]]

style: "width:100px"
data: { controller: "stimulus_controller" }
class: "red"
class: "10"


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/attrify/parser.rb', line 107

def parse_attributes(attributes)
  unless attributes.is_a?(Hash)
    raise ArgumentError, "Invalid attributes list: Expected a Hash, got #{attributes.class}"
  end

  if is_simple_operation?(attributes)
    raise ArgumentError, "Invalid Attributes List: got an operation"
  end

  parsed_attributes = {}

  attributes.each do |key, value|
    parsed_attributes[key] = parse_attribute(key, value)
  end
  parsed_attributes
end

.parse_base(base) ⇒ Object



13
14
15
# File 'lib/attrify/parser.rb', line 13

def parse_base(base)
  parse_slots(base)
end

.parse_compounds(compounds) ⇒ Object

Raises:

  • (ArgumentError)


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/attrify/parser.rb', line 25

def parse_compounds(compounds)
  raise ArgumentError, "Invalid compounds structure: Expected an Array" unless compounds.is_a?(Array)
  return [] if compounds.empty?

  compounds.map do |compound|
    # Ensure each compound is a Hash and contains :variant and :attributes keys
    unless compound.is_a?(Hash) && compound.key?(:variants) && compound.key?(:attributes)
      raise ArgumentError, "Invalid compound structure: Each compound must have :variants and :attributes keys"
    end

    # Parse the attributes section using parse_slots
    {
      variants: compound[:variants], # Keep the variants as they are
      attributes: parse_slots(compound[:attributes]) # Parse the attributes section using parse_slots
    }
  end
end

.parse_defaults(defaults) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/attrify/parser.rb', line 43

def parse_defaults(defaults)
  # Ensure the defaults is a hash
  unless defaults.is_a?(Hash)
    raise ArgumentError, "Defaults must be a hash, got #{defaults.class}"
  end

  defaults.each_with_object({}) do |(key, value), hash|
    # Ensure keys are symbols.
    unless key.is_a?(Symbol)
      raise ArgumentError, "All keys must be symbols. Got key #{key.inspect} (#{key.class})"
    end

    hash[key] = if value.is_a?(Symbol)
      value
    elsif value.respond_to?(:to_s)
      value.to_s
    else
      raise ArgumentError, "Value #{value.inspect} cannot be used as an default value"
    end
  end

  defaults
end

.parse_operation(operation) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/attrify/parser.rb', line 162

def parse_operation(operation)
  case operation
  when Hash
    if !is_simple_operation?(operation)
      raise ArgumentError, "Invalid operation: got #{operation}"
    end
    operation.transform_values { |v|
      if v.is_a?(Array)
        v.map { |x| x.is_a?(Proc) ? x : x.to_s }
      else
        [v.is_a?(Proc) ? v : v.to_s]
      end
    }
  when Array
    {set: operation.map { |v| v.is_a?(Proc) ? v : v.to_s }}
  when Proc
    {set: [operation]}
  else
    {set: Array(operation.to_s)}
  end
end

.parse_operations(value) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/attrify/parser.rb', line 135

def parse_operations(value)
  case value
  when Hash
    # Check if the hash is a simple operation or needs further parsing
    if is_simple_operation?(value)
      [parse_operation(value)]
    else
      value.transform_values { |v|
        parsed_operation = parse_operations(v)
        if is_simple_operation?(parsed_operation)
          [parsed_operation]
        else
          parsed_operation
        end
      }
    end
  when Array
    if value.any? { |v| is_simple_operation?(v) }
      value.map { |v| parse_operation(v) }
    else
      [parse_operation(value)]
    end
  else
    [parse_operation(value)]
  end
end

.parse_slot(slot) ⇒ Object

class: [{set: %w[bg-blue-500 text-white]],
style:  "width:100px",
data: { controller: "stimulus_controller" },
# this one is a slot
nested: { sub_slot: class:"red", class: "10"}

}

Raises:

  • (ArgumentError)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/attrify/parser.rb', line 82

def parse_slot(slot)
  raise ArgumentError, "Invalid slot structure: Expected a Hash #{slot}" unless slot.is_a?(Hash)

  attributes = slot[:attributes] || {}

  nested_slots = nested_slots(slot)
  additional_attributes = slot.reject { |key, _| key == :attributes || nested_slots.include?(key) }

  deep_merge_hashes!(attributes, additional_attributes)

  parsed_slot = {}
  parsed_slot[:attributes] = parse_attributes(attributes) unless attributes.empty?

  # Recursively handle nested slots
  nested_slots.each do |nested_slot_name|
    parsed_slot[nested_slot_name] = parse_slot(slot[nested_slot_name])
  end
  parsed_slot
end

.parse_slots(slots) ⇒ Object



67
68
69
70
71
72
73
# File 'lib/attrify/parser.rb', line 67

def parse_slots(slots)
  parsed_value = parse_slot(slots)
  if parsed_value.key?(:attributes)
    parsed_value = {main: parsed_value}
  end
  parsed_value
end

.parse_variants(variants) ⇒ Object



17
18
19
20
21
22
23
# File 'lib/attrify/parser.rb', line 17

def parse_variants(variants)
  variants.transform_values do |variant_options|
    variant_options.transform_values do |option|
      parse_slots(option)
    end
  end
end