2017-10-17 61 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你已经被警告!

相关问题