Consider a class that supports a number of configurable properties.  

As a concrete example, take a class that represents an HTML link.  It
requires that a "url" and link "content" be provided.  It also supports two
optional attributes: "title" and "target".

    Link
      url
      content
      ?title
      ?target
   
I've seen a bunch of different ways of configuring such objects ...

----
1. SettingAttributes

The obvious way is just to create the instance, and then call
writer-methods to set attributes, e.g.

    class Link 
        def initialize(url, content)
            @url = url
            @content = content
        end
        attr_accessor :url, :content, :link, :target
    end

    link = Link.new(url, "here")
    link.title = "the whole story"

----
2. OptionalArguments 

You can have initialize() support optional (positional) arguments, e.g.

    class Link 
        def initialize(url, content, title = nil, target = nil)
            @url = url
            @content = content
            @title = title
            @target = target
        end
        attr_accessor :url, :content, :link, :target
    end

    link = Link.new(url, "here", "the whole story")

but, this doesn't scale well: if you have a bunch of optional attributes,
you have to start inserting "nil":

    link2 = Link.new(url, "here", nil, "helpFrame")

----
3. OptionalArgumentMap

Another alternative is pass in a map of named optional args, e.g.

    class Link 
        def initialize(url, content, args = {})
          @url = url
          @content = content
          @title = args[:title]
          @target = args[:target]
        end
    end 

    link = Link.new("http://", "here", {:title => "the whole story"})
    helplink = Link.new("/help", "help" {:target => "helpFrame"})

As I understand it, there's some syntax-sugar planned for Ruby-2.0, that
would make this a bit cleaner:

    link = Link.new("http://", "here", title: "the whole story")

Right?

----
4. YieldSelf

I've seen some people include a "yield self" in the initialize() method,
which allows you to do something like this:

    class Link 
        def initialize(url, content)
          @url = url
          @content = content
          yield self if block_given?
        end
    end 

    link = Link.new(url, "here") { |l|
        l.title = "the whole story"
    }

Hmmm.  How does this help, exactly?  I guess it could save you from having
to use a temp variable, in some cases.

----
5. InstanceEval

Or, you can use instance_eval():

    class Link
        def initialize(url, content, &config)
          @url = url
          @content = content
          instance_eval(&config) if (config)
        end
    end 

    link = Link.new("http://", "here") { 
        @title = "the whole story" 
    }

This is a nifty trick, though it does have the downside that you can set
arbitrary instance-variables in the block, breaking class encapsulation.

----
In Summary

Where am I going to with this?  No idea.  I guess I'm just wondering what
y'all consider to be the benefits/problems of each approach.

-- 
cheers, MikeW

"He smelled as if he had just eaten a mustard-coated camel ..."
    -- Martin Amis, "London Fields"