portable perspectives

a blog about programming, life, universe and everything

More Obscure Features of Ruby

First go look at Nick Sieger's post about strange perlisms in ruby, cause it may be interesting for you. But talking about strange features in ruby, I believe there are some that may result even stranger, cause they are not even inherited from other languages, but are matz' own creation, I believe.

super on builtin methods

if you're redefining a builtin method you can use super to access the original one:

>> def puts(*args)
>>  super(*args)
>>  super(*args)
>> end
=> nil
>> puts 123
123
123

yet if you try with your own:

>> def foo() puts "foo" end
=> nil
>> def foo() super end
=> nil
>> foo
NoMethodError: super: no superclass method `foo'
        from (irb):8:in `foo'
        from (irb):10

super without arguments

I knew this feature for long, but never used it in real coding, even if I keep thinking it's handy. super, when used without arguments, passes all the arguments, so the above example would become:

>> def puts(a,b)
>>  super
>>  super
>> end
=> nil
>> puts 345, 567
345
567
345
567
=> nil

The evil context-sensitive while and until modifiers:

Can you tell the difference between this two lines?

 puts 'hello' while false
 begin puts 'hello' end while false

Well, the difference is that the latter will print "hello", because the while modifier always does at least one evaluation of the expression when preceded by a begin..end block. The same happens with the until modifier. Luckily, this evil behaviour is supposed to disappear.

do something, handle exceptions.. or else?

Did you know that ruby's begin allows the definition of an else clause? The else clause is actually part of the rescue part of the block,. and is executed whenever an exception is not raised:

>> def check(x)
>>  begin
?>   raise if x==2
>>  rescue
>>   "error"
>>  else
?>   "ok"
>>  end
>> end
=> nil
>> check(1)
=> "ok"
>> check(2)
=> "error"

..and of course, you do not need begin..

because, I believe you know this, you can write:

>> def check(x)
>>   raise if x==2
>>  rescue
>>   "error"
>>  else
?>   "ok"
>> end
=> nil
>> check(1)
=> "ok"
>> check(2)
=> "error"

methods with whitespace, yay!

I find this quite useful, actually. If you define a method bypassing the ruby parser with define_method you can give it any name you want.

>> class K
>>  define_method("method: hard to get") { 'got!' }
>> end
=> #
>> K.new.send 'method: hard to get'
=> "got!"

You won't be able to call the method with normal ruby syntax, which makes it less or more useful depending on your problem space.

And finally, there is a whole slant of strange things that I believe are remnants of matz' experimenting with the language (is alias $global $other_global used somewhere outside of english.rb?), and even if some of them are quite frightening (if /regex/ anyone?) they will be phased out, so it's ok. If I recall correct ruby also had a glob operator ( <*.c> ) that was killed in the early days, so I trust matz to fix the oddities of the language sooner or later :)

AddThis Social Bookmark Button

4 Responses to “More Obscure Features of Ruby”

  1. Radarek Says:

    “super on builtin methods” Try this:

    module Kernel
      def my_method
        puts "!"
      end
    end
    
    my_method
    
    def my_method
      puts "?"
      super
    end
    

    And it works! But why? ‘super’ search the same method in included modules and in parent class (recursively) but it can’t call the same, but previusly defined method (like in your example). ‘puts’ method is defined in Kernel module so it works. If ‘puts’ method was defined in “global scope” (precisely, in Object class, because simple ‘def method’ define method in Object class) your first example wouldn’t work.

    Watch this:

    class B
      def x
        puts "x"
      end
    end
    
    def B.x
      puts "y"
      super # error
    end
    

    But…

    class B
      def x
        puts "x"
      end
    end
    
    class C < B
      def x
        puts "y"
        super # it works
      end
    end
    

    Sometimes it could be hard to understand (I thought for a while that super could call only method from parent class, I didn’t know about Module example).

  2. riffraff Says:

    ah yes, I knew that this is a side effect of methods in main appearing as private methods in Object, but didn’t think of writing it, thank you :)

    (Oh and I’ll fix your formatting ;)

  3. Csaba Says:

    Hi,

    The execution of the statement

    begin puts 'hello' end while false
    

    Is logical! And similar staements exist in most other programming language.

    That is the reason why cunstructs like >puts ‘hello’ while false< is usally avoided since the avaluation order is not clear (=second part is evaluated first, and determines if (or how) first part is executed! (Normal spokenlanguage is not always (rearely) clear and logical, but programming langue must (should) be!

  4. riffraff Says:

    Hi Csaba, thanks for your comment. Yeah, I know most languages have a repeat/until loop, and this behaviour is logical if you’re used to them :)

    But the point is that postfix while in ruby behaves like a statement modifier, and all of them evaluate the condition before the expression.

    Yet, to offer an at-least once semantic ruby has a special case for the combination of begin..end and this keyword, that makes it behave differently from begin p :x end if false, for example.

    Anyway matz is the authority in this topic.

Sorry, comments are closed for this article.