Class: Hashstructor::Member

Inherits:
Object
  • Object
show all
Defined in:
lib/hashstructor/member.rb

Overview

A member within a Hashstructor class that should be populated by the hash passed into #initialize.

Constant Summary collapse

VALID_MEMBER_TYPES =

The allowed #member_types for a Member:

  • :normal - a normal value. raises error if hash or array given unless the :no_collections option is set.
  • :hash - a hash, with all keys symbolized unless the :string_keys option is set.
  • :array - an array
  • :set - a set

Note that these types refer to the "collection status" of the member. A :normal member will happily accept any value unless a :custom_type option is passed.

[ :normal, :hash, :set, :array ].freeze
BOOL_PROC =

The procedure used in VALID_VALUE_TYPES for both TrueClass and FalseClass.

Proc.new do |v|
  case v
    when true
      true
    when false
      false
    else
      raise "'#{v}' not stringable" unless v.respond_to?(:to_s) && !v.nil?
      v = v.downcase
      case v.downcase
        when "true", "t", "on", "yes"
          true
        when "false", "f", "off", "no"
          false
        else
          raise HashstructorError, "unknown value when parsing boolean: #{v}"
      end
  end
end
VALID_VALUE_TYPES =

A hash of Class => Proc converters for value types. Any value type in this list, as well as any class that includes or prepends Hashstructor, is valid for #value_type. This is intentionally not frozen; if you want to extend it for your own use cases, I'm not going to get in your way.

{
  String => Proc.new do |v|
    v.to_s
  end,
  Symbol => Proc.new do |v|
    v.to_sym
  end,
  Integer => Proc.new do |v|
    Integer(v.to_s)
  end,
  Float => Proc.new do |v|
    Float(v.to_s)
  end,
  TrueClass => BOOL_PROC,
  FalseClass => BOOL_PROC,
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, name, options) ⇒ Member

Returns a new instance of Member.

Raises:



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/hashstructor/member.rb', line 99

def initialize(klass, name, options)
  member_type = options[:member_type] || :normal
  options.delete(:member_type)
  value_type = options[:value_type]
  options.delete(:value_type)
  required = !!(options[:required])
  options.delete(:required)
  attr_kind = options[:attr_kind]
  options.delete(:attr_kind)

  @options = options.freeze

  raise HashstructorError, "'name' must respond to :to_sym." unless name.respond_to?(:to_sym)
  @name = name.to_sym

  raise HashstructorError, "'member_type' (#{member_type}) must be one of: [ #{VALID_MEMBER_TYPES.join(", ")} ]" \
    unless VALID_MEMBER_TYPES.include?(member_type.to_sym)

  raise HashstructorError, "'member_type' must be :normal to use 'default_value'." \
    if member_type != :normal && options[:default_value]

  @member_type = member_type.to_sym

  raise HashstructorError, "'value_type' must be nil or a Class." \
    unless value_type == nil || value_type.is_a?(Class)
  raise HashstructorError, "'value_type' class, #{value_type.name}, must be in " +
        "VALID_VALUE_TYPES ([ #{VALID_VALUE_TYPES.keys.map { |c| c.name}.join(", ")} ]) " +
        "or include or prepend Hashstructor." \
    unless value_type == nil || VALID_VALUE_TYPES[value_type] != nil || value_type.ancestors.include?(Hashstructor)

  @value_type = value_type

  raise HashstructorError, "'required' must be true if 'default_value'" \
    if !required && options[:default_value]
  @required = required

  raise HashstructorError, "'validation' must be a Proc." unless options[:validation].nil? || options[:validation].is_a?(Proc)


  case attr_kind
    when nil
      # do nothing
    when :reader
      klass.send(:attr_reader, @name)
    when :accessor
      klass.send(:attr_accessor, @name)
    else
      raise HashstructorError, "Unrecognized attr_kind: #{attr_kind}"
  end
  @attr_kind = attr_kind
end

Instance Attribute Details

#attr_kind(nil, :reader, :accessor) (readonly)

Specifies what type of attr (nil, :reader, or :accessor) that this member should define on its class.

Returns:

  • ((nil, :reader, :accessor))

    the type of attr to create.



94
95
96
# File 'lib/hashstructor/member.rb', line 94

def attr_kind
  @attr_kind
end

#member_typeSymbol (readonly)

Returns the type of the member; see VALID_MEMBER_TYPES.

Returns:



23
24
25
# File 'lib/hashstructor/member.rb', line 23

def member_type
  @member_type
end

#nameSymbol (readonly)

Returns the name of the member, in the parsed hash.

Returns:

  • (Symbol)

    the name of the member, in the parsed hash.



20
21
22
# File 'lib/hashstructor/member.rb', line 20

def name
  @name
end

#optionsHash (readonly)

Returns a (frozen) set of all extra options passed to the member.

Returns:

  • (Hash)

    a (frozen) set of all extra options passed to the member.



97
98
99
# File 'lib/hashstructor/member.rb', line 97

def options
  @options
end

#requiredObject (readonly)

If true, attempting to construct this object without setting this member will raise an error.



88
89
90
# File 'lib/hashstructor/member.rb', line 88

def required
  @required
end

#value_type(nil, Class) (readonly)

Determines the class that Hashstructor should attempt to coerce a given value into. For example, Fixnum will attempt to coerce a scalar value into a Fixnum.

The valid types for #value_type are:

  • String
  • Symbol
  • Integer
  • Float
  • TrueClass or FalseClass (for booleans)
  • any class that includes or prepends Hashstructor

Returns:

  • ((nil, Class))

    the type of the value stored in this member.



83
84
85
# File 'lib/hashstructor/member.rb', line 83

def value_type
  @value_type
end

Instance Method Details

#parse_single(value) ⇒ Object

Parses the passed-in value (always a single item; InstanceMethods#hashstruct handles the breaking down of arrays and hashes) and returns a value according to #value_type.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/hashstructor/member.rb', line 153

def parse_single(value)
  retval = 
    if value_type.nil?
      value
    elsif value_type.ancestors.include?(Hashstructor)
      raise HashstructorError, "No hash provided for building a Hashstructor object." unless value.is_a?(Hash)

      value_type.new(value)
    else
      VALID_VALUE_TYPES[value_type].call(value)
    end

  if options[:validation]
    errors = []
    options[:validation].call(retval, errors)

    if !errors.empty?
      raise HashstructorError, "Validation failure for '#{name}': #{errors.join("; ")}"
    end
  end

  retval
end