proper idiomatic ruby

5 views
Skip to first unread message

William Hertling

unread,
Nov 2, 2009, 6:51:25 PM11/2/09
to pdxruby
I started using Ruby to fulfill some practical needs, then ended up
doing Rails development on a Facebook app. I've learned enough to do
what I need to do, but I always have the sense that I could be writing
much better ruby code than I do.

For example, I seem to have sprinkled through my code various
permutations of if x == nil or x == "", as well as "if x == nil or
x.size == 0". Partly this is laziness on my part: I don't care to take
the effort to know the exact return value, whether it's an empty
string versus nil, or an empty array versus nil. Yet there must be
some better, more ruby, way of writing that sort of expression. Is
there?

In general, do folks have any recommendations for how to learn good
ruby style?

Thanks,
Will

Chuck Vose

unread,
Nov 2, 2009, 7:21:15 PM11/2/09
to pdx...@googlegroups.com
The answer is always to read other people's code. Every time you see
one of the rails/ruby core people post a gem just give it a read and
see what you can and can't understand. Some will be so far above you
that you won't get it for a while, but some will be right at your
level and you'll learn a lot.

As to your specific question, I find that ruby's post conditions are
extremely fun to use. It's also worth noting that the only things that
are false in ruby are nil and false so that may help keep the number
of conditions you need to test on down to a minimum.

So for me I use this idiom a lot in my code. I don't know if it's good
code but it's what I use :)

puts x*3 unless x.nil?
or
<%=h member.network if member %>

There also used to be a blog called The Rails Way which talked a lot
about code idioms but I haven't seen it updated in ages. I guess they
lost interest. But the blog still exists and is filled with little
idiomatic bits.

Chuck Vose
www.chuckvose.com

Igal Koshevoy

unread,
Nov 2, 2009, 7:28:03 PM11/2/09
to pdx...@googlegroups.com
William Hertling wrote:
> I started using Ruby to fulfill some practical needs, then ended up
> doing Rails development on a Facebook app. I've learned enough to do
> what I need to do, but I always have the sense that I could be writing
> much better ruby code than I do.
>
> For example, I seem to have sprinkled through my code various
> permutations of if x == nil or x == "", as well as "if x == nil or
> x.size == 0". Partly this is laziness on my part: I don't care to take
> the effort to know the exact return value, whether it's an empty
> string versus nil, or an empty array versus nil. Yet there must be
> some better, more ruby, way of writing that sort of expression. Is
> there?
>
If you're using a library like Ruby on Rails, ActiveSupport or Facets,
you'll be able to make calls like `if x.blank?` which do both of these
checks at once.

> In general, do folks have any recommendations for how to learn good
> ruby style?

If you recognize that something is ugly enough to bother you, consider
yourself blessed with vision and cursed with the desire to do better.
You can harness this power by seeking out solutions to addressing these
annoyances, and asking the mailing list and peers for advice is great.

It really helps to read other people's well-written libraries. I learned
many good techniques by reading the Ruby on Rails source code, although
admittedly, there's a frightening amount of indirection in places but I
usually understand why. Another good place to look is the Facets
library, it's full of nice, short methods that do amazing things.

Try to find opportunities to write code socially by pair programming,
sprinting and such. The discussions you have together on "That's ugly,
how can we make this better?" will really help.

...

I'd really like to get some code sprints going again, they were really
good for these sorts of discussions. Now that I'm recovering from my
illness, I hope to start making it to the Thursday hackathons at the
Lucky Lab and invite others to join me there. I'll post a reminder on
Wednesday. :)

-igal

Jason Noble

unread,
Nov 2, 2009, 7:29:02 PM11/2/09
to pdx...@googlegroups.com

Rein Henrichs gave a speech at the Atlanta Ruby User's Group (AtlRUG)
back in February talking about some styling stuff. It's available
online at http://atlruby.org/news-pixie/posts/95-Ruby-loves-you

I would suggest writing a helper function to DRY (Don't Repeat
Yourself) your code, i.e.:

