From a71fe1b21cc78b99459098aee8d65d49a663d652 Mon Sep 17 00:00:00 2001 From: msalzburg Date: Wed, 9 Aug 2023 22:21:38 +0200 Subject: [PATCH] Support element initialization via components attributes Hash Renames the components attributes Hash to attributes_or_elements. Enhances the initialize_elements method to lookup available element values from the attributes_or_elements Hash and assigns them. --- .rubocop_todo.yml | 7 ++- lib/elemental_components/element.rb | 34 +++++++++---- test/elemental_components/component_test.rb | 55 +++++++++++++++++++++ 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d57734e..1366275 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-08-09 18:43:11 UTC using RuboCop version 1.56.0. +# on 2023-08-09 19:56:28 UTC using RuboCop version 1.56.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -12,3 +12,8 @@ Gemspec/RequiredRubyVersion: Exclude: - 'elemental_components.gemspec' + +# Offense count: 1 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 13 diff --git a/lib/elemental_components/element.rb b/lib/elemental_components/element.rb index b60d33a..8b528c8 100644 --- a/lib/elemental_components/element.rb +++ b/lib/elemental_components/element.rb @@ -67,10 +67,10 @@ def self.define_method_or_raise(method_name, &block) end private_class_method :define_method_or_raise - def initialize(view, attributes = nil, &block) + def initialize(view, attributes_or_elements = nil, &block) @view = view - initialize_attributes(attributes || {}) - initialize_elements + initialize_attributes(attributes_or_elements || {}) + initialize_elements(attributes_or_elements || {}) @yield = block_given? ? @view.capture(self, &block) : nil validate! end @@ -85,28 +85,42 @@ def content protected - def initialize_attributes(attributes) + def initialize_attributes(attributes_or_elements) self.class.attributes.each do |name, options| - set_instance_variable(name, attribute_value(attributes, name, options[:default])) + set_instance_variable(name, attribute_value(attributes_or_elements, name, options[:default])) end end - def attribute_value(attributes, name, default) - return attributes[name] if attributes.key?(name) - - default.dup + def attribute_value(attributes_or_elements, name, default) + attributes_or_elements.key?(name) ? attributes_or_elements[name] : default.dup end - def initialize_elements + def initialize_elements(attributes_or_elements) self.class.elements.each do |name, options| if (plural_name = options[:multiple]) set_instance_variable(plural_name, []) + + if (plural_values = element_value(attributes_or_elements, plural_name)) + plural_values.each { |plural_value| initialize_element(name, plural_value) } + end else set_instance_variable(name, nil) + + if (single_value = element_value(attributes_or_elements, name)) + initialize_element(name, single_value) + end end end end + def initialize_element(name, value) + value.is_a?(Hash) ? send(name.to_sym, value) : send(name.to_sym, {}) { value } + end + + def element_value(attributes_or_elements, name) + attributes_or_elements.key?(name) ? attributes_or_elements[name] : nil + end + private def get_instance_variable(name) diff --git a/test/elemental_components/component_test.rb b/test/elemental_components/component_test.rb index 17fe4f0..4d744a5 100644 --- a/test/elemental_components/component_test.rb +++ b/test/elemental_components/component_test.rb @@ -105,6 +105,61 @@ class ElementalComponents::ComponentTest < ActiveSupport::TestCase assert_equal "bar", component.foos[1].content end + test "initialize element with multiple true via plural_name in attributes hash" do + component_class = Class.new(ElementalComponents::Component) do + element :item, multiple: true + end + component = component_class.new(view_class.new, items: %w[foo bar]) + assert_equal 2, component.items.length + assert_equal "foo", component.items[0].content + assert_equal "bar", component.items[1].content + end + + test "initialize element with multiple true via plural_name in attributes hash and via block" do + component_class = Class.new(ElementalComponents::Component) do + element :item, multiple: true + end + component = component_class.new(view_class.new, items: %w[foo bar]) + component.item { "baz" } + assert_equal 3, component.items.length + assert_equal "foo", component.items[0].content + assert_equal "bar", component.items[1].content + assert_equal "baz", component.items[2].content + end + + test "initialize element with multiple true and attributes via plural_name in attributes hash" do + component_class = Class.new(ElementalComponents::Component) do + element :item, multiple: true do + attribute :title + attribute :count + end + end + component = component_class.new(view_class.new, items: [{ title: "foo", count: 1 }, { title: "bar", count: 2 }]) + assert_equal 2, component.items.length + assert_equal "foo", component.items[0].title + assert_equal 1, component.items[0].count + assert_equal "bar", component.items[1].title + assert_equal 2, component.items[1].count + end + + test "initialize element with multiple true and attributes via plural_name in attributes hash and via block" do + component_class = Class.new(ElementalComponents::Component) do + element :item, multiple: true do + attribute :title + attribute :count + end + end + component = component_class.new(view_class.new, items: [{ title: "foo", count: 1 }, { title: "bar", count: 2 }]) + component.item({ title: "baz", count: 3 }) + assert_equal 3, component.items.length + assert_equal "foo", component.items[0].title + assert_equal 1, component.items[0].count + assert_equal "bar", component.items[1].title + assert_equal 2, component.items[1].count + assert_equal "baz", component.items[2].title + assert_equal 3, component.items[2].count + end + test "initialize element with multiple true when singular and plural name are the same" do component_class = Class.new(ElementalComponents::Component) do element :foos, multiple: true