Module: Candy::Piece

Includes:
Crunch, Crunch::Document, Embeddable
Included in:
CandyHash
Defined in:
lib/candy/piece.rb

Overview

Handles autopersistence and single-object retrieval for an arbitrary Ruby class. For retrieving many objects, include Candy::Collection somewhere else or use the magic Candy() factory.

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Methods included from Embeddable

#candy_adopt

Methods included from Crunch::Document

#inc, #inc!, #operate, #operate!, #retrieve, #set, #set!

Methods included from Crunch

#collection, #collection=

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

Candy’s magic ingredient. Assigning to any unknown attribute will push that value into the Mongo collection. Retrieving any unknown attribute will return that value from this record in the Mongo collection.



122
123
124
125
126
127
128
129
130
# File 'lib/candy/piece.rb', line 122

def method_missing(name, *args, &block)
  if name =~ /(.*)=$/  # We're assigning
    self[$1.to_sym] = args[0]
  elsif name =~ /(.*)\?$/  # We're asking
    (self[$1.to_sym] ? true : false)
  else
    self[name]
  end
end

Instance Method Details

#==(subject) ⇒ Object

Objects are equal if they point to the same MongoDB record (unless both have IDs of nil, in which case they’re never equal.)



114
115
116
117
118
# File 'lib/candy/piece.rb', line 114

def ==(subject)
  return false if id.nil?
  return false unless subject.respond_to?(:id)
  self.id == subject.id 
end

#[](key) ⇒ Object

Hash-like getter. If we don’t have a value yet, we pull from the database looking for one. Fields pulled from the database are keyed as symbols in the hash.



134
135
136
# File 'lib/candy/piece.rb', line 134

def [](key)
  candy[key] 
end

#[]=(key, value) ⇒ Object

Hash-like setter. Updates the object’s internal state, and writes to the database if the state has changed. Keys should be passed in as symbols for best consistency with the database.



140
141
142
143
144
# File 'lib/candy/piece.rb', line 140

def []=(key, value)
  property = candy_coat(key, value) # Transform hashes and arrays, and communicate embedding
  candy[key] = property
  set key => property
end

#candyObject

Returns the hash of memoized values.



108
109
110
# File 'lib/candy/piece.rb', line 108

def candy
  @__candy ||= retrieve || {}
end

#from_candy(hash) ⇒ Object

Unwraps the values passed to us from MongoDB, setting parent attributes on any embedded Candy objects.



176
177
178
179
180
181
182
183
# File 'lib/candy/piece.rb', line 176

def from_candy(hash) 
  unwrapped = {}
  hash.each do |key, value|
    field = Wrapper.unwrap_key(key)
    unwrapped[field] = Wrapper.unwrap(value, self, field)
  end
  unwrapped
end

#idObject

Shortcut to the document ID.



102
103
104
# File 'lib/candy/piece.rb', line 102

def id
  @__candy_id
end

#initialize(*args, &block) ⇒ Object

Our initializer expects the last argument to be a hash of values. If the hash contains an ‘_id’ field we assume we’re being constructed from a MongoDB document and we unwrap the remaining values; otherwise we assume we’re a new document and set any values in the hash as if they were assigned. Any other arguments are not our business and will be passed down the chain.



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/candy/piece.rb', line 89

def initialize(*args, &block)
  if args[-1].is_a?(Hash)
    data = args.pop
    if data.delete(EMBED_KEY) or @__candy_id = data.delete('_id')  # We're an embedded or existing document
      @__candy = self.from_candy(data)
    else
      data.each {|key, value| send("#{key}=", value)}  # Assign all the data we're given
    end
  end
  super
end

#keysObject

Returns the keys we’ve stored.



153
154
155
# File 'lib/candy/piece.rb', line 153

def keys
  candy.keys
end

#refreshObject

Clears memoized data so that the next read pulls from the database.



147
148
149
150
# File 'lib/candy/piece.rb', line 147

def refresh
  @__candy = nil
  self
end

#to_candyObject

Converts the object into a hash for MongoDB storage. Keep in mind that wrapping happens after this stage, so it’s best to use symbols for keys and leave internal arrays and hashes alone.



170
171
172
# File 'lib/candy/piece.rb', line 170

def to_candy
  candy.merge(CLASS_KEY => self.class.name)
end

#to_sObject

Convenience method for debugging. Shows the class, the Mongo ID, and the saved state hash.



163
164
165
# File 'lib/candy/piece.rb', line 163

def to_s
  "#{self.class.name} (#{id})#{candy.inspect}"
end

#valuesObject

Returns the values we’ve stored.



158
159
160
# File 'lib/candy/piece.rb', line 158

def values
  candy.values
end