def is_nil_or_blank(x)
x.nil? || x == ''
end

Then call it with if is_nil_or_blank(variable_name) ... end

A quick intro for myself. I'm a Ruby/Rails developer based in
Atlanta, GA. I've been using Ruby for two and a half years and teach
a beginning Ruby on Rails class called Emerald City (http://groups.google.com/group/atlrug-emeraldcity
). Emerald City is a coding group of the Atlanta Ruby Users Group ( ~
100 members), I'm also a co-leader for the AtlRUG group.

I'm looking to relocate to the Seattle/Portland area within the next
five years or so. In an effort to get to know the tech market
better, I've started networking and that's how I found pdxruby.

I hope you don't mind me lurking on the mailing list. :)

Jason
http://jasonnoble.org
http://github.com/jasonnoble

Igal Koshevoy

unread,
Nov 2, 2009, 7:47:43 PM11/2/09
to pdx...@googlegroups.com
Jason Noble wrote:
> Rein Henrichs gave a speech at the Atlanta Ruby User's Group (AtlRUG)
> back in February talking about some styling stuff. It's available
> online at http://atlruby.org/news-pixie/posts/95-Ruby-loves-you
>
Great, thanks for sharing the link. I've subscribed to the feed, there
seem to be some interesting talks. I'm downloading the talk and will
check it out later.

> I would suggest writing a helper function to DRY (Don't Repeat
> Yourself) your code, i.e.:
>
> def is_nil_or_blank(x)
> x.nil? || x == ''
> end
>
> Then call it with if is_nil_or_blank(variable_name) ... end
>

Compare the above technique with this conceptually similar one in Ruby
on Rails' activesupport-2.3.4/lib/active_support/core_ext/blank.rb

class Object
# An object is blank if it's false, empty, or a whitespace string.
# For example, "", " ", +nil+, [], and {} are blank.
#
# This simplifies
#
# if !address.nil? && !address.empty?
#
# to
#
# if !address.blank?
def blank?
respond_to?(:empty?) ? empty? : !self
end
end


> A quick intro for myself. I'm a Ruby/Rails developer based in
> Atlanta, GA. I've been using Ruby for two and a half years and teach
> a beginning Ruby on Rails class called Emerald City (http://groups.google.com/group/atlrug-emeraldcity
> ). Emerald City is a coding group of the Atlanta Ruby Users Group ( ~
> 100 members), I'm also a co-leader for the AtlRUG group.
>
> I'm looking to relocate to the Seattle/Portland area within the next
> five years or so. In an effort to get to know the tech market
> better, I've started networking and that's how I found pdxruby.
>
> I hope you don't mind me lurking on the mailing list. :)

Great, glad to have here. :)

-igal

Chuck Vose

unread,
Nov 2, 2009, 7:57:40 PM11/2/09
to pdx...@googlegroups.com
>  def blank?
>    respond_to?(:empty?) ? empty? : !self
>  end

Hah, I'd never thought about !self. That's hilarious and totally wonderful.

I really want to start doing some sprints as well. I'm working in a
PHP shop now and I don't want my skills to get rusty until I get back
into Ruby development. If you guys show up and can't find people to
program with please give me a ring: I've probably forgotten but I do
really want to sprint. Same goes for if you're just bored and want to
hack something out involving a tin can, a wiimote, and 3 dust bunnies.
I'm sure we can make it do something entertaining. :P

My contact for all the world to see is:
Chuck Vose
651-214-0272

Markus

unread,
Nov 2, 2009, 8:27:43 PM11/2/09
to pdx...@googlegroups.com

> class Object
> # An object is blank if it's false, empty, or a whitespace string.
> # For example, "", " ", +nil+, [], and {} are blank.
> #
> # This simplifies
> #
> # if !address.nil? && !address.empty?
> #
> # to
> #
> # if !address.blank?
> def blank?
> respond_to?(:empty?) ? empty? : !self
> end
> end

As long as you're going to be extending object, you could get the same
semantics by just writing (w. Python style indentation, 'cause that's
how my brain works):

