Class: Hashie::Dash

Inherits:
Hash
  • Object
show all
Includes:
Extensions::PrettyInspect
Defined in:
lib/hashie/dash.rb

Overview

A Dash is a 'defined' or 'discrete' Hash, that is, a Hash that has a set of defined keys that are accessible (with optional defaults) and only those keys may be set or read.

Dashes are useful when you need to create a very simple lightweight data object that needs even fewer options and resources than something like a DataMapper resource.

It is preferrable to a Struct because of the in-class API for defining properties as well as per-property defaults.

Direct Known Subclasses

Trash

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Extensions::PrettyInspect

#hashie_inspect, included

Methods inherited from Hash

#to_hash, #to_json, #to_mash

Methods included from Extensions::StringifyKeys

#stringify_keys, #stringify_keys!

Methods included from Extensions::StringifyKeys::ClassMethods

#stringify_keys, #stringify_keys!, #stringify_keys_recursively!

Constructor Details

#initialize(attributes = {}, &block) ⇒ Dash

You may initialize a Dash with an attributes hash just like you would many other kinds of data objects.


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/hashie/dash.rb', line 104

def initialize(attributes = {}, &block)
  super(&block)

  self.class.defaults.each_pair do |prop, value|
    self[prop] = begin
      val = value.dup
      if val.is_a?(Proc)
        val.arity == 1 ? val.call(self) : val.call
      else
        val
      end
    rescue TypeError
      value
    end
  end

  initialize_attributes(attributes)
  assert_required_attributes_set!
end

Class Attribute Details

.defaultsObject (readonly)

Returns the value of attribute defaults


60
61
62
# File 'lib/hashie/dash.rb', line 60

def defaults
  @defaults
end

.gettersObject (readonly)

Returns the value of attribute getters


61
62
63
# File 'lib/hashie/dash.rb', line 61

def getters
  @getters
end

.propertiesObject (readonly)

Returns the value of attribute properties


60
61
62
# File 'lib/hashie/dash.rb', line 60

def properties
  @properties
end

.required_propertiesObject (readonly)

Returns the value of attribute required_properties


62
63
64
# File 'lib/hashie/dash.rb', line 62

def required_properties
  @required_properties
end

Class Method Details

.inherited(klass) ⇒ Object


69
70
71
72
73
74
75
76
# File 'lib/hashie/dash.rb', line 69

def self.inherited(klass)
  super
  (@subclasses ||= Set.new) << klass
  klass.instance_variable_set('@properties', properties.dup)
  klass.instance_variable_set('@getters', getters.dup)
  klass.instance_variable_set('@defaults', defaults.dup)
  klass.instance_variable_set('@required_properties', required_properties.dup)
end

.property(property_name, options = {}) ⇒ Object

Defines a property on the Dash. Options are as follows:

  • :default - Specify a default value for this property, to be returned before a value is set on the property in a new Dash.

  • :required - Specify the value as required for this property, to raise an error if a value is unset in a new or existing Dash. If a Proc is provided, it will be run in the context of the Dash instance. If a Symbol is provided, the property it represents must not be nil. The property is only required if the value is truthy.

  • :message - Specify custom error message for required property


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/hashie/dash.rb', line 36

def self.property(property_name, options = {})
  properties << property_name

  if options.key?(:default)
    defaults[property_name] = options[:default]
  elsif defaults.key?(property_name)
    defaults.delete property_name
  end

  define_getter_for(property_name)
  define_setter_for(property_name)

  @subclasses.each { |klass| klass.property(property_name, options) } if defined? @subclasses

  condition = options.delete(:required)
  if condition
    message = options.delete(:message) || "is required for #{name}."
    required_properties[property_name] = { condition: condition, message: message }
  elsif options.key?(:message)
    raise ArgumentError, 'The :message option should be used with :required option.'
  end
end

.property?(name) ⇒ Boolean

Check to see if the specified property has already been defined.

Returns:

  • (Boolean)

80
81
82
# File 'lib/hashie/dash.rb', line 80

def self.property?(name)
  properties.include? name
end

.required?(name) ⇒ Boolean

Check to see if the specified property is required.

Returns:

  • (Boolean)

86
87
88
# File 'lib/hashie/dash.rb', line 86

def self.required?(name)
  required_properties.key? name
end

Instance Method Details

#[](property) ⇒ Object

Retrieve a value from the Dash (will return the property's default value if it hasn't been set).


130
131
132
133
134
135
136
137
138
139
140
# File 'lib/hashie/dash.rb', line 130

def [](property)
  assert_property_exists! property
  value = super(property)
  # If the value is a lambda, proc, or whatever answers to call, eval the thing!
  if value.is_a? Proc
    self[property] = value.call # Set the result of the call as a value
  else
    yield value if block_given?
    value
  end
end

#[]=(property, value) ⇒ Object

Set a value on the Dash in a Hash-like way. Only works on pre-existing properties.


144
145
146
147
148
# File 'lib/hashie/dash.rb', line 144

def []=(property, value)
  assert_property_required! property, value
  assert_property_exists! property
  super(property, value)
end

#merge(other_hash) ⇒ Object


150
151
152
153
154
155
156
# File 'lib/hashie/dash.rb', line 150

def merge(other_hash)
  new_dash = dup
  other_hash.each do |k, v|
    new_dash[k] = block_given? ? yield(k, self[k], v) : v
  end
  new_dash
end

#merge!(other_hash) ⇒ Object


158
159
160
161
162
163
# File 'lib/hashie/dash.rb', line 158

def merge!(other_hash)
  other_hash.each do |k, v|
    self[k] = block_given? ? yield(k, self[k], v) : v
  end
  self
end

#replace(other_hash) ⇒ Object


165
166
167
168
169
170
# File 'lib/hashie/dash.rb', line 165

def replace(other_hash)
  other_hash = self.class.defaults.merge(other_hash)
  (keys - other_hash.keys).each { |key| delete(key) }
  other_hash.each { |key, value| self[key] = value }
  self
end

#update_attributes!(attributes) ⇒ Object


172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/hashie/dash.rb', line 172

def update_attributes!(attributes)
  update_attributes(attributes)

  self.class.defaults.each_pair do |prop, value|
    next unless self[prop].nil?
    self[prop] = begin
      value.dup
    rescue TypeError
      value
    end
  end
  assert_required_attributes_set!
end