lib/maintain/maintainer.rb in maintain-0.2.23 vs lib/maintain/maintainer.rb in maintain-0.3.0

- old
+ new

@@ -1,32 +1,57 @@ # encoding: UTF-8 module Maintain class Maintainer attr_reader :back_end + class << self + def call_method_or_proc(method, instance) + if method.is_a?(Proc) + instance.instance_eval(&method) + else + instance.send(method) + end + end + end + def aggregate(name, conditions, options = {}) if conditions.is_a?(Hash) && conditions.has_key?(:as) options = conditions conditions = options[:as] end aggregates[name] = conditions - # Now we're going to add proxies to test for state being in this aggregate. Don't create - # this method unless it doesn't exist. + + # Now we're going to add proxies to test for state being in this + # aggregate. Don't create this method unless it doesn't exist. boolean_method = "#{name}?" if method_free?(boolean_method) - # Define it if'n it don't already exit! These are just proxies - so Foo.maintains(:state) { state :awesome } - # will now have Foo.new.awesome?. But that's really just a proxy for Foo.new.state.awesome? + # Define it if'n it don't already exist! These are just proxies - so + # Foo.maintains(:state) { state :awesome } will now have + # Foo.new.awesome?. But that's really just a proxy for + # Foo.new.state.awesome? # So they're just shortcuts for brevity's sake. maintainee.class_eval <<-EOC def #{boolean_method} #{@attribute}.#{boolean_method} end EOC end + # Now define the state if back_end - back_end.aggregate(maintainee, name, @attribute, conditions.select{|value| states.has_key?(value) }.map{|value| states[value][:value].is_a?(Symbol) ? states[value][:value].to_s : states[value][:value] }.compact, {:force => options[:force]}) + conditions = conditions.select { |value| states.has_key?(value) } + conditions = conditions.map do |value| + if states[value][:value].is_a?(Symbol) + states[value][:value].to_s + else + states[value][:value] + end + end + conditions = conditions.compact + back_end.aggregate(maintainee, name, @attribute, conditions, { + force: options[:force] + }) end end def aggregates @aggregates ||= {} @@ -55,15 +80,20 @@ def default? !!@default end def hook(event, state, instance) - if state && state.to_s.strip != '' && hooks[state.to_sym] && hook_definitions = hooks[state.to_sym][event.to_sym] + if state && state.to_s.strip != '' && hooks[state.to_sym] + hook_definitions = hooks[state.to_sym][event.to_sym] || [] hook_definitions.each do |hook_definition| - next if hook_definition[:if] && !call_method_or_proc_on_instance(hook_definition[:if], instance) - next if hook_definition[:unless] && call_method_or_proc_on_instance(hook_definition[:unless], instance) - call_method_or_proc_on_instance(hook_definition[:method], instance) + if hook_definition[:if] + next unless call_method_or_proc(hook_definition[:if], instance) + end + if hook_definition[:unless] + next if call_method_or_proc(hook_definition[:unless], instance) + end + call_method_or_proc(hook_definition[:method], instance) end end end def initialize(maintainee, attribute, options = {}) @@ -84,22 +114,22 @@ def integer? !!@integer end def on(*args, &block) - options = {:when => :before}.merge(args.last.is_a?(Hash) ? args.pop : {}) + options = {when: :before}.merge(args.last.is_a?(Hash) ? args.pop : {}) event, state = args.shift, args.shift method = args.shift if block_given? method = block end if back_end && back_end.respond_to?(:on) back_end.on(maintainee, @attribute, event, state, method, options) else hooks[state.to_sym] ||= {} hooks[state.to_sym][event.to_sym] ||= [] - method_hash = {:method => method}.merge(options) + method_hash = {method: method}.merge(options) if old_definition = hooks[state.to_sym][event.to_sym].find{|hook| hook[:method] == method} old_definition.merge!(method_hash) else hooks[state.to_sym][event.to_sym].push(method_hash) end @@ -125,18 +155,19 @@ value = 2 ** value.to_i elsif value.is_a?(Integer) integer(true) end value ||= name - states[name] = {:compare_value => !bitmask? && value.is_a?(Integer) ? value : @increment, :value => value} + states[name] = {compare_value: !bitmask? && value.is_a?(Integer) ? value : @increment, value: value} @increment += 1 if back_end - back_end.state maintainee, name, @attribute, value.is_a?(Symbol) ? value.to_s : value, :force => options[:force] + back_end.state maintainee, name, @attribute, value.is_a?(Symbol) ? value.to_s : value, force: options[:force] end - # We need the states hash to contain the compare_value for this guy before we can set defaults on the bitmask, - # since the default should actually be a bitmask of all possible default states + # We need the states hash to contain the compare_value for this guy + # before we can set defaults on the bitmask, since the default should + # actually be a bitmask of all possible default states if options.has_key?(:default) default(name) end if options.has_key?(:enter) @@ -145,39 +176,43 @@ if options.has_key?(:exit) on :exit, name.to_sym, options.delete(:exit) end - # Now we're going to add proxies to test for state. These methods only get added if a - # method of their name doesn't already exist. + # Now we're going tests for state. Shortcuts to these methods only get + # added if a method of their name doesn't already exist. boolean_method = "#{name}?" - # Override any attribute_state? methods, because those we need for hooks... + shortcut = options[:force] || method_free?(boolean_method) maintainee.class_eval <<-EOC def #{@attribute}_#{boolean_method} - #{@attribute}.#{boolean_method} + #{@attribute} == #{value.inspect} end - #{"alias :#{boolean_method} :#{@attribute}_#{boolean_method}" if method_free?(boolean_method) || options[:force]} + #{"alias :#{boolean_method} :#{@attribute}_#{boolean_method}" if shortcut} EOC - # Last but not least, add bang methods to automatically convert to state. Like boolean - # methods above, these only get added if they're not already things that are things. + # Last but not least, add bang methods to automatically convert to state. + # Like boolean methods above, these only get added if they're not already + # things that are things. bang_method = "#{name}!" - # Override any attribute_state! methods + shortcut = options[:force] || method_free?(bang_method) maintainee.class_eval <<-EOC def #{@attribute}_#{bang_method} - #{@attribute}.#{bang_method} + self.#{@attribute} = #{value.inspect} end - #{"alias :#{bang_method} :#{@attribute}_#{bang_method}" if method_free?(bang_method) || options[:force]} + #{"alias :#{bang_method} :#{@attribute}_#{bang_method}" if shortcut} EOC end def states @states ||= {} end def value(instance, initial = nil) - initial = (back_end && back_end.read(instance, @attribute)) || initial || @default + if back_end + initial = back_end.read(instance, @attribute) + end + initial ||= initial || @default if bitmask? BitmaskValue.new(self, initial || 0) elsif integer? IntegerValue.new(self, initial) else @@ -196,21 +231,18 @@ def method_free?(method_name, class_method = false) # Ugly hack so we don't fetch it 100 times for no reason maintainee_class = maintainee if class_method - respond_to = maintainee_class.respond_to?(method_name) - methods = maintainee_class.public_methods + maintainee_class.private_methods + maintainee_class.protected_methods + return false if maintainee_class.respond_to?(method_name) + methods = maintainee_class.public_methods + methods += maintainee_class.private_methods + methods += maintainee_class.protected_methods else - respond_to = false methods = maintainee_class.instance_methods - # methods = %w(instance_methods public_instance_methods private_instance_methods protected_instance_methods).inject([]) do |methods, method| - # methods + maintainee_class.send(method) - # end.uniq end - # Ruby 1.8 returns arrays of strings; ruby 1.9 returns arrays of symbols. "Awesome." - !respond_to && !methods.include?(method_name) && !methods.include?(method_name.to_sym) + !methods.include?(method_name.to_sym) end def method_missing(method, *args) if states.has_key?(method) states[method][:value] @@ -218,14 +250,10 @@ super end end private - def call_method_or_proc_on_instance(method, instance) - if method.is_a?(Proc) - instance.instance_eval(&method) - else - instance.send(method) - end + def call_method_or_proc(method, instance) + self.class.call_method_or_proc(method, instance) end end -end \ No newline at end of file +end