StackOverflow cool Ruby questions 2

Welcome in this second post of this series. Just before I list the questions of this one, I want to mention 2 things:

  • You can follow StackOverflow tagged Ruby questions on twitter using the user: sof_ruby
  • Some ppl feel shy to ask or even to answer, my (little) experience in life taught me that If you don't ask, you don't learn. If you don't participate, you don't learn. On the other side that's the benefit of pair programming, ain't it?

Now let's proceed to questions:

Hash Autovivification

Hash Autovivication in simple words is the ability to do things like:

a={}
a['b']['c']['d']['e']='f'

The cool idea here is that all intermediate-level hashs will be created automatically.
We can't do that directly in Ruby, a statement like the previous one will issue an error : NoMethodError: undefined method `[]' for nil:NilClass

The question title is: ruby hash autovivification (facets)

The question text is:
Here is a clever trick to enable hash autovivification in ruby (taken from facets):

# Monkey patching Hash class:
# File lib/core/facets/hash/autonew.rb, line 19
  def self.autonew(*args)
    leet = lambda { |hsh, key| hsh[key] = new( &leet ) }
    new(*args,&leet)
  end

Although it works (of course), I find it really frustrating that I can't figure out how this two liner does what it does.

The answer is:
The standard new method for Hash accepts a block. This block is called in the event of trying to access a key in the Hash which does not exist. The block is passed the Hash itself and the key that was requested (the two parameters) and should return the value that should be returned for the requested key.

You will notice that the leet lambda does 2 things. It returns a new Hash with leet itself as the block for handling defaults. This is the behaviour which allows autonew to work for Hashes of arbitrary depth. It also assigns this new Hash to hsh[key] so that next time you request the same key you will get the existing Hash rather than a new one being created.

So:

a = Hash.autonew
a['b']['c']['d']['e']='f' #=> "f"
a.inspect #=> {"b"=>{"c"=>{"d"=>{"e"=>"f"}}}}

Class instance variables

This answer of this one is easy, but the idea of Class instance variables is what matters.

The question title is: Total newbie: Instance variables in ruby?

The question text is:
Pardon the total newbiew question but why is @game_score always nil?

class Bowling
  @game_score = 0
    def hit(pins)
      @game_score = @game_score + pins
    end

    def score
      @game_score
    end
end

The answer is:
Because you don't have

def initialize
  @game_score = 0
end

The assignment in the class definition is not doing what you think it is doing, and when hit gets invoked it can't add to nil.
If you now ask what happened to @game_score?, well, always remember Class is an object and Object is a class.
It's way cool the way Ruby classes have this Zen-like "real" existence. Ruby doesn't precisely have named classes, rather, class names are references to objects of class Class. By assigning to @game_score outside of an instance method you created a class instance variable, an attribute of the class object Bowling, which is an instance of class Class. These objects are not, in general, very useful. (See Chapter 1, The Ruby Way, Hal Fulton.)

You can reach the @game_score class instance variable by doing this:

class << Bowling
  attr_accessor :game_score
end

Bowling.game_score #=> 0
Bowling.game_score = 6 #=> 6

(A question for you: What is the difference between class variables and class instance variables?)

Creating data structures in Ruby

I have committed a mistake myself in answering this question :P, however remember: If you don't try, you don't learn.

The question title is: Can the array be reinvented in Ruby?

The question text is:
This is just a hypothetical question, if you wouldn't have the Array and the Hash class, would there be any way of implementing an Array class in pure Ruby? How?

The answer is:
Yes we can:

class MyArray
  include Enumerable

  def initialize
    @size = 0
  end

  def <<(val)
    instance_variable_set("@a#{@size}".to_sym, val)
    @size += 1
  end

  def [](n)
    instance_variable_get("@a#{n}")
  end

  def length
    @size
  end

  def each
    0.upto(@size - 1) { |n| yield self[n] }
  end
end

a = MyArray.new
a << 1
a << 2
p a.to_a     #=> [1,2]

This works by creating instance variables @a0, @a1, etc. on the object to represent array indices 0, 1, etc. It has constant time length and index operations. The rest of the operations (remove, etc.) are a bit more effort to implement, but it's absolutely possible.

Note that the constant time property for the index operation depends on the underlying Ruby runtime using an appropriate data structure for instance variables.

Hash#reject

The question title is: Update attributes unless blank?

The question text is:
I have an existing Project record, and I'm importing a CSV file to update the associated Project attributes. However, often the CSV will contain blank fields and I don't want to overright exisiting attributes if the related CSV field is blank.

Something like this:

project.update_attributes(:name => row.field('project_name') unless row.field('project_name').blank?,                                                                         
                          :owner => row.field('project_owner') unless row.field('project_owner').blank?,
                          :due_date => row.field('project_due_date') unless row.field('project_due_date').blank?)

The answer is:

