A Cool Way of Passing Arguments in Ruby

As I was programming the game engine for Ruby Tower Defense, I realized something: Sometimes you want to pass arguments out of order (So you can leave certain default parameters, but skip past others). It appears that in Ruby, there is no built-in way to do this. To give an example:

class Text < Engine::GameObject
    def initialize x=0, y=0, text="TEST STRING", size=20, \
        color=[255,255,255], font="FreeSans.ttf", aa=true
        # initialization code here
    end
end

So if I wanted to have the text “Hi!” at 200, 50:

Text.new(200, 50,"Hi!")

But what if I want to change anti-aliasing (aa) to false? So far, I’d been entering everything in order. I remembered back to when I was using Python, where I could pass arguments out of order, if I specified the variable names. I tried this in Ruby:

Text.new(x=200, y=50, text="Hi!", aa=false)

and size would become equal to false, not what I wanted…

Then after messing around for a little while, I found out that you can pass a hash to a method, in a way that looks about right from the outside:

Text.new(:x => 200, :y => 50, :text => "Hi!", :aa => false)
# It looks event better if you leave off the parenthesis,
# but if I don't wordpress turns x into a smily

But has some problems on the inside:

class Text < Engine::GameObject
    # Creates a new Text object
    #
    # Parameters are in hash format (i.e. Text.new(:x => 30, :y => 500) )
    # Takes:
    # * x position (:x)
    # * y position (:y)
    # * the text to display (:text)
    # * Life (:life)
    # * color (:color)
    # * Anti-Aliasing (true or false) (:aa)
    # * Font Size (:size)
    # * Font file to use (must be ttf) (:font)
    def initialize settings={}
        # ||= is the ruby conditional assignment
        # operator, only if the variable has no value
        # is it assigned the value
        settings[:x] ||= 0
        settings[:y] ||= 0
        settings[:text] ||= "TEST STRING"
        settings[:life] ||= 1
        settings[:color] ||= [255,255,255]
        settings[:aa] ||= true # Anti-Aliasing
        settings[:size] ||= 20
        settings[:font] ||="FreeSans.ttf"
        # ...
    end
end

This works, but with two drawbacks:

  1. More to type (but I could create a function to make this better)
  2. We lose auto documentation, and have to write it ourselves

Update: See comments

It’d be much better, IMO, if Ruby supported this internally… But this’ll have to do for now!

Advertisements

~ by Tyler Church on September 22, 2009.

2 Responses to “A Cool Way of Passing Arguments in Ruby”

  1. One of my favorite ways to handle this is to define a default_settings hash in the method, then use “settings = default_settings.merge( settings )”. If the list of settings isn’t too long, I’ll also often copy it into the arguments list for auto-documentation purposes.

    def initialize( settings = {:x => 0, :y => 0} )
      default_settings = {:x => 0, :y => 0}
      settings = default_settings.merge( settings )
      # ...
    end
    
    • Didn’t know hashes had a merge method (I didn’t check the docs…). Thanks for letting me know!

      I’ll go and add that now… hack hack hack hack

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: