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.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/hashie/dash.rb', line 94

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

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

  initialize_attributes(attributes)
  assert_required_attributes_set!
end

Class Attribute Details

.defaultsObject (readonly)

Returns the value of attribute defaults.



65
66
67
# File 'lib/hashie/dash.rb', line 65

def defaults
  @defaults
end

.propertiesObject (readonly)

Returns the value of attribute properties.



65
66
67
# File 'lib/hashie/dash.rb', line 65

def properties
  @properties
end

.required_propertiesObject (readonly)

Returns the value of attribute required_properties.



66
67
68
# File 'lib/hashie/dash.rb', line 66

def required_properties
  @required_properties
end

Class Method Details

.inherited(klass) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/hashie/dash.rb', line 72

def self.inherited(klass)
  super
  (@subclasses ||= Set.new) << klass
  klass.instance_variable_set('@properties', properties.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
58
59
60
61
62
# 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

  unless instance_methods.map(&:to_s).include?("#{property_name}=")
    define_method(property_name) { |&block| self.[](property_name, &block) }
    property_assignment = "#{property_name}=".to_sym
    define_method(property_assignment) { |value| self.[]=(property_name, value) }
  end

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

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

.property?(name) ⇒ Boolean

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

Returns:

  • (Boolean)


82
83
84
# File 'lib/hashie/dash.rb', line 82

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

.required?(name) ⇒ Boolean

Check to see if the specified property is required.

Returns:

  • (Boolean)


88
89
90
# File 'lib/hashie/dash.rb', line 88

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).



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/hashie/dash.rb', line 116

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.



130
131
132
133
134
# File 'lib/hashie/dash.rb', line 130

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

#merge(other_hash) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/hashie/dash.rb', line 136

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



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

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



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

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



158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/hashie/dash.rb', line 158

def update_attributes!(attributes)
  initialize_attributes(attributes)

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