class Object
def empty?
!self
end
end

and just calling x.empty? as your test. For Strings, Arrays, etc.
you'll get the usual empty? and for everything else you'll get !self.

-- Markus

Igal Koshevoy

unread,
Nov 2, 2009, 10:05:47 PM11/2/09
to pdx...@googlegroups.com
That's clever and seems to work, but I feel that there's an important issue.

The "empty?" method is found on a number of standard Ruby objects.
Changing how objects respond to a standard method is naughty. This
particular change probably won't hurt anyone, but is a step down a
slippery slope that should be approached with caution.

In contrast, the "blank?" method approach adds new behavior not present
in standard Ruby objects, which makes it clean and safe.

-igal

PS: I like how the term "Python style indentation" and its use above
should make both Ruby and Python programmers squirm. :)
PPS: I look forward to your brain-twister for tomorrow's meeting, if you
have time to prepare one.

Jerry Hilts

unread,
Nov 2, 2009, 11:47:12 PM11/2/09
to pdx...@googlegroups.com
You act as if this is the first time you've seen Markus writing 'naughty' code.

On 02 Nov, 2009, at 19:05, Igal Koshevoy wrote:

The "empty?" method is found on a number of standard Ruby objects.
Changing how objects respond to a standard method is naughty. ...

Sam Livingston-Gray

unread,
Nov 3, 2009, 12:23:40 AM11/3/09
to pdx...@googlegroups.com
On Nov 2, 2009, at 4:28 PM, Igal Koshevoy wrote:
> If you're using a library like Ruby on Rails, ActiveSupport or Facets,
> you'll be able to make calls like `if x.blank?` which do both of these
> checks at once.

Note also that ActiveSupport added #present? -- which is the opposite
of #blank? -- sometime after I learned about #blank?.

Quite useful for removing double negatives (e.g., "if !foo.blank?").

-Sam

Markus

unread,
Nov 3, 2009, 12:44:34 AM11/3/09
to pdx...@googlegroups.com
> > As long as you're going to be extending object, you could get the same
> > semantics by just writing (w. Python style indentation, 'cause that's
> > how my brain works):
> >
> > class Object
> > def empty?
> > !self
> > end
> > end
> >
> > and just calling x.empty? as your test. For Strings, Arrays, etc.
> > you'll get the usual empty? and for everything else you'll get !self.

> That's clever and seems to work, but I feel that there's an important issue.

> The "empty?" method is found on a number of standard Ruby objects.
> Changing how objects respond to a standard method is naughty. This
> particular change probably won't hurt anyone, but is a step down a
> slippery slope that should be approached with caution.

> In contrast, the "blank?" method approach adds new behavior not present
> in standard Ruby objects, which makes it clean and safe.

So a few random counter points, 'cause feeling around to find out where
the edge is in cases like this is both interesting and fun:

* Adding "empty?" in this way doesn't conflict with the behavior
of existing classes which implement "empty?", it simply gives it
(in a reasonable way) to classes that presently don't have it.

In other words, it doesn't "change how objects respond to a
standard method" at all; it just extends the method to cover all
objects.

* Adding "blank?" to Object, by the same token, isn't really any
safer--you could still conflict with a library that had defined
it with different semantics.

-- Markus

P.S. If you are worried about things like that, you probably don't want
to use rails.

Ever.

You should probably delete it off your system.

Oh, and gems too.

And don't get me started on how sausages are made.


Ben Munat

unread,
Nov 3, 2009, 1:16:54 AM11/3/09
to pdx...@googlegroups.com
Nice. Didn't know that.

b

Chuck Vose

unread,
Nov 3, 2009, 11:10:08 AM11/3/09
to pdx...@googlegroups.com
So can we agree then that the proper idiomatic ruby code should
probably never be used by the squeamish? In fact, probably proper ruby
shouldn't be used by anyone.

Maybe the bit about Ruby making programmers happy is that every day we
go to work and create unspeakable acts of treason against respectable
programming culture.

Jason LaPier

