lib/cistern/collection.rb
# frozen_string_literal: true
module Cistern::Collection
include Cistern::HashSupport
BLACKLISTED_ARRAY_METHODS = [
:compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
:shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
:keep_if, :pop, :shift, :delete_at, :compact
].to_set # :nodoc:
def self.cistern_collection(cistern, klass, name)
cistern.const_get(:Collections).module_eval <<-EOS, __FILE__, __LINE__
def #{name}(attributes={})
#{klass.name}.new(attributes.merge(cistern: self))
end
EOS
end
attr_accessor :records, :loaded, :cistern
def service=(service)
Cistern.deprecation(
'#service= is deprecated. Please use #cistern=',
caller[0]
)
@cistern = service
end
def service
Cistern.deprecation(
'#service is deprecated. Please use #cistern',
caller[0]
)
@cistern
end
module ClassMethods
def model(new_model = nil)
@_model ||= new_model
end
# @deprecated Use {#cistern_method} instead
def service_method(name = nil)
Cistern.deprecation(
'#service_method is deprecated. Please use #cistern_method',
caller[0]
)
@_cistern_method ||= name
end
def cistern_method(name = nil)
@_cistern_method ||= name
end
end
alias_method :build, :initialize
def initialize(attributes = {})
@loaded = false
merge_attributes(attributes)
end
def all(_ = {})
fail NotImplementedError
end
def create(attributes = {})
new(attributes).save
end
def get(_identity)
fail NotImplementedError
end
def clear
self.loaded = false
records && records.clear
end
def inspect
if Cistern.formatter
Cistern.formatter.call(self)
else super
end
end
# @api private
def load_records
all unless loaded
end
# Should be called within #all to load records into the collection
# @param [Array<Hash>] objects list of record attributes to be loaded
# @return self
def load(objects)
self.records = (objects || []).map { |object| new(object) }
self.loaded = true
self
end
def model
self.class.model
end
def new(attributes = {})
unless attributes.is_a?(::Hash)
fail(ArgumentError.new("Initialization parameters must be an attributes hash, got #{attributes.class} #{attributes.inspect}"))
end
model.new(
{
collection: self,
cistern: cistern,
}.merge(attributes)
)
end
def reload
clear
load_records
self
end
def to_a
load_records
records || []
end
def respond_to?(method, include_private = false)
super || array_delegable?(method)
end
def ==(comparison_object)
comparison_object.equal?(self) ||
(comparison_object.is_a?(self.class) &&
comparison_object.to_a == to_a)
end
protected
def array_delegable?(method)
Array.method_defined?(method) && !BLACKLISTED_ARRAY_METHODS.include?(method)
end
def method_missing(method, *args, &block)
if array_delegable?(method)
to_a.public_send(method, *args, &block)
else
super
end
end
end