类 Object
Object
是所有 Ruby 对象的默认根类。 Object
继承自 BasicObject
,这允许创建替代的对象层次结构。 Object
上的方法对所有类都可用,除非被明确覆盖。
Object
混合了 Kernel
模块,使内置的内核函数在全局范围内可用。尽管 Object
的实例方法是由 Kernel
模块定义的,但为了清晰起见,我们选择在这里记录它们。
在引用从 Object
继承的类中的常量时,您不需要使用完整的命名空间。例如,在 YourClass
中引用 File
将找到顶层的 File
类。
在 Object 方法的描述中,参数 symbol 指的是一个符号,它可以是一个带引号的字符串或一个 Symbol
(例如 :name
)。
内容¶ ↑
首先,看看其他地方。类 Object
-
继承自 类 BasicObject。
-
包含 模块 Kernel。
这里,类 Object 提供了以下方法:
查询¶ ↑
-
!~
: 如果self
不匹配给定对象,则返回true
,否则返回false
。 -
<=>
: 如果self
和给定对象object
是同一个对象,或者self == object
,则返回 0;否则返回nil
。 -
instance_of?
: 返回self
是否是给定类的实例。 -
instance_variable_defined?
: 返回给定的实例变量是否在self
中定义。 -
methods
: 返回self
中公共和受保护方法的符号名称数组。 -
nil?
: 返回false
。 (只有nil
对方法nil?
返回true
。) -
object_id
: 返回对应于self
的整数,该整数对于当前进程是唯一的。 -
private_methods
: 返回self
中私有方法的符号名称数组。 -
protected_methods
: 返回self
中受保护方法的符号名称数组。 -
public_method
: 返回self
中给定公共方法的Method
对象。 -
public_methods
: 返回self
中公共方法的符号名称数组。 -
respond_to?
: 返回self
是否响应给定方法。 -
singleton_class
: 返回self
的单例类。 -
singleton_method
: 返回self
中给定单例方法的Method
对象。 -
singleton_methods
: 返回self
中单例方法的符号名称数组。 -
define_singleton_method
: 为self
中给定的符号方法名和块或 proc 定义一个单例方法。 -
extend
: 将给定的模块包含在self
的单例类中。 -
public_send
: 使用给定的参数调用self
中给定的公共方法。 -
send
: 使用给定的参数调用self
中给定的方法。
实例变量¶ ↑
-
instance_variable_get
: 返回self
中给定实例变量的值,如果实例变量未设置则返回nil
。 -
instance_variable_set
: 将self
中给定实例变量的值设置为给定的对象。 -
instance_variables
: 返回self
中实例变量的符号名称数组。 -
remove_instance_variable
: 从self
中删除命名的实例变量。
其他¶ ↑
-
clone
: 返回self
的浅拷贝,包括单例类和冻结状态。 -
define_singleton_method
: 为self
中给定的符号方法名和块或 proc 定义一个单例方法。 -
dup
: 返回self
的浅层未冻结副本。 -
enum_for
(别名为to_enum
): 使用给定的方法、参数和块为self
返回一个Enumerator
。 -
extend
: 将给定的模块包含在self
的单例类中。 -
freeze
: 阻止对self
的进一步修改。 -
hash
: 返回self
的整数哈希值。 -
inspect
: 返回self
的人类可读字符串表示形式。 -
itself
: 返回self
。 -
method_missing
: 当在self
上调用未定义的方法时,会调用Method
。 -
public_send
: 使用给定的参数调用self
中给定的公共方法。 -
send
: 使用给定的参数调用self
中给定的方法。 -
to_s
: 返回self
的字符串表示形式。
常量
- ARGF
ARGF
是一个流,专为处理作为命令行参数给出的文件或通过STDIN
传入的文件的脚本而设计。有关更多详细信息,请参阅
ARGF
(类)。- ARGV
ARGV
包含用于运行 ruby 的命令行参数。可以使用像
OptionParser
这样的库来处理命令行参数。- CROSS_COMPILING
- DATA
DATA
是一个File
,其中包含执行文件的 data 部分。要创建 data 部分,请使用__END__
$ cat t.rb puts DATA.gets __END__ hello world! $ ruby t.rb hello world!
- ENV
ENV 是环境变量的类似 Hash 的访问器。
有关更多详细信息,请参阅
ENV
(类)。- RUBY_COPYRIGHT
ruby 的版权字符串
- RUBY_DESCRIPTION
完整的 ruby 版本字符串,例如
ruby -v
打印- RUBY_ENGINE
此 ruby 使用的引擎或解释器。
- RUBY_ENGINE_VERSION
此 ruby 使用的引擎或解释器的版本。
- RUBY_PATCHLEVEL
此 ruby 的补丁级别。如果这是 ruby 的开发版本,则补丁级别将为 -1
- RUBY_PLATFORM
此 ruby 的平台
- RUBY_RELEASE_DATE
此 ruby 发布的日期
- RUBY_REVISION
此 ruby 的 GIT 提交哈希。
- RUBY_VERSION
正在运行的 ruby 版本
- Readline
- RubyLex
- STDERR
保存原始 stderr
- STDIN
保存原始 stdin
- STDOUT
保存原始 stdout
- TOPLEVEL_BINDING
顶层作用域的
Binding
- WIN32OLE_EVENT
- WIN32OLE_METHOD
- WIN32OLE_PARAM
- WIN32OLE_RECORD
- WIN32OLE_TYPE
- WIN32OLE_TYPELIB
- WIN32OLE_VARIABLE
- WIN32OLE_VARIANT
公共类方法
# File ext/psych/lib/psych/core_ext.rb, line 3 def self.yaml_tag url Psych.add_tag(url, self) end
公共实例方法
如果两个对象不匹配(使用 =~ 方法),则返回 true,否则返回 false。
static VALUE rb_obj_not_match(VALUE obj1, VALUE obj2) { VALUE result = rb_funcall(obj1, id_match, 1, obj2); return rb_obj_not(result); }
如果 obj
和 other
是同一个对象或 obj == other
,则返回 0,否则返回 nil。
The <=>
用于各种方法比较对象,例如 Enumerable#sort
,Enumerable#max
等。
您对 <=>
的实现应该返回以下值之一:-1、0、1 或 nil。-1 表示 self 小于 other。0 表示 self 等于 other。1 表示 self 大于 other。Nil 表示两个值无法比较。
当您定义 <=>
时,您可以包含 Comparable
以获得方法 <=、<、==
、>=、> 和 between?
static VALUE rb_obj_cmp(VALUE obj1, VALUE obj2) { if (rb_equal(obj1, obj2)) return INT2FIX(0); return Qnil; }
将 args
传递给 CSV::instance
。
CSV("CSV,data").read #=> [["CSV", "data"]]
如果给定一个代码块,则将实例传递给代码块,并且返回值将成为代码块的返回值。
CSV("CSV,data") { |c| c.read.any? { |a| a.include?("data") } } #=> true CSV("CSV,data") { |c| c.read.any? { |a| a.include?("zombies") } } #=> false
也可以给出 CSV
选项。
io = StringIO.new CSV(io, col_sep: ";") { |csv| csv << ["a", "b", "c"] }
此 API 不支持 Ractor。
# File lib/csv.rb, line 2876 def CSV(*args, **options, &block) CSV.instance(*args, **options, &block) end
此库的主要接口。用于在定义类时设置委托。
class MyClass < DelegateClass(ClassToDelegateTo) # Step 1 def initialize super(obj_of_ClassToDelegateTo) # Step 2 end end
或
MyClass = DelegateClass(ClassToDelegateTo) do # Step 1 def initialize super(obj_of_ClassToDelegateTo) # Step 2 end end
以下是从 Tempfile
中使用的示例,它实际上是一个 File
对象,但对存储位置和何时应删除 File
有几个特殊规则。这使得它成为使用委托的教科书式完美示例。
class Tempfile < DelegateClass(File) # constant and class member data initialization... def initialize(basename, tmpdir=Dir::tmpdir) # build up file path/name in var tmpname... @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600) # ... super(@tmpfile) # below this point, all methods of File are supported... end # ... end
# File lib/delegate.rb, line 394 def DelegateClass(superclass, &block) klass = Class.new(Delegator) ignores = [*::Delegator.public_api, :to_s, :inspect, :=~, :!~, :===] protected_instance_methods = superclass.protected_instance_methods protected_instance_methods -= ignores public_instance_methods = superclass.public_instance_methods public_instance_methods -= ignores klass.module_eval do def __getobj__ # :nodoc: unless defined?(@delegate_dc_obj) return yield if block_given? __raise__ ::ArgumentError, "not delegated" end @delegate_dc_obj end def __setobj__(obj) # :nodoc: __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj) @delegate_dc_obj = obj end protected_instance_methods.each do |method| define_method(method, Delegator.delegating_block(method)) protected method end public_instance_methods.each do |method| define_method(method, Delegator.delegating_block(method)) end end klass.define_singleton_method :public_instance_methods do |all=true| super(all) | superclass.public_instance_methods end klass.define_singleton_method :protected_instance_methods do |all=true| super(all) | superclass.protected_instance_methods end klass.define_singleton_method :instance_methods do |all=true| super(all) | superclass.instance_methods end klass.define_singleton_method :public_instance_method do |name| super(name) rescue NameError raise unless self.public_instance_methods.include?(name) superclass.public_instance_method(name) end klass.define_singleton_method :instance_method do |name| super(name) rescue NameError raise unless self.instance_methods.include?(name) superclass.instance_method(name) end klass.module_eval(&block) if block return klass end
以线程安全的方式通过 name
返回一个 Digest
子类,即使涉及按需加载。
require 'digest' Digest("MD5") # => Digest::MD5 Digest(:SHA256) # => Digest::SHA256 Digest(:Foo) # => LoadError: library not found for class Digest::Foo -- digest/foo
# File ext/digest/lib/digest.rb, line 110 def Digest(name) const = name.to_sym Digest::REQUIRE_MUTEX.synchronize { # Ignore autoload's because it is void when we have #const_missing Digest.const_missing(const) } rescue LoadError # Constants do not necessarily rely on digest/*. if Digest.const_defined?(const) Digest.const_get(const) else raise end end
在接收者中定义一个公共单例方法。method 参数可以是 Proc
、Method
或 UnboundMethod
对象。如果指定了块,则将其用作方法体。如果块或方法具有参数,则将其用作方法参数。
class A class << self def class_name to_s end end end A.define_singleton_method(:who_am_i) do "I am: #{class_name}" end A.who_am_i # ==> "I am: A" guy = "Bob" guy.define_singleton_method(:hello) { "#{self}: Hello there!" } guy.hello #=> "Bob: Hello there!" chris = "Chris" chris.define_singleton_method(:greet) {|greeting| "#{greeting}, I'm Chris!" } chris.greet("Hi") #=> "Hi, I'm Chris!"
static VALUE rb_obj_define_method(int argc, VALUE *argv, VALUE obj) { VALUE klass = rb_singleton_class(obj); const rb_scope_visibility_t scope_visi = {METHOD_VISI_PUBLIC, FALSE}; return rb_mod_define_method_with_visibility(argc, argv, klass, &scope_visi); }
在给定端口上写入 self
1.display "cat".display [ 4, 5, 6 ].display puts
输出
1cat[4, 5, 6]
static VALUE rb_obj_display(int argc, VALUE *argv, VALUE self) { VALUE out; out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]); rb_io_write(out, self); return Qnil; }
生成obj的浅拷贝——obj的实例变量被复制,但它们引用的对象没有被复制。
此方法可能具有特定于类的行为。如果是这样,该行为将在类的 #initialize_copy
方法下进行记录。
关于 dup 与 clone¶ ↑
通常,clone
和 dup
在子类中可能具有不同的语义。虽然 clone
用于复制对象,包括其内部状态,但 dup
通常使用子类对象的类来创建新实例。
使用 dup
时,不会复制对象已扩展的任何模块。
class Klass attr_accessor :str end module Foo def foo; 'foo'; end end s1 = Klass.new #=> #<Klass:0x401b3a38> s1.extend(Foo) #=> #<Klass:0x401b3a38> s1.foo #=> "foo" s2 = s1.clone #=> #<Klass:0x401be280> s2.foo #=> "foo" s3 = s1.dup #=> #<Klass:0x401c1084> s3.foo #=> NoMethodError: undefined method `foo' for #<Klass:0x401c1084>
VALUE rb_obj_dup(VALUE obj) { VALUE dup; if (special_object_p(obj)) { return obj; } dup = rb_obj_alloc(rb_obj_class(obj)); return rb_obj_dup_setup(obj, dup); }
创建一个新的 Enumerator
,它将通过在 obj
上调用 method
来枚举,如果存在,则传递 args
。方法yield的内容成为枚举器的值。
如果给定块,它将用于计算枚举器的大小,而无需迭代它(参见 Enumerator#size
)。
示例¶ ↑
str = "xyz" enum = str.enum_for(:each_byte) enum.each { |b| puts b } # => 120 # => 121 # => 122 # protect an array from being modified by some_method a = [1, 2, 3] some_method(a.to_enum) # String#split in block form is more memory-effective: very_large_string.split("|") { |chunk| return chunk if chunk.include?('DATE') } # This could be rewritten more idiomatically with to_enum: very_large_string.to_enum(:split, "|").lazy.grep(/DATE/).first
在为泛型 Enumerable
定义方法时,通常会在没有传递块的情况下调用 to_enum
。
以下是一个示例,包含参数传递和大小块
module Enumerable # a generic method to repeat the values of any enumerable def repeat(n) raise ArgumentError, "#{n} is negative!" if n < 0 unless block_given? return to_enum(__method__, n) do # __method__ is :repeat here sz = size # Call size and multiply by n... sz * n if sz # but return nil if size itself is nil end end each do |*val| n.times { yield *val } end end end %i[hello world].repeat(2) { |w| puts w } # => Prints 'hello', 'hello', 'world', 'world' enum = (1..14).repeat(3) # => returns an Enumerator when called without a block enum.first(4) # => [1, 1, 1, 2] enum.size # => 42
相等性 - 在 Object
级别,==
仅当 obj
和 other
是同一个对象时才返回 true
。通常,此方法在子类中被重写以提供特定于类的含义。
与 ==
不同,equal?
方法不应被子类重写,因为它用于确定对象标识(即,a.equal?(b)
当且仅当 a
与 b
是同一个对象时)。
obj = "a" other = obj.dup obj == other #=> true obj.equal? other #=> false obj.equal? obj #=> true
eql?
方法如果 obj
和 other
指向同一个哈希键,则返回 true
。这由 Hash
用于测试成员的相等性。对于任何一对 eql?
返回 true
的对象,这两个对象的 hash
值必须相等。因此,任何重写 eql?
的子类也应该相应地重写 hash
。
对于 Object
类的对象,eql?
等同于 ==
。子类通常通过将 eql?
设为其重写的 ==
方法的别名来延续这一传统,但也有例外。例如,Numeric
类型在 ==
中执行类型转换,但在 eql?
中不执行类型转换,因此
1 == 1.0 #=> true 1.eql? 1.0 #=> false
VALUE rb_obj_equal(VALUE obj1, VALUE obj2) { return RBOOL(obj1 == obj2); }
将参数中给出的每个模块的实例方法添加到obj中。
module Mod def hello "Hello from Mod.\n" end end class Klass def hello "Hello from Klass.\n" end end k = Klass.new k.hello #=> "Hello from Klass.\n" k.extend(Mod) #=> #<Klass:0x401b3bc8> k.hello #=> "Hello from Mod.\n"
static VALUE rb_obj_extend(int argc, VALUE *argv, VALUE obj) { int i; ID id_extend_object, id_extended; CONST_ID(id_extend_object, "extend_object"); CONST_ID(id_extended, "extended"); rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); for (i = 0; i < argc; i++) { Check_Type(argv[i], T_MODULE); if (FL_TEST(argv[i], RMODULE_IS_REFINEMENT)) { rb_raise(rb_eTypeError, "Cannot extend object with refinement"); } } while (argc--) { rb_funcall(argv[argc], id_extend_object, 1, obj); rb_funcall(argv[argc], id_extended, 1, obj); } return obj; }
阻止对obj的进一步修改。如果尝试修改,将引发 FrozenError
。无法解冻已冻结的对象。另请参见 Object#frozen?
。
此方法返回自身。
a = [ "a", "b", "c" ] a.freeze a << "z"
产生
prog.rb:3:in `<<': can't modify frozen Array (FrozenError) from prog.rb:3
以下类的对象始终被冻结:Integer
、Float
、Symbol
。
VALUE rb_obj_freeze(VALUE obj) { if (!OBJ_FROZEN(obj)) { OBJ_FREEZE(obj); if (SPECIAL_CONST_P(obj)) { rb_bug("special consts should be frozen."); } } return obj; }
为该对象生成一个 Integer
哈希值。此函数必须具有以下属性:a.eql?(b)
意味着 a.hash == b.hash
。
哈希值与 eql?
一起由 Hash
类使用,以确定两个对象是否引用相同的哈希键。任何超过 Integer
容量的哈希值将在使用前被截断。
对象的哈希值可能在 Ruby 的调用或实现之间不相同。如果您需要跨 Ruby 调用和实现的稳定标识符,则需要使用自定义方法生成一个。
某些核心类(例如 Integer
)使用内置的哈希计算,并且在用作哈希键时不会调用 hash
方法。
在基于多个值实现自己的 hash
时,最佳实践是使用数组的哈希码组合类和任何值
例如
def hash [self.class, a, b, c].hash end
这样做的原因是 Array#hash
方法已经具有安全有效地组合多个哈希值的逻辑。
VALUE rb_obj_hash(VALUE obj) { long hnum = any_hash(obj, objid_hash); return ST2FIX(hnum); }
返回一个包含obj的人类可读表示的字符串。默认的 inspect
显示对象的类名、其内存地址的编码以及实例变量及其值的列表(通过对每个实例变量调用 inspect
)。用户定义的类应该覆盖此方法,以提供obj的更好表示。在覆盖此方法时,它应该返回一个编码与默认外部编码兼容的字符串。
[ 1, 2, 3..4, 'five' ].inspect #=> "[1, 2, 3..4, \"five\"]" Time.new.inspect #=> "2008-03-08 19:43:39 +0900" class Foo end Foo.new.inspect #=> "#<Foo:0x0300c868>" class Bar def initialize @bar = 1 end end Bar.new.inspect #=> "#<Bar:0x0300c868 @bar=1>"
static VALUE rb_obj_inspect(VALUE obj) { if (rb_ivar_count(obj) > 0) { VALUE str; VALUE c = rb_class_name(CLASS_OF(obj)); str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj); return rb_exec_recursive(inspect_obj, obj, str); } else { return rb_any_to_s(obj); } }
如果obj是给定类的实例,则返回true
。另请参见 Object#kind_of?
。
class A; end class B < A; end class C < B; end b = B.new b.instance_of? A #=> false b.instance_of? B #=> true b.instance_of? C #=> false
VALUE rb_obj_is_instance_of(VALUE obj, VALUE c) { c = class_or_module_required(c); return RBOOL(rb_obj_class(obj) == c); }
如果给定的实例变量在 obj 中定义,则返回 true
。 String
参数将转换为符号。
class Fred def initialize(p1, p2) @a, @b = p1, p2 end end fred = Fred.new('cat', 99) fred.instance_variable_defined?(:@a) #=> true fred.instance_variable_defined?("@b") #=> true fred.instance_variable_defined?("@c") #=> false
static VALUE rb_obj_ivar_defined(VALUE obj, VALUE iv) { ID id = id_for_var(obj, iv, instance); if (!id) { return Qfalse; } return rb_ivar_defined(obj, id); }
返回给定实例变量的值,如果实例变量未设置,则返回 nil。 对于常规实例变量,应包含变量名称的 @
部分。 如果提供的符号不是有效的实例变量名称,则会抛出 NameError
异常。 String
参数将转换为符号。
class Fred def initialize(p1, p2) @a, @b = p1, p2 end end fred = Fred.new('cat', 99) fred.instance_variable_get(:@a) #=> "cat" fred.instance_variable_get("@b") #=> 99
static VALUE rb_obj_ivar_get(VALUE obj, VALUE iv) { ID id = id_for_var(obj, iv, instance); if (!id) { return Qnil; } return rb_ivar_get(obj, id); }
将 symbol 指定的实例变量设置为给定的对象。 这可能会绕过类作者的封装意图,因此应谨慎使用。 变量不必在此调用之前存在。 如果实例变量名称作为字符串传递,则该字符串将转换为符号。
class Fred def initialize(p1, p2) @a, @b = p1, p2 end end fred = Fred.new('cat', 99) fred.instance_variable_set(:@a, 'dog') #=> "dog" fred.instance_variable_set(:@c, 'cat') #=> "cat" fred.inspect #=> "#<Fred:0x401b3da8 @a=\"dog\", @b=99, @c=\"cat\">"
static VALUE rb_obj_ivar_set_m(VALUE obj, VALUE iv, VALUE val) { ID id = id_for_var(obj, iv, instance); if (!id) id = rb_intern_str(iv); return rb_ivar_set(obj, id, val); }
返回接收者的实例变量名称数组。 请注意,仅仅定义一个访问器不会创建相应的实例变量。
class Fred attr_accessor :a1 def initialize @iv = 3 end end Fred.new.instance_variables #=> [:@iv]
VALUE rb_obj_instance_variables(VALUE obj) { VALUE ary; ary = rb_ary_new(); rb_ivar_foreach(obj, ivar_i, ary); return ary; }
如果 class 是 obj 的类,或者 class 是 obj 的超类之一或包含在 obj 中的模块,则返回 true
。
module M; end class A include M end class B < A; end class C < B; end b = B.new b.is_a? A #=> true b.is_a? B #=> true b.is_a? C #=> false b.is_a? M #=> true b.kind_of? A #=> true b.kind_of? B #=> true b.kind_of? C #=> false b.kind_of? M #=> true
返回接收者。
string = "my string" string.itself.object_id == string.object_id #=> true
static VALUE rb_obj_itself(VALUE obj) { return obj; }
如果 class 是 obj 的类,或者 class 是 obj 的超类之一或包含在 obj 中的模块,则返回 true
。
module M; end class A include M end class B < A; end class C < B; end b = B.new b.is_a? A #=> true b.is_a? B #=> true b.is_a? C #=> false b.is_a? M #=> true b.kind_of? A #=> true b.kind_of? B #=> true b.kind_of? C #=> false b.kind_of? M #=> true
VALUE rb_obj_is_kind_of(VALUE obj, VALUE c) { VALUE cl = CLASS_OF(obj); RUBY_ASSERT(RB_TYPE_P(cl, T_CLASS)); // Fastest path: If the object's class is an exact match we know `c` is a // class without checking type and can return immediately. if (cl == c) return Qtrue; // Note: YJIT needs this function to never allocate and never raise when // `c` is a class or a module. if (LIKELY(RB_TYPE_P(c, T_CLASS))) { // Fast path: Both are T_CLASS return class_search_class_ancestor(cl, c); } else if (RB_TYPE_P(c, T_ICLASS)) { // First check if we inherit the includer // If we do we can return true immediately VALUE includer = RCLASS_INCLUDER(c); if (cl == includer) return Qtrue; // Usually includer is a T_CLASS here, except when including into an // already included Module. // If it is a class, attempt the fast class-to-class check and return // true if there is a match. if (RB_TYPE_P(includer, T_CLASS) && class_search_class_ancestor(cl, includer)) return Qtrue; // We don't include the ICLASS directly, so must check if we inherit // the module via another include return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c))); } else if (RB_TYPE_P(c, T_MODULE)) { // Slow path: check each ancestor in the linked list and its method table return RBOOL(class_search_ancestor(cl, RCLASS_ORIGIN(c))); } else { rb_raise(rb_eTypeError, "class or module required"); UNREACHABLE_RETURN(Qfalse); } }
在obj中查找名为方法的接收器,返回一个Method
对象(或引发NameError
)。Method
对象在obj的对象实例中充当闭包,因此实例变量和self
的值仍然可用。
class Demo def initialize(n) @iv = n end def hello() "Hello, @iv = #{@iv}" end end k = Demo.new(99) m = k.method(:hello) m.call #=> "Hello, @iv = 99" l = Demo.new('Fred') m = l.method("hello") m.call #=> "Hello, @iv = Fred"
请注意,Method
实现了to_proc
方法,这意味着它可以与迭代器一起使用。
[ 1, 2, 3 ].each(&method(:puts)) # => prints 3 lines to stdout out = File.open('test.txt', 'w') [ 1, 2, 3 ].each(&out.method(:puts)) # => prints 3 lines to file require 'date' %w[2017-03-01 2017-03-02].collect(&Date.method(:parse)) #=> [#<Date: 2017-03-01 ((2457814j,0s,0n),+0s,2299161j)>, #<Date: 2017-03-02 ((2457815j,0s,0n),+0s,2299161j)>]
VALUE rb_obj_method(VALUE obj, VALUE vid) { return obj_method(obj, vid, FALSE); }
返回obj的公共和受保护方法的名称列表。这将包括obj的祖先中可访问的所有方法。如果可选参数为false
,则返回obj的公共和受保护单例方法的数组,该数组不包括obj中包含的模块中的方法。
class Klass def klass_method() end end k = Klass.new k.methods[0..9] #=> [:klass_method, :nil?, :===, # :==~, :!, :eql? # :hash, :<=>, :class, :singleton_class] k.methods.length #=> 56 k.methods(false) #=> [] def k.singleton_method; end k.methods(false) #=> [:singleton_method] module M123; def m123; end end k.extend M123 k.methods(false) #=> [:singleton_method]
VALUE rb_obj_methods(int argc, const VALUE *argv, VALUE obj) { rb_check_arity(argc, 0, 1); if (argc > 0 && !RTEST(argv[0])) { return rb_obj_singleton_methods(argc, argv, obj); } return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_i); }
只有nil对象对nil?
响应true
。
Object.new.nil? #=> false nil.nil? #=> true
VALUE rb_false(VALUE obj) { return Qfalse; }
返回obj
的整数标识符。
对于给定对象,对object_id
的所有调用都将返回相同的数字,并且没有两个活动对象将共享一个id。
注意:为了优化,某些内置类对象会被重复使用。对于立即值和冻结字符串文字来说就是这样。
BasicObject
实现了__id__
,Kernel
实现了object_id
。
立即值不是通过引用传递,而是通过值传递:nil
、true
、false
、Fixnums、Symbols和一些Floats。
Object.new.object_id == Object.new.object_id # => false (21 * 2).object_id == (21 * 2).object_id # => true "hello".object_id == "hello".object_id # => false "hi".freeze.object_id == "hi".freeze.object_id # => true
VALUE rb_obj_id(VALUE obj) { /* * 32-bit VALUE space * MSB ------------------------ LSB * false 00000000000000000000000000000000 * true 00000000000000000000000000000010 * nil 00000000000000000000000000000100 * undef 00000000000000000000000000000110 * symbol ssssssssssssssssssssssss00001110 * object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE)) * fixnum fffffffffffffffffffffffffffffff1 * * object_id space * LSB * false 00000000000000000000000000000000 * true 00000000000000000000000000000010 * nil 00000000000000000000000000000100 * undef 00000000000000000000000000000110 * symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S = s...s * A + 4) * object oooooooooooooooooooooooooooooo0 o...o % A = 0 * fixnum fffffffffffffffffffffffffffffff1 bignum if required * * where A = sizeof(RVALUE)/4 * * sizeof(RVALUE) is * 20 if 32-bit, double is 4-byte aligned * 24 if 32-bit, double is 8-byte aligned * 40 if 64-bit */ return rb_find_object_id(obj, cached_object_id); }
返回obj可访问的私有方法列表。如果all参数设置为false
,则只列出接收器中的那些方法。
VALUE rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj) { return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_priv_i); }
返回obj可访问的受保护方法列表。如果all参数设置为false
,则只列出接收器中的那些方法。
VALUE rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj) { return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_prot_i); }
类似于 method,仅搜索公共方法。
VALUE rb_obj_public_method(VALUE obj, VALUE vid) { return obj_method(obj, vid, TRUE); }
返回 obj 可访问的公共方法列表。如果 all 参数设置为 false
,则只列出接收器中的方法。
VALUE rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj) { return class_instance_method_list(argc, argv, CLASS_OF(obj), 1, ins_methods_pub_i); }
调用由 symbol 标识的方法,并将任何指定的参数传递给它。与 send 不同,public_send
仅调用公共方法。当方法由字符串标识时,字符串将转换为符号。
1.public_send(:puts, "hello") # causes NoMethodError
static VALUE rb_f_public_send(int argc, VALUE *argv, VALUE recv) { return send_internal_kw(argc, argv, recv, CALL_PUBLIC); }
从 obj 中删除命名的实例变量,并返回该变量的值。 String
参数将转换为符号。
class Dummy attr_reader :var def initialize @var = 99 end def remove remove_instance_variable(:@var) end end d = Dummy.new d.var #=> 99 d.remove #=> 99 d.var #=> nil
VALUE rb_obj_remove_instance_variable(VALUE obj, VALUE name) { const ID id = id_for_var(obj, name, an, instance); // Frozen check comes here because it's expected that we raise a // NameError (from the id_for_var check) before we raise a FrozenError rb_check_frozen(obj); if (id) { VALUE val = rb_ivar_delete(obj, id, Qundef); if (val != Qundef) return val; } rb_name_err_raise("instance variable %1$s not defined", obj, name); UNREACHABLE_RETURN(Qnil); }
如果 obj 响应给定方法,则返回 true
。只有当可选的第二个参数计算结果为 true
时,私有和受保护的方法才会包含在搜索中。
如果方法未实现,例如 Windows 上的 Process.fork
,GNU/Linux 上的 File.lchmod
等,则返回 false。
如果方法未定义,则调用 respond_to_missing?
方法并返回结果。
当方法名称参数以字符串形式给出时,字符串将转换为符号。
static VALUE obj_respond_to(int argc, VALUE *argv, VALUE obj) { VALUE mid, priv; ID id; rb_execution_context_t *ec = GET_EC(); rb_scan_args(argc, argv, "11", &mid, &priv); if (!(id = rb_check_id(&mid))) { VALUE ret = basic_obj_respond_to_missing(ec, CLASS_OF(obj), obj, rb_to_symbol(mid), priv); if (UNDEF_P(ret)) ret = Qfalse; return ret; } return RBOOL(basic_obj_respond_to(ec, obj, id, !RTEST(priv))); }
不要直接使用此方法。
挂钩方法,用于返回 obj 是否可以响应 id 方法。
当方法名称参数以字符串形式给出时,字符串将转换为符号。
参见 respond_to?
和 BasicObject
的示例。
static VALUE obj_respond_to_missing(VALUE obj, VALUE mid, VALUE priv) { return Qfalse; }
调用由symbol标识的方法,并将指定的任何参数传递给它。当方法由字符串标识时,字符串将被转换为符号。
BasicObject
实现 __send__
,Kernel
实现 send
。当obj具有与Socket
相同的名称时,__send__
比 send
更安全。另请参见 public_send
。
class Klass def hello(*args) "Hello " + args.join(' ') end end k = Klass.new k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
VALUE rb_f_send(int argc, VALUE *argv, VALUE recv) { return send_internal_kw(argc, argv, recv, CALL_FCALL); }
返回obj的单例类。如果obj没有单例类,此方法将创建一个新的单例类。
如果obj是nil
、true
或false
,它将分别返回NilClass
、TrueClass
或FalseClass
。如果obj是Integer
、Float
或Symbol
,它将引发TypeError
。
Object.new.singleton_class #=> #<Class:#<Object:0xb7ce1e24>> String.singleton_class #=> #<Class:String> nil.singleton_class #=> NilClass
static VALUE rb_obj_singleton_class(VALUE obj) { return rb_singleton_class(obj); }
类似于method,仅搜索单例方法。
class Demo def initialize(n) @iv = n end def hello() "Hello, @iv = #{@iv}" end end k = Demo.new(99) def k.hi "Hi, @iv = #{@iv}" end m = k.singleton_method(:hi) m.call #=> "Hi, @iv = 99" m = k.singleton_method(:hello) #=> NameError
VALUE rb_obj_singleton_method(VALUE obj, VALUE vid) { VALUE klass = rb_singleton_class_get(obj); ID id = rb_check_id(&vid); if (NIL_P(klass) || NIL_P(klass = RCLASS_ORIGIN(klass)) || !NIL_P(rb_special_singleton_class(obj))) { /* goto undef; */ } else if (! id) { VALUE m = mnew_missing_by_name(klass, obj, &vid, FALSE, rb_cMethod); if (m) return m; /* else goto undef; */ } else { const rb_method_entry_t *me = rb_method_entry_at(klass, id); vid = ID2SYM(id); if (UNDEFINED_METHOD_ENTRY_P(me)) { /* goto undef; */ } else if (UNDEFINED_REFINED_METHOD_P(me->def)) { /* goto undef; */ } else { return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE); } } /* undef: */ rb_name_err_raise("undefined singleton method `%1$s' for `%2$s'", obj, vid); UNREACHABLE_RETURN(Qundef); }
返回obj的单例方法名称数组。如果可选的all参数为true,则列表将包含包含在obj中的模块中的方法。仅返回公共和受保护的单例方法。
module Other def three() end end class Single def Single.four() end end a = Single.new def a.one() end class << a include Other def two() end end Single.singleton_methods #=> [:four] a.singleton_methods(false) #=> [:two, :one] a.singleton_methods #=> [:two, :one, :three]
VALUE rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj) { VALUE ary, klass, origin; struct method_entry_arg me_arg; struct rb_id_table *mtbl; int recur = TRUE; if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]); if (RB_TYPE_P(obj, T_CLASS) && FL_TEST(obj, FL_SINGLETON)) { rb_singleton_class(obj); } klass = CLASS_OF(obj); origin = RCLASS_ORIGIN(klass); me_arg.list = st_init_numtable(); me_arg.recur = recur; if (klass && FL_TEST(klass, FL_SINGLETON)) { if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg); klass = RCLASS_SUPER(klass); } if (recur) { while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) { if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg); klass = RCLASS_SUPER(klass); } } ary = rb_ary_new2(me_arg.list->num_entries); st_foreach(me_arg.list, ins_methods_i, ary); st_free_table(me_arg.list); return ary; }
创建一个新的 Enumerator
,它将通过在 obj
上调用 method
来枚举,如果存在,则传递 args
。方法yield的内容成为枚举器的值。
如果给定块,它将用于计算枚举器的大小,而无需迭代它(参见 Enumerator#size
)。
示例¶ ↑
str = "xyz" enum = str.enum_for(:each_byte) enum.each { |b| puts b } # => 120 # => 121 # => 122 # protect an array from being modified by some_method a = [1, 2, 3] some_method(a.to_enum) # String#split in block form is more memory-effective: very_large_string.split("|") { |chunk| return chunk if chunk.include?('DATE') } # This could be rewritten more idiomatically with to_enum: very_large_string.to_enum(:split, "|").lazy.grep(/DATE/).first
在为泛型 Enumerable
定义方法时,通常会在没有传递块的情况下调用 to_enum
。
以下是一个示例,包含参数传递和大小块
module Enumerable # a generic method to repeat the values of any enumerable def repeat(n) raise ArgumentError, "#{n} is negative!" if n < 0 unless block_given? return to_enum(__method__, n) do # __method__ is :repeat here sz = size # Call size and multiply by n... sz * n if sz # but return nil if size itself is nil end end each do |*val| n.times { yield *val } end end end %i[hello world].repeat(2) { |w| puts w } # => Prints 'hello', 'hello', 'world', 'world' enum = (1..14).repeat(3) # => returns an Enumerator when called without a block enum.first(4) # => [1, 1, 1, 2] enum.size # => 42
static VALUE obj_to_enum(int argc, VALUE *argv, VALUE obj) { VALUE enumerator, meth = sym_each; if (argc > 0) { --argc; meth = *argv++; } enumerator = rb_enumeratorize_with_size(obj, meth, argc, argv, 0); if (rb_block_given_p()) { RB_OBJ_WRITE(enumerator, &enumerator_ptr(enumerator)->size, rb_block_proc()); } return enumerator; }
返回表示obj的字符串。默认的to_s
打印对象的类和对象 ID 的编码。作为特殊情况,作为 Ruby 程序初始执行上下文的顶级对象返回“main”。
VALUE rb_any_to_s(VALUE obj) { VALUE str; VALUE cname = rb_class_name(CLASS_OF(obj)); str = rb_sprintf("#<%"PRIsVALUE":%p>", cname, (void*)obj); return str; }
将对象转换为YAML
。有关可用options
的更多信息,请参见Psych.dump
。
# File ext/psych/lib/psych/core_ext.rb, line 12 def to_yaml options = {} Psych.dump self, options end
仅在您需要 IRB::XMP
标准库时才可用的便捷方法。
创建一个新的 XMP
对象,使用给定的表达式作为 exps
参数,可选绑定作为 bind
或使用顶层绑定。然后使用 :XMP
提示模式评估给定的表达式。
例如
require 'irb/xmp' ctx = binding xmp 'foo = "bar"', ctx #=> foo = "bar" #==>"bar" ctx.eval 'foo' #=> "bar"
有关更多信息,请参见 XMP.new
。
# File lib/irb/xmp.rb, line 159 def xmp(exps, bind = nil) bind = IRB::Frame.top(1) unless bind xmp = XMP.new(bind) xmp.puts exps xmp end