unread,
Nov 3, 2009, 11:24:00 AM11/3/09
to pdx...@googlegroups.com
Actually, based on your original example, I think it's safe to say that in ruby, particularly in many ruby libraries (rails, facets, etc) if you want to test for truthiness (beyond a simple comparison), there's probably a method that ends in ? that can help you out. 

The part that causes me grief is sometimes, the method will start with is_ - as in something.is_a?(Thing). This makes your if statements read very nicely: 
  do_this if something.is_a?(Thing)
But most of the time, you don't have the is_, so you get: 
  do_this if something.present? 
and I want to write: 
  do_this if something.is_present?

Which makes me wonder if some rubyist somewhere has written some method missing magic to try any is_method? without the is_, so I can use is_blank? and get blank?

- Jason L.

--
My Rails and Linux Blog: http://offtheline.net

Chuck Vose

unread,
Nov 3, 2009, 11:26:33 AM11/3/09
to pdx...@googlegroups.com
Try it Jason, it's not that big a leap. We'll tell you if you're going
in the wrong direction.

This should be a wave discussion :P

Sam Livingston-Gray

unread,
Nov 3, 2009, 11:49:26 AM11/3/09
to pdx...@googlegroups.com
Now I'm envisioning a module that implements #truthy? and #falsy?...

class Object
include Colbert
end

-Sam

Jacob Helwig

unread,
Nov 3, 2009, 11:43:29 AM11/3/09
to pdx...@googlegroups.com
On Tue, Nov 3, 2009 at 08:24, Jason LaPier <jason....@gmail.com> wrote:
> Actually, based on your original example, I think it's safe to say that in
> ruby, particularly in many ruby libraries (rails, facets, etc) if you want
> to test for truthiness (beyond a simple comparison), there's probably a
> method that ends in ? that can help you out.
> The part that causes me grief is sometimes, the method will start with is_ -
> as in something.is_a?(Thing). This makes your if statements read very
> nicely:
>   do_this if something.is_a?(Thing)
> But most of the time, you don't have the is_, so you get:
>   do_this if something.present?
> and I want to write:
>   do_this if something.is_present?
>
> Which makes me wonder if some rubyist somewhere has written some method
> missing magic to try any is_method? without the is_, so I can use is_blank?
> and get blank?
> - Jason L.
>

This method missing magic is how RSpec handles a lot of the be_*
matchers. For example: "foo.should be_null" ends up checking if
"foo.null?" is true. Works for any ? method. "foo.should
be_some_crazy_check_that_only_works_on_foos" works just fine.

Not sure if that really helps you, but it's certainly very close to
the behavior you're describing.

-Jacob

Brent Miller

unread,
Nov 3, 2009, 12:08:18 PM11/3/09
to pdx...@googlegroups.com
Here's a first cut:

class Object
def method_missing_with_is?(*args)
method_name = args.shift
if method_name.to_s =~ /^is_(.*)\?$/ && respond_to?("#{$1}?")
self.send("#{$1}?", *args)
else
method_missing_without_is?(method_name, *args)
end
end
# alias_method_chain :method_missing, :is?
alias_method :method_missing_without_is?, :method_missing
alias_method :method_missing, :method_missing_with_is?
end

In a Rails environment you could use alias_method_chain instead of the
two alias_method calls. Here's what it gives:

>> [].empty?
=> true
>> [].is_empty?
=> true
>> [].foo?
NoMethodError: undefined method `foo?' for []:Array
from (eval):7:in `method_missing'
from (irb):2

Enjoy!

Brent

On Nov 3, 2009, at 8:24 AM, Jason LaPier wrote:

=======================================================
Brent Miller
http://www.foliosus.com/

"The problem is that once you have done away with the
ability to make judgments as to right and wrong, true
and false, etc., there's no real culture left. All
that remains is clog dancing and macrame."
-- Neal Stephenson
=======================================================

Jesse Hallett

unread,
Nov 3, 2009, 1:05:54 PM11/3/09
to pdx...@googlegroups.com

