What's a nice clean way to use an options hash with defaults values as a parameter in ruby

后端 未结 5 946
轻奢々
轻奢々 2021-02-04 16:32

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
         


        
相关标签:
5条回答
  • 2021-02-04 16:45

    Rails 6 (don't know what version is this available from) has a semantic alias:

    def a_method(options={})
      options.with_defaults!(
        a_key: :a_default_value,
        b_key: :b_default_value,
        ..
      )
      ..
    end
    
    0 讨论(0)
  • 2021-02-04 16:53

    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

    0 讨论(0)
  • 2021-02-04 16:59
    def foo(options = {})
      options = { ... defaults ... }.merge(options)
    end
    
    0 讨论(0)
  • 2021-02-04 17:04

    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
    
    0 讨论(0)
  • 2021-02-04 17:04

    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.

    0 讨论(0)
提交回复
热议问题