In article <6165abef.0201260158.46e2e01a / posting.google.com>,
kate turing <kturing / yahoo.com> wrote:
>Mike Sassak <msassak / speakeasy.org> wrote in message
>news:<1012006343.5969.3.camel / synecdoche>...
>> Could you elaborate on how you want your program to work?
>
>Thanks for the response. I am doing something very similar 
>to your second example.
>
>I'll try to flesh out my problem a little more without 
>dragging the application's obscure domain into the problem. 
>FooMgr is a factory and manager for Foo objects. I'm doing 
>this sort of this:
>
>fm = FooMgr.new
>resources.each do |r|
>  f = fm.createFoo(r)
>end
>
># Assume there's a FooMgr.[] method that returns a foo.
># I want this to work.
>fm[somekey].doPublicThing  
>
># I want this to not work.
>fm[somekey].doPrivateThing 
^^^^^^^^^^^^^^^^^^^^^^^^^^^
This part should already work (not work) as you wish, correct?

>
># and i want this method to work
>def FooMgr.frobulate 
>   #@foos is a private
>   @foos[somekey].doPrivateThing
>end
>

def FooMgr.frobulate
   @foos[somekey].send(:doPrivateThing)
end
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This should allow you to do what you want(?)

>Also, I'd like to enforce that Foo objects can only
>be created by a FooMgr. The first possibility that
>comes to mind is protecting Foo.initialize in the 
>same way that I'd like to protect Foo.doPrivateThing.
>

Actually, I think you have to override new somehow and make it private.
I've been playing with it a bit, and so far haven't been successful.
Maybe someone else can offer a solution to this part.

>Looking into #send was an interesting read. But it 
>feels a little low-level. Well, a lot.
>

Yes, so we hide it in the FooMgr.frobulate method.

>I don't think I can cleanly do exactly what I want in 
>Ruby. Maybe I just need to get comfortable with leaving 
>doPrivateThing public, as much as it pains me. BUT, I
>suspect that someone out there (who is less tainted by 
>C++) has a Ruby-friendly way of accomplishing the same 
>thing. Hope they speak up.

Maybe it's possible that one could define a C++-like friend  mechanism in 
class Class?  you could add a class variable array called @@friends and 
you could add classes which are 'friend's of the current class to this 
array - then somehow (and this is what I'm not sure of) calls to a class's 
private or protected methods could be checked against the @@friends list 
to determine if it's OK to proceed.... but I'm just thinking out loud 
here, I don't have any idea how to do this (or even if it's possible)  
maybe someone else can build on this idea. 


Here's a question for everyone on the list:
Why are there both send and __send__ methods that seem to do exactly the 
same thing?


Also: does anyone else find it a bit worrisome that send can 'break 
in' and call an object's private methods?
Just a thought, how about:  
send - works as it does now.
send_protected - can only call an object's public or protected methods
send_public - can only call an object's public methods

[it probably would have been better to have the default send not be able 
to call an object's private and protected methods so that we would have: 
send - calls only an object's public methods
send_protected - calls an object's public and protected methods
send_private - calls an object's public,protected and private methods
....but as the say, the cow's already out of the barn]

Actually, it would be pretty easy to define these types of 'send's 
ourselves since you can get a list of an objects public,private and 
protected methods:

class Object
alias oldsend, send
  def send(methID,*args)
    unless self.public_methods.include?(methID)
       raise "trying to call protected or private method"
    end
  end
  def send_protected(methID,*args)
    unless self.public_methods.include?(methID) || 
           self.protected_methods.include?(methID)
       raise "trying to call private method"
    end
  end
  def send_private(methID,*args)
    oldsend(methID,*args)
  end
end