The only trouble with that method missing trick is preserving it down through the inheritance hierarchy.  If any class implements `method_missing` without using alias_method_chain then the new semantics will be lost.

Rspec doesn't have that problem because it handles all of the method missing magic in `Kernel`.

That said, I plan to start using alias_method_chain with all of my `method_missing` definitions from now on :)

> Actually, based on your original example, I think it's safe to say > that in ruby, particularly ...

=======================================================
Brent Miller
http://www.foliosus.com/

"The problem is that once you have done away with the
ability to make judgments as to right and wrong, true
and false, etc., there's no real culture left.  All
that remains is clog dancing and macrame."
                                    -- Neal Stephenson
=======================================================

--~--~---------~--~----~------------~-------~--~----~ You received this message because you are su...

Igal Koshevoy

unread,
Nov 3, 2009, 1:28:09 PM11/3/09
to pdx...@googlegroups.com
Markus wrote:
>>> As long as you're going to be extending object, you could get the same
>>> semantics by just writing (w. Python style indentation, 'cause that's
>>> how my brain works):
>>>
>>> class Object
>>> def empty?
>>> !self
>>> end
>>> end
>>>
>>> and just calling x.empty? as your test. For Strings, Arrays, etc.
>>> you'll get the usual empty? and for everything else you'll get !self.
>>>
>
>
>> That's clever and seems to work, but I feel that there's an important issue.
>>
>> The "empty?" method is found on a number of standard Ruby objects.
>> Changing how objects respond to a standard method is naughty. This
>> particular change probably won't hurt anyone, but is a step down a
>> slippery slope that should be approached with caution.
>>
>> In contrast, the "blank?" method approach adds new behavior not present
>> in standard Ruby objects, which makes it clean and safe.
>>
> So a few random counter points, 'cause feeling around to find out where
> the edge is in cases like this is both interesting and fun:
>
I recognize that this proposed "empty?" extension is not a big deal, but
I feel it's worth discussing as a concept because changes to existing
behavior can lead to much unneeded suffering, particularly in more
egregious cases.

> * Adding "empty?" in this way doesn't conflict with the behavior
> of existing classes which implement "empty?", it simply gives it
> (in a reasonable way) to classes that presently don't have it.
>
> In other words, it doesn't "change how objects respond to a
> standard method" at all; it just extends the method to cover all
> objects.
>

The "empty?" method is a standard part of many Ruby objects and there's
existing code that relies on its behavior and whether it's present. A
quick grep showed dozens of uses of "respond_to?(:empty?)" in my
libraries. Your patch changes this behavior, and may therefore break
these libraries, hence my concern.

> * Adding "blank?" to Object, by the same token, isn't really any
> safer--you could still conflict with a library that had defined
> it with different semantics.

I'm talking about reducing the likelihood of breakage and the effort
needed for a fix. It's easier to avoid loading an additional custom
library that redefines a same-named new behavior than it is to fix all
the existing libraries that depend on some standard behavior that changed.

> P.S. If you are worried about things like that, you probably don't want
> to use rails.

I like Rails and appreciate many of the extensions provided by
ActiveSupport. However, I've lost plenty of hours trying to unravel
really bizarre bugs caused by their changes to standard behavior of
methods like "to_s", "inspect", etc. Eventually these things were fixed,
but it wasted a lot of time for many people before the desired new
behavior could be reconciled with the expected standard old behavior.

