moduleTemplemoduleMixins# @api privatemoduleEngineDSLdefchain_modified!enddefappend(*args,&block)chain<<chain_element(args,block)chain_modified!enddefprepend(*args,&block)chain.unshift(chain_element(args,block))chain_modified!enddefremove(name)name=chain_name(name)found=falsechain.reject!do|i|ifi.first==namefound=trueelsefalseendendraise"#{name} not found"unlessfoundchain_modified!endaliasuseappenddefbefore(name,*args,&block)name=chain_name(name)e=chain_element(args,block)found,i=false,0whilei<chain.sizeifchain[i].first==namefound=truechain.insert(i,e)i+=2elsei+=1endendraise"#{name} not found"unlessfoundchain_modified!enddefafter(name,*args,&block)name=chain_name(name)e=chain_element(args,block)found,i=false,0whilei<chain.sizeifchain[i].first==namefound=truei+=1chain.insert(i,e)endi+=1endraise"#{name} not found"unlessfoundchain_modified!enddefreplace(name,*args,&block)name=chain_name(name)e=chain_element(args,block)found=falsechain.each_with_indexdo|c,i|ifc.first==namefound=truechain[i]=eendendraise"#{name} not found"unlessfoundchain_modified!end# Shortcuts to access namespaces{filter: Temple::Filters,generator: Temple::Generators,html: Temple::HTML}.eachdo|method,mod|define_method(method)do|name,*options|use(name,mod.const_get(name),*options)endendprivatedefchain_name(name)name=Class===name?name.name.to_sym:nameraise(ArgumentError,'Name argument must be Class or Symbol')unlessSymbol===namenameenddefchain_class_constructor(filter,local_options)define_options(filter.options.valid_keys)ifrespond_to?(:define_options)&&filter.respond_to?(:options)procdo|engine|opts={}.update(engine.options)opts.delete_if{|k,v|!filter.options.valid_key?(k)}iffilter.respond_to?(:options)opts.update(local_options)iflocal_optionsfilter.new(opts)endenddefchain_proc_constructor(name,filter)raise(ArgumentError,'Proc or blocks must have arity 0 or 1')iffilter.arity>1method_name="FILTER #{name}"ifClass===selfdefine_method(method_name,&filter)filter=instance_method(method_name)iffilter.arity==1proc{|engine|filter.bind(engine)}elseprocdo|engine|f=filter.bind(engine).callraise'Constructor must return callable object'unlessf.respond_to?(:call)fendendelse(class<<self;self;end).class_eval{define_method(method_name,&filter)}filter=method(method_name)proc{|engine|filter}endenddefchain_callable_constructor(filter)raise(ArgumentError,'Class or callable argument is required')unlessfilter.respond_to?(:call)proc{|engine|filter}enddefchain_element(args,block)name=args.shiftifClass===namefilter=namename=filter.name.to_symelseraise(ArgumentError,'Name argument must be Class or Symbol')unlessSymbol===nameendifblockraise(ArgumentError,'Class and block argument are not allowed at the same time')iffilterfilter=blockendfilter||=args.shiftcasefilterwhenProc# Proc or block argument# The proc is converted to a method of the engine class.# The proc can then access the option hash of the engine.raise(ArgumentError,'Too many arguments')unlessargs.empty?[name,chain_proc_constructor(name,filter)]whenClass# Class argument (e.g Filter class)# The options are passed to the classes constructor.raise(ArgumentError,'Too many arguments')ifargs.size>1[name,chain_class_constructor(filter,args.first)]else# Other callable argument (e.g. Object of class which implements #call or Method)# The callable has no access to the option hash of the engine.raise(ArgumentError,'Too many arguments')unlessargs.empty?[name,chain_callable_constructor(filter)]endendendendend