stateful.rb
上传用户:netsea168
上传日期:2022-07-22
资源大小:4652k
文件大小:3k
源码类别:

Ajax

开发平台:

Others

  1. module Stateful
  2.   class State
  3.     def initialize(model)
  4.       @model = model
  5.     end
  6.     def to_s
  7.       self.class.to_s.demodulize
  8.     end
  9.     def exit_hook(target_state)
  10.       RAILS_DEFAULT_LOGGER.debug("#{model} leaving state #{self}")
  11.     end
  12.     def enter_hook
  13.       RAILS_DEFAULT_LOGGER.debug("#{model} entering state #{self}")
  14.     end
  15.     def method_missing(predicate, *args)
  16.       if predicate.to_s.last == '?'
  17.         self.class.to_s.demodulize.underscore == predicate.to_s.chop
  18.       else
  19.         if block_given?
  20.           super(predicate, *args) { |*block_args| yield(*block_args) }
  21.         else
  22.           super(predicate, *args)
  23.         end
  24.       end
  25.     end
  26.     def ==(other_state)
  27.       self.class == other_state.class
  28.     end
  29.     def hash
  30.       self.class.hash
  31.     end
  32.     private
  33.     attr_reader :model
  34.   end
  35.   def self.included(base)
  36.     base.extend ClassMethods
  37.   end
  38.   module ClassMethods
  39.     def has_state(field, options = {})
  40.       options.assert_valid_keys(:valid_states, :handles, :initial_state)
  41.       unless states = options[:valid_states]
  42.         raise "You must specify at least one state"
  43.       end
  44.       states        = states.collect &:to_sym
  45.       delegations   = Set.new(options[:handles]) + states.collect { |value| "#{value}?" }
  46.       initial_state = options[:initial_state] || states.first
  47.       state_writer_method(field, states, initial_state)
  48.       state_reader_method(field, states, initial_state)
  49.       delegations.each do |value|
  50.         delegate value, :to => field
  51.       end
  52.     end
  53.     def state_reader_method(name, states, initial_state)
  54.       module_eval <<-end_meth
  55.         def #{name}(force_reload = false)
  56.           if @#{name}_obj.nil? || force_reload
  57.             memento = read_attribute(#{name.inspect}) || #{initial_state.inspect}
  58.             unless #{states.inspect}.include? memento.to_sym
  59.               raise "Invalid state: #{memento} in the database."
  60.             end
  61.             @#{name}_obj = self.class.class_eval(memento.to_s.classify).new(self)
  62.           end
  63.           @#{name}_obj
  64.         end
  65.       end_meth
  66.     end
  67.     def state_writer_method(name, states, initial_state)
  68.       module_eval <<-end_meth
  69.         def #{name}=(state)
  70.           case state
  71.           when Symbol
  72.             set_#{name}_from_symbol state
  73.           when String
  74.             set_#{name}_from_symbol state.to_sym
  75.           else
  76.             raise "You must set the state with a symbol or a string"
  77.           end
  78.         end
  79.         def set_#{name}_from_symbol(memento)
  80.           unless #{states.inspect}.include?(memento)
  81.             raise "Invalid state: " + memento
  82.           end
  83.           self[:#{name}] = memento.to_s
  84.           new_state = self.class.class_eval(memento.to_s.classify).new(self)
  85.           @#{name}_obj.exit_hook(new_state) if @#{name}_obj
  86.           @#{name}_obj = new_state
  87.           @#{name}_obj.enter_hook
  88.           @#{name}_obj
  89.         end
  90.       end_meth
  91.     end
  92.   end
  93. end