class ActiveCabinet
@!attribute [r] attributes
@return [Hash] the attributes of the record
@!attribute [r] error
@return [String, nil] the last validation error, after calling {valid?}
{ActiveCabinet} lets you create a HashCabinet
collection model by subclassing {ActiveCabinet}:
class Song < ActiveCabinet end
Now, you can perform CRUD operations on this collection, which will be persisted to disk:
# Create Song.create id: 1, title: 'Moonchild', artist: 'Iron Maiden' # Read moonchild = Song[1] # or Song.find 1 # Update moonchild.title = "22 Acacia Avenue" moonchild.save # or moonchild.update! title: "22 Acacia Avenue" # Delete Song.delete 1
Constants
- VERSION
Attributes
Public Class Methods
Creates and saves a new record instance.
@param [String] id the record id. @param [Hash] attributes the attributes to create.
# File lib/active_cabinet/metaclass.rb, line 40 def []=(id, attributes) create attributes.merge(id: id) end
Returns all records.
@return [Array] array of all records.
# File lib/active_cabinet/metaclass.rb, line 58 def all cabinet.values.map do |attributes| new(attributes) end end
Returns all records, as an Array of Hashes.
@return [Array] array of all records.
# File lib/active_cabinet/metaclass.rb, line 67 def all_attributes cabinet.values end
Returns an array containing the keys of all allowed attributes as defined by {required_attributes}, {optional_attributes} and {default_attributes}.
@return [Array<Symbol>] array of required attribute keys.
# File lib/active_cabinet/metaclass.rb, line 175 def allowed_attributes (optional_attributes || []) + required_attributes + default_attributes.keys end
Returns the HashCabinet
instance.
@return [HashCabinet] the HashCabinet
object.
# File lib/active_cabinet/metaclass.rb, line 231 def cabinet @cabinet ||= HashCabinet.new "#{Config.dir}/#{cabinet_name}" end
Returns or sets the cabinet name. Defaults to the name of the class, lowercase.
@param [String] name the name of the cabinet file. @return [String] name the name of the cabinet file.
# File lib/active_cabinet/metaclass.rb, line 240 def cabinet_name(new_name = nil) if new_name @cabinet = nil @cabinet_name = new_name else @cabinet_name ||= self.to_s.downcase.gsub('::', '_') end end
Creates and saves a new record instance.
@param [Hash] attributes the attributes to create. @return [Object] the record.
# File lib/active_cabinet/metaclass.rb, line 48 def create(attributes) record = new attributes record.save || record end
Sets the default record attribute values.
@param [Hash<Symbol, Object>] **attributes one or more attribute names and values. @return [Hash<Symbol, Object>] the hash of the default attributes.
# File lib/active_cabinet/metaclass.rb, line 213 def default_attributes(args = nil) if args @default_attributes = args else @default_attributes ||= {} end end
Deletes a record matching the id
.
@param [String] id the record ID. @return [Boolean] true
on success, false
otherwise.
# File lib/active_cabinet/metaclass.rb, line 151 def delete(id) !!cabinet.delete(id) end
Deletes a record for which the block returns true.
@example Delete records using a block
Song.delete_if { |record| record[:artist] == "Iron Maiden" }
# File lib/active_cabinet/metaclass.rb, line 159 def delete_if cabinet.delete_if { |key, _value| yield self[key] } end
Deletes all records.
# File lib/active_cabinet/metaclass.rb, line 164 def drop cabinet.clear end
Yields each record to the given block.
@yieldparam [Object] record all record instances.
# File lib/active_cabinet/metaclass.rb, line 118 def each cabinet.each_value do |attributes| yield new(attributes) end end
Returns the record matching the id
. When providing a Hash with a single key-value pair, it will return the first matching object from the respective {where} query.
@example Retrieve a record by ID
Song.find 1 Song[1]
@example Retrieve a different attributes
Song.find artist: "Iron Maiden" Song[artist: "Iron Maiden"]
@return [Object, nil] the object if found, or nil
.
# File lib/active_cabinet/metaclass.rb, line 105 def find(id) if id.is_a? Hash where(id).first else attributes = cabinet[id] attributes ? new(attributes) : nil end end
Returns the first record.
@return [Object] the record.
# File lib/active_cabinet/metaclass.rb, line 127 def first find keys.first end
Returns the last record.
@return [Object] the record.
# File lib/active_cabinet/metaclass.rb, line 134 def last find keys.last end
Initializes a new record with {attributes}
@param [Hash] attributes record attributes
# File lib/active_cabinet.rb, line 16 def initialize(attributes = {}) @attributes = default_attributes.merge attributes.transform_keys(&:to_sym) end
Sets the optional record attribute names.
@param [Array<Symbol>] *attributes one or more attribute names. @return [Array<Symbol>] the array of optional attributes.
# File lib/active_cabinet/metaclass.rb, line 198 def optional_attributes(*args) args = args.first if args.first.is_a? Array if args.first === false @optional_attributes = false elsif args.any? @optional_attributes = *args else @optional_attributes.nil? ? [] : @optional_attributes end end
Returns a random racord.
@return [Object] the record.
# File lib/active_cabinet/metaclass.rb, line 141 def random find keys.sample end
Sets the required record attribute names.
@param [Array<Symbol>] *attributes one or more attribute names. @return [Array<Symbol>] the array of required attributes.
# File lib/active_cabinet/metaclass.rb, line 183 def required_attributes(*args) args = args.first if args.first.is_a? Array if args.any? @required_attributes = args @required_attributes.push :id unless @required_attributes.include? :id @required_attributes else @required_attributes ||= [:id] end end
Returns all records as a hash, with record IDs as the keys.
# File lib/active_cabinet/metaclass.rb, line 224 def to_h cabinet.to_h.map { |id, attributes| [id, new(attributes)] }.to_h end
Returns an array of records for which the block returns true. When query
is provided, it should be a Hash with a single key and value. The result will be records that have a matching attribute.
@example Search using a Hash query
Song.where artist: "Iron Maiden"
@example Search using a block
Song.where { |record| record[:artist] == "Iron Maiden" }
@yieldparam [Object] record all record instances. @return [Array<Object>] record all record instances.
# File lib/active_cabinet/metaclass.rb, line 83 def where(query = nil) if query key, value = query.first all.select { |record| record[key] == value } else all.select { |record| yield record } end end
Public Instance Methods
Returns the attribute value for the given key.
@return [Object] the attribute value.
# File lib/active_cabinet.rb, line 75 def [](key) attributes[key] end
Sets the attribute value for the given key.
@param [Symbol] key the attribute key. @param [Object] value the attribute value.
# File lib/active_cabinet.rb, line 83 def []=(key, value) attributes[key] = value end
Returns an array containing {required_attributes} and {optional_attributes}.
@return [Array<Symbol>] array of required attribute keys.
# File lib/active_cabinet.rb, line 25 def allowed_attributes self.class.allowed_attributes end
# File lib/active_cabinet.rb, line 45 def default_attributes self.class.default_attributes end
Provides read/write access to {attributes}
# File lib/active_cabinet.rb, line 90 def method_missing(method_name, *args, &blk) name = method_name return attributes[name] if attributes.has_key? name suffix = nil if name.to_s.end_with?('=', '?') suffix = name[-1] name = name[0..-2].to_sym end case suffix when "=" attributes[name] = args.first when "?" !!attributes[name] else super end end
Returns an array of optional record attributes.
@see ActiveCabinet.optional_attributes
. @return [Array<Symbol>] the array of optional attributes
# File lib/active_cabinet.rb, line 41 def optional_attributes self.class.optional_attributes end
Reads the attributes of the record from the cabinet and returns the record itself. If the record is not stored on disk, returns nil
.
@return [self, nil] the object or nil
if the object is not stored.
# File lib/active_cabinet.rb, line 129 def reload return nil unless saved? update cabinet[id] self end
Returns an array of required record attributes.
@see ActiveCabinet.required_attributes
. @return [Array<Symbol>] the array of required attributes
# File lib/active_cabinet.rb, line 33 def required_attributes self.class.required_attributes end
Returns true
when calling #respond_to?
with an attribute name.
@return [Boolean] true
if there is a matching attribute.
# File lib/active_cabinet.rb, line 117 def respond_to_missing?(method_name, include_private = false) name = method_name name = name[0..-2].to_sym if name.to_s.end_with?('=', '?') attributes.has_key?(name) || super end
Saves the record to the cabinet if it is valid. Returns the record on success, or false
on failure.
@return [self, false] the record or false
on failure.
# File lib/active_cabinet.rb, line 139 def save if valid? cabinet[id] = attributes self else false end end
Returns true
if the record exists in the cabinet.
@note This method only verifies that the ID of the record exists. The
attributes of the instance and the stored record may differ.
@return [Boolean] true
if the record is saved in the cabinet.
# File lib/active_cabinet.rb, line 154 def saved? cabinet.key? id end
Returns a Hash of attributes
@return [Hash<Symbol, Object>] the hash of attriibutes/
# File lib/active_cabinet.rb, line 178 def to_h attributes end
Update the record with new or modified attributes.
@param [Hash] new_attributes record attributes
# File lib/active_cabinet.rb, line 161 def update(new_attributes) @attributes = attributes.merge(new_attributes.transform_keys &:to_sym) end
Update the record with new or modified attributes, and save.
@param [Hash] new_attributes record attributes
# File lib/active_cabinet.rb, line 168 def update!(new_attributes) update new_attributes save end
Returns true
if the object is valid.
@return [Boolean] true
if the record is valid.
# File lib/active_cabinet.rb, line 52 def valid? missing_keys = required_attributes - attributes.keys if missing_keys.any? @error = "missing required attributes: #{missing_keys}" return false end if !optional_attributes or optional_attributes.any? invalid_keys = attributes.keys - allowed_attributes if invalid_keys.any? @error = "invalid attributes: #{invalid_keys}" return false end end true end
Protected Instance Methods
# File lib/active_cabinet.rb, line 184 def cabinet self.class.cabinet end