diff options
Diffstat (limited to 'activesupport/lib/active_support/core_ext/module')
12 files changed, 121 insertions, 71 deletions
diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index c48bd3354a..6f64d11627 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # Allows you to make aliases for attributes, which includes # getter, setter, and a predicate. diff --git a/activesupport/lib/active_support/core_ext/module/anonymous.rb b/activesupport/lib/active_support/core_ext/module/anonymous.rb index 510c9a5430..d1c86b8722 100644 --- a/activesupport/lib/active_support/core_ext/module/anonymous.rb +++ b/activesupport/lib/active_support/core_ext/module/anonymous.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # A module may or may not have a name. # diff --git a/activesupport/lib/active_support/core_ext/module/attr_internal.rb b/activesupport/lib/active_support/core_ext/module/attr_internal.rb index 5081d5f7a3..7801f6d181 100644 --- a/activesupport/lib/active_support/core_ext/module/attr_internal.rb +++ b/activesupport/lib/active_support/core_ext/module/attr_internal.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # Declares an attribute reader backed by an internally-named instance variable. def attr_internal_reader(*attrs) diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index 2c24081eb9..580baffa2b 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/array/extract_options" require "active_support/core_ext/regexp" @@ -38,13 +40,10 @@ class Module # # Person.new.hair_colors # => NoMethodError # - # - # Also, you can pass a block to set up the attribute with a default value. + # You can set a default value for the attribute. # # module HairColors - # mattr_reader :hair_colors do - # [:brown, :black, :blonde, :red] - # end + # mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red] # end # # class Person @@ -52,8 +51,7 @@ class Module # end # # Person.new.hair_colors # => [:brown, :black, :blonde, :red] - def mattr_reader(*syms) - options = syms.extract_options! + def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil) syms.each do |sym| raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@ -64,14 +62,16 @@ class Module end EOS - unless options[:instance_reader] == false || options[:instance_accessor] == false + if instance_reader && instance_accessor class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym} @@#{sym} end EOS end - class_variable_set("@@#{sym}", yield) if block_given? + + sym_default_value = (block_given? && default.nil?) ? yield : default + class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? end end alias :cattr_reader :mattr_reader @@ -107,12 +107,10 @@ class Module # # Person.new.hair_colors = [:blonde, :red] # => NoMethodError # - # Also, you can pass a block to set up the attribute with a default value. + # You can set a default value for the attribute. # # module HairColors - # mattr_writer :hair_colors do - # [:brown, :black, :blonde, :red] - # end + # mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red] # end # # class Person @@ -120,8 +118,7 @@ class Module # end # # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] - def mattr_writer(*syms) - options = syms.extract_options! + def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil) syms.each do |sym| raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) class_eval(<<-EOS, __FILE__, __LINE__ + 1) @@ -132,14 +129,16 @@ class Module end EOS - unless options[:instance_writer] == false || options[:instance_accessor] == false + if instance_writer && instance_accessor class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{sym}=(obj) @@#{sym} = obj end EOS end - send("#{sym}=", yield) if block_given? + + sym_default_value = (block_given? && default.nil?) ? yield : default + send("#{sym}=", sym_default_value) unless sym_default_value.nil? end end alias :cattr_writer :mattr_writer @@ -197,12 +196,10 @@ class Module # Person.new.hair_colors = [:brown] # => NoMethodError # Person.new.hair_colors # => NoMethodError # - # Also you can pass a block to set up the attribute with a default value. + # You can set a default value for the attribute. # # module HairColors - # mattr_accessor :hair_colors do - # [:brown, :black, :blonde, :red] - # end + # mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red] # end # # class Person @@ -210,9 +207,9 @@ class Module # end # # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] - def mattr_accessor(*syms, &blk) - mattr_reader(*syms, &blk) - mattr_writer(*syms) + def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk) + mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, &blk) + mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default) end alias :cattr_accessor :mattr_accessor end diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb index 1e82b4acc2..4b9b6ea9bd 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/array/extract_options" require "active_support/core_ext/regexp" diff --git a/activesupport/lib/active_support/core_ext/module/concerning.rb b/activesupport/lib/active_support/core_ext/module/concerning.rb index 97b0a382ce..370a948eea 100644 --- a/activesupport/lib/active_support/core_ext/module/concerning.rb +++ b/activesupport/lib/active_support/core_ext/module/concerning.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/concern" class Module diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 85ab739095..a77f903db5 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "set" require "active_support/core_ext/regexp" @@ -174,7 +176,7 @@ class Module to = to.to_s to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to) - methods.each do |method| + methods.map do |method| # Attribute writer methods only accept one argument. Makes sure []= # methods still accept two arguments. definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block" @@ -219,48 +221,43 @@ class Module # When building decorators, a common pattern may emerge: # # class Partition - # def initialize(first_event) - # @events = [ first_event ] + # def initialize(event) + # @event = event # end # - # def people - # if @events.first.detail.people.any? - # @events.collect { |e| Array(e.detail.people) }.flatten.uniq - # else - # @events.collect(&:creator).uniq - # end + # def person + # @event.detail.person || @event.creator # end # # private # def respond_to_missing?(name, include_private = false) - # @events.respond_to?(name, include_private) + # @event.respond_to?(name, include_private) # end # # def method_missing(method, *args, &block) - # @events.send(method, *args, &block) + # @event.send(method, *args, &block) # end # end # - # With `Module#delegate_missing_to`, the above is condensed to: + # With <tt>Module#delegate_missing_to</tt>, the above is condensed to: # # class Partition - # delegate_missing_to :@events + # delegate_missing_to :@event # - # def initialize(first_event) - # @events = [ first_event ] + # def initialize(event) + # @event = event # end # - # def people - # if @events.first.detail.people.any? - # @events.collect { |e| Array(e.detail.people) }.flatten.uniq - # else - # @events.collect(&:creator).uniq - # end + # def person + # @event.detail.person || @event.creator # end # end # - # The target can be anything callable within the object. E.g. instance - # variables, methods, constants and the likes. + # The target can be anything callable within the object, e.g. instance + # variables, methods, constants, etc. + # + # The delegated method must be public on the target, otherwise it will + # raise +NoMethodError+. def delegate_missing_to(target) target = target.to_s target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target) @@ -277,7 +274,15 @@ class Module if #{target}.respond_to?(method) #{target}.public_send(method, *args, &block) else - super + begin + super + rescue NoMethodError + if #{target}.nil? + raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil" + else + raise + end + end end end RUBY diff --git a/activesupport/lib/active_support/core_ext/module/deprecation.rb b/activesupport/lib/active_support/core_ext/module/deprecation.rb index f3f2e7f5fc..71c42eb357 100644 --- a/activesupport/lib/active_support/core_ext/module/deprecation.rb +++ b/activesupport/lib/active_support/core_ext/module/deprecation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # deprecate :foo # deprecate bar: 'message' diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb index ca20a6d4c5..c5bb598bd1 100644 --- a/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/inflector" class Module diff --git a/activesupport/lib/active_support/core_ext/module/reachable.rb b/activesupport/lib/active_support/core_ext/module/reachable.rb index b89a38f26c..e9cbda5245 100644 --- a/activesupport/lib/active_support/core_ext/module/reachable.rb +++ b/activesupport/lib/active_support/core_ext/module/reachable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/module/anonymous" require "active_support/core_ext/string/inflections" @@ -5,4 +7,5 @@ class Module def reachable? #:nodoc: !anonymous? && name.safe_constantize.equal?(self) end + deprecate :reachable? end diff --git a/activesupport/lib/active_support/core_ext/module/redefine_method.rb b/activesupport/lib/active_support/core_ext/module/redefine_method.rb new file mode 100644 index 0000000000..a0a6622ca4 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/module/redefine_method.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +class Module + if RUBY_VERSION >= "2.3" + # Marks the named method as intended to be redefined, if it exists. + # Suppresses the Ruby method redefinition warning. Prefer + # #redefine_method where possible. + def silence_redefinition_of_method(method) + if method_defined?(method) || private_method_defined?(method) + # This suppresses the "method redefined" warning; the self-alias + # looks odd, but means we don't need to generate a unique name + alias_method method, method + end + end + else + def silence_redefinition_of_method(method) + if method_defined?(method) || private_method_defined?(method) + alias_method :__rails_redefine, method + remove_method :__rails_redefine + end + end + end + + # Replaces the existing method definition, if there is one, with the passed + # block as its body. + def redefine_method(method, &block) + visibility = method_visibility(method) + silence_redefinition_of_method(method) + define_method(method, &block) + send(visibility, method) + end + + # Replaces the existing singleton method definition, if there is one, with + # the passed block as its body. + def redefine_singleton_method(method, &block) + singleton_class.redefine_method(method, &block) + end + + def method_visibility(method) # :nodoc: + case + when private_method_defined?(method) + :private + when protected_method_defined?(method) + :protected + else + :public + end + end +end diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb index d5ec16d68a..97eb5f9eca 100644 --- a/activesupport/lib/active_support/core_ext/module/remove_method.rb +++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb @@ -1,3 +1,7 @@ +# frozen_string_literal: true + +require "active_support/core_ext/module/redefine_method" + class Module # Removes the named method, if it exists. def remove_possible_method(method) @@ -8,28 +12,6 @@ class Module # Removes the named singleton method, if it exists. def remove_possible_singleton_method(method) - singleton_class.instance_eval do - remove_possible_method(method) - end - end - - # Replaces the existing method definition, if there is one, with the passed - # block as its body. - def redefine_method(method, &block) - visibility = method_visibility(method) - remove_possible_method(method) - define_method(method, &block) - send(visibility, method) - end - - def method_visibility(method) # :nodoc: - case - when private_method_defined?(method) - :private - when protected_method_defined?(method) - :protected - else - :public - end + singleton_class.remove_possible_method(method) end end |