lib/liquid-rails/drops/drop.rb
module Liquid
module Rails
class Drop < ::Liquid::Drop
class << self
attr_accessor :_attributes
attr_accessor :_associations
end
def self.inherited(base)
base._attributes = []
base._associations = {}
end
def self.attributes(*attrs)
@_attributes.concat attrs
attrs.each do |attr|
next if method_defined?(attr)
define_method(attr) do
object.send(attr)
end
end
end
# By default, `Product` maps to `ProductDrop`.
# Array of products maps to `Liquid::Rails::CollectionDrop`.
def self.drop_class_for(resource)
if resource.respond_to?(:to_ary)
Liquid::Rails::CollectionDrop
else
if self == Liquid::Rails::Drop
resource.drop_class
else
self
end
end
end
# Create a drop instance when it cannot be inferred.
def self.dropify(resource, options={})
drop_class = if options[:class_name]
options[:class_name].constantize
else
drop_class_for(resource)
end
drop_class.new(resource, options.except(:class_name))
end
def self.belongs_to(*attrs)
associate(:belongs_to, attrs)
end
def self.has_many(*attrs)
associate(:has_many, attrs)
end
def self.has_one(*attrs)
associate(:has_one, attrs)
end
def self.associate(type, attrs)
options = attrs.extract_options!
self._associations = _associations.dup
attrs.each do |attr|
next if method_defined?(attr)
define_method attr do
value = instance_variable_get("@_#{attr}")
return value if value
association = object.send(attr)
return nil if association.nil?
drop_instance = Liquid::Rails::Drop.dropify(association, options)
instance_variable_set("@_#{attr}", drop_instance)
end
self._associations[attr] = { type: type, options: options }
end
end
# Wraps an object in a new instance of the drop.
def initialize(object, options={})
@object = object
end
def attributes
@attributes ||= self.class._attributes.dup.each_with_object({}) do |name, hash|
hash[name.to_s] = send(name)
end
end
def as_json(options={})
attributes.as_json(options)
end
def to_json(options={})
as_json.to_json(options)
end
def liquid_method_missing(method)
return nil unless @context && @context.strict_variables
raise ::Liquid::UndefinedDropMethod, <<~HEREDOC
undefined method #{method} for #{self.class}
Did you forget to add it to `attributes`?
HEREDOC
end
def inspect
"#<#{self.class.name} @object: #{object.inspect} @attributes: #{attributes.inspect}>"
end
def ==(other)
other.present? && other.object == @object
end
protected
attr_reader :object
end
end
end