diff --git a/lib/stroma.rb b/lib/stroma.rb index 76f73fc..f254120 100644 --- a/lib/stroma.rb +++ b/lib/stroma.rb @@ -2,8 +2,6 @@ require "zeitwerk" -require "active_support/all" - loader = Zeitwerk::Loader.for_gem loader.ignore("#{__dir__}/stroma/test_kit/rspec") loader.inflector.inflect( diff --git a/lib/stroma/dsl/generator.rb b/lib/stroma/dsl/generator.rb index 365a336..8bfa489 100644 --- a/lib/stroma/dsl/generator.rb +++ b/lib/stroma/dsl/generator.rb @@ -82,30 +82,14 @@ def included(base) const_set(:ClassMethods, class_methods) end - label_module(mod, "Stroma::DSL(#{matrix.name})") - label_module(class_methods, "Stroma::DSL(#{matrix.name})::ClassMethods") + Utils.name_module(mod, "Stroma::DSL(#{matrix.name})") + Utils.name_module(class_methods, "Stroma::DSL(#{matrix.name})::ClassMethods") mod end private - # Assigns a descriptive label to an anonymous module for debugging. - # Uses set_temporary_name (Ruby 3.3+) when available. - # - # TODO: Remove the else branch when Ruby 3.2 support is dropped. - # The define_singleton_method fallback is a temporary workaround - # that only affects #inspect and #to_s. Unlike set_temporary_name, - # it does not set #name, so the module remains technically anonymous. - def label_module(mod, label) - if mod.respond_to?(:set_temporary_name) - mod.set_temporary_name(label) - else - mod.define_singleton_method(:inspect) { label } - mod.define_singleton_method(:to_s) { label } - end - end - # Builds the ClassMethods module. # # @return [Module] The ClassMethods module diff --git a/lib/stroma/hooks/hook.rb b/lib/stroma/hooks/hook.rb index 0617d6c..1593eec 100644 --- a/lib/stroma/hooks/hook.rb +++ b/lib/stroma/hooks/hook.rb @@ -46,7 +46,7 @@ module Hooks # @param extension [Module] Extension module to include # @raise [Exceptions::InvalidHookType] If type is invalid def initialize(type:, target_key:, extension:) - if VALID_HOOK_TYPES.exclude?(type) + unless VALID_HOOK_TYPES.include?(type) raise Exceptions::InvalidHookType, "Invalid hook type: #{type.inspect}. Valid types: #{VALID_HOOK_TYPES.map(&:inspect).join(', ')}" end diff --git a/lib/stroma/registry.rb b/lib/stroma/registry.rb index 6258882..9a10622 100644 --- a/lib/stroma/registry.rb +++ b/lib/stroma/registry.rb @@ -70,6 +70,7 @@ def finalize! return if @finalized @entries.freeze + @keys = @entries.map(&:key).freeze @finalized = true end @@ -88,7 +89,7 @@ def entries # @return [Array] The registry keys def keys ensure_finalized! - @entries.map(&:key) + @keys end # Checks if a key is registered. @@ -98,7 +99,7 @@ def keys # @return [Boolean] true if the key is registered def key?(key) ensure_finalized! - @entries.any? { |e| e.key == key.to_sym } + @keys.include?(key.to_sym) end private diff --git a/lib/stroma/utils.rb b/lib/stroma/utils.rb new file mode 100644 index 0000000..9f70501 --- /dev/null +++ b/lib/stroma/utils.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Stroma + # Shared utility methods for the Stroma framework. + # + # ## Purpose + # + # Provides common helper methods used across multiple Stroma components. + # All methods are module functions - callable as both module methods + # and instance methods when included. + module Utils + module_function + + # Assigns a temporary name to an anonymous module for debugging clarity. + # Uses set_temporary_name (Ruby 3.3+) when available. + # + # TODO: Remove the else branch when Ruby 3.2 support is dropped. + # The define_singleton_method fallback is a temporary workaround + # that only affects #inspect and #to_s. Unlike set_temporary_name, + # it does not set #name, so the module remains technically anonymous. + # + # @param mod [Module] The module to name + # @param name [String] The temporary name + # @return [void] + def name_module(mod, name) + if mod.respond_to?(:set_temporary_name) + mod.set_temporary_name(name) + else + mod.define_singleton_method(:inspect) { name } + mod.define_singleton_method(:to_s) { name } + end + end + end +end diff --git a/sig/lib/stroma/dsl/generator.rbs b/sig/lib/stroma/dsl/generator.rbs index 6411754..8953dbe 100644 --- a/sig/lib/stroma/dsl/generator.rbs +++ b/sig/lib/stroma/dsl/generator.rbs @@ -11,8 +11,6 @@ module Stroma private - def label_module: (Module mod, String label) -> void - def build_class_methods: () -> Module end end diff --git a/sig/lib/stroma/registry.rbs b/sig/lib/stroma/registry.rbs index a631fa8..4e3e13b 100644 --- a/sig/lib/stroma/registry.rbs +++ b/sig/lib/stroma/registry.rbs @@ -2,6 +2,7 @@ module Stroma class Registry @matrix_name: Symbol @entries: Array[Entry] + @keys: Array[Symbol] @finalized: bool attr_reader matrix_name: Symbol diff --git a/sig/lib/stroma/utils.rbs b/sig/lib/stroma/utils.rbs new file mode 100644 index 0000000..cd660d5 --- /dev/null +++ b/sig/lib/stroma/utils.rbs @@ -0,0 +1,9 @@ +module Stroma + module Utils + def self.name_module: (Module mod, String name) -> void + + private + + def name_module: (Module mod, String name) -> void + end +end diff --git a/spec/stroma/utils_spec.rb b/spec/stroma/utils_spec.rb new file mode 100644 index 0000000..858926b --- /dev/null +++ b/spec/stroma/utils_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +RSpec.describe Stroma::Utils do + describe ".name_module" do + let(:mod) { Module.new } + let(:name) { "Stroma::Test(example)" } + + before { described_class.name_module(mod, name) } + + it "sets inspect to the name" do + expect(mod.inspect).to eq(name) + end + + it "sets to_s to the name" do + expect(mod.to_s).to eq(name) + end + end +end diff --git a/spec/stroma/version_spec.rb b/spec/stroma/version_spec.rb index 8d63ca7..ae7e3bb 100644 --- a/spec/stroma/version_spec.rb +++ b/spec/stroma/version_spec.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true RSpec.describe Stroma::VERSION do - it { expect(Stroma::VERSION::STRING).to be_present } + it { expect(Stroma::VERSION::STRING).not_to be_nil } end