class Olfactory::Template
Attributes
block_invocations[RW]
default_mode[RW]
default_populated[RW]
default_populated_transients[RW]
definition[RW]
dictionaries[RW]
sequences[RW]
transients[RW]
Public Class Methods
new(definition, options = {})
click to toggle source
# File lib/olfactory/template.rb, line 12 def initialize(definition, options = {}) self.definition = definition self.transients = options[:transients] ? options[:transients].clone : {} self.sequences = options[:sequences] ? options[:sequences].clone : {} self.dictionaries = options[:dictionaries] ? options[:dictionaries].clone : {} self.default_populated = {} self.default_populated_transients = {} self.block_invocations = [] end
Public Instance Methods
add_defaults(mode)
click to toggle source
# File lib/olfactory/template.rb, line 257 def add_defaults(mode) # Prevents overwrites of custom values by defaults self.default_mode = true # Hackish for sure, but its efficient... case mode when :before default_definitions = definition.t_befores[:all] when :after default_definitions = definition.t_afters[:all] when :before_embedded default_definitions = definition.t_befores[:embedded] when :after_embedded default_definitions = definition.t_afters[:embedded] end default_definitions ||= [] default_definitions.reject! { |dfn| dfn[:run] == :once && self.block_invocations.include?(dfn.object_id) } default_definitions.each do |default_definition| if default_definition[:evaluator] default_definition[:evaluator].call(self) elsif default_definition[:preset] preset_definition = definition.find_preset_definition(default_definition[:preset]) preset_definition[:evaluator].call(self) end self.block_invocations << default_definition.object_id if default_definition[:run] # Mark block as invoked end self.default_mode = false end
build(name, *args)
click to toggle source
# File lib/olfactory/template.rb, line 241 def build(name, *args) if instantiator_definition = self.definition.t_instantiators[name] instantiator_definition[:evaluator].call(self, *args) end end
can_set_field?(name)
click to toggle source
# File lib/olfactory/template.rb, line 59 def can_set_field?(name) !(self.default_mode && self.has_key?(name)) || (self.default_mode && (self.default_populated[name] == true)) end
construct(block, options = {})
click to toggle source
# File lib/olfactory/template.rb, line 22 def construct(block, options = {}) self.add_defaults(:before) if options[:defaults].nil? || options[:defaults] if block # Block can be nil (when we want only defaults) if options[:value] block.call(self, options[:value]) else block.call(self) end end self.add_defaults(:after) if options[:defaults].nil? || options[:defaults] self end
construct_macro(macro_definition, args, block)
click to toggle source
# File lib/olfactory/template.rb, line 286 def construct_macro(macro_definition, args, block) if macro_definition[:evaluator] macro_definition[:evaluator].call(self, *args) end end
construct_many_items(item_definition, quantity, arr, args, block)
click to toggle source
# File lib/olfactory/template.rb, line 326 def construct_many_items(item_definition, quantity, arr, args, block) # Integer, Block if quantity && block Array.new(quantity) { block.call } # Array elsif arr arr # Object, Object... else args end end
construct_many_subtemplates(subtemplate_definition, quantity, preset_name, block)
click to toggle source
# File lib/olfactory/template.rb, line 303 def construct_many_subtemplates(subtemplate_definition, quantity, preset_name, block) # Integer, Block if quantity && block Array.new(quantity) { subtemplate_definition.construct(block, :transients => self.transients) } # Integer, Preset Name elsif quantity && preset_name subtemplate_definition.construct_preset(preset_name, quantity, :transients => self.transients) # Integer elsif quantity Array.new(quantity) { subtemplate_definition.construct(nil, :transients => self.transients) } else nil end end
construct_one_item(item_definition, obj, block)
click to toggle source
# File lib/olfactory/template.rb, line 317 def construct_one_item(item_definition, obj, block) if block block.call elsif obj obj else nil end end
construct_one_subtemplate(subtemplate_definition, preset_name, block)
click to toggle source
# File lib/olfactory/template.rb, line 291 def construct_one_subtemplate(subtemplate_definition, preset_name, block) # Block if block subtemplate_definition.construct(block, :transients => self.transients) # Preset Name elsif preset_name subtemplate_definition.construct_preset(preset_name, 1, :transients => self.transients) # Default (nothing) else subtemplate_definition.construct(nil, :transients => self.transients) end end
create(name, *args)
click to toggle source
# File lib/olfactory/template.rb, line 246 def create(name, *args) obj = self.build(name, *args) if obj.class <= Array obj.each { |o| o.save! if o.respond_to?(:save!) } elsif obj.class <= Hash obj.values.each { |o| o.save! if o.respond_to?(:save!) } elsif obj.respond_to?(:save!) obj.save! end obj end
extract_variable_name(args)
click to toggle source
# File lib/olfactory/template.rb, line 62 def extract_variable_name(args) variable_name = args.first raise "Must provide a name when adding to a named field!" if variable_name.nil? variable_name end
generate(name, options = {}, &block)
click to toggle source
# File lib/olfactory/template.rb, line 226 def generate(name, options = {}, &block) sequence = self.definition.t_sequences[name] # Template scope if sequence && sequence[:scope] == :template value = sequence.generate(options, block) # Instance scope elsif sequence && sequence[:scope] == :instance self.sequences[name] ||= sequence.dup.reset value = self.sequences[name].generate(options, block) # self.sequences[name][:current_seed] += 1 if !options.has_key?(:seed) else raise "Unknown sequence '#{name}'!" end value end
method_missing(meth, *args, &block)
click to toggle source
Calls superclass method
# File lib/olfactory/template.rb, line 51 def method_missing(meth, *args, &block) # Explicit fields if field_definition = self.definition.find_field_definition(meth) populate_field(field_definition, meth, args, block) else super # Unknown method end end
populate_field(field_definition, meth, args, block)
click to toggle source
# File lib/olfactory/template.rb, line 67 def populate_field(field_definition, meth, args, block) if field_definition[:type] == :macro field_value = construct_macro(field_definition, args, block) do_not_set_value = true elsif field_definition[:type] == :subtemplate && can_set_field?(field_definition[:name]) subtemplate_name = field_definition.has_key?(:template) ? field_definition[:template] : field_definition[:name] subtemplate_definition = Olfactory.templates[subtemplate_name] subtemplate_definition ||= Olfactory.templates[field_definition[:singular]] if subtemplate_definition # Invoke before clauses self.add_defaults(:before_embedded) # self.default_mode = true # before_block = field_definition[:evaluator] # before_block.call(self) if before_block # self.default_mode = false if field_definition[:collection] && field_definition[:collection] <= Array # Embeds many if meth == field_definition[:singular] # Singular grammar = :singular preset_name = args.first field_value = construct_one_subtemplate(subtemplate_definition, preset_name, block) else # Plural grammar = :plural quantity = args.detect { |value| value.class <= Integer } preset_name = args.detect { |value| value != quantity } field_value = construct_many_subtemplates(subtemplate_definition, quantity, preset_name, block) do_not_set_value if field_value.nil? end elsif field_definition[:collection] && field_definition[:collection] <= Hash # Embeds many named if meth == field_definition[:singular] # Singular grammar = :singular variable_name = extract_variable_name(args) args = args[1..(args.size-1)] preset_name = args.first field_value = construct_one_subtemplate(subtemplate_definition, preset_name, block) do_not_set_value if field_value.nil? # || field_value.empty? else # Plural grammar = :plural do_not_set_value = true # UNSUPPORTED end else # Embeds one preset_name = args.first field_value = construct_one_subtemplate(subtemplate_definition, preset_name, block) do_not_set_value if field_value.nil? end # Invoke after clauses self.add_defaults(:after_embedded) else raise "Could not find a template matching '#{subtemplate_name}'!" end elsif field_definition[:type] == :item && can_set_field?(field_definition[:name]) if field_definition[:collection] && field_definition[:collection] <= Array # Has many if meth == field_definition[:singular] # Singular grammar = :singular obj = args.count == 1 ? args.first : args field_value = construct_one_item(field_definition, obj, block) do_not_set_value = true if field_value.nil? else # Plural grammar = :plural quantity = args.first if block && args.first.class <= Integer arr = args.first if args.count == 1 && args.first.class <= Array field_value = construct_many_items(field_definition, quantity, arr, args, block) do_not_set_value = true if field_value.empty? end elsif field_definition[:collection] && field_definition[:collection] <= Hash # Has many named if meth == field_definition[:singular] # Singular grammar = :singular variable_name = extract_variable_name(args) args = args[1..(args.size-1)] obj = args.first field_value = construct_one_item(field_definition, obj, block) do_not_set_value = true if field_value.nil? else # Plural grammar = :plural hash = args.first if args.first.class <= Hash # Hash if hash field_value = hash end do_not_set_value = true if field_value.nil? || field_value.empty? end else # Has one obj = args.first field_value = construct_one_item(field_definition, obj, block) end elsif field_definition.class == Olfactory::Dictionary if field_definition.scope == :template return_value = field_definition elsif field_definition.scope == :instance return_value = (self.dictionaries[meth] ||= {}) end do_not_set_value = true else do_not_set_value = true end # Add field value to template if !do_not_set_value if field_definition[:collection] self[field_definition[:name]] ||= field_definition[:collection].new if field_definition[:collection] <= Array if grammar == :plural return_value = self[field_definition[:name]].concat(field_value) elsif grammar == :singular return_value = self[field_definition[:name]] << field_value end elsif field_definition[:collection] <= Hash if grammar == :plural return_value = self[field_definition[:name]].merge!(field_value) elsif grammar == :singular return_value = self[field_definition[:name]][variable_name] = field_value end end else return_value = self[field_definition[:name]] = field_value end if self.default_mode && (self.default_populated[field_definition[:name]] != false) self.default_populated[field_definition[:name]] = true else self.default_populated[field_definition[:name]] = false end end return_value end
reset_dictionaries(*names)
click to toggle source
# File lib/olfactory/template.rb, line 342 def reset_dictionaries(*names) names = self.dictionaries.keys if names.empty? names.each { |name| self.dictionaries[name].reset } end
reset_sequences(*names)
click to toggle source
# File lib/olfactory/template.rb, line 338 def reset_sequences(*names) names = self.sequences.keys if names.empty? names.each { |name| self.sequences[name].reset } end
save!()
click to toggle source
# File lib/olfactory/template.rb, line 34 def save! # Items, then subtemplates [self.definition.t_items, self.definition.t_subtemplates].each do |field_group_definitions| field_group_definitions.each do |field_name, field_definition| if field_value = self[field_name] if field_definition[:collection] && field_definition[:collection] <= Array field_value.each { |value| value.save! if value.respond_to?(:save!) } elsif field_definition[:collection] && field_definition[:collection] <= Hash field_value.values.each { |value| value.save! if value.respond_to?(:save!) } else field_value.save! if field_value.respond_to?(:save!) end end end end end
transient(name, value = nil, &block)
click to toggle source
# File lib/olfactory/template.rb, line 216 def transient(name, value = nil, &block) if !(self.default_mode && self.transients.has_key?(name)) || (self.default_mode && (self.default_populated_transients[name] == true)) self.transients[name] = (block ? block.call : value) if self.default_mode && (self.default_populated_transients[name] != false) self.default_populated_transients[name] = true else self.default_populated_transients[name] = false end end end