为什么这不起作用:
class Myclass
include HTTParty
def dosomething
base_uri("some_url")
end
end
Run Code Online (Sandbox Code Playgroud)
base_uri方法是HTTParty的类方法.如果我从我的类,任何实例方法之外或类方法中调用它,它工作正常,但是当尝试从实例方法调用它时,我得到"NoMethodError:undefined方法`base_uri'用于#"
为什么?不应该有一些方法从我的实例方法中引用HTTParty类,所以我可以调用那个HTTParty类方法?
我可以将它更改为类方法,但是我的类的每个实例都将具有相同的base_uri值.
为什么不起作用?因为这不是Ruby的工作方式.同样,这不起作用:
class Foo
def self.utility_method; ...; end
def inst_method
utility_method # Error! This instance has no method named "utility_method"
end
end
Run Code Online (Sandbox Code Playgroud)
您可以通过以下方式解决此问题:
class MyClass
include HTTParty
def dosomething
HTTParty.base_uri("some_url")
end
end
Run Code Online (Sandbox Code Playgroud)
让我们更深入地了解方法查找如何与模块一起工作.首先,一些代码:
module M
def self.m1; end
def m2; end
end
class Foo
include M
end
p Foo.methods - Object.methods #=> []
p Foo.new.methods - Object.methods #=> [:m2]
class Bar
extend M
end
p Bar.methods - Object.methods #=> [:m2]
p Bar.new.methods - Object.methods #=> []
class Jim; end
j = Jim.new
j.extend M
p j.methods - Object.methods #=> [:m2]
Run Code Online (Sandbox Code Playgroud)
正如我们所看到的,你可以使用extend
一个对象(一个类或一个实例)来为对象本身(而不是实例)使用模块的'instance'方法,但你不能使模块的'类方法'成为由任何东西继承.你能得到的最接近的是这个成语:
module M2
module ClassMethods
def m1; end # Define as an instance method of this sub-module!
end
extend ClassMethods # Make all methods on the submodule also my own
def self.included(k)
k.extend(ClassMethods) # When included in a class, extend that class with
end # my special class methods
def m2; end
end
class Foo
include M2
end
p Foo.methods - Object.methods #=> [:m1]
p Foo.new.methods - Object.methods #=> [:m2]
Run Code Online (Sandbox Code Playgroud)
如果该HTTParty
模块使用上面的图案,所以做出的base_uri
方法适用于您的MyClass
,那么你可以这样做:
class MyClass
include HTTParty
def dosomething
self.class.base_uri("some_url")
end
end
Run Code Online (Sandbox Code Playgroud)
...但这比直接引用拥有该方法的模块更有用.
最后,因为这可能对你有帮助,这是我几年前制作的图表.(它缺少Ruby 1.9中的一些核心对象BasicObject
,但是仍然适用.点击查看PDF版本.图中的注释#3特别适用.)
Ruby方法查找流程http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png