DRY Ruby Initialization with Hash Argument

后端 未结 6 2102

I find myself using hash arguments to constructors quite a bit, especially when writing DSLs for configuration or other bits of API that the end user will be exposed to. Wha

6条回答
  •  无人及你
    2020-11-29 17:32

    Given your hashes would include ActiveSupport::CoreExtensions::Hash::Slice, there is a very nice solution:

    class Example
    
      PROPERTIES = [:name, :age]
    
      attr_reader *PROPERTIES  #<-- use the star expansion operator here
    
      def initialize(args)
        args.slice(PROPERTIES).each {|k,v|  #<-- slice comes from ActiveSupport
          instance_variable_set "@#{k}", v
        } if args.is_a? Hash
      end
    end
    

    I would abstract this to a generic module which you could include and which defines a "has_properties" method to set the properties and do the proper initialization (this is untested, take it as pseudo code):

    module HasProperties
      def self.has_properties *args
        class_eval { attr_reader *args }
      end
    
      def self.included base
        base.extend InstanceMethods
      end
    
      module InstanceMethods
        def initialize(args)
          args.slice(PROPERTIES).each {|k,v|
            instance_variable_set "@#{k}", v
          } if args.is_a? Hash
        end
      end
    end
    

提交回复
热议问题