views:

1182

answers:

3

Coming from a long history of C-style syntax and now trying to learn Ruby (on Rails), I've been having my share of issues with its idioms and such, but today I hit one I didn't expect to have a problem with and I can't see whatever it is that must be right in front of my face.

I have a Binary class that includes a private method to derive a URI value from a path value (uri and path are attributes of the class). I'm calling self.get_uri_from_path() from within Binary.upload(), but I get:

Attempt to call private method

A snippet of the model looks like this:

class Binary < ActiveRecord::Base
  has_one :image

  def upload( uploaded_file, save = false )
    save_as = File.join( self.get_bin_root(), '_tmp', uploaded_file.original_path )

    # write the file to a temporary directory
    # set a few object properties

    self.path   = save_as.sub( Rails.root.to_s + '/', '' )
    self.uri    = self.get_uri_from_path()
  end

  private

  def get_uri_from_path
    return self.path.sub( 'public', '' )
  end
end

Am I making the call incorrectly? Am I missing something else that's even more fundamental? The only place that Binary.get_uri_from_path() is being called from - at the moment - is Binary.upload(). I'd expect to be able to call a private method from within the same class unless Ruby does something markedly different from other languages I've used.

Thanks.

+5  A: 

Don't do

self.get_uri_from_path()

do

get_uri_from_path()

Because...

  class AccessPrivate
    def a
    end
    private :a # a is private method

    def accessing_private
      a              # sure! 
      self.a         # nope! private methods cannot be called with an explicit receiver at all, even if that receiver is "self"
      other_object.a # nope, a is private, you can't get it (but if it was protected, you could!)
    end
  end

via

marcgg
Thanks. A little more digging helped me understand the differences in private methods of Ruby vs. other languages. I just didn't expect differences at that level.
Rob Wilkerson
you're welcome. It's true it's a bit more tricky, but it actually makes sense after a while :)
marcgg
I'm finding that a lot of Ruby is terrific - laconic, yet expressive - but I'm definitely having to fight through the idiom deltas. :-)
Rob Wilkerson
+1  A: 

I believe that the proper idiom in this case is not self.get_uri_from_path() but rather simply get_uri_from_path(). The self is redundant. Further notes: * self.path calls the path method on self, which is presumably defined in the parent class. If you had wanted to access the instance variable directly, you could have said @path. (@ is the sigil for instance variables.) * Parentheses for method arguments are optional except where their absence would cause ambiguity. You could, if you chose, replace get_uri_from_path() with get_uri_from_path. This stands in contrast to Javascript, where a function with no parens represents that function as a value rather than an application of that function.

Thom Smith
Yeah, I'm aware of the optional parens, but I keep seeing stuff without them and I don't like the ambiguity. Is it a variable or is it a method? I'd rather not have to ask myself that question every time I see it. Maybe that gets easier over time.
Rob Wilkerson
A: 

there is a heck though where you can call private method in any situation, that being:

object.send(:private_method)

I believe 1.9 has a different implementation of this trick

penger
Yes, 1.9 has the send! method.
Thom Smith
At this point, I'm just trying to learn and understand the rules. I'll worry about "breaking" them later. :-)
Rob Wilkerson