2017-10-17 50 views
1

我想有這樣的事情:如何只允許一個類訪問另一個類的方法?

class A 
    def only_B_can_call_me 
    'called_by_B' 
    end 
end 

class B 
    def do_stuff(a) 
    a.only_B_can_call_me 
    end 
end 

class C 
    def do_stuff(a) 
    a.only_B_can_call_me # how to forbid it? 
    end 
end 

B.new.do_stuff(A.new) # => 'called_by_B' 
C.new.do_stuff(A.new) # => it should not be allowed!!! but how to do it? 

的一種方式做到這一點是讓only_B_can_call_me的私有方法和使用a.send(:only_B_can_call_me) B. OK裏面,它的工作原理。但是我可能會在C裏面做同樣的事情......所以,我認爲這不是一個好方法。有沒有其他方法可以做到這一點? (允許一個方法只是通過一個特定的類的實例來訪問。)

(我知道,最終總是能夠從使用send任何地點訪問任何方法,但我想從send讓自己走在這種情況下。 )

+0

哪個是您的實際Ruby版本? –

+0

我目前在紅寶石2.4.1 – Djunzu

+0

那麼,我希望我的解決方案能夠幫助你,我很樂意提供幫助。我試過了,它的工作原理https://repl.it/Mmt5/6你可以在那裏看到 –

回答

4

沒有明確的解決方案。如果B可以做到這一點,那麼C也可以。與其他語言不同,ruby沒有「內部」或「包裝」可見性修飾符,如果A和B在相同的「包」中,但C是外部的。如果該方法是私密的,則甚至B必須使用send。如果它是公開的,C就可以調用它。 B在您的示例中不是A的子類,所以protected修飾符不適用。

一個骯髒的方法是檢查calleronly_B_can_call_me。它返回整個調用堆棧。所以你可以檢查它是否確實是B或否則拒絕。但這是非常脆弱的,完全不推薦。

+0

這是一個完美的解釋,爲什麼......感謝分享,並告訴我我的錯誤,你的規則!是一個加號 –

+0

塞爾吉奧,你知道更多關於Ruby,我會非常感謝,如果你可以檢查我的更新的答案,並再次評論,非常感謝 –

0

這是我可以@Sergio Tulentsev的幫助下做到最好:

class A 
    def only_B_can_call_me(b) 
    return unless b.class == B # here you are asking 
    'called_by_B' 
    end 
end 

class B 
    def do_stuff(a) 
    a.only_B_can_call_me(self) # how to forbid it? ask if self is B 
    end 
end 

class C 
    def do_stuff(a) 
    a.only_B_can_call_me(self) # how to forbid it? ask if self is B 
    end 
end 

使用子類的其他方式:

class A 
    def only_B_can_call_me 
    'called_by_B' 
    end 
end 

class B < A 
    def do_stuff 
    self.only_B_can_call_me 
    end 
end 

class C 
    def do_stuff 
    self.only_B_can_call_me # how to forbid it?, like this C hasn't the method, B does 
    end 
end 



puts(B.new.do_stuff) # => 'called_by_B' 
puts(C.new.do_stuff) # => it should not be allowed!!! but how to do it? 
+0

這是行不通的:) –

+1

'self.class'會從來不是'B.class' –

+1

'self.class'是'C','B.class'是'Class'。他們永遠不會平等。 –

0

Sergio的答案是正確的,但是如果你真的需要一個黑客看看下面的代碼:

class CallerClass 
    def self.get (c) 
    line = c.first.scan(/^.*:(.*):.*/).first.first.to_i 
    file = c.first.scan(/^(.*?):/).first.first 
    func = c.first.scan(/:in `(.*)?'/).first.first 
    fc = File.readlines(file) 
    caller_class = nil 

    caller_class = '<main>' if func == '<main>' 

    line.downto(0) do |it| 
     break if caller_class 
     caller_class = fc[it].scan(/^\s*class\s+(.*)\s+/).first.first if fc[it] =~ /^\s*class\s+(.*)\s+/ 
    end 
    caller_class 
    end 

end 

class A 
    def only_B_can_call_me 
    caller_class = CallerClass.get(caller) 
    raise "'#{caller_class}' is not an allowed caller" unless caller_class == 'B' 
    'called_by_B' 
    end 
end 

class B 
    def do_stuff 
    A.new.only_B_can_call_me 
    end 
end 

class C 
    def do_stuff 
    A.new.only_B_can_call_me 
    end 
end 

B.new.do_stuff #called_by_B 
C.new.do_stuff #Raises exception 

OBS。這是一個脆弱的Ruby代碼使用正則表達式解析,這是一個HACK你已經被警告!

相關問題