Module: SuperState::ClassMethods

Defined in:
lib/super_state.rb

Instance Method Summary collapse

Instance Method Details

#define_state_methods(method_name, state_names = nil) ⇒ Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/super_state.rb', line 191

def define_state_methods(method_name, state_names=nil)
  state_names ||= method_name
  
  # Loan.completed # scope
  self.scope method_name, self.scope_by_super_state(state_names)
  
  # pretty much;
  #   def record.completed?
  #     record.status == "completed"
  #   end
  define_method("#{method_name}?") do
    StateArray.new(state_names).include?(self.current_super_state)
  end
end

#define_state_transition_method(method_name, state_hash, save_method, &transition_block) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/super_state.rb', line 206

def define_state_transition_method(method_name, state_hash, save_method, &transition_block)
  
  # pretty much;
  #   def record.complete!
  #     if record.pending?
  #       record.status = "completed"
  #       record.save!
  #     else
  #       raise SuperState::BadState
  #     end
  #   end
  define_method(method_name) do |*args|
    if to_state = state_hash[self.current_super_state]

      state_before = self.current_super_state
      self.set_super_state(to_state)

      if transition_block
        params = args.shift || {}
        self.instance_exec(params, &transition_block)
      end

      unless rtn = self.send(save_method)
        self.set_super_state(state_before, false) #roll it back on failure
      end
      rtn
    else
      raise SuperState::BadState, "#{method_name} can only be called from states #{state_hash.keys.inspect}"
    end
  end
  
end

#in_state(state_name) ⇒ Object

a wrapper around state based scopes to avoid malicious arguments;

Loan.in_state(:disbursed) => Loan.disbursed
Loan.in_state("active")   => Loan.active
Loan.in_state("all")      => Loan.scoped
Loan.in_state("")         => Loan.scoped
Loan.in_state("something_evil") => Exception!


137
138
139
140
141
142
143
# File 'lib/super_state.rb', line 137

def in_state(state_name)
  if state_array = self.super_states(state_name)
    self.scope_by_super_state(state_array)
  else
    raise BadState, "you are trying to scope by something other than a super state (or super state group)"
  end
end

#scope_by_super_state(state_names) ⇒ Object



163
164
165
166
167
168
169
# File 'lib/super_state.rb', line 163

def scope_by_super_state(state_names)
  if state_names.is_a?(StateArray) && state_names.all_states?
    self.scoped
  else
    self.where(self.super_state_column => SuperState.canonicalise(state_names))
  end
end

#state_transition(transition_name, state_hash, &transition_block) ⇒ Object

state_transition :complete, :processing => :completed



178
179
180
181
182
183
# File 'lib/super_state.rb', line 178

def state_transition(transition_name, state_hash, &transition_block)
  state_hash = state_hash.stringify_keys
  
  define_state_transition_method(transition_name,       state_hash, :save,  &transition_block)
  define_state_transition_method("#{transition_name}!", state_hash, :save!, &transition_block)
end

#super_state(state_name, options = {}) ⇒ Object



122
123
124
125
126
127
128
# File 'lib/super_state.rb', line 122

def super_state(state_name, options={})
  if options[:initial] || self.initial_super_state.nil?
    self.initial_super_state = state_name
  end
  define_state_methods(state_name)
  self.__super_states << state_name
end

#super_state_columnObject

internal methods



187
188
189
# File 'lib/super_state.rb', line 187

def super_state_column
  :status
end

#super_state_group(group_name, group_states) ⇒ Object

super_state_group(:active, [:approved, :requested, :disbursed])



172
173
174
175
# File 'lib/super_state.rb', line 172

def super_state_group(group_name, group_states)
  define_state_methods(group_name, group_states)
  self.super_state_groups[group_name] = group_states
end

#super_states(state_name = nil) ⇒ Object

self.super_states => [“first”, “second”, “third”] self.super_states(“”) => [“first”, “second”, “third”] self.super_states(“all”) => [“first”, “second”, “third”]

self.super_states(“first”) => [“first”]

self.super_states(“final”) => [“second”, “third”]



153
154
155
156
157
158
159
160
161
# File 'lib/super_state.rb', line 153

def super_states(state_name=nil)
  if state_name.blank? || state_name == "all"
    self.__super_states
  elsif self.__super_states.include?(state_name)
    StateArray.new(state_name)
  elsif self.super_state_groups.include?(state_name)
    self.super_state_groups[state_name]
  end
end

#super_states_for_select(options = {}) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/super_state.rb', line 109

def super_states_for_select(options={})
  rtn = []
  if options[:include_all]
    rtn << ["<All>", "all"]
  end
  if options[:include_groups]
    rtn += self.super_state_groups.keys.for_select
  end
  rtn += self.super_states.for_select
  
  rtn
end