class MetalArchives::BaseModel

Abstract model class

Attributes

properties[RW]

Array of declared properties

Public Class Methods

new(hash = {}) click to toggle source

Generic shallow copy constructor

# File lib/metal_archives/models/base_model.rb, line 11
def initialize(hash = {})
  raise Errors::NotImplementedError, "no :id property in model" unless respond_to? :id?, true

  hash.each do |property, value|
    instance_variable_set("@#{property}", value) if self.class.properties.include? property
  end
end

Protected Class Methods

boolean(name, opts = {}) click to toggle source

Defines a model boolean property. This method is an alias for enum name, :values => [true, false]

name

Name of the property

opts
multiple

Whether or not the property has multiple values (which turns it into an Array of type)

# File lib/metal_archives/models/base_model.rb, line 213
def boolean(name, opts = {})
  enum name, opts.merge(values: [true, false])
end
cache() click to toggle source

Get class-level object cache

# File lib/metal_archives/models/base_model.rb, line 90
def cache
  @cache ||= MetalArchives::LRUCache.new MetalArchives.config.cache_size
end
enum(name, opts) click to toggle source

Defines a model enum property.

name

Name of the property

opts
values

Required. An array of possible values

multiple

Whether or not the property has multiple values (which turns it into an Array of type)

# File lib/metal_archives/models/base_model.rb, line 166
def enum(name, opts)
  raise ArgumentError, "opts[:values] is required" unless opts && opts[:values]

  (@properties ||= []) << name

  # property
  define_method(name) do
    load! unless loaded? && instance_variable_defined?("@#{name}")
    instance_variable_get("@#{name}")
  end

  # property?
  define_method("#{name}?") do
    load! unless loaded? && instance_variable_defined?("@#{name}")

    property = instance_variable_get("@#{name}")
    property.respond_to?(:empty?) ? !property.empty? : !property.nil?
  end

  # property=
  define_method("#{name}=") do |value|
    # Check enum type
    if opts[:multiple]
      raise MetalArchives::Errors::TypeError, "invalid enum value #{value}, must be Array for #{name}" unless value.is_a? Array

      value.each do |val|
        raise MetalArchives::Errors::TypeError, "invalid enum value #{val} for #{name}" unless opts[:values].include? val
      end
    else
      raise MetalArchives::Errors::TypeError, "invalid enum value #{value} for #{name}" unless opts[:values].include? value
    end

    instance_variable_set name, value
  end
end
property(name, opts = {}) click to toggle source

Defines a model property.

name

Name of the property

opts
type

Data type of property (a constant)

Default: String

multiple

Whether or not the property has multiple values (which turns it into an Array of type)

# File lib/metal_archives/models/base_model.rb, line 112
def property(name, opts = {})
  (@properties ||= []) << name

  # property
  define_method(name) do
    load! unless loaded? && instance_variable_defined?("@#{name}") || name == :id
    instance_variable_get("@#{name}")
  end

  # property?
  define_method("#{name}?") do
    load! unless loaded? && instance_variable_defined?("@#{name}") || name == :id

    property = instance_variable_get("@#{name}")
    property.respond_to?(:empty?) ? !property.empty? : !property.nil?
  end

  # property=
  define_method("#{name}=") do |value|
    if value.nil?
      instance_variable_set "@#{name}", value
      return
    end

    # Check value type
    type = opts[:type] || String
    if opts[:multiple]
      raise MetalArchives::Errors::TypeError, "invalid type #{value.class}, must be Array for #{name}" unless value.is_a? Array

      value.each do |val|
        raise MetalArchives::Errors::TypeError, "invalid type #{val.class}, must be #{type} for #{name}" unless val.is_a? type
      end
    else
      raise MetalArchives::Errors::TypeError, "invalid type #{value.class}, must be #{type} for #{name}" unless value.is_a? type
    end

    instance_variable_set "@#{name}", value
  end
end

Public Instance Methods

==(obj) click to toggle source

Returns true if two objects have the same type and id

# File lib/metal_archives/models/base_model.rb, line 22
def ==(obj)
  obj.instance_of?(self.class) && id == obj.id
end
cached?() click to toggle source

Whether or not the object is currently cached

# File lib/metal_archives/models/base_model.rb, line 62
def cached?
  loaded? && self.class.cache.include?(id)
end
load!() click to toggle source

Fetch, parse and load the data

Raises
# File lib/metal_archives/models/base_model.rb, line 33
def load!
  raise Errors::InvalidIDError, "no id present" unless id

  # Use constructor to set attributes
  initialize assemble

  # Set empty properties to nil
  self.class.properties.each do |prop|
    instance_variable_set("@#{prop}", nil) unless instance_variable_defined? "@#{prop}"
  end

  @loaded = true
  self.class.cache[id] = self
rescue StandardError => e
  # Don't cache invalid requests
  self.class.cache.delete id
  raise e
end
loaded?() click to toggle source

Whether or not the object is currently loaded

# File lib/metal_archives/models/base_model.rb, line 55
def loaded?
  !@loaded.nil?
end

Protected Instance Methods

assemble() click to toggle source

Fetch the data and assemble the model

Override this method

Raises
# File lib/metal_archives/models/base_model.rb, line 77
def assemble
  raise Errors::NotImplementedError, "method :assemble not implemented"
end