在`main`和`Object`中定义

时间:2016-01-18 20:14:39

标签: ruby object

它等同于在主环境中定义方法:

def foo; end

并将其定义为Object的实例方法:

class Object
  def foo; end
end

还是有办法区分它们吗?

4 个答案:

答案 0 :(得分:2)

当你没有指定一个对象的单身类时,应该定义方法,即当你不说

def bar.foo; end

但只是

def foo; end

然后该方法在所谓的default definee中定义。通常,默认的definee是词汇封闭的module,但在顶层,Object 默认情况下方法变为private。 (默认的definee也可以通过各种元编程方法来改变。)

因此,您发布的两个代码段不等于,因为第一个会定义private方法,第二个会定义public方法:

def foo; end

method(:foo).owner
# => Object

Object.private_instance_methods(false).include?(:foo)
# => true

但是

class Object; def foo; end end

method(:foo).owner
# => Object

Object.private_instance_methods(false).include?(:foo)
# => false

请注意,在IRb和其他一些REPL中,顶级方法最终可能会public。这是一个众所周知的不兼容性,泄露了这些REPL的私有内部实现细节,并且不是 Ruby语义的官方部分。

答案 1 :(得分:1)

对于我运行一些测试,我看到在main的上下文中定义的方法被设置为private_instance_methods而不是Object的{​​{1}}。这意味着除非您在public_methods上专门定义私有实例方法,否则您应该能够区分它们。

奇怪的是我无法确认其他帖子显示这些是Object的公共方法。如果有人对此有任何见解,我很乐意理解。 (也许它与使用Object?)

有关

我在1.9.3,2.0.0,2.1.5和2.2.3中也是如此,所以我不确定为什么其他人会得到不同的答案。

<强> /scripts/test.rb

pry

(原始输出):

ruby​​ 1.9.3p551(2014-11-13)[i386-mingw32]

puts "RUBY_VERSION: #{RUBY_VERSION}"
puts 'def foo; "in Main";end'
def foo; "in Main";end
puts "foo method response: #{foo}"
puts "Object.private_instance_methods:#{Object.private_instance_methods(false).inspect}"
puts "Trying to call Object.new.foo"
Object.new.foo

ruby​​ 2.0.0p247(2013-06-27)[x64-mingw32]

RUBY_VERSION: 1.9.3
def foo; "in Main";end
foo method response: in Main
Object.private_instance_methods:[:foo]
Trying to call Object.new.foo
/scripts/test.rb:7:in `<main>': private method `foo' called for #<Object:0x640368> (NoMethodError)

ruby​​ 2.1.5p273(2014-11-13修订版48405)[i386-mingw32]

RUBY_VERSION: 2.0.0
def foo; "in Main";end
foo method response: in Main
Object.private_instance_methods:[:foo]
Trying to call Object.new.foo
/scripts/test.rb:7:in `<main>': private method `foo' called for #<Object:0x00000002d34b98> (NoMethodError)

ruby​​ 2.2.3p173(2015-08-18修订版51636)[i386-mingw32]

RUBY_VERSION: 2.1.5
def foo; "in Main";end
foo method response: in Main
Object.private_instance_methods:[:foo]
Trying to call Object.new.foo
/scripts/test.rb:7:in `<main>': private method `foo' called for #<Object:0x2bec750> (NoMethodError)

答案 2 :(得分:0)

Ruby 2.2.1。

self
#=> main
self == Object
#=> false
Object === self
#=> true

所以mainObject的一个实例。

main不等于Object - 这些是不同的事情。

mainObject

中定义的方法
def foo; end
self.class.instance_methods(false)
#=> [:pry, :__binding__, :foo]

class Object
  def bar; end
end  
#=> :bar
self.class.instance_methods(false)
#=> [:pry, :__binding__, :foo, :bar]

可用于mainObject的新实例:

foo
#=> nil
bar
#=> nil
Object.new.foo
#=> nil
Object.new.bar
#=> nil

修改

我们可以检查main中定义的方法的所有者(发生在Object):

method(:foo).owner
#=> Object

这意味着您无法区分mainObject中定义的方法。

在Ruby 2.2.1上,它成为Object的公共实例方法:

Object.public_method_defined?(:foo)
#=> true

答案 3 :(得分:0)

最后,他们似乎是相同的,正如安德烈·迪内科的回答所说的那样。但是,我担心的是在main上定义一个方法应该导致在main的单例类上定义一个实例方法,这与类Object不同。例如,如果我在普通对象上定义一个方法,我可以看到它成为其单例类的实例方法:

s = ""
def s.bar; end
s.singleton_class.instance_methods(false) # => [:bar]

然而,对于main,它是不同的。在main上定义方法不会导致它成为其单例类的实例方法。返回的列表不包括:foo

def foo; end
singleton_class.instance_methods(false)
# => [:inspect, :to_s, :source, :kill, :exit, :conf, :context, :irb_quit, :quit, :irb_print_working_workspace, :irb_cwws, :irb_pwws, :cwws, :pwws, :irb_current_working_binding, :irb_print_working_binding, :irb_cwb, :irb_pwb, :irb_chws, :irb_cws, :chws, :cws, :irb_change_binding, :irb_cb, :cb, :workspaces, :irb_bindings, :bindings, :irb_pushws, :pushws, :irb_push_binding, :irb_pushb, :pushb, :irb_popws, :popws, :irb_pop_binding, :irb_popb, :popb, :jobs, :fg, :help]

所以看起来该方法会跳转main的单例类,并直接在Object上定义。因此,他们无法区分。