What's a nice clean way to use an options hash

2019-03-14 01:43发布

Let's say I want a method which will be called like this:

 tiger = create_tiger( :num_stripes => 12, :max_speed => 43.2 )
 tiger.num_stripes # will be 12

where some of the options have default values:

 tiger = create_tiger( :max_speed => 43.2 )
 tiger.num_stripes # will have some default value

what's a nice idiomatic ruby way of implementing that defaulting behaviour in the method implementation?

标签: ruby hash
4条回答
兄弟一词,经得起流年.
2楼-- · 2019-03-14 02:20

It's usually best to encapsulate safe defaults in a Hash that's declared as a constant. For example:

require 'ostruct'

require 'ostruct'

class Tiger < OpenStruct
  DEFAULTS = {
    :num_stripes => 12,
    :max_speed => 43.2
  }.freeze

  def initialize(options = { })
    super(DEFAULTS.merge(options))
  end
end

tiger = Tiger.new(:max_speed => 19.95)

puts tiger.max_speed
puts tiger.num_stripes

It is important to note when merging Hash objects that String and Symbol keys are different and will not be combined as you might expect. In the Rails environment, you can always convert one to the other using Hash#symbolize_keys or by declaring them as HashWithIndifferentAccess which maps away the difference for you.

查看更多
该账号已被封号
3楼-- · 2019-03-14 02:21

If you're using Rails (not just plain Ruby), a slightly shorter method is

def foo(options = {})
  options.reverse_merge! { ... defaults ... }
end

This has the added advantage of allowing you to do multiple lines a tad bit more cleanly:

def foo(options = {})
  options.reverse_merge!(
    :some_default => true,
    :other_default => 5
  )
end
查看更多
女痞
4楼-- · 2019-03-14 02:31
def foo(options = {})
  options = { ... defaults ... }.merge(options)
end
查看更多
乱世女痞
5楼-- · 2019-03-14 02:35

In case anyone is seeing this from google, this question is old and out of date. The modern and much cleaner answer (with Ruby > 2.0) is to use keyword arguments. They have several advantages.

1.) you can require the name of the key in the hash. (in ruby > 2.1)

2.) you don't have to "unpack" the hash in the function. The keys are simply handed to you as variables. (thus you don't have to do like speed = opts[:speed])

3.) It's cleaner

def foo(num_stripes: 12, **rest)
  print num_stripes, rest
end

foo({max_speed: 42}) # would print '12, {max_speed: 42}'

see full ruby docs here: http://www.ruby-doc.org/core-2.1.0/doc/syntax/methods_rdoc.html#label-Array%2FHash+Argument

and a good little blog post here: http://robots.thoughtbot.com/ruby-2-keyword-arguments

查看更多
登录 后发表回答