我想有这样的事情:
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
成为私有方法并在B中使用a.send(:only_B_can_call_me)
。确定,它可以正常工作。但我可能会在C内做同样的事情...所以,我认为这不是一个好方法。有没有其他方法可以做到这一点? (允许仅通过特定类的实例访问方法。)
(我知道最终总是可以使用send
从任何地方访问任何方法。但我想在这种情况下让自己远离send
。)
答案 0 :(得分:4)
没有明确的解决方案。如果B可以做到,那么C也可以。与其他语言不同,ruby没有"内部"或"包"可见性修饰符,如果A和B在同一个"包"中,它可以帮助你,但C是外部的。如果该方法是私有的,即使B必须使用send
。如果它是公开的,C可以直接调用它。在您的示例中,B不是A的子类,因此protected
修饰符不适用。
一种肮脏的方法是检查caller
中的only_B_can_call_me
。它返回整个callstack。所以你可以检查它是否确实是B或否则拒绝。但这非常脆弱,完全不推荐。
答案 1 :(得分: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?
答案 2 :(得分:0)
塞尔吉奥的回答是正确的,但如果你真的需要黑客,请看下面的代码:
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 你已被警告!!