From: Phrogz on
Below are two files that differ only in the 2nd line of code in each.
Can you guess what difference they will reveal? I must admit I was
surprised when I ran into this.

$ cat alias.rb
class Object
alias_method :to_js, :inspect
end

class Array
def to_js; "[#{map{|o|o.to_js}.join(',')}]"; end
end

class Hash
def to_js
"{#{map{|k,v| "#{k.to_s.to_js}:#{v.to_js}" }.join(',')}}"
end
end

[ 1, [true], {a:"foo"} ].each{ |o| puts o.to_js }

$ cat wrapped.rb
class Object
def to_js; inspect; end
end

class Array
def to_js; "[#{map{|o|o.to_js}.join(',')}]"; end
end

class Hash
def to_js
"{#{map{|k,v| "#{k.to_s.to_js}:#{v.to_js}" }.join(',')}}"
end
end

[ 1, [true], {a:"foo"} ].each{ |o| puts o.to_js }
From: Robert Klemme on
2010/3/31 Phrogz <phrogz(a)mac.com>:
> Below are two files that differ only in the 2nd line of code in each.
> Can you guess what difference they will reveal? I must admit I was
> surprised when I ran into this.
>
> $ cat alias.rb
>  class Object
>    alias_method :to_js, :inspect
>  end

This one always invokes Object#inspect - unless you override #to_js explicitly.

> $ cat wrapped.rb
>  class Object
>    def to_js; inspect; end
>  end

This is the one you really want IMHO: #to_js delegates to whatever
#inspect is present in the class.

Pretty straightforward inheritance behavior - although I'd concede
that it's subtle.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

From: Martin DeMello on
On Wed, Mar 31, 2010 at 10:01 AM, Phrogz <phrogz(a)mac.com> wrote:
> Below are two files that differ only in the 2nd line of code in each.
> Can you guess what difference they will reveal? I must admit I was
> surprised when I ran into this.

It's pretty clear if you think of it in terms of message handlers and
method objects

>  class Object
>    alias_method :to_js, :inspect
>  end

This binds the message handler Object#to_js to the method object
Object#inspect. This should be illustrative:

$ cat test.rb
class Object
alias_method :to_js, :inspect
alias_method :inspect, :hash
end

a = Object.new
puts a.inspect
p a
puts a.to_js

$ ruby test.rb
67266180
67266180
#<Object:0x804cd08>

> $ cat wrapped.rb
>  class Object
>    def to_js; inspect; end
>  end

This creates a new method object, which contains a thunk that sends
the message "inspect" to self when it is invoked, and binds the
Object#to_js message handler to that method object.

martin

From: Phrogz on
On Mar 31, 3:19 am, Robert Klemme <shortcut...(a)googlemail.com> wrote:
> 2010/3/31 Phrogz <phr...(a)mac.com>:
>
> > Below are two files that differ only in the 2nd line of code in each.
> > Can you guess what difference they will reveal? I must admit I was
> > surprised when I ran into this.
>
> > $ cat alias.rb
> >  class Object
> >    alias_method :to_js, :inspect
> >  end
>
> This one always invokes Object#inspect - unless you override #to_js explicitly.

Yes; specifically, in this case, Object#inspect on a String calls
#to_s (because it's defined), so:
puts "foo".to_js
#=> foo
instead of the desired "foo" (with quotes).