79 lines
2.2 KiB
Ruby
79 lines
2.2 KiB
Ruby
|
require 'set'
|
||
|
|
||
|
module Liquid
|
||
|
# A drop in liquid is a class which allows you to export DOM like things to liquid.
|
||
|
# Methods of drops are callable.
|
||
|
# The main use for liquid drops is to implement lazy loaded objects.
|
||
|
# If you would like to make data available to the web designers which you don't want loaded unless needed then
|
||
|
# a drop is a great way to do that.
|
||
|
#
|
||
|
# Example:
|
||
|
#
|
||
|
# class ProductDrop < Liquid::Drop
|
||
|
# def top_sales
|
||
|
# Shop.current.products.find(:all, :order => 'sales', :limit => 10 )
|
||
|
# end
|
||
|
# end
|
||
|
#
|
||
|
# tmpl = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {%endfor%} ' )
|
||
|
# tmpl.render('product' => ProductDrop.new ) # will invoke top_sales query.
|
||
|
#
|
||
|
# Your drop can either implement the methods sans any parameters
|
||
|
# or implement the liquid_method_missing(name) method which is a catch all.
|
||
|
class Drop
|
||
|
attr_writer :context
|
||
|
|
||
|
# Catch all for the method
|
||
|
def liquid_method_missing(method)
|
||
|
return nil unless @context && @context.strict_variables
|
||
|
raise Liquid::UndefinedDropMethod, "undefined method #{method}"
|
||
|
end
|
||
|
|
||
|
# called by liquid to invoke a drop
|
||
|
def invoke_drop(method_or_key)
|
||
|
if self.class.invokable?(method_or_key)
|
||
|
send(method_or_key)
|
||
|
else
|
||
|
liquid_method_missing(method_or_key)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def key?(_name)
|
||
|
true
|
||
|
end
|
||
|
|
||
|
def inspect
|
||
|
self.class.to_s
|
||
|
end
|
||
|
|
||
|
def to_liquid
|
||
|
self
|
||
|
end
|
||
|
|
||
|
def to_s
|
||
|
self.class.name
|
||
|
end
|
||
|
|
||
|
alias_method :[], :invoke_drop
|
||
|
|
||
|
# Check for method existence without invoking respond_to?, which creates symbols
|
||
|
def self.invokable?(method_name)
|
||
|
invokable_methods.include?(method_name.to_s)
|
||
|
end
|
||
|
|
||
|
def self.invokable_methods
|
||
|
@invokable_methods ||= begin
|
||
|
blacklist = Liquid::Drop.public_instance_methods + [:each]
|
||
|
|
||
|
if include?(Enumerable)
|
||
|
blacklist += Enumerable.public_instance_methods
|
||
|
blacklist -= [:sort, :count, :first, :min, :max, :include?]
|
||
|
end
|
||
|
|
||
|
whitelist = [:to_liquid] + (public_instance_methods - blacklist)
|
||
|
Set.new(whitelist.map(&:to_s))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|