Class: Hyperactive::Record

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperactive/record.rb

Overview

A convenient base class to inherit when you want the basic utility methods provided by for example ActiveRecord::Base *hint hint*.

NB: After an instance is created, it will actually return a copy within your local machine which is not what is usually the case. Every other time you fetch it using a select or other method you will instead receive a proxy object to the database. This means that nothing you do to it at that point will be persistent or even necessarily have a defined result. Therefore: do not use MyRecordSubclass.new to MyRecordSubclass#initialize objects, instead use MyRecordSubclass.get_instance, since it will return a fresh proxy object instead of the devious original:

my_instance = MyRecordSubclass.get_instance(*the_same_arguments_as_to_initialize)

Direct Known Subclasses

Tree

Constant Summary collapse

HOST =

The host we are running on.

"#{Socket::gethostbyname(Socket::gethostname)[0]}" rescue "localhost"
@@create_hooks_by_class =
{}
@@destroy_hooks_by_class =
{}
@@save_hooks_by_class =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#record_idObject (readonly)

Our semi-unique id.



299
300
301
# File 'lib/hyperactive/record.rb', line 299

def record_id
  @record_id
end

Class Method Details

.create_hooksObject

Return our create_hooks, which can then be treated as any old Array.

These must be callable objects with an arity of 1 that will be sent the instance about to be created (initial insertion into the database system) that take a block argument.

The block argument will be a Proc that actually injects the instance into the database system.

Use this to preprocess, validate and/or postprocess your instances upon creation.



174
175
176
# File 'lib/hyperactive/record.rb', line 174

def self.create_hooks
  self.get_hook_array_by_class(@@create_hooks_by_class)
end

.destroy_hooksObject

Return our destroy_hooks, which can then be treated as any old Array.

These must be callable objects with an arity of 1 that will be sent the instance about to be destroyed (removal from the database system) that take a block argument.

The block argument will be a Proc that actually removes the instance from the database system.

Use this to preprocess, validate and/or postprocess your instances upon destruction.



191
192
193
# File 'lib/hyperactive/record.rb', line 191

def self.destroy_hooks
  self.get_hook_array_by_class(@@destroy_hooks_by_class)
end

.find(record_id) ⇒ Object

Return the record with record_id.



265
266
267
# File 'lib/hyperactive/record.rb', line 265

def self.find(record_id)
  CAPTAIN[record_id]
end

.get_instance(*arguments) ⇒ Object

Use this method to get new instances of this class, since it will actually make sure it both resides in the database and return a proxy to the remote object.



281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/hyperactive/record.rb', line 281

def self.get_instance(*arguments)
  instance = self.new(*arguments)
  instance.instance_eval do
    @record_id = Digest::SHA1.hexdigest("#{HOST}:#{Time.new.to_f}:#{self.object_id}:#{rand(1 << 32)}")
  end

  Hyperactive::Hooker.call_with_hooks(instance, *self.create_hooks) do
    CAPTAIN[instance.record_id] = instance
  end

  proxy = CAPTAIN[instance.record_id]

  return proxy
end

.index_by(*attributes) ⇒ Object



213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/hyperactive/record.rb', line 213

def self.index_by(*attributes)
  attribute_key_part = IndexBuilder.get_attribute_key_part(attributes)
  self.class_eval <<END
def self.find_by_#{attributes.join("_and_")}(*args)
key = "#{attribute_key_part}::" + IndexBuilder.get_value_key_part(args)
CAPTAIN[key]
end
END
  index_builder = IndexBuilder.new(attributes)
  self.save_hooks << index_builder
  self.destroy_hooks << index_builder
end

.reject(name, matcher) ⇒ Object

Will define a method called name that will include all existing instances of this class that when sent to matcher.call does not return true. Will only return instances saved after this rejector is defined.



250
251
252
253
254
255
256
257
258
259
260
# File 'lib/hyperactive/record.rb', line 250

def self.reject(name, matcher)
  key = self.collection_key(name)
  CAPTAIN[key] ||= Tree.get_instance
  self.class_eval <<END
def self.#{name}
CAPTAIN["#{key}"]
end
END
  self.save_hooks << MatchSaver.new(key, matcher, :reject)
  self.destroy_hooks << MatchSaver.new(key, matcher, :delete_unless_match)
end

.save_hooksObject

Return our save_hooks, which can then be treated as any old Array.

These must be callable objects with an arity of 1 that will be sent [the old version, the new version] of the instance about to be saved (storage into the database system) along with a block argument.

The block argument will be a Proc that actually saves the instance into the database system.

Use this to preprocess, validate and/or postprocess your instances upon saving.



209
210
211
# File 'lib/hyperactive/record.rb', line 209

def self.save_hooks
  self.get_hook_array_by_class(@@save_hooks_by_class)
end

.select(name, matcher) ⇒ Object

Will define a method called name that will include all existing instances of this class that when sent to matcher.call return true. Will only return instances saved after this selector is defined.



232
233
234
235
236
237
238
239
240
241
242
# File 'lib/hyperactive/record.rb', line 232

def self.select(name, matcher)
  key = self.collection_key(name)
  CAPTAIN[key] ||= Tree.get_instance
  self.class_eval <<END
def self.#{name}
CAPTAIN["#{key}"]
end
END
  self.save_hooks << MatchSaver.new(key, matcher, :select)
  self.destroy_hooks << MatchSaver.new(key, matcher, :delete_if_match)
end

.setup(options = {}) ⇒ Object

Call this if you want to change the default database connector to something else.



157
158
159
# File 'lib/hyperactive/record.rb', line 157

def self.setup(options = {})
  CAPTAIN.setup(options[:pirate_options])
end

.transaction(&block) ⇒ Object

Will execute block within a transaction.



272
273
274
# File 'lib/hyperactive/record.rb', line 272

def self.transaction(&block)
  CAPTAIN.transaction(&block)
end

Instance Method Details

#destroyObject

Remove this instance from the database calling all the right hooks.

Freezes this instance after having deleted it.

Returns false without destroying anything if any of the @@pre_destroy_hooks returns false.

Returns true otherwise.



323
324
325
326
327
328
# File 'lib/hyperactive/record.rb', line 323

def destroy
  Hyperactive::Hooker.call_with_hooks(self, *self.class.destroy_hooks) do
    CAPTAIN.delete(@record_id)
    self.freeze
  end
end

#save_hook(old_value, &block) ⇒ Object

This will allow us to wrap any write of us to persistent storage in the @@save_hooks as long as the Archipelago::Hashish provider supports it. See Archipelago::Hashish::BerkeleyHashish for an example of Hashish providers that do this.



307
308
309
310
311
# File 'lib/hyperactive/record.rb', line 307

def save_hook(old_value, &block)
  Hyperactive::Hooker.call_with_hooks([old_value, self], *self.class.save_hooks) do
    yield
  end
end