module Muve::Model

Muve models imitate some behavior that one may commonly expect of typical models. There are mechanisms in place for creation, modification, retrieval and the removal of resources.

In order to make this a flexible solution, models never take care of handling the persisting of the resources they manange. That part of the lifing is dispatched to the Model::Store object which may be though of as an adaptor.

– TODO: Include ActiveRecord::Model instead of using this tedious implementation ++

Public Class Methods

connection() click to toggle source

Connection to the datastore

# File lib/muve.rb, line 48
def self.connection
  begin
  @@conn
  rescue => e
    raise NotConfigured, "the connection has not been defined"
  end
end
connection=(connection) click to toggle source

Set the connection to the datastore

# File lib/muve.rb, line 39
def self.connection=connection
  (@@conn = connection) if (connection)
end
database() click to toggle source

Database instance to be used by the adaptor

# File lib/muve.rb, line 57
def self.database
  begin
    @@db
  rescue => e
    raise NotConfigured, "the database has not been defined"
  end
end
database=(database) click to toggle source
# File lib/muve.rb, line 43
def self.database=database
  (@@db = database) if (database)
end
handler() click to toggle source
# File lib/muve/model.rb, line 50
def self.handler
  @handler
end
included(base) click to toggle source
# File lib/muve/model.rb, line 35
def self.included(base)
  base.extend ClassMethods
end
init(handler=nil) click to toggle source

Initializes the Muve::Model class. Use the Muve::Model::init method to set a adaptor to take care of the retrieval and storage of resources.

# File lib/muve/model.rb, line 46
def self.init(handler=nil)
  @handler = handler if handler
end
new(params={}) click to toggle source
# File lib/muve/model.rb, line 19
def initialize(params={})
  params = {} unless params
  params.each do |attr, value|
    next if invalid_attributes.include? attr.to_s
    self.public_send "#{attr}=", value
  end

  @new_record = true
  @destroyed = false
end

Public Instance Methods

==(rival) click to toggle source
# File lib/muve/model.rb, line 39
def ==(rival)
  return false unless rival.kind_of? self.class
  self.attributes == rival.attributes
end
attributes() click to toggle source

Returns a Hash of the attributes for the current resource.

# File lib/muve/model.rb, line 141
def attributes
  self.class.extract_attributes(
    resource: self,
    fields: fields,
    invalid_attributes: invalid_attributes,
    id: self.id
  )
end
attributes=(data) click to toggle source
# File lib/muve/model.rb, line 135
def attributes=(data)
  Helper.symbolize_keys(data).each { |k, v| self.public_send("#{k}=", v) }
  self
end
connection() click to toggle source

Connection to the datastore

# File lib/muve.rb, line 29
def connection
  Model.connection
end
database() click to toggle source

Database instance for the model

# File lib/muve.rb, line 34
def database
  Model.database
end
destroy() click to toggle source

Destroy a resource

# File lib/muve/model.rb, line 92
def destroy
  if adaptor.delete(self.class, id) == true
    @destroyed = true 
  end
end
destroyed?() click to toggle source

Returns true if the resource in question has been destroyed

# File lib/muve/model.rb, line 112
def destroyed?
  @destroyed
end
id() click to toggle source
# File lib/muve/model.rb, line 126
def id
  @id
end
invalid?() click to toggle source

Returns true if the resource fails any validation

# File lib/muve/model.rb, line 122
def invalid?
  !valid?
end
new_record?() click to toggle source

Returns true if the resource has recently been instantiated but not yet written to the data store.

# File lib/muve/model.rb, line 100
def new_record?
  @new_record = true if @new_record.nil?
  @new_record
end
persisted?() click to toggle source

Returns true if the resource is not newly instantiated or recently destroyed.

# File lib/muve/model.rb, line 107
def persisted?
  !(new_record? || destroyed?)
end
reload() click to toggle source
# File lib/muve/model.rb, line 30
def reload
  self.send(:populate, extract(adaptor.get(self.class, id), self.class)) if id
  self
end
save() click to toggle source

Save a resource

# File lib/muve/model.rb, line 84
def save
  # TODO: be more verbose about the nature of the failure, if any
  (create_or_update if valid?) or false
rescue => e
  false
end
save!() click to toggle source

Save a resource and raises an SaveError on failure

# File lib/muve/model.rb, line 76
def save!
  raise ValidationError, "validation failed" unless valid?
  create_or_update
rescue => e
  raise SaveError, "Save failed because #{e} was raised"
end
to_hash(level=0, limit=1) click to toggle source

Returns a hash of the object and subsequently containing objects that respond to to_hash. In order to avoid circular reference hell you can set the limit.

By default on the the root object and its children a explored. Everything beyond that range is discarded.

# File lib/muve/model.rb, line 62
def to_hash(level=0, limit=1)
  hash = {}
  attributes.map { |k, v|
    if v.respond_to? :to_hash
      (hash[k.to_sym] = v.to_hash(level+1, limit)) if level < limit
    else
      #(raise AssocError, "#Associated #{v.class} for #{k} must respond to #to_hash or be a Hash") unless v.kind_of? Hash
      hash[k.to_sym] = v
    end
  }
  hash
end
to_param() click to toggle source

The parameterized identifier of the resource

# File lib/muve/model.rb, line 131
def to_param
  id && id.to_s
end
valid?() click to toggle source

Returns a true if the resource passes all validations

# File lib/muve/model.rb, line 117
def valid?
  false
end

Private Instance Methods

adaptor() click to toggle source
# File lib/muve/model.rb, line 201
def adaptor
  self.class.adaptor
end
convert(resource) click to toggle source
# File lib/muve/model.rb, line 209
def convert(resource)
  self.class.convert(resource)
end
create(attr) click to toggle source

Creates the record and performs the necessary housekeeping (e.g.: setting the new id and un-marking the new_record?

# File lib/muve/model.rb, line 190
def create(attr)
  @id = adaptor.create(self.class, attr)
  # TODO: deal with unsuccessful #create
  @new_record = false
end
create_or_update() click to toggle source
# File lib/muve/model.rb, line 176
def create_or_update
  result = new_record? ? create(storeable_attributes) : update(storeable_attributes)
  self
end
extract(storeable, klass=nil) click to toggle source
# File lib/muve/model.rb, line 205
def extract(storeable, klass=nil)
  self.class.extract(storeable, klass)
end
fields() click to toggle source

A manifest of the fields known to the model. The model logic seeks counsel from this resource to determine which properties to write and read from the repository.

# File lib/muve/model.rb, line 184
def fields
  []
end
invalid_attributes() click to toggle source

Reserved attributes. These keys are not available to the user because they are used to handle plumbing (library internal operations).

# File lib/muve/model.rb, line 153
def invalid_attributes
  %w(id adaptor)
end
populate(details) click to toggle source
# File lib/muve/model.rb, line 157
def populate(details)
  details = {} unless details

  @id = details[:id] if details.key? :id

  details.each do |attr, value|
    next if invalid_attributes.include? attr.to_s
    self.public_send "#{attr}=", value if fields.include? attr.to_sym
  end

  @new_record = false if details.key? :id
end
storeable_attributes() click to toggle source
# File lib/muve/model.rb, line 170
def storeable_attributes
  hash = {}
  attributes.map { |k, v| hash[k] = convert(v) }
  hash
end
update(attr) click to toggle source

TODO: Update the record and return the number of modified rows

# File lib/muve/model.rb, line 197
def update(attr)
  adaptor.update(self.class, id, attr)
end