From c0470f84ed40fe1a8797f0ff8ff86dd653cfef2b Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Mon, 2 Feb 2026 15:15:43 -0600 Subject: [PATCH 1/6] Refactor IconGenerator to be idempotent + class option # Conflicts: # example_rails8/Gemfile # example_rails8/Gemfile.lock # Conflicts: # lib/generators/rolemodel/optics/icons/icons_generator.rb --- lib/generators/rolemodel/optics/icons/USAGE | 11 ++++-- .../rolemodel/optics/icons/icons_generator.rb | 28 +++++++------ .../templates/app/helpers/icon_helper.rb.tt | 21 +++++----- .../rolemodel/optics/icons_generator_spec.rb | 39 +++++++++++++++---- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/lib/generators/rolemodel/optics/icons/USAGE b/lib/generators/rolemodel/optics/icons/USAGE index 7d306e47..100aea4b 100644 --- a/lib/generators/rolemodel/optics/icons/USAGE +++ b/lib/generators/rolemodel/optics/icons/USAGE @@ -1,8 +1,11 @@ Description: - runs the icons optics generator + runs the Optics Icon Generator Example: - rails generate rolemodel:optics:icons + bin/rails generate rolemodel:optics:icons --icon-library=tabler - This will create: - app/helpers/icon_helper.rb + This will create: + app/helpers/icon_helper.rb + + Which provides a simple view helper for rendering Icons: + = button_to icon('trash'), @post, method: :destroy diff --git a/lib/generators/rolemodel/optics/icons/icons_generator.rb b/lib/generators/rolemodel/optics/icons/icons_generator.rb index 4a3ccbfe..5a924c0e 100644 --- a/lib/generators/rolemodel/optics/icons/icons_generator.rb +++ b/lib/generators/rolemodel/optics/icons/icons_generator.rb @@ -6,28 +6,32 @@ module Optics class IconsGenerator < Rolemodel::BaseGenerator source_root File.expand_path('templates', __dir__) - SUPPORTED_LIBRARIES = { + SUPPORTED_LIBRARIES = HashWithIndifferentAccess.new( material: 'filled, size, weight, emphasis, additional_classes, color, hover_text', phosphor: 'duotone, filled, size, weight, additional_classes, color, hover_text', tabler: 'filled, size, additional_classes, color, hover_text', feather: 'size, additional_classes, color, hover_text', lucide: 'size, additional_classes, color, hover_text', custom: 'filled, size, weight, emphasis, additional_classes, color, hover_text' - }.freeze + ).freeze - def add_view_helper - say 'generating icon helper', :green + source_root File.expand_path('templates', __dir__) + class_option :icon_library, type: :string, default: SUPPORTED_LIBRARIES.keys.first, + desc: "The icon library to use (#{SUPPORTED_LIBRARIES.keys.join(', ')})" - @chosen_library = ask( - 'What icon library would you like to add?', - default: SUPPORTED_LIBRARIES.keys.first.to_s, - limited_to: SUPPORTED_LIBRARIES.keys.map(&:to_s) - ) + def remove_existing_icon_helper_and_builders + remove_dir 'app/icon_builders' + remove_file 'app/helpers/icon_helper.rb' + end + + def add_view_helper + say 'Generating IconHelper Module', :green - @supported_properties = SUPPORTED_LIBRARIES[@chosen_library.to_sym] + @chosen_library = options['icon_library'] + @supported_properties = SUPPORTED_LIBRARIES.fetch(@chosen_library) - copy_file 'app/icon_builders/icon_builder.rb' - copy_file "app/icon_builders/#{@chosen_library}_icon_builder.rb" + template 'app/icon_builders/icon_builder.rb' + template "app/icon_builders/#{@chosen_library}_icon_builder.rb" template 'app/helpers/icon_helper.rb' end end diff --git a/lib/generators/rolemodel/optics/icons/templates/app/helpers/icon_helper.rb.tt b/lib/generators/rolemodel/optics/icons/templates/app/helpers/icon_helper.rb.tt index 03f36c1c..20e70863 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/helpers/icon_helper.rb.tt +++ b/lib/generators/rolemodel/optics/icons/templates/app/helpers/icon_helper.rb.tt @@ -1,19 +1,16 @@ # frozen_string_literal: true -# Helper method that renders icons from different icon libraries. +# Helper method that renders icons from your icon library of choice. +# # Usage: -# = icon('home', size: 'x-large', color: 'primary') -# = flash_icon('notice', size: 'x-large', color: 'primary') +# = icon('home', size: 'x-large', color: 'primary') +# = flash_icon('notice', size: 'x-large', color: 'primary') +# +# The chosen icon library is <%= @chosen_library %>. This can be +# changed by rerunning the generator with a different --icon-library option. +# +# Run `bin/rails g rolemodel:optics:icons --help` for an up-to-date list of available libraries. # -# The default library is Material Icons, but can be changed here by pulling -# in a different builder from RoleModel Rails. -# Available libraries: -# - MaterialIconBuilder -# - PhosphorIconBuilder -# - TablerIconBuilder -# - FeatherIconBuilder -# - LucideIconBuilder -# - CustomIconBuilder module IconHelper # <%= @supported_properties %> def icon(name, **) diff --git a/spec/generators/rolemodel/optics/icons_generator_spec.rb b/spec/generators/rolemodel/optics/icons_generator_spec.rb index bc171384..3523bfb2 100644 --- a/spec/generators/rolemodel/optics/icons_generator_spec.rb +++ b/spec/generators/rolemodel/optics/icons_generator_spec.rb @@ -1,12 +1,37 @@ RSpec.describe Rolemodel::Optics::IconsGenerator, type: :generator do - before do - respond_to_prompt with: 'phosphor' # choose an icon library - run_generator_against_test_app + context 'default icon library' do + before { run_generator_against_test_app } + + it 'adds the correct helper and builders' do + assert_file 'app/helpers/icon_helper.rb' + assert_file 'app/icon_builders/icon_builder.rb' + assert_file 'app/icon_builders/material_icon_builder.rb' + end + end + + context 'selecting an alternate icon library via command line option' do + before { run_generator_against_test_app(['--icon-library=phosphor']) } + + it 'adds the correct helper and builders' do + assert_file 'app/helpers/icon_helper.rb' + assert_file 'app/icon_builders/icon_builder.rb' + assert_file 'app/icon_builders/phosphor_icon_builder.rb' + end end - it 'adds the correct helper and builders' do - assert_file 'app/helpers/icon_helper.rb' - assert_file 'app/icon_builders/icon_builder.rb' - assert_file 'app/icon_builders/phosphor_icon_builder.rb' + context 're-running the generator' do + it 'removes existing helper and builders before adding new ones' do + assert_no_file 'app/helpers/icon_helper.rb' + + run_generator_against_test_app(['--icon-library=tabler']) + assert_file 'app/helpers/icon_helper.rb' + assert_file 'app/icon_builders/tabler_icon_builder.rb' + + run_generator_against_test_app + assert_file 'app/helpers/icon_helper.rb' + assert_file 'app/icon_builders/material_icon_builder.rb' + + assert_no_file 'app/icon_builders/tabler_icon_builder.rb' + end end end From e04728faa717dceb5f8da38f4459778aa03a78fe Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Wed, 11 Feb 2026 10:32:10 -0600 Subject: [PATCH 2/6] remove default for class option, falling back to prompt --- .../rolemodel/optics/icons/icons_generator.rb | 10 ++++++---- .../rolemodel/optics/icons_generator_spec.rb | 9 +++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/generators/rolemodel/optics/icons/icons_generator.rb b/lib/generators/rolemodel/optics/icons/icons_generator.rb index 5a924c0e..8d0e0dae 100644 --- a/lib/generators/rolemodel/optics/icons/icons_generator.rb +++ b/lib/generators/rolemodel/optics/icons/icons_generator.rb @@ -16,8 +16,7 @@ class IconsGenerator < Rolemodel::BaseGenerator ).freeze source_root File.expand_path('templates', __dir__) - class_option :icon_library, type: :string, default: SUPPORTED_LIBRARIES.keys.first, - desc: "The icon library to use (#{SUPPORTED_LIBRARIES.keys.join(', ')})" + class_option :icon_library, type: :string, desc: "The icon library to use (#{SUPPORTED_LIBRARIES.keys.join(', ')})" def remove_existing_icon_helper_and_builders remove_dir 'app/icon_builders' @@ -25,9 +24,12 @@ def remove_existing_icon_helper_and_builders end def add_view_helper - say 'Generating IconHelper Module', :green - @chosen_library = options['icon_library'] + @chosen_library ||= ask( + 'What icon library would you like to add?', + default: SUPPORTED_LIBRARIES.keys.first.to_s, + limited_to: SUPPORTED_LIBRARIES.keys.map(&:to_s) + ) @supported_properties = SUPPORTED_LIBRARIES.fetch(@chosen_library) template 'app/icon_builders/icon_builder.rb' diff --git a/spec/generators/rolemodel/optics/icons_generator_spec.rb b/spec/generators/rolemodel/optics/icons_generator_spec.rb index 3523bfb2..81ce75ed 100644 --- a/spec/generators/rolemodel/optics/icons_generator_spec.rb +++ b/spec/generators/rolemodel/optics/icons_generator_spec.rb @@ -1,6 +1,9 @@ RSpec.describe Rolemodel::Optics::IconsGenerator, type: :generator do context 'default icon library' do - before { run_generator_against_test_app } + before do + respond_to_prompt with: 'material' # choose an icon library + run_generator_against_test_app + end it 'adds the correct helper and builders' do assert_file 'app/helpers/icon_helper.rb' @@ -27,11 +30,13 @@ assert_file 'app/helpers/icon_helper.rb' assert_file 'app/icon_builders/tabler_icon_builder.rb' + respond_to_prompt with: 'feather' # choose an icon library run_generator_against_test_app assert_file 'app/helpers/icon_helper.rb' - assert_file 'app/icon_builders/material_icon_builder.rb' + assert_file 'app/icon_builders/feather_icon_builder.rb' assert_no_file 'app/icon_builders/tabler_icon_builder.rb' + assert_no_file 'app/icon_builders/material_icon_builder.rb' end end end From 2b2f194680a282593563b9b81501ffaa581d6071 Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Fri, 13 Feb 2026 09:21:00 -0600 Subject: [PATCH 3/6] resolve merge conflicts --- lib/generators/rolemodel/optics/icons/icons_generator.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/generators/rolemodel/optics/icons/icons_generator.rb b/lib/generators/rolemodel/optics/icons/icons_generator.rb index 8d0e0dae..f3a2dd10 100644 --- a/lib/generators/rolemodel/optics/icons/icons_generator.rb +++ b/lib/generators/rolemodel/optics/icons/icons_generator.rb @@ -4,8 +4,6 @@ module Rolemodel module Optics # Generates the icon helper and icon builders for the chosen icon library class IconsGenerator < Rolemodel::BaseGenerator - source_root File.expand_path('templates', __dir__) - SUPPORTED_LIBRARIES = HashWithIndifferentAccess.new( material: 'filled, size, weight, emphasis, additional_classes, color, hover_text', phosphor: 'duotone, filled, size, weight, additional_classes, color, hover_text', @@ -24,7 +22,7 @@ def remove_existing_icon_helper_and_builders end def add_view_helper - @chosen_library = options['icon_library'] + @chosen_library = options['icon_library'] @chosen_library ||= ask( 'What icon library would you like to add?', default: SUPPORTED_LIBRARIES.keys.first.to_s, From a2ae63dfe30eac7f40dfe767126e208f1cf4284d Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Fri, 13 Feb 2026 09:21:35 -0600 Subject: [PATCH 4/6] bin/bump_version --patch --- Gemfile.lock | 2 +- example_rails7/Gemfile.lock | 2 +- example_rails8/Gemfile.lock | 4 ++-- lib/rolemodel_rails/version.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e4f6dada..bb6cf419 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - rolemodel_rails (0.25.0) + rolemodel_rails (0.25.1) rails (> 7.1) GEM diff --git a/example_rails7/Gemfile.lock b/example_rails7/Gemfile.lock index afe0a114..daf9598f 100644 --- a/example_rails7/Gemfile.lock +++ b/example_rails7/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - rolemodel_rails (0.25.0) + rolemodel_rails (0.25.1) rails (> 7.1) GEM diff --git a/example_rails8/Gemfile.lock b/example_rails8/Gemfile.lock index b24564f7..546960ce 100644 --- a/example_rails8/Gemfile.lock +++ b/example_rails8/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - rolemodel_rails (0.25.0) + rolemodel_rails (0.25.1) rails (> 7.1) GEM @@ -521,7 +521,7 @@ CHECKSUMS regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4 reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835 rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142 - rolemodel_rails (0.25.0) + rolemodel_rails (0.25.1) rubocop (1.84.1) sha256=14cc626f355141f5a2ef53c10a68d66b13bb30639b26370a76559096cc6bcc1a rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834 diff --git a/lib/rolemodel_rails/version.rb b/lib/rolemodel_rails/version.rb index fb9de63e..62509551 100644 --- a/lib/rolemodel_rails/version.rb +++ b/lib/rolemodel_rails/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module RolemodelRails - VERSION = '0.25.0' + VERSION = '0.25.1' end From 5230ae032f33baeb28f4e0b18d6bece1d7dffaf1 Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Fri, 13 Feb 2026 09:25:37 -0600 Subject: [PATCH 5/6] minor refactor --- .../rolemodel/optics/icons/icons_generator.rb | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/generators/rolemodel/optics/icons/icons_generator.rb b/lib/generators/rolemodel/optics/icons/icons_generator.rb index f3a2dd10..bd11887c 100644 --- a/lib/generators/rolemodel/optics/icons/icons_generator.rb +++ b/lib/generators/rolemodel/optics/icons/icons_generator.rb @@ -22,18 +22,23 @@ def remove_existing_icon_helper_and_builders end def add_view_helper - @chosen_library = options['icon_library'] - @chosen_library ||= ask( - 'What icon library would you like to add?', - default: SUPPORTED_LIBRARIES.keys.first.to_s, - limited_to: SUPPORTED_LIBRARIES.keys.map(&:to_s) - ) + @chosen_library = chosen_icon_library @supported_properties = SUPPORTED_LIBRARIES.fetch(@chosen_library) template 'app/icon_builders/icon_builder.rb' template "app/icon_builders/#{@chosen_library}_icon_builder.rb" template 'app/helpers/icon_helper.rb' end + + private + + def chosen_icon_library + return options['icon_library'] if options.icon_library? + + ask('What icon library would you like to add?', + default: SUPPORTED_LIBRARIES.keys.first.to_s, + limited_to: SUPPORTED_LIBRARIES.keys.map(&:to_s)) + end end end end From af4046b94b22a744071d0de62489d84f40a89bff Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Fri, 13 Feb 2026 14:55:47 -0600 Subject: [PATCH 6/6] change from --icon-library to separate flags for each library --- lib/generators/rolemodel.rb | 1 + lib/generators/rolemodel/optics/icons/USAGE | 11 ++++------ .../rolemodel/optics/icons/icons_generator.rb | 20 +++++++++++-------- .../rolemodel/optics/icons_generator_spec.rb | 4 ++-- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/generators/rolemodel.rb b/lib/generators/rolemodel.rb index 42e077d2..e6bc5754 100644 --- a/lib/generators/rolemodel.rb +++ b/lib/generators/rolemodel.rb @@ -1,5 +1,6 @@ require 'rails' require 'pathname' +require 'rails/generators' require 'rails/generators/bundle_helper' require_relative 'rolemodel/replace_content_helper' diff --git a/lib/generators/rolemodel/optics/icons/USAGE b/lib/generators/rolemodel/optics/icons/USAGE index 100aea4b..f322e112 100644 --- a/lib/generators/rolemodel/optics/icons/USAGE +++ b/lib/generators/rolemodel/optics/icons/USAGE @@ -1,11 +1,8 @@ Description: - runs the Optics Icon Generator + Generates a ViewHelper Integrated With The Icon Provider of Your Choice Example: - bin/rails generate rolemodel:optics:icons --icon-library=tabler + bin/rails generate rolemodel:optics:icons --feather - This will create: - app/helpers/icon_helper.rb - - Which provides a simple view helper for rendering Icons: - = button_to icon('trash'), @post, method: :destroy + And then in a slim template/partial: + = button_to icon('delete'), @post, method: :delete diff --git a/lib/generators/rolemodel/optics/icons/icons_generator.rb b/lib/generators/rolemodel/optics/icons/icons_generator.rb index bd11887c..5ec4b7e8 100644 --- a/lib/generators/rolemodel/optics/icons/icons_generator.rb +++ b/lib/generators/rolemodel/optics/icons/icons_generator.rb @@ -14,7 +14,11 @@ class IconsGenerator < Rolemodel::BaseGenerator ).freeze source_root File.expand_path('templates', __dir__) - class_option :icon_library, type: :string, desc: "The icon library to use (#{SUPPORTED_LIBRARIES.keys.join(', ')})" + class_exclusive do + SUPPORTED_LIBRARIES.keys.each do |library| + class_option library, type: :boolean, lazy_default: false, desc: "Use #{library} icon library" + end + end def remove_existing_icon_helper_and_builders remove_dir 'app/icon_builders' @@ -22,7 +26,7 @@ def remove_existing_icon_helper_and_builders end def add_view_helper - @chosen_library = chosen_icon_library + @chosen_library = capture_user_selection @supported_properties = SUPPORTED_LIBRARIES.fetch(@chosen_library) template 'app/icon_builders/icon_builder.rb' @@ -32,12 +36,12 @@ def add_view_helper private - def chosen_icon_library - return options['icon_library'] if options.icon_library? - - ask('What icon library would you like to add?', - default: SUPPORTED_LIBRARIES.keys.first.to_s, - limited_to: SUPPORTED_LIBRARIES.keys.map(&:to_s)) + def capture_user_selection + options.except(*%i[skip_namespace skip_collision_check]).invert[true] || ask( + 'What icon library would you like to add?', + default: SUPPORTED_LIBRARIES.keys.first.to_s, + limited_to: SUPPORTED_LIBRARIES.keys.map(&:to_s) + ) end end end diff --git a/spec/generators/rolemodel/optics/icons_generator_spec.rb b/spec/generators/rolemodel/optics/icons_generator_spec.rb index 81ce75ed..a5a0da6b 100644 --- a/spec/generators/rolemodel/optics/icons_generator_spec.rb +++ b/spec/generators/rolemodel/optics/icons_generator_spec.rb @@ -13,7 +13,7 @@ end context 'selecting an alternate icon library via command line option' do - before { run_generator_against_test_app(['--icon-library=phosphor']) } + before { run_generator_against_test_app(['--phosphor']) } it 'adds the correct helper and builders' do assert_file 'app/helpers/icon_helper.rb' @@ -26,7 +26,7 @@ it 'removes existing helper and builders before adding new ones' do assert_no_file 'app/helpers/icon_helper.rb' - run_generator_against_test_app(['--icon-library=tabler']) + run_generator_against_test_app(['--tabler']) assert_file 'app/helpers/icon_helper.rb' assert_file 'app/icon_builders/tabler_icon_builder.rb'