> Oh, and [probably don't want to use] gems too.
>
It's hard to avoid, but can be a pain. For example, I had to ship fixes
for many apps that broke when RubyGems 1.3.5 was released because it
changed what it was monkey patching. Again, that's just the sort of
thing I'm concerned about.

-igal

Markus

unread,
Nov 3, 2009, 2:16:05 PM11/3/09
to pdx...@googlegroups.com
> I recognize that this proposed "empty?" extension is not a big deal, but
> I feel it's worth discussing as a concept because changes to existing
> behavior can lead to much unneeded suffering, particularly in more
> egregious cases.

Agreed. And if even a few people on the list enjoy or learn from the
back and forth, so much the better.

> > * Adding "empty?" in this way doesn't conflict with the behavior
> > of existing classes which implement "empty?", it simply gives it
> > (in a reasonable way) to classes that presently don't have it.
> >
> > In other words, it doesn't "change how objects respond to a
> > standard method" at all; it just extends the method to cover all
> > objects.
> >
> The "empty?" method is a standard part of many Ruby objects and there's
> existing code that relies on its behavior and whether it's present. A
> quick grep showed dozens of uses of "respond_to?(:empty?)" in my
> libraries. Your patch changes this behavior, and may therefore break
> these libraries, hence my concern.

Argh! You sank my battleship!

This (the use of respond_to? (& defined?, and methods.include? and ...))
is the only real killer counter argument I could see to this point. If
you'd gone too easy on me I was going to bring it up myself.

The only semi-cogent counter-counter argument I can see is that such
testing, if done "honestly" should not break under the mooted extension
of empty?'s range of applicability. They could, for example, occur only
in fungible implementations of the same functionality we're after, or
similar constructs.

I fear, though, that at least some of them would turn out to be
"dishonest" uses--testing for empty, say, as a proxy for checking for
indexablity or enumerablity (I once saw exactly this, because the coder
knew he could write "respont_to? :empty?" but didn't think he could
write "respond_to? :[]=") or even worse, as a backdoor way of doing
class-based dispatch (aka the "Duct taping" anti-pattern).


> > P.S. If you are worried about things like that, you probably don't want
> > to use rails.

> I like Rails and appreciate many of the extensions provided by
> ActiveSupport. However, I've lost plenty of hours trying to unravel
> really bizarre bugs caused by their changes to standard behavior of
> methods like "to_s", "inspect", etc. Eventually these things were fixed,
> but it wasted a lot of time for many people before the desired new
> behavior could be reconciled with the expected standard old behavior.

Yep, I'm right with you.

Except maybe for the "I like Rails" part. ;)

-- Markus


Kevin Scaldeferri

unread,
Nov 3, 2009, 2:31:08 PM11/3/09
to pdx...@googlegroups.com

On Nov 3, 2009, at 11:16 AM, Markus wrote:

>>> * Adding "empty?" in this way doesn't conflict with the
>>> behavior
>>> of existing classes which implement "empty?", it simply
>>> gives it
>>> (in a reasonable way) to classes that presently don't have
>>> it.
>>>
>>> In other words, it doesn't "change how objects respond to a
>>> standard method" at all; it just extends the method to
>>> cover all
>>> objects.
>>>
>> The "empty?" method is a standard part of many Ruby objects and
>> there's
>> existing code that relies on its behavior and whether it's present. A
>> quick grep showed dozens of uses of "respond_to?(:empty?)" in my
>> libraries. Your patch changes this behavior, and may therefore break
>> these libraries, hence my concern.
>
> Argh! You sank my battleship!
>
> This (the use of respond_to? (& defined?, and methods.include?
> and ...))
> is the only real killer counter argument I could see to this point.
> If
> you'd gone too easy on me I was going to bring it up myself.


This brings up a question in my mind. In the Perl community, it's
considered good practice that anytime you use AUTOLOAD, you should
also override UNIVERSAL::can to respond in "the right way". However,
I don't think I've ever seen a Ruby class with a method_missing also
override respond_to?. Do Rubyists simply not consider this a
problem? Or are they just lazy? :-)


-kevin

Igal Koshevoy

unread,
Nov 3, 2009, 2:33:26 PM11/3/09
to pdx...@googlegroups.com
Jokes aside, this discussion is a useful reminder that the "right" way
to do things is dependent on the problem's context, person's values and
community's culture.[1]

In real-world Ruby coding, I think most teams would quickly settle the
original question by using the "blank?" method provided by Rails'
ActiveSupport or Facets because these are commonly-used and well-tested
solutions. As for whether one should tinker with "empty?" or make other
adventuresome changes, this is often settled if it causes enough
displeasure or errors.

