2012-07-19 34 views
4

爲什麼這個不行:使用一個混合的方法實例方法中的

class Myclass 
include HTTParty 

    def dosomething 
    base_uri("some_url") 
    end 


end 

的base_uri方法是HTTParty的類方法。如果我從我的類,任何實例方法或類方法之外調用它,但是當嘗試從實例方法調用它時,它工作正常,但我得到「NoMethodError:undefined method`base_uri'for#」

爲什麼?不應該有方法從我的實例方法中引用HTTParty類,以便我可以調用該HTTParty類方法?

我可以將它更改爲一個類方法,但是然後我的類的每個實例的base_uri都會具有相同的值。

回答

8

它爲什麼不起作用?因爲這不是Ruby的工作原理。同樣,這不起作用:

class Foo 
    def self.utility_method; ...; end 
    def inst_method 
    utility_method # Error! This instance has no method named "utility_method" 
    end 
end 

你可以變通的作法只是在做:

class MyClass 
    include HTTParty 
    def dosomething 
    HTTParty.base_uri("some_url") 
    end 
end 

讓我們來看看方法查找與模塊是如何工作的更深。首先,一些代碼:

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] 

正如我們看到的,你可以使用extend引起的對象(類或實例)使用模塊的「實例」方法對象本身(而不是實例),但是不能使模塊的「類方法」被任何東西繼承。你可以得到的最接近的是這個成語:

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] 

如果HTTParty模塊使用上面的圖案,因此提供了base_uri方法對你MyClass,那麼你可以做到這一點:

class MyClass 
    include HTTParty 
    def dosomething 
    self.class.base_uri("some_url") 
    end 
end 

...但這比直接引用擁有該方法的模塊更有用。

最後,因爲這可能對你有所幫助,下面是我幾年前製作的圖表。 (它缺少一些核心對象從Ruby 1.9的,像BasicObject,但在其他方面仍然適用。點擊PDF版本。注意#3從圖中尤爲適用。)

Ruby Method Lookup Flow http://phrogz.net/RubyLibs/RubyMethodLookupFlow.png

+0

感謝。 'HTTParty.get'在一個實例方法內工作,但'HTTParty.base_uri'不能。看起來像是因爲HTTParty定義了self.get而不是self.base_uri。那麼,我認爲這意味着無法爲不同的實例使用具有不同base_uri的HTTParty? – wadesworld 2012-07-19 22:02:26

+1

@wadesworld base_uri在該類的單例類中設置該屬性。這意味着你不應該動態改變它,因爲你的代碼將不再是線程安全的。沒有什麼要求你設置base_uri,你可以在每個請求中指定URI。 – 2012-07-19 22:36:58

+0

@wadesworld如[HTTParty :: ClassMethods#base_uri'的文檔](http://rdoc.info/github/jnunemaker/httparty/HTTParty/ClassMethods#base_uri-instance_method)所示,模塊使用確切的模式I如上所述。因此,該值存儲在類中,而不是實例中,您需要修改該庫或按需要重複更改每個實例的值。看到我上面的最後一個例子和這個評論中的鏈接是如何被設計使用的。 – Phrogz 2012-07-19 22:37:15

1
class Myclass 
    include HTTParty 

    def dosomething 
    Myclass.base_uri("some_url") 
    end 

end 
相關問題