module Hashmake module HashMakeable # Use the included hook to also extend the including class with HashMake # class methods def self.included(base) base.extend(ClassMethods) end # Process a hash that contains 'hashed args'. Each hashed arg is intended to # be used in initializing an object instance. # # @param [Enumerable] arg_specs An enumerable of ArgSpec objects. Each object # details an arg key that might be expected in the # args hash. # @param [Hash] hashed_args A hash that should contain at least all the required # keys and valid values, according to the arg_specs passed in. # Nonrequired keys can be given as well, but if they are # not then a default value is assigned (again, according to # arg_specs passed in). def hash_make arg_specs, hashed_args, assign_args = true arg_specs.each do |arg_spec| raise ArgumentError, "arg_specs item #{arg_spec} is not a ArgSpec" unless arg_spec.is_a?(ArgSpec) end raise ArgumentError, "hashed_args is not a Hash" unless hashed_args.is_a?(Hash) arg_specs.each do |arg_spec| key = arg_spec.key if hashed_args.has_key?(key) val = hashed_args[key] else if arg_spec.reqd raise ArgumentError, "hashed_args does not have required key #{key}" else if arg_spec.default.is_a?(Proc) && arg_spec.type != Proc val = arg_spec.default.call else val = arg_spec.default end end end if arg_spec.array raise ArgumentError, "val #{val} is not an array" unless val.is_a?(Array) val.each do |item| raise ArgumentError, "array item #{item} is not a #{arg_spec.type}" unless item.is_a?(arg_spec.type) end else raise ArgumentError, "val #{val} is not a #{arg_spec.type}" unless val.is_a?(arg_spec.type) end if assign_args raise ArgumentError, "value #{val} is not valid" unless arg_spec.validator.call(val) self.instance_variable_set("@#{key.to_s}".to_sym, val) end end end # Contains class methods to be added to a class that includes the # HashMakeable module. module ClassMethods end end end