From ac76052471a5fcbcfe7ec95e4e126319f38c5cef Mon Sep 17 00:00:00 2001 From: Alexander Pauly Date: Wed, 24 Jun 2020 19:58:19 +0200 Subject: [PATCH 1/3] Allow injecting a custom renderer class ++ allow customized locals assignment in custom renderer --- .rubocop.yml | 6 +++--- lib/komponent/component_renderer.rb | 28 ++++++++++++++----------- lib/komponent/komponent_helper.rb | 3 ++- test/komponent/komponent_helper_test.rb | 12 +++++++++++ 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 1db1119..1208aba 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -55,9 +55,6 @@ Naming/PredicateName: Naming/VariableName: Enabled: true -Layout/AlignParameters: - Enabled: true - Layout/BlockAlignment: Enabled: true EnforcedStyleAlignWith: start_of_block @@ -89,6 +86,9 @@ Layout/EmptyLines: Layout/EmptyLinesAroundAccessModifier: Enabled: true +Layout/ParameterAlignment: + Enabled: true + Layout/SpaceAroundBlockParameters: Enabled: true diff --git a/lib/komponent/component_renderer.rb b/lib/komponent/component_renderer.rb index f343ebf..55cb0c1 100644 --- a/lib/komponent/component_renderer.rb +++ b/lib/komponent/component_renderer.rb @@ -36,6 +36,16 @@ def render(component, locals = {}, options = {}, &block) end end + def assign_property_value(property_name, property_options, locals) + return if locals.has_key?(property_name) + + if property_options.has_key?(:default) + locals[property_name] = property_options[:default] + elsif property_options[:required] + raise "Missing required component parameter: #{property_name}" + end + end + private def _render(component, locals = {}, options = {}, &block) @@ -53,20 +63,14 @@ def _render(component, locals = {}, options = {}, &block) @lookup_context.prefixes = ["components/#{component}"] - @context.instance_eval do - if component_module.respond_to?(:properties) - locals = locals.dup - component_module.properties.each do |name, options| - unless locals.has_key?(name) - if options.has_key?(:default) - locals[name] = options[:default] - elsif options[:required] - raise "Missing required component parameter: #{name}" - end - end - end + if component_module.respond_to?(:properties) + locals = locals.dup + component_module.properties.each do |name, options| + assign_property_value(name, options, locals) end + end + @context.instance_eval do locals.each do |name, value| instance_variable_set(:"@#{name}", locals[name]) end diff --git a/lib/komponent/komponent_helper.rb b/lib/komponent/komponent_helper.rb index bc8a564..08106d9 100644 --- a/lib/komponent/komponent_helper.rb +++ b/lib/komponent/komponent_helper.rb @@ -5,7 +5,8 @@ module KomponentHelper def component(component_name, locals = {}, options = {}, &block) captured_block = proc { |args| capture(args, &block) } if block_given? - Komponent::ComponentRenderer.new( + renderer_klass = options.delete(:renderer) || Komponent::ComponentRenderer + renderer_klass.new( controller, view_flow || (view && view.view_flow), ).render( diff --git a/test/komponent/komponent_helper_test.rb b/test/komponent/komponent_helper_test.rb index bc3f4a9..4a28ed6 100644 --- a/test/komponent/komponent_helper_test.rb +++ b/test/komponent/komponent_helper_test.rb @@ -9,6 +9,18 @@ def test_helper_raises_component_missing_error end end + def test_inject_custom_renderer + custom_renderer_klass = Class.new(Komponent::ComponentRenderer) do + def render(*args) + 'custom_render_method' + end + end + + assert_equal \ + 'custom_render_method', + component('world', {}, renderer: custom_renderer_klass) + end + def test_helper_renders_namespaced_component assert_equal \ %(
namespaced_button_component
), From 8d6ed838dd139a1dc365d9af3f27b96927a9f52c Mon Sep 17 00:00:00 2001 From: Alexander Pauly Date: Sat, 4 Jul 2020 00:31:28 +0200 Subject: [PATCH 2/3] Added custom renderer section to readme --- README.md | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bb1b078..21950da 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ This gem has been inspired by our Rails development practices at [Ouvrages](http - [Helpers](#helpers) - [Component partials](#component-partials) - [Namespacing components](#namespacing-components) + - [Custom Renderer](#custom-renderer) - [Stimulus integration](#stimulus-integration) - [Internationalization](#internationalization) - [Available locales configuration](#available-locales-configuration) @@ -182,7 +183,7 @@ Each component comes with a Ruby `module`. You can use it to set properties: module ButtonComponent extend ComponentHelper - + property :href, required: true property :text, default: 'My button' end @@ -204,7 +205,7 @@ If your partial becomes too complex and you want to extract logic from it, you m module ButtonComponent extend ComponentHelper - + property :href, required: true property :text, default: 'My button' @@ -257,6 +258,43 @@ rails generate component admin/header This will create the component in an `admin` folder, and name its Ruby module `AdminHeaderComponent`. +### Custom renderer + +Komponents supports using a custom renderer to customize renderering behaviour. + +```rb +# frontend/components/button/button_component.rb + +module ButtonComponent + extend ComponentHelper + + property :text, default: 'My button', my_custom_option: true +end +``` + +```rb +# somwhere inside your app, e.g. app/models/my_custom_renderer.rb + +class MyCustomRenderer < Komponent::ComponentRenderer + def assign_property_value(property_name, property_options, locals) + if property_options[:my_custom_option] + original_value = locals[property_name] + locals[property_name] = I18n.t(property_name, default: original_value) + else + super + end + end +end +``` + +```slim +/ app/views/pages/home.html.slim + +/ Use custom renderer class += component "button", { text: 'Click here' }, renderer: MyCustomRenderer +``` + + ### Stimulus integration Komponent supports [Stimulus](https://github.com/stimulusjs/stimulus) >= 1.0. From dc63ec11066caeaf711aae644afb03fce143446d Mon Sep 17 00:00:00 2001 From: Hans Lemuet Date: Wed, 7 Oct 2020 09:52:33 +0200 Subject: [PATCH 3/3] Rewrite "Custom renderer" section in README --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 21950da..15f209f 100644 --- a/README.md +++ b/README.md @@ -260,7 +260,9 @@ This will create the component in an `admin` folder, and name its Ruby module `A ### Custom renderer -Komponents supports using a custom renderer to customize renderering behaviour. +Komponent supports using a custom renderer if you want to customize rendering behaviour. + +For instance, you can use this to add I18n to your properties: ```rb # frontend/components/button/button_component.rb @@ -268,16 +270,16 @@ Komponents supports using a custom renderer to customize renderering behaviour. module ButtonComponent extend ComponentHelper - property :text, default: 'My button', my_custom_option: true + property :text, default: 'My button', custom_localize: true end ``` ```rb -# somwhere inside your app, e.g. app/models/my_custom_renderer.rb +# somwhere inside your app, e.g. app/models/localized_component_renderer.rb -class MyCustomRenderer < Komponent::ComponentRenderer +class LocalizedComponentRenderer < Komponent::ComponentRenderer def assign_property_value(property_name, property_options, locals) - if property_options[:my_custom_option] + if property_options[:custom_localize] original_value = locals[property_name] locals[property_name] = I18n.t(property_name, default: original_value) else @@ -291,7 +293,7 @@ end / app/views/pages/home.html.slim / Use custom renderer class -= component "button", { text: 'Click here' }, renderer: MyCustomRenderer += component "button", { text: 'Click here' }, renderer: LocalizedComponentRenderer ```