属性访问器¶ ↑
为类/模块属性扩展模块对象,提供类/模块和实例访问器,就像原生 attr* 访问器用于实例属性一样。
按线程的属性访问器¶ ↑
为类/模块属性扩展模块对象,提供类/模块和实例访问器,就像原生 attr* 访问器用于实例属性一样,但这是按线程进行的。
因此,值被限定在 Thread.current 空间下,以模块的类名作为键。
请注意,如果 Rails.application.config.active_support.isolation_level 被设置为 :fiber,它也可以按 Fiber 进行限定。
- A
- C
- D
- M
- R
- S
- T
Attributes
| [R] | attr_internal_naming_format |
类公共方法
attr_internal_naming_format=(format) 链接
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attr_internal.rb, line 25 def attr_internal_naming_format=(format) if format.start_with?("@") raise ArgumentError, <<~MESSAGE.squish Setting `attr_internal_naming_format` with a `@` prefix is not supported. You can simply replace #{format.inspect} by #{format.delete_prefix("@").inspect}. MESSAGE end @attr_internal_naming_format = format end
实例公共方法
alias_attribute(new_name, old_name) 链接
允许您为属性创建别名,包括 getter、setter 和 predicate。
class Content < ActiveRecord::Base # has a title attribute end class Email < Content alias_attribute :subject, :title end e = Email.find(1) e.title # => "Superstars" e.subject # => "Superstars" e.subject? # => true e.subject = "Megastars" e.title # => "Megastars"
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/aliasing.rb, line 21 def alias_attribute(new_name, old_name) # The following reader methods use an explicit `self` receiver in order to # support aliases that start with an uppercase letter. Otherwise, they would # be resolved as constants instead. module_eval <<-STR, __FILE__, __LINE__ + 1 def #{new_name}; self.#{old_name}; end # def subject; self.title; end def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end STR end
anonymous?() 链接
模块可能有名,也可能没有名。
module M; end M.name # => "M" m = Module.new m.name # => nil
anonymous? 方法在模块没有名称时返回 true,否则返回 false。
Module.new.anonymous? # => true module M; end M.anonymous? # => false
当模块首次被赋值给一个常量时,它就会获得一个名称。这可以通过 module 或 class 关键字,或通过显式赋值来完成。
m = Module.new # creates an anonymous module m.anonymous? # => true M = m # m gets a name here as a side-effect m.name # => "M" m.anonymous? # => false
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/anonymous.rb, line 27 def anonymous? name.nil? end
attr_internal_accessor(*attrs) 链接
声明一个由内部命名的实例变量支持的属性读取器和写入器。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attr_internal.rb, line 16 def attr_internal_accessor(*attrs) attr_internal_reader(*attrs) attr_internal_writer(*attrs) end
attr_internal_reader(*attrs) 链接
声明一个由内部命名的实例变量支持的属性读取器。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attr_internal.rb, line 5 def attr_internal_reader(*attrs) attrs.each { |attr_name| attr_internal_define(attr_name, :reader) } end
attr_internal_writer(*attrs) 链接
声明一个由内部命名的实例变量支持的属性写入器。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attr_internal.rb, line 10 def attr_internal_writer(*attrs) attrs.each { |attr_name| attr_internal_define(attr_name, :writer) } end
cattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk) 链接
cattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil, location: nil) 链接
cattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil, location: nil) 链接
deep_dup() 链接
如果模块或类是匿名的,则返回其副本。如果它有名,则返回 self。
Object.deep_dup == Object # => true klass = Class.new klass.deep_dup == klass # => false
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/object/deep_dup.rb, line 64 def deep_dup if name.nil? super else self end end
delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil) 链接
提供一个 delegate 类方法,以便轻松地将包含对象的公共方法暴露为自己的方法。
选项¶ ↑
-
:to- 指定目标对象名称,作为符号或字符串。 -
:prefix- 使用目标名称或自定义前缀为新方法添加前缀。 -
:allow_nil- 如果设置为 true,则防止引发ActiveSupport::DelegationError。 -
:private- 如果设置为 true,则将方法可见性更改为私有。
宏接收一个或多个方法名(指定为符号或字符串)以及目标对象的名称(通过 :to 选项指定,同样是符号或字符串)。
委托对于 Active Record 关联特别有用。
class Greeter < ActiveRecord::Base def hello 'hello' end def goodbye 'goodbye' end end class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello, to: :greeter end Foo.new.hello # => "hello" Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
允许委托到同一目标的多个委托。
class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello, :goodbye, to: :greeter end Foo.new.goodbye # => "goodbye"
可以通过提供符号来将方法委托给实例变量、类变量或常量。
class Foo CONSTANT_ARRAY = [0,1,2,3] @@class_array = [4,5,6,7] def initialize @instance_array = [8,9,10,11] end delegate :sum, to: :CONSTANT_ARRAY delegate :min, to: :@@class_array delegate :max, to: :@instance_array end Foo.new.sum # => 6 Foo.new.min # => 4 Foo.new.max # => 11
也可以通过使用 :class 将方法委托给类。
class Foo def self.hello "world" end delegate :hello, to: :class end Foo.new.hello # => "world"
可以通过 :prefix 选项选择性地为委托添加前缀。如果值为 true,则委托方法将以被委托对象的名称为前缀。
Person = Struct.new(:name, :address) class Invoice < Struct.new(:client) delegate :name, :address, to: :client, prefix: true end john_doe = Person.new('John Doe', 'Vimmersvej 13') invoice = Invoice.new(john_doe) invoice.client_name # => "John Doe" invoice.client_address # => "Vimmersvej 13"
也可以提供自定义前缀。
class Invoice < Struct.new(:client) delegate :name, :address, to: :client, prefix: :customer end invoice = Invoice.new(john_doe) invoice.customer_name # => 'John Doe' invoice.customer_address # => 'Vimmersvej 13'
默认情况下,委托方法是公共的。传递 private: true 来更改此行为。
class User < ActiveRecord::Base has_one :profile delegate :first_name, to: :profile delegate :date_of_birth, to: :profile, private: true def age Date.today.year - date_of_birth.year end end User.new.first_name # => "Tomas" User.new.date_of_birth # => NoMethodError: private method `date_of_birth' called for #<User:0x00000008221340> User.new.age # => 2
如果目标为 nil 且不响应委托的方法,则会引发 ActiveSupport::DelegationError。如果希望改为返回 nil,请使用 :allow_nil 选项。
class User < ActiveRecord::Base has_one :profile delegate :age, to: :profile end User.new.age # => ActiveSupport::DelegationError: User#age delegated to profile.age, but profile is nil
但如果还没有配置文件也没关系,不应该成为错误条件。
class User < ActiveRecord::Base has_one :profile delegate :age, to: :profile, allow_nil: true end User.new.age # nil
请注意,如果目标不是 nil,则无论 :allow_nil 选项如何,都会尝试调用该方法,因此如果该对象不响应该方法,仍然会引发异常。
class Foo def initialize(bar) @bar = bar end delegate :name, to: :@bar, allow_nil: true end Foo.new("Bar").name # raises NoMethodError: undefined method `name'
目标方法必须是公共的,否则将引发 NoMethodError。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/delegation.rb, line 160 def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil) ::ActiveSupport::Delegation.generate( self, methods, location: caller_locations(1, 1).first, to: to, prefix: prefix, allow_nil: allow_nil, private: private, ) end
delegate_missing_to(target, allow_nil: nil) 链接
在构建装饰器时,可能会出现一种常见模式。
class Partition def initialize(event) @event = event end def person detail.person || creator end private def respond_to_missing?(name, include_private = false) @event.respond_to?(name, include_private) end def method_missing(method, *args, &block) @event.send(method, *args, &block) end end
使用 Module#delegate_missing_to,上述代码可以精简为:
class Partition delegate_missing_to :@event def initialize(event) @event = event end def person detail.person || creator end end
目标可以是对象内的任何可调用内容,例如实例变量、方法、常量等。
委托方法必须在目标对象上是公共的,否则将引发 ActiveSupport::DelegationError。如果希望改为返回 nil,请使用 :allow_nil 选项。
由于在调用 Marshal.dump(object) 时可能与委托目标方法添加或删除实例变量而产生的干扰,因此 marshal_dump 和 _dump 方法被豁免委托。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/delegation.rb, line 218 def delegate_missing_to(target, allow_nil: nil) ::ActiveSupport::Delegation.generate_method_missing( self, target, allow_nil: allow_nil, ) end
deprecate(*method_names, deprecator:, **options) 链接
deprecate :foo, deprecator: MyLib.deprecator deprecate :foo, bar: "warning!", deprecator: MyLib.deprecator
deprecator 通常是 ActiveSupport::Deprecation 的实例,但您也可以传递任何响应 deprecation_warning(deprecated_method_name, message, caller_backtrace) 的对象,您可以在其中实现自定义警告行为。
class MyLib::Deprecator def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil) message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}" Kernel.warn message end end
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/deprecation.rb, line 17 def deprecate(*method_names, deprecator:, **options) if deprecator.is_a?(ActiveSupport::Deprecation) deprecator.deprecate_methods(self, *method_names, **options) elsif deprecator # we just need any instance to call deprecate_methods, but the deprecation will be emitted by deprecator ActiveSupport.deprecator.deprecate_methods(self, *method_names, **options, deprecator: deprecator) end end
mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk) 链接
为类属性同时定义类和实例访问器。创建的所有类方法和实例方法都将是公共的,即使此方法是以私有或受保护的访问修饰符调用的。
module HairColors mattr_accessor :hair_colors end class Person include HairColors end HairColors.hair_colors = [:brown, :black, :blonde, :red] HairColors.hair_colors # => [:brown, :black, :blonde, :red] Person.new.hair_colors # => [:brown, :black, :blonde, :red]
如果子类更改了值,那么父类的值也会改变。同样,如果父类更改了值,子类的值也会改变。
class Citizen < Person end Citizen.new.hair_colors << :blue Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
要省略实例写入器方法,请传递 instance_writer: false。要省略实例读取器方法,请传递 instance_reader: false。
module HairColors mattr_accessor :hair_colors, instance_writer: false, instance_reader: false end class Person include HairColors end Person.new.hair_colors = [:brown] # => NoMethodError Person.new.hair_colors # => NoMethodError
或者传递 instance_accessor: false,省略这两个实例方法。
module HairColors mattr_accessor :hair_colors, instance_accessor: false end class Person include HairColors end Person.new.hair_colors = [:brown] # => NoMethodError Person.new.hair_colors # => NoMethodError
您可以为属性设置默认值。
module HairColors mattr_accessor :hair_colors, default: [:brown, :black, :blonde, :red] mattr_accessor(:hair_styles) { [:long, :short] } end class Person include HairColors end Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] Person.class_variable_get("@@hair_styles") # => [:long, :short]
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attribute_accessors.rb, line 208 def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk) location = caller_locations(1, 1).first mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, location: location, &blk) mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default, location: location) end
mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil, location: nil) 链接
定义一个类属性并创建类和实例读取器方法。如果类变量尚未定义,则其值将设置为 nil。创建的所有类方法和实例方法都将是公共的,即使此方法是以私有或受保护的访问修饰符调用的。
module HairColors mattr_reader :hair_colors end HairColors.hair_colors # => nil HairColors.class_variable_set("@@hair_colors", [:brown, :black]) HairColors.hair_colors # => [:brown, :black]
属性名必须是 Ruby 中的有效方法名。
module Foo mattr_reader :"1_Badname" end # => NameError: invalid attribute name: 1_Badname
要省略实例读取器方法,请传递 instance_reader: false 或 instance_accessor: false。
module HairColors mattr_reader :hair_colors, instance_reader: false end class Person include HairColors end Person.new.hair_colors # => NoMethodError
您可以为属性设置默认值。
module HairColors mattr_reader :hair_colors, default: [:brown, :black, :blonde, :red] mattr_reader(:hair_styles) { [:long, :short] } end class Person include HairColors end Person.new.hair_colors # => [:brown, :black, :blonde, :red] Person.new.hair_styles # => [:long, :short]
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attribute_accessors.rb, line 55 def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil, location: nil) raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class? location ||= caller_locations(1, 1).first definition = [] syms.each do |sym| raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) definition << "def self.#{sym}; @@#{sym}; end" if instance_reader && instance_accessor definition << "def #{sym}; @@#{sym}; end" end sym_default_value = (block_given? && default.nil?) ? yield : default class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}") end module_eval(definition.join(";"), location.path, location.lineno) end
mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil, location: nil) 链接
定义一个类属性并创建类和实例写入器方法以允许对该属性进行赋值。创建的所有类方法和实例方法都将是公共的,即使此方法是以私有或受保护的访问修饰符调用的。
module HairColors mattr_writer :hair_colors end class Person include HairColors end HairColors.hair_colors = [:brown, :black] Person.class_variable_get("@@hair_colors") # => [:brown, :black] Person.new.hair_colors = [:blonde, :red] HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
要省略实例写入器方法,请传递 instance_writer: false 或 instance_accessor: false。
module HairColors mattr_writer :hair_colors, instance_writer: false end class Person include HairColors end Person.new.hair_colors = [:blonde, :red] # => NoMethodError
您可以为属性设置默认值。
module HairColors mattr_writer :hair_colors, default: [:brown, :black, :blonde, :red] mattr_writer(:hair_styles) { [:long, :short] } end class Person include HairColors end Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red] Person.class_variable_get("@@hair_styles") # => [:long, :short]
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attribute_accessors.rb, line 121 def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil, location: nil) raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class? location ||= caller_locations(1, 1).first definition = [] syms.each do |sym| raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym) definition << "def self.#{sym}=(val); @@#{sym} = val; end" if instance_writer && instance_accessor definition << "def #{sym}=(val); @@#{sym} = val; end" end sym_default_value = (block_given? && default.nil?) ? yield : default class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}") end module_eval(definition.join(";"), location.path, location.lineno) end
module_parent() 链接
返回包含此模块的模块(根据其名称)。
module M module N end end X = M::N M::N.module_parent # => M X.module_parent # => M
顶级模块和匿名模块的父对象是 Object。
M.module_parent # => Object Module.new.module_parent # => Object
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/introspection.rb, line 37 def module_parent module_parent_name ? ActiveSupport::Inflector.constantize(module_parent_name) : Object end
module_parent_name() 链接
返回包含此模块的模块的名称。
M::N.module_parent_name # => "M"
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/introspection.rb, line 9 def module_parent_name if defined?(@parent_name) @parent_name else name = self.name return if name.nil? parent_name = name =~ /::[^:]+\z/ ? -$` : nil @parent_name = parent_name unless frozen? parent_name end end
module_parents() 链接
根据其名称返回此模块的所有父模块,按嵌套顺序从内到外排序。接收者不包含在结果中。
module M module N end end X = M::N M.module_parents # => [Object] M::N.module_parents # => [M, Object] X.module_parents # => [M, Object]
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/introspection.rb, line 53 def module_parents parents = [] if module_parent_name parts = module_parent_name.split("::") until parts.empty? parents << ActiveSupport::Inflector.constantize(parts * "::") parts.pop end end parents << Object unless parents.include? Object parents end
redefine_method(method, &block) 链接
如果已存在同名方法,则用传递的块作为其主体来替换现有方法定义。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/redefine_method.rb, line 17 def redefine_method(method, &block) visibility = method_visibility(method) silence_redefinition_of_method(method) define_method(method, &block) send(visibility, method) end
redefine_singleton_method(method, &block) 链接
如果已存在同名单例方法,则用传递的块作为其主体来替换现有单例方法定义。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/redefine_method.rb, line 26 def redefine_singleton_method(method, &block) singleton_class.redefine_method(method, &block) end
remove_possible_method(method) 链接
如果存在,则移除指定名称的方法。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/remove_method.rb, line 7 def remove_possible_method(method) if method_defined?(method) || private_method_defined?(method) undef_method(method) end end
remove_possible_singleton_method(method) 链接
如果存在,则移除指定名称的单例方法。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/remove_method.rb, line 14 def remove_possible_singleton_method(method) singleton_class.remove_possible_method(method) end
silence_redefinition_of_method(method) 链接
标记指定名称的方法为准备重新定义(如果存在)。抑制 Ruby 方法重新定义警告。尽可能使用 redefine_method。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/redefine_method.rb, line 7 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
thread_cattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil) 链接
thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil) 链接
为类属性同时定义类和实例访问器。
class Account thread_mattr_accessor :user end Account.user = "DHH" Account.user # => "DHH" Account.new.user # => "DHH"
与 mattr_accessor 不同,值**不**与子类或父类共享。如果子类更改了值,父类的值不会改变。如果父类更改了值,子类的值也不会改变。
class Customer < Account end Account.user # => "DHH" Customer.user # => nil Customer.user = "Rafael" Customer.user # => "Rafael" Account.user # => "DHH"
要省略实例写入器方法,请传递 instance_writer: false。要省略实例读取器方法,请传递 instance_reader: false。
class Current thread_mattr_accessor :user, instance_writer: false, instance_reader: false end Current.new.user = "DHH" # => NoMethodError Current.new.user # => NoMethodError
或者传递 instance_accessor: false,省略这两个实例方法。
class Current thread_mattr_accessor :user, instance_accessor: false end Current.new.user = "DHH" # => NoMethodError Current.new.user # => NoMethodError
可以使用 :default 选项指定默认值。由于多个线程可以访问默认值,因此非冻结的默认值将被 dup 并冻结。
来源: 显示 | 在 GitHub 上
# File activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb, line 170 def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil) thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default) thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor) end