From b15047fd4248fbfea7dddd72acc9e44138ffc819 Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Sat, 16 May 2026 22:32:12 -0400 Subject: [PATCH 1/3] Move IconBuilders into The engine (#190) - Move icon builders to lib/rolemodel/optics - Add rolemodel/optics to engine paths - Add Rolemodel::Optics module to autoload icon builders - Update Icon Generator & specs - Add Opt-In to local IconBuilder installation option - Add Utility::TaskTools module --- Gemfile.lock | 3 +- README.md | 11 ++- example_rails_legacy/Gemfile.lock | 2 +- .../rolemodel/optics/icons/README.md | 7 +- .../rolemodel/optics/icons/icons_generator.rb | 23 +++--- .../templates/app/helpers/icon_helper.rb.tt | 6 +- lib/rolemodel-rails.rb | 2 + lib/rolemodel/optics.rb | 9 +++ .../optics}/custom_icon_builder.rb | 2 +- .../optics}/feather_icon_builder.rb | 2 +- .../optics}/icon_builder.rb | 2 +- .../optics}/lucide_icon_builder.rb | 2 +- .../optics}/material_icon_builder.rb | 2 +- .../optics}/phosphor_icon_builder.rb | 2 +- .../optics}/tabler_icon_builder.rb | 2 +- lib/rolemodel/utility.rb | 3 + lib/rolemodel/utility/task_tools.rb | 48 +++++++++++++ lib/rolemodel/version.rb | 2 +- rolemodel-rails.gemspec | 1 + .../rolemodel/optics/icons_generator_spec.rb | 70 ++++++++++++++----- 20 files changed, 157 insertions(+), 44 deletions(-) create mode 100644 lib/rolemodel/optics.rb rename lib/{generators/rolemodel/optics/icons/templates/app/icon_builders => rolemodel/optics}/custom_icon_builder.rb (94%) rename lib/{generators/rolemodel/optics/icons/templates/app/icon_builders => rolemodel/optics}/feather_icon_builder.rb (82%) rename lib/{generators/rolemodel/optics/icons/templates/app/icon_builders => rolemodel/optics}/icon_builder.rb (97%) rename lib/{generators/rolemodel/optics/icons/templates/app/icon_builders => rolemodel/optics}/lucide_icon_builder.rb (82%) rename lib/{generators/rolemodel/optics/icons/templates/app/icon_builders => rolemodel/optics}/material_icon_builder.rb (88%) rename lib/{generators/rolemodel/optics/icons/templates/app/icon_builders => rolemodel/optics}/phosphor_icon_builder.rb (86%) rename lib/{generators/rolemodel/optics/icons/templates/app/icon_builders => rolemodel/optics}/tabler_icon_builder.rb (83%) create mode 100644 lib/rolemodel/utility.rb create mode 100644 lib/rolemodel/utility/task_tools.rb diff --git a/Gemfile.lock b/Gemfile.lock index e235a589..48869346 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,8 @@ PATH remote: . specs: - rolemodel-rails (1.1.0) + rolemodel-rails (2.0.0) + benchmark rails (> 7.1) GEM diff --git a/README.md b/README.md index a076891e..8d329810 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,15 @@ rails db:create Add this line to your application's Gemfile: ```ruby -gem 'rolemodel-rails', group: :development +gem 'rolemodel-rails' ``` +> [!IMPORTANT] +> We used to recommend putting rolemodel-rails in the development gem group. This is no longer supported, because some Rolemodel namespaced utility modules and classes are expected to be available at runtime. + And then execute: - $ bundle + $ bundle install ## Usage @@ -116,10 +119,6 @@ bin/new_generator testing/fantasitic_specs 'A Fantastic Testing Framework' We use the embeded Rails apps (`example_rails_current` & `example_rails_legacy`) to test generators against. They reference the rolemodel-rails gem by local path, so you can navigate into one of them and run your generator for immediate feedback while developing. -> [!IMPORTANT] -> Before submitting a PR, run `bin/bump_version` to ensure the Gem builds successfully & that everything continues to stay in sync & up-to-date.

-> For very small changes & bug fixes, prefer `bin/bump_version --patch`. - ## Testing Generator specs should be added to the [spec](./spec) directory. diff --git a/example_rails_legacy/Gemfile.lock b/example_rails_legacy/Gemfile.lock index bca04a45..379115b4 100644 --- a/example_rails_legacy/Gemfile.lock +++ b/example_rails_legacy/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - rolemodel-rails (1.1.0) + rolemodel-rails (2.0.0) rails (> 7.1) GEM diff --git a/lib/generators/rolemodel/optics/icons/README.md b/lib/generators/rolemodel/optics/icons/README.md index fbf26ea9..8697e32f 100644 --- a/lib/generators/rolemodel/optics/icons/README.md +++ b/lib/generators/rolemodel/optics/icons/README.md @@ -4,4 +4,9 @@ ## What you get -Adds icon helper for handling material icons and custom icons +Adds icon helper for handling icon generation using the provider of your choice. + +## Icon Builder Customization + +Run the generator with the `-i` option to install the IconBuilders themselves in your +application's `lib/rolemodel/optics` directory. diff --git a/lib/generators/rolemodel/optics/icons/icons_generator.rb b/lib/generators/rolemodel/optics/icons/icons_generator.rb index 2614d65a..2e2b5f46 100644 --- a/lib/generators/rolemodel/optics/icons/icons_generator.rb +++ b/lib/generators/rolemodel/optics/icons/icons_generator.rb @@ -4,6 +4,7 @@ module Rolemodel module Optics # Generates the icon helper and icon builders for the chosen icon library class IconsGenerator < Rolemodel::GeneratorBase + BUILDER_DIR = 'rolemodel/optics' SUPPORTED_LIBRARIES = HashWithIndifferentAccess.new( material: 'filled, size, weight, emphasis, additional_classes, color, hover_text', phosphor: 'duotone, filled, size, weight, additional_classes, color, hover_text', @@ -14,30 +15,34 @@ class IconsGenerator < Rolemodel::GeneratorBase ).freeze source_root File.expand_path('templates', __dir__) + class_option :install_builders, aliases: '-i', type: :boolean, default: false, + desc: "Install IconBuilder classes for customization" + 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' - remove_file 'app/helpers/icon_helper.rb' - end - def add_view_helper @chosen_library = capture_user_selection @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' + template 'app/helpers/icon_helper.rb', force: true + end + + def install_builders + return unless options.install_builders? + + source_paths << File.expand_path(BUILDER_DIR, Rolemodel::GEM_LIB) + copy_file 'icon_builder.rb', "lib/#{BUILDER_DIR}/icon_builder.rb", force: true + copy_file "#{@chosen_library}_icon_builder.rb", "lib/#{BUILDER_DIR}/#{@chosen_library}_icon_builder.rb", force: true end private def capture_user_selection - options.except(*%i[skip_namespace skip_collision_check]).invert[true] || ask( + options.slice(*SUPPORTED_LIBRARIES.keys).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) 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 20e70863..46beee6c 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,5 +1,7 @@ # frozen_string_literal: true +require 'rolemodel/optics' + # Helper method that renders icons from your icon library of choice. # # Usage: @@ -14,11 +16,11 @@ module IconHelper # <%= @supported_properties %> def icon(name, **) - <%= @chosen_library.classify %>IconBuilder.new(name, **).build + Rolemodel::Optics::<%= @chosen_library.classify %>IconBuilder.new(name, **).build end # <%= @supported_properties %> def flash_icon(type, **) - <%= @chosen_library.classify %>IconBuilder.flash_icon(type, **).build + Rolemodel::Optics::<%= @chosen_library.classify %>IconBuilder.flash_icon(type, **).build end end diff --git a/lib/rolemodel-rails.rb b/lib/rolemodel-rails.rb index d6ccc1df..06e1ef26 100644 --- a/lib/rolemodel-rails.rb +++ b/lib/rolemodel-rails.rb @@ -3,6 +3,8 @@ module Rolemodel NODE_VERSION = '24.12.0' RUBY_VERSION = '4.0.1' + + GEM_LIB = File.expand_path(__dir__) end require 'rolemodel/version' diff --git a/lib/rolemodel/optics.rb b/lib/rolemodel/optics.rb new file mode 100644 index 00000000..9c5c32e0 --- /dev/null +++ b/lib/rolemodel/optics.rb @@ -0,0 +1,9 @@ +module Rolemodel::Optics + autoload :IconBuilder, 'rolemodel/optics/icon_builder' + autoload :CustomIconBuilder, 'rolemodel/optics/custom_icon_builder' + autoload :FeatherIconBuilder, 'rolemodel/optics/feather_icon_builder' + autoload :LucideIconBuilder, 'rolemodel/optics/lucide_icon_builder' + autoload :MaterialIconBuilder, 'rolemodel/optics/material_icon_builder' + autoload :PhosphorIconBuilder, 'rolemodel/optics/phosphor_icon_builder' + autoload :TablerIconBuilder, 'rolemodel/optics/tabler_icon_builder' +end diff --git a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/custom_icon_builder.rb b/lib/rolemodel/optics/custom_icon_builder.rb similarity index 94% rename from lib/generators/rolemodel/optics/icons/templates/app/icon_builders/custom_icon_builder.rb rename to lib/rolemodel/optics/custom_icon_builder.rb index cef0e2c1..bc5f5858 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/custom_icon_builder.rb +++ b/lib/rolemodel/optics/custom_icon_builder.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # CustomIconBuilder is an IconBuilder that allows for custom SVG icons to be used in the application. -class CustomIconBuilder < IconBuilder +class Rolemodel::Optics::CustomIconBuilder < Rolemodel::Optics::IconBuilder def self.flash_icons { notice: 'circle-check', diff --git a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/feather_icon_builder.rb b/lib/rolemodel/optics/feather_icon_builder.rb similarity index 82% rename from lib/generators/rolemodel/optics/icons/templates/app/icon_builders/feather_icon_builder.rb rename to lib/rolemodel/optics/feather_icon_builder.rb index 8396d578..bf31e6ce 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/feather_icon_builder.rb +++ b/lib/rolemodel/optics/feather_icon_builder.rb @@ -2,7 +2,7 @@ # FeatherIconBuilder is an IconBuilder that allows for Feather icons to be used in the application. # https://feathericons.com/ -class FeatherIconBuilder < IconBuilder +class Rolemodel::Optics::FeatherIconBuilder < Rolemodel::Optics::IconBuilder def self.flash_icons { notice: 'check-circle', diff --git a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/icon_builder.rb b/lib/rolemodel/optics/icon_builder.rb similarity index 97% rename from lib/generators/rolemodel/optics/icons/templates/app/icon_builders/icon_builder.rb rename to lib/rolemodel/optics/icon_builder.rb index 4f60bcab..691abaf5 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/icon_builder.rb +++ b/lib/rolemodel/optics/icon_builder.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class IconBuilder +class Rolemodel::Optics::IconBuilder include ActionView::Helpers::TagHelper attr_reader :name, :filled, :size, :weight, :emphasis, :duotone, :additional_classes, :color, :hover_text diff --git a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/lucide_icon_builder.rb b/lib/rolemodel/optics/lucide_icon_builder.rb similarity index 82% rename from lib/generators/rolemodel/optics/icons/templates/app/icon_builders/lucide_icon_builder.rb rename to lib/rolemodel/optics/lucide_icon_builder.rb index 9ce21bad..7905484f 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/lucide_icon_builder.rb +++ b/lib/rolemodel/optics/lucide_icon_builder.rb @@ -2,7 +2,7 @@ # LucideIconBuilder is an IconBuilder that allows for Lucide icons to be used in the application. # https://lucide.dev/icons/ -class LucideIconBuilder < IconBuilder +class Rolemodel::Optics::LucideIconBuilder < Rolemodel::Optics::IconBuilder def self.flash_icons { notice: 'circle-check', diff --git a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/material_icon_builder.rb b/lib/rolemodel/optics/material_icon_builder.rb similarity index 88% rename from lib/generators/rolemodel/optics/icons/templates/app/icon_builders/material_icon_builder.rb rename to lib/rolemodel/optics/material_icon_builder.rb index b20d8be4..2310fe16 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/material_icon_builder.rb +++ b/lib/rolemodel/optics/material_icon_builder.rb @@ -2,7 +2,7 @@ # MaterialIconBuilder is an IconBuilder that allows for Material icons to be used in the application. # https://fonts.google.com/icons -class MaterialIconBuilder < IconBuilder +class Rolemodel::Optics::MaterialIconBuilder < Rolemodel::Optics::IconBuilder def self.flash_icons { notice: 'check_circle', diff --git a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/phosphor_icon_builder.rb b/lib/rolemodel/optics/phosphor_icon_builder.rb similarity index 86% rename from lib/generators/rolemodel/optics/icons/templates/app/icon_builders/phosphor_icon_builder.rb rename to lib/rolemodel/optics/phosphor_icon_builder.rb index bcc7c59a..b128165e 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/phosphor_icon_builder.rb +++ b/lib/rolemodel/optics/phosphor_icon_builder.rb @@ -2,7 +2,7 @@ # PhosphorIconBuilder is an IconBuilder that allows for Phosphor icons to be used in the application. # https://phosphoricons.com/ -class PhosphorIconBuilder < IconBuilder +class Rolemodel::Optics::PhosphorIconBuilder < Rolemodel::Optics::IconBuilder def self.flash_icons { notice: 'check-circle', diff --git a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/tabler_icon_builder.rb b/lib/rolemodel/optics/tabler_icon_builder.rb similarity index 83% rename from lib/generators/rolemodel/optics/icons/templates/app/icon_builders/tabler_icon_builder.rb rename to lib/rolemodel/optics/tabler_icon_builder.rb index 4fdd9995..66650b10 100644 --- a/lib/generators/rolemodel/optics/icons/templates/app/icon_builders/tabler_icon_builder.rb +++ b/lib/rolemodel/optics/tabler_icon_builder.rb @@ -2,7 +2,7 @@ # TablerIconBuilder is an IconBuilder that allows for Tabler icons to be used in the application. # https://tablericons.com/ -class TablerIconBuilder < IconBuilder +class Rolemodel::Optics::TablerIconBuilder < Rolemodel::Optics::IconBuilder def self.flash_icons { notice: 'circle-check', diff --git a/lib/rolemodel/utility.rb b/lib/rolemodel/utility.rb new file mode 100644 index 00000000..79df8b3a --- /dev/null +++ b/lib/rolemodel/utility.rb @@ -0,0 +1,3 @@ +module Rolemodel::Utility + autoload :TaskTools, 'rolemodel/utility/task_tools' +end diff --git a/lib/rolemodel/utility/task_tools.rb b/lib/rolemodel/utility/task_tools.rb new file mode 100644 index 00000000..34b138f9 --- /dev/null +++ b/lib/rolemodel/utility/task_tools.rb @@ -0,0 +1,48 @@ +require 'benchmark' + +module Rolemodel + module Utility + module TaskTools + PROGRESS = %w[⠏ ⠇ ⠧ ⠦ ⠴ ⠼ ⠸ ⠹ ⠙ ⠋].to_enum + + # based on the migration helper of the same name + def say_with_time(message, &) + say message + time = Benchmark.measure(&) + say '%.4fs' % time.real, :subitem + end + + def say(message, subitem = false) # rubocop:disable Style/OptionalBooleanParameter + puts "#{subitem ? ' ->' : '--'} #{message}" # rubocop:disable Rails/Output + end + + ## + # Indicate the progress of a long-running process + # + # Usage (with a known total): + # 100.times do |i| + # indicate_progress(i, 100) + # end + # + # Only update every 'report_interval' iteration for eye-trackable animation speed + # Also displays a completion percentage if a total is provided + def indicate_progress(index, total = nil, report_interval: 9) + return unless (index % report_interval).zero? + + print("#{indicator} #{to_percent(index, total) if total}\r") # rubocop:disable Rails/Output + end + + private + + def indicator + PROGRESS.next + rescue StopIteration + PROGRESS.rewind.next + end + + def to_percent(index, total) + '%3.f%%' % (index / total.to_f * 100.0) + end + end + end +end diff --git a/lib/rolemodel/version.rb b/lib/rolemodel/version.rb index 1a8d23a7..1e0fd13e 100644 --- a/lib/rolemodel/version.rb +++ b/lib/rolemodel/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Rolemodel - VERSION = '1.1.0' + VERSION = '2.0.0' end diff --git a/rolemodel-rails.gemspec b/rolemodel-rails.gemspec index 86b7962e..d132406d 100644 --- a/rolemodel-rails.gemspec +++ b/rolemodel-rails.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_dependency 'rails', '> 7.1' + spec.add_dependency 'benchmark' spec.add_development_dependency 'bundler', '~> 4' spec.add_development_dependency 'generator_spec', '~> 0.10' diff --git a/spec/generators/rolemodel/optics/icons_generator_spec.rb b/spec/generators/rolemodel/optics/icons_generator_spec.rb index a5a0da6b..f2704cdc 100644 --- a/spec/generators/rolemodel/optics/icons_generator_spec.rb +++ b/spec/generators/rolemodel/optics/icons_generator_spec.rb @@ -5,20 +5,36 @@ run_generator_against_test_app 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/material_icon_builder.rb' + it 'adds the correct helper' do + assert_file 'app/helpers/icon_helper.rb' do |helper| + assert_instance_method :icon, helper + assert_match(/MaterialIconBuilder/, helper) + end end end context 'selecting an alternate icon library via command line option' do before { run_generator_against_test_app(['--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' + it 'adds the correct helper' do + assert_file 'app/helpers/icon_helper.rb' do |helper| + assert_instance_method :icon, helper + assert_match(/PhosphorIconBuilder/, helper) + end + end + end + + context 'selecting an alternate icon library via prompt' do + before do + respond_to_prompt with: 'feather' # choose an icon library + run_generator_against_test_app + end + + it 'adds the correct helper' do + assert_file 'app/helpers/icon_helper.rb' do |helper| + assert_instance_method :icon, helper + assert_match(/FeatherIconBuilder/, helper) + end end end @@ -27,16 +43,38 @@ assert_no_file 'app/helpers/icon_helper.rb' run_generator_against_test_app(['--tabler']) - assert_file 'app/helpers/icon_helper.rb' - assert_file 'app/icon_builders/tabler_icon_builder.rb' + assert_file 'app/helpers/icon_helper.rb' do |helper| + assert_instance_method :icon, helper + assert_match(/TablerIconBuilder/, helper) + assert_no_match(/PhosphorIconBuilder/, helper) + end - 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/feather_icon_builder.rb' + run_generator_against_test_app(['--lucide']) + assert_file 'app/helpers/icon_helper.rb' do |helper| + assert_instance_method :icon, helper + assert_match(/LucideIconBuilder/, helper) + assert_no_match(/TablerIconBuilder/, helper) + end + end + end + + context 'installing builders' do + before do + run_generator_against_test_app(['--phosphor', '--install-builders']) + end + + it 'copies the base IconBuilder and the chosen library builder to the app lib directory' do + assert_file 'lib/rolemodel/optics/icon_builder.rb' + assert_file 'lib/rolemodel/optics/phosphor_icon_builder.rb' + end + end + + context 'not installing builders (default)' do + before { run_generator_against_test_app(['--phosphor']) } - assert_no_file 'app/icon_builders/tabler_icon_builder.rb' - assert_no_file 'app/icon_builders/material_icon_builder.rb' + it 'does not copy any builder files to the app lib directory' do + assert_no_file 'lib/rolemodel/optics/icon_builder.rb' + assert_no_file 'lib/rolemodel/optics/phosphor_icon_builder.rb' end end end From 3b082fb3e84a19e2999f4b2cb17c9b80cdbebd8c Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Mon, 18 May 2026 23:10:49 -0500 Subject: [PATCH 2/3] minor fiddling --- lib/rolemodel/optics/icon_builder.rb | 27 +++++++++------------------ lib/rolemodel/utility/task_tools.rb | 14 ++++---------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/lib/rolemodel/optics/icon_builder.rb b/lib/rolemodel/optics/icon_builder.rb index 691abaf5..4f68aeae 100644 --- a/lib/rolemodel/optics/icon_builder.rb +++ b/lib/rolemodel/optics/icon_builder.rb @@ -4,11 +4,13 @@ class Rolemodel::Optics::IconBuilder include ActionView::Helpers::TagHelper attr_reader :name, :filled, :size, :weight, :emphasis, :duotone, :additional_classes, :color, :hover_text + alias title hover_text DEFAULT_SIZE = 'medium' DEFAULT_WEIGHT = 'normal' DEFAULT_EMPHASIS = 'normal' + # TODO: consider Data.define a custom options object if all of these parameters are indeed necessary. def initialize( # rubocop:disable Metrics/ParameterLists name, filled: false, @@ -42,32 +44,21 @@ def self.flash_icons def build options = { class: tag_classes.compact_blank.join(' '), - title: hover_text - } - - if color.present? + title: hover_text, # color: primary, neutral, alerts-notice, alerts-warning, alerts-danger, alerts-info - options[:style] = "#{color_attribute}: var(--op-color-#{color}-base);" - end + style: ("#{color_attribute}: var(--op-color-#{color}-base);" if color.present?) + }.compact_blank - tag.send(tag_method, tag_contents, **options) + tag.public_send(tag_method, tag_contents, **options) end private - def tag_method - raise NotImplementedError - end - - def tag_contents - '' - end - def tag_classes ['icon', size == DEFAULT_SIZE ? '' : "icon--#{size}", additional_classes] end - def color_attribute - 'color' - end + def color_attribute = 'color' + def tag_contents = '' + def tag_method = :i end diff --git a/lib/rolemodel/utility/task_tools.rb b/lib/rolemodel/utility/task_tools.rb index 34b138f9..c89f33c3 100644 --- a/lib/rolemodel/utility/task_tools.rb +++ b/lib/rolemodel/utility/task_tools.rb @@ -3,16 +3,16 @@ module Rolemodel module Utility module TaskTools - PROGRESS = %w[⠏ ⠇ ⠧ ⠦ ⠴ ⠼ ⠸ ⠹ ⠙ ⠋].to_enum + PROGRESS = %w[⠏ ⠇ ⠧ ⠦ ⠴ ⠼ ⠸ ⠹ ⠙ ⠋].cycle # based on the migration helper of the same name def say_with_time(message, &) say message time = Benchmark.measure(&) - say '%.4fs' % time.real, :subitem + say '%.4fs' % time.real, subitem: true end - def say(message, subitem = false) # rubocop:disable Style/OptionalBooleanParameter + def say(message, subitem: false) puts "#{subitem ? ' ->' : '--'} #{message}" # rubocop:disable Rails/Output end @@ -29,17 +29,11 @@ def say(message, subitem = false) # rubocop:disable Style/OptionalBooleanParamet def indicate_progress(index, total = nil, report_interval: 9) return unless (index % report_interval).zero? - print("#{indicator} #{to_percent(index, total) if total}\r") # rubocop:disable Rails/Output + print("#{PROGRESS.next} #{to_percent(index, total) if total}\r") # rubocop:disable Rails/Output end private - def indicator - PROGRESS.next - rescue StopIteration - PROGRESS.rewind.next - end - def to_percent(index, total) '%3.f%%' % (index / total.to_f * 100.0) end From a5dc19a2b2cda9099fae15f9aecf952186d15e9d Mon Sep 17 00:00:00 2001 From: Andy Cohen Date: Mon, 18 May 2026 23:27:47 -0500 Subject: [PATCH 3/3] Add IconBuilder specs --- spec/helpers/icon_builder_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 spec/helpers/icon_builder_spec.rb diff --git a/spec/helpers/icon_builder_spec.rb b/spec/helpers/icon_builder_spec.rb new file mode 100644 index 00000000..403c0246 --- /dev/null +++ b/spec/helpers/icon_builder_spec.rb @@ -0,0 +1,21 @@ +require 'action_view' +require 'erb' +require 'rolemodel/optics' + + +RSpec.describe Rolemodel::Optics::MaterialIconBuilder, type: :helper do + include ActionView::Helpers + + let(:builder) { Rolemodel::Optics::MaterialIconBuilder.new('home', **options) } + + describe 'default options' do + let(:options) { {} } + it 'renders an icon with the correct class' do + expect(builder.build).to eq('home') + end + end + + describe 'hover_text' + describe 'color' + describe 'additional_classes' +end