-igal

[1] This discussion would have gone rather differently if posted to the
Python mailing list:
Q: What's the right way to do ____?
A: No, go read PEP-8: http://www.python.org/dev/peps/pep-0008/
Q: Is it okay to change how ___ behaves?
A: No, that's not Pythonic.
Versus the Perl mailing list:
Q: What's the right way to do ___?
A: Sure! There's More Than One Way To Do It.
Q: Is it okay to change how ____ behaves?
A: Sure! Here are some tips:
http://www.csse.monash.edu.au/~damian/papers/HTML/Perligata.html

Duncan Beevers

unread,
Nov 3, 2009, 2:33:34 PM11/3/09
to pdx...@googlegroups.com
Here's a quick is_? implementation that doesn't rely on method aliasing, just plain old ruby inheritance.

module IsNess
  IS = /^is_(.+\?)$/
  def method_missing m, *args
    if IS === m.to_s
      send($1, *args)
    else
      super
    end
  end
end

class Object
  include IsNess
end


# Try it out
class Foo
  def orange?
    true
  end
end

f = Foo.new
f.is_orange?

Markus

unread,
Nov 3, 2009, 2:47:52 PM11/3/09
to pdx...@googlegroups.com

> This brings up a question in my mind. In the Perl community, it's
> considered good practice that anytime you use AUTOLOAD, you should
> also override UNIVERSAL::can to respond in "the right way". However,
> I don't think I've ever seen a Ruby class with a method_missing also
> override respond_to?. Do Rubyists simply not consider this a
> problem? Or are they just lazy? :-)

Excellent point. The problem (IMHO) is that the barrier is much higher
for properly overriding "respond_to?" --

1) You have to properly chain it, and be aware that (at least in
theory) other may be doing the same thing at the same level.

2) If you are responding to "wildcard" methods, you have to make
sure that you match the same templates in both places (not DRY)
or add a level of shared template matching (not as simple).

3) If you are overriding a deeper method missing (perhaps
unintentionally!) you have to figure out what methods it adds
and mask them.

Even worse is the question of what to do with My_class.methods -- should
it be extended to match? What if the method_missing can respond to an
unbounded (effectively infinite) list of messages? Do you return them
as a lazy list, or...?

-- Markus

Brent Miller

unread,
Nov 3, 2009, 2:53:50 PM11/3/09
to pdx...@googlegroups.com
One way to get around this problem is to have your method missing
define the missing methods. So if I call:

my_obj.is_empty?

the method_missing does this:

def is_empty?
empty?
end

That solves the problem, but only *after* the first invocation:

my_obj = []
my_obj.respond_to?(:is_empty?) # => false
my_obj.is_empty? # => true
my_obj.respond_to?(:is_empty?) # => true

It's a reasonable compromise that saves you from the non-dry
templating problem.

Brent

Markus

unread,
Nov 3, 2009, 2:56:44 PM11/3/09
to pdx...@googlegroups.com
Igal --

Ah ha!

My straw man rises from the dead!

> > > In other words, it doesn't "change how objects respond to a
> > > standard method" at all; it just extends the method to cover all
> > > objects.

> > The "empty?" method is a standard part of many Ruby objects and there's
> > existing code that relies on its behavior and whether it's present. A
> > quick grep showed dozens of uses of "respond_to?(:empty?)" in my
> > libraries. Your patch changes this behavior, and may therefore break
> > these libraries, hence my concern.
>
> Argh! You sank my battleship!
>
> This (the use of respond_to? (& defined?, and methods.include? and ...))
> is the only real killer counter argument I could see to this point. If
> you'd gone too easy on me I was going to bring it up myself.

But as Keven implicitly pointed out, if the "empty?" monkey patch were
done with method_missing (or if we overrode "respond_to?" to hide it!)
the problem goes away.

Yeeeeee...haaaaa!

-- Markus

