2012-04-25 53 views
4

我红宝石1.8.7,为什么我可以在main中使用require,但是不能使用self.require?Ruby需要和self.require

require('date') # ok 
self.require('date') 
NoMethodError: private method `require' called for main:Object 
from (irb):22 
from /usr/lib/ruby/1.8/date.rb:437 

众所周知,主要是Object类: IRB(主要):045:0>自 =>主

irb(main):043:0> self.class 
=> Object 

但我发现它有内核的mixin:

irb(main):042:0> self.class.included_modules 
=> [Kernel] 

此外,我发现要求是自己的私人方法:

irb(main):037:0> self.private_methods 
=> [... "require", ...] 

同样的方式,我不能用self.attr_accessor:

irb(main):051:0> class X 
irb(main):052:1> self.attr_accessor(:ssss) 
irb(main):053:1> end 
NoMethodError: private method `attr_accessor' called for X:Class 
from (irb):52 
from /usr/lib/ruby/1.8/date.rb:437 

如何它的发生?有人可以澄清这个问题吗?

+0

此外,我不能使用自我。类定义中的attr_accessor: – user1355943 2012-04-25 11:10:36

+0

'self.send(:require,'date')' – fl00r 2012-04-25 12:43:58

回答

2

检查以下简单的例子:

class Person 
    def initialize(age) 
    @age = age 
    end 

    def compare_to(other) 
    # we're calling a protected method on the other instance of the current class 
    age <=> other.age 
    end 

    # it will not work if we use 'private' here 
    protected 

    def age 
    @age 
    end 
end 

在Ruby中,我们有隐性和显性方法接收器,请检查下面的代码片段:

class Foo 
    def a; end 

    # call 'a' with explicit 'self' as receiver 
    def b; self.a; end 

    # call 'a' with implicit 'self' as receiver 
    def c; a; end 
end 
红宝石

基本上如果一个方法是private它可以仅在implicit接收器(不含self关键字)上被调用。在你的例子中,require是一个private方法,定义了Kernel模块,它只能在implicit主题上调用。

2

require是一种私人方法。所以,你不能把它仅仅作为

Object.require 'date' 

但是你可以使用Ruby的eval叫它/发送方法:

Object.send(:require, 'date') 
# or 
self.send(:require', 'date') 

什么其实很呈三角

require 'date' 

例如pry console将其解释为

instance_exec do 
    require 'date' 
end 

我相信Ruby解释器的功能几乎相同。它会将任何顶级命令作为instance_exec块传递给Object,后者可以调用任何私有方法。

0

私有方法只能用隐式接收方来调用。这意味着require将工作,但self.require不会。

可以在self上调用受保护的方法,并且可以在任何对象上显式调用公共方法。

这些是唯一的限制。是的,您可以在子类中使用私有方法,并且send将绕过任何和所有访问控制。

+1

private setters *可以被称为'self.attr =:foo',事实上,它们*有*被这样调用,因为'attar =:foo'是一个局部变量赋值。 – 2012-04-26 01:12:34

+0

@JörgWMittag,你说得对。这是否适用于任何以'='结尾的方法,或仅由'attr_writer'和'attr_accessor'定义的setters?你能提供一个链接到实现这种行为的来源吗? – 2012-04-26 11:19:12

+1

'attr_writer'绝对没有什么特别的。实际上,它实际上只是'class Module; def attr_writer(* attrs)attrs.each do | attr | define_method(:“#{atttr} =”)do | val | instance_variable_set(:“@#{attr}”,val)end end end end'。所以,是的,这适用于任何以'='结尾的方法,否则你永远无法调用它。 [这是相关规范](https://GitHub.Com/RubySpec/RubySpec/blob/master/language/send_spec.rb#L202-216)。 – 2012-04-26 12:07:03