Named Parameters in Ruby Structs

后端 未结 12 1627
小蘑菇
小蘑菇 2020-12-29 20:12

I\'m pretty new to Ruby so apologies if this is an obvious question.

I\'d like to use named parameters when instantiating a Struct, i.e. be able to specify which ite

相关标签:
12条回答
  • 2020-12-29 20:47

    Have you considered OpenStruct?

    require 'ostruct'
    
    person = OpenStruct.new(:name => "John", :age => 20)
    p person               # #<OpenStruct name="John", age=20>
    p person.name          # "John"
    p person.adress        # nil
    
    0 讨论(0)
  • 2020-12-29 20:48

    With newer versions of Ruby you can use keyword_init: true:

    Movie = Struct.new(:title, :length, :rating, keyword_init: true)
    
    Movie.new(title: 'Title', length: '120m', rating: 'R')
      # => #<struct Movie title="Title", length="120m", rating="R">
    
    0 讨论(0)
  • 2020-12-29 20:53

    Based on @Andrew Grimm's answer, but using Ruby 2.0's keyword arguments:

    class Struct
    
      # allow keyword arguments for Structs
      def initialize(*args, **kwargs)
        param_hash = kwargs.any? ? kwargs : Hash[ members.zip(args) ]
        param_hash.each { |k,v| self[k] = v }
      end
    
    end
    

    Note that this does not allow mixing of regular and keyword arguments-- you can only use one or the other.

    0 讨论(0)
  • 2020-12-29 20:56

    If your hash keys are in order you can call the splat operator to the rescue:

    NavLink = Struct.new(:name, :url, :title)
    link = { 
      name: 'Stack Overflow', 
      url: 'https://stackoverflow.com', 
      title: 'Sure whatever' 
    }
    actual_link = NavLink.new(*link.values) 
    #<struct NavLink name="Stack Overflow", url="https://stackoverflow.com", title="Sure whatever"> 
    
    0 讨论(0)
  • 2020-12-29 20:59

    You could rearrange the ifs.

    class MyStruct < Struct
      # Override the initialize to handle hashes of named parameters
      def initialize *args
        # I think this is called a guard clause
        # I suspect the *args is redundant but I'm not certain
        return super *args unless (args.length == 1 and args.first.instance_of? Hash)
        args.first.each_pair do |k, v|
          # I can't remember what having the conditional on the same line is called
          self[k] = v if members.include? k
        end
      end
    end
    
    0 讨论(0)
  • 2020-12-29 21:01

    For a 1-to-1 equivalent with the Struct behavior (raise when the required argument is not given) I use this sometimes (Ruby 2+):

    def Struct.keyed(*attribute_names)
      Struct.new(*attribute_names) do
        def initialize(**kwargs)
          attr_values = attribute_names.map{|a| kwargs.fetch(a) }
          super(*attr_values)
        end
      end
    end
    

    and from there on

    class SimpleExecutor < Struct.keyed :foo, :bar
      ...
    end
    

    This will raise a KeyError if you missed an argument, so real nice for stricter constructors and constructors with lots of arguments, data transfer objects and the like.

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