From f909bb2c30ab54923beab75e902f7c534b9f0ce4 Mon Sep 17 00:00:00 2001 From: Carlos Chitty Date: Tue, 10 Jun 2025 11:56:30 -0400 Subject: [PATCH 1/2] Add respond_to_missing? to classes defining method_missing to improve respond_to? behavior --- .rubocop_todo.yml | 7 ------- app/helpers/application_helper.rb | 5 +++++ app/models/spree/gateway.rb | 4 ++++ app/models/spree/preferences/configuration.rb | 5 +++++ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 421215463d..208d9a09c1 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -273,13 +273,6 @@ Style/MapToHash: - 'lib/reporting/reports/enterprise_fee_summary/fee_summary.rb' - 'lib/tasks/sample_data/user_factory.rb' -# Offense count: 3 -Style/MissingRespondToMissing: - Exclude: - - 'app/helpers/application_helper.rb' - - 'app/models/spree/gateway.rb' - - 'app/models/spree/preferences/configuration.rb' - # Offense count: 38 Style/OpenStructUse: Exclude: diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f7787e35b9..47e89122ba 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -45,6 +45,11 @@ module ApplicationHelper form_for(name, *(args << options.merge(builder: AngularFormBuilder)), &) end + def respond_to_missing?(method_name, include_private = false) + (method_name.to_s.end_with?('_path', + '_url') && spree.respond_to?(method_name, include_private)) || super + end + # Pass URL helper calls on to spree where applicable so that we don't need to use # spree.foo_path in any view rendered from non-spree-namespaced controllers. def method_missing(method, *args, &) diff --git a/app/models/spree/gateway.rb b/app/models/spree/gateway.rb index 9dd4046c3a..0a20269050 100644 --- a/app/models/spree/gateway.rb +++ b/app/models/spree/gateway.rb @@ -30,6 +30,10 @@ module Spree preferences.transform_keys(&:to_sym) end + def respond_to_missing?(method_name, include_private = false) + @provider.respond_to?(method_name, include_private) || super + end + def method_missing(method, *args) if @provider.nil? || !@provider.respond_to?(method) super diff --git a/app/models/spree/preferences/configuration.rb b/app/models/spree/preferences/configuration.rb index b534a31cfc..d028dc41cd 100644 --- a/app/models/spree/preferences/configuration.rb +++ b/app/models/spree/preferences/configuration.rb @@ -57,6 +57,11 @@ module Spree set_preference args[0], args[1] end + def respond_to_missing?(method_name, include_private = false) + name = method_name.to_s.chomp('=') + has_preference?(name) || super + end + def method_missing(method, *args) name = method.to_s.gsub('=', '') if has_preference? name From 37bf3f495f436408916bf00b4909dcc5c13c91a4 Mon Sep 17 00:00:00 2001 From: Carlos Chitty Date: Tue, 10 Jun 2025 12:37:23 -0400 Subject: [PATCH 2/2] Refactor preference access to use define_method instead of method_missing Replaces dynamic method handling with explicit getters and setters to avoid recursion issues and improve clarity. --- app/models/spree/preferences/configuration.rb | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/app/models/spree/preferences/configuration.rb b/app/models/spree/preferences/configuration.rb index d028dc41cd..464047d390 100644 --- a/app/models/spree/preferences/configuration.rb +++ b/app/models/spree/preferences/configuration.rb @@ -27,6 +27,20 @@ module Spree class Configuration include Spree::Preferences::Preferable + class << self + def preference(name, type, *args) + super + + define_method(name) do + get_preference(name) + end + + define_method("#{name}=") do |value| + set_preference(name, value) + end + end + end + def configure yield(self) if block_given? end @@ -56,24 +70,6 @@ module Spree set_preference args[0], args[1] end - - def respond_to_missing?(method_name, include_private = false) - name = method_name.to_s.chomp('=') - has_preference?(name) || super - end - - def method_missing(method, *args) - name = method.to_s.gsub('=', '') - if has_preference? name - if method.to_s =~ /=$/ - set_preference(name, args.first) - else - get_preference name - end - else - super - end - end end end end