P.S. For anyone out there who might think I'm seriously recommending
this, ask around about me. And for anyone who thinks I'm _not_ serious
about these sorts of tricks being a real, tangible possibility, go dig
up early discussions on bignum, open structs, active_support, active
record, gems, the agents library, etc.


Markus

unread,
Nov 3, 2009, 3:51:58 PM11/3/09
to pdx...@googlegroups.com
On Tue, 2009-11-03 at 11:53 -0800, Brent Miller wrote:
> One way to get around this problem is to have your method missing
> define the missing methods. So if I call:
>
> my_obj.is_empty?
>
> the method_missing does this:
>
> def is_empty?
> empty?
> end
>
> That solves the problem, but only *after* the first invocation:
>
> my_obj = []
> my_obj.respond_to?(:is_empty?) # => false
> my_obj.is_empty? # => true
> my_obj.respond_to?(:is_empty?) # => true
>
> It's a reasonable compromise that saves you from the non-dry
> templating problem.

Reasonable, unless no one ever blindly calls the method (they always
check to see if it's there first).

So to work this requires that the calling code act unsafely or do ugly
rescue stuff.

Also, it doesn't deal with all cases as nicely:

* Methods that are called only once on each object of a classes
* Methods that change with circumstance
* Large sets of methods that are called once each

-- Markus

John Labovitz

unread,
Nov 3, 2009, 8:03:22 PM11/3/09
to pdx...@googlegroups.com
On 3 Nov 2009, at 11:31 AM, Kevin Scaldeferri wrote:

> This brings up a question in my mind. In the Perl community, it's
> considered good practice that anytime you use AUTOLOAD, you should
> also override UNIVERSAL::can to respond in "the right way". However,
> I don't think I've ever seen a Ruby class with a method_missing also
> override respond_to?. Do Rubyists simply not consider this a
> problem? Or are they just lazy? :-)

I've done it in some custom extensions to Builder::XmlMarkup to make
#to_s work sanely. I'm sorry to say I can't remember exactly *why* I
did it, but I think I was finding that otherwise calling #to_s on the
builder object was causing <to_s> elements to be inserted into the
final XML. Of course, this might be a special case because Builder
uses a "blank slate" object. Anyway, FWIW...

module Builder

class XmlMarkup

def to_html; target!; end
def to_str; target!; end
def to_s; target!; end

def respond_to?(method_id, include_private=false)
method_name = method_id.to_s
%w{to_html to_str to_s}.include?(method_name) || method_name
=~ /^[A-Za-z0-9]+$/
end

end

--John

Markus Roberts

unread,
Nov 3, 2009, 8:09:40 PM11/3/09
to pdx...@googlegroups.com

Odd. I wouldn't think you'd need to do that in the first place, since
just defining the method as you do should update the "respond_to?"
results (they're dynamically generated). But since you aren't calling
super, you aren't getting that effect, but you are saying it responds
to all alpha-numeric methods, but not the "target!" that it obviously
does respond to...why were you doing this again?

-- Markus


John Labovitz

unread,
Nov 3, 2009, 8:34:03 PM11/3/09
to pdx...@googlegroups.com
Sigh. I can't seem to duplicate whatever it was I attempting to fix
in the first place.

Never mind. ;)

--John

mar...@reality.com

unread,
Nov 4, 2009, 1:18:56 AM11/4/09
to pdx...@googlegroups.com

*laugh*

I know that feeling. I've got a directory full of solutions just waiting for me to remember (or encounter) their corresponding problems.

-- Markus
Sent via BlackBerry from T-Mobile

Craig McClanahan

unread,
Nov 4, 2009, 1:40:03 AM11/4/09
to pdx...@googlegroups.com
On Tue, Nov 3, 2009 at 10:18 PM, <mar...@reality.com> wrote:
>
> *laugh*
>
> I know that feeling.  I've got a directory full of solutions just waiting for me to remember (or encounter) their corresponding problems.

Years ago I had a colleague with a directory just like that, plus a
few things that were a bit more, umm, proactive. He called his
directory "~/weapons" :-).

Craig McClanahan
Reply all
Reply to author
Forward
0 new messages