Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making an option false by default

Tags:

ruby

This is a common way to set a default in Ruby:

class QuietByDefault
  def initialize(opts = {})
    @verbose = opts[:verbose]
  end
end

This is an easy trap to fall into:

class VerboseNoMatterWhat
  def initialize(opts = {})
    @verbose = opts[:verbose] || true
  end
end

This is a correct way to do it:

class VerboseByDefault
  def initialize(opts = {})
    @verbose = opts.include?(:verbose) ? opts[:verbose] : true
  end
end

What is the best / cleanest way to code VerboseByDefault? (I could factor it out, of course.)

What pattern is widely used, if any, in Ruby code in general? Does ActiveSupport have a pattern for this? (Minimal is better -- I don't need a full command line option parser.)

Ranting P.S.: I don't like the asymmetry between code that handles a default true vs. code that handles a default false option. A pattern that makes changing between the two -- without causing bugs -- would be a good thing to see.

like image 718
David J. Avatar asked Aug 13 '12 17:08

David J.


2 Answers

A simple way to do it is by using the second argument to Hash#fetch

class VerboseByDefault
  def initialize(opts = {})
    @verbose = opts.fetch(:verbose, true)
  end
end

For complex defaults, fetch can also take a block, which is executed if the value isn't in the hash. See: http://ruby-doc.org/core-1.9.3/Hash.html#method-i-fetch

like image 150
Tim Peters Avatar answered Sep 28 '22 01:09

Tim Peters


I've commonly seen it as setting all your defaults, and then merging them with the opts. such as..

def initialize(opts = {})
  @options = { :verbose => false, :foo => 42 } 
  @options.merge!(opts)
  # ...
end

This way all of your options are set in one place and you just merge the user supplied ones.

like image 42
Doon Avatar answered Sep 28 '22 02:09

Doon