project.update_attributes({:name => row.field('project_name'),                                                                         
                          :owner => row.field('project_owner'),
                          :due_date => row.field('project_due_date')}.reject{|k,v| v.blank?})

Ruby 'private' behavior

The key point here to remember is that private, protected and pulbic are just other methods defined in Ruby Module class.

The question title is: Are there good reasons for ‘private’ to work the way it does in Ruby?

The question text is:
It took me a while to understand how private methods work in Ruby, and it really strikes me as being very awkward. Does anyone know if there are good reasons for private methods to be handled the way they are? Is it just historic reasons? Or implementation reasons? Or are there good solid logical reasons (ie. semantic)?

For example:

class Person
  private
  attr_reader :weight
end

class Spy < Person
 private
  attr_accessor :code
 public
  def test
    code          #(1) OK: you can call a private method in self
    Spy.new.code  #(2) ERROR: cannot call a private method on any other object
    self.code     #(3) ERROR!!! cannot call a private method explicitly on 'self'
    code="xyz"    #(4) Ok, it runs, but it actually creates a local variable!!!
    self.code="z" #(5) OK! This is the only case where explicit 'self' is ok
    weight        #(6) OK! You can call a private method defined in a base class
  end
end
  • Ruby's behaviour on lines (1), (2) and (5) seems reasonable.
  • The fact that (6) is ok is a bit strange, especially coming from Java and C++. Any good reason for this?
  • I really do not understand why (3) fails ! An explanation, anyone?
  • The problem on line (4) looks like an ambiguity in the grammar, which has nothing to do with 'private'.
  • Any ideas?

The answer is:

You might find it helpful to read ruby's definition of public, private and protected (Skip to Access Control)

Ruby's private is analogous to Java's protected. There is no Ruby equivalent of Java's private. But there are ways to fake it.

Private is defined as methods/variables that can only be called implicitly. This is why statements 2 and 3 fail. In other words, private limits methods/variables to the context of a class or subclass in which they are defined. Inheritance passes private methods to the subclasses and can therefore be accessed with an implicit self. (Explaining why statement 6 works.)

I think you're looking for something closer to protected. Which behaves similarly to Java accessors that are not given a visibility (eg: public, private, protected) By changing the private in Spy to protected all 6 of your statements work. Protected methods can be called by any instance of the defining class or their subclasses. Either explicitly or implicitly called on self are valid statements for protected methods so long as the caller is either the class of the object responding to the call, or inherits from it.

class Person
  private
  attr_reader :weight
end

class Spy < Person
 protected
  attr_accessor :code
 public
  def test
    code          #(1) OK: you can call a private method in self
    Spy.new.code  #(2) OK: Calling protected method on another instance from same class family or a descendant.
    self.code     #(3) OK: Calling protected method on with explicit self is allowed with protected
    code="xyz"    #(4) Ok, it runs, but it actually creates a local variable!!!
    self.code="z" #(5) OK! This is the only case where explicit 'self' is ok
    weight        #(6) OK! You can call a private method defined in a base class
  end
end

s = Spy.new
s.test # succeeds
s.code #(7) Error: Calling protected method outside of the class or its descendants.

As for statement 4. You are correct in assuming this is to avoid ambiguity. It's more a safeguard to the potential harm of ruby's dynamic nature. It ensures that you cannot override accessors by opening up the class again later. A situation that can arise, for example by eval'ing tainted code.

I can only speculate on he design decisions that led to these behaviours. For most of it I feel it comes down to the dynamic nature of the language.

P.S. If you really want to give things the java definition of private. Only available to the class in which it's defined, not even subclasses. You could add an self.inherited method to your classes to remove references to the methods you want to limit access to.

Making the weight attribute inaccessible from subclasses:

class Person
  private
  attr_reader :weight

  def initialize
    @weight = 5
  end

  def self.inherited(subclass)
    subclass.send :undef_method, :weight
  end
end

class Spy < Person
 private
  attr_accessor :code
 public
  def test
     weight       
  end
end

Person.new.send(:weight)  # => 5
Spy.new.send(:weight)  #=> Unhelpful undefined method error

It may make more sense to replace the undef_method call to something like this:

  def self.inherited(subclass)
    subclass.class_eval %{
      def weight 
        raise "Private method called from subclass. Access Denied"
      end
     }
  end

Which provides a much more helpful error and the same functionality.

The send is necessary to get around calling private methods for other classes. Only used to prove that things are actually working.

Which in hindsight, makes private and protected useless. If you're really serious about protecting your methods you will have to override send to block them. You could also make send private.

It ends up being one of those "Damned if you do, damned if you don't" situations. There are legitimate uses of calling send from outside an object. And overriding send requires some tricky code to account for the variable number of arguments that can be sent to any method.

That's an exercise for another time.

Suggestions/comments regarding the content of this series are welcome! Have your say!