class NaturalBornSlugger::AttributeComposer
Public Class Methods
default_options()
click to toggle source
# File lib/natural_born_slugger/attribute_composer.rb, line 15 def self.default_options { require_all: false, join_with: '', callback: false } end
extract_dependencies_from_options(dependencies={})
click to toggle source
# File lib/natural_born_slugger/attribute_composer.rb, line 23 def self.extract_dependencies_from_options(dependencies={}) options = default_options.dup options.keys.each do |option| if dependencies.has_key? option options[option] = dependencies.delete(option) end end [dependencies, options] end
new(name, options)
click to toggle source
# File lib/natural_born_slugger/attribute_composer.rb, line 6 def initialize(name, options) @name = name.to_s @dependencies, options = self.class.extract_dependencies_from_options(options) options.each do |option, value| self.instance_variable_set("@#{option}", value) end raise ConfigurationError.new(self.name, name, "no dependent attributes were specified") if @dependencies.empty? end
resolve_dependency(object, dependency)
click to toggle source
# File lib/natural_born_slugger/attribute_composer.rb, line 33 def self.resolve_dependency(object, dependency) dependency_chain = dependency.to_s.split('.') dependency_chain.each do |method| object = object.try :send, method break unless object end object end
Public Instance Methods
add_to(klass)
click to toggle source
Adds composite attribute methods to the class:
a getter, and updater method.
Also adds a setter that either calls the updater
or throws an error, depending on configuration
# File lib/natural_born_slugger/attribute_composer.rb, line 85 def add_to(klass) unless klass.respond_to? :composite_attributes klass.class_attribute(:composite_attributes) end klass.composite_attributes ||= {} klass.composite_attributes[@name] = self klass.send :define_method, "update_#{@name}".to_sym do name = __method__.to_s.gsub 'update_', '' new_value = self.class.composite_attributes[name].evaluate(self) if self.respond_to? "#{name}=".to_sym new_value = self.send "#{name}=".to_sym, new_value end self.instance_variable_set("@#{name}", new_value) #TODO: What is the fate of callbacks? Should the feature be removed? Potential race condition if the value was mutated by the callback #composer.callback(self, old_value, new_value) new_value end # Define instance attribute getter: calls setter klass.send :define_method, @name do name = __method__.to_s if frozen? self.instance_variable_get("@#{name}") else self.send "update_#{name}".to_sym end end end
callback(object, old_value, new_value)
click to toggle source
# File lib/natural_born_slugger/attribute_composer.rb, line 72 def callback(object, old_value, new_value) if @callback unless old_value == new_value object.instance_exec old_value, new_value, &@callback end end end
compose_attribute(resolved_dependencies)
click to toggle source
# File lib/natural_born_slugger/attribute_composer.rb, line 43 def compose_attribute(resolved_dependencies) resolved_dependencies.map do |resolved_dependency, strategy| case strategy when Symbol # Symbols represent string methods to call on the resolved dependency resolved_dependency.to_s.send(strategy) when String # Strings represent formats to fit the resolved dependency into strategy % resolved_dependency when Regexp # Regexps represent patterns to pull out of the resolved dependency and join resolved_dependency.scan(strategy).join(@join_with) when Proc # Procs should take one parameter and return a string or nil strategy.call(resolved_dependency) else # If no strategy provided, use resolved dependency as is resolved_dependency.to_s end # Remove nil components if `compact_dependencies` is true end.reject{|string| not string or string.empty? }.join(@join_with) end
evaluate(object)
click to toggle source
# File lib/natural_born_slugger/attribute_composer.rb, line 61 def evaluate(object) resolved_dependencies = @dependencies.map do |dependency, strategy| [self.class.resolve_dependency(object, dependency), strategy] end # Check existence of all attribute dependencies if `require_all` is true if @require_all ? resolved_dependencies.map(&:first).all? : true composite = compose_attribute(resolved_dependencies) composite.empty? ? nil : composite end end