Skip to content

Instantly share code, notes, and snippets.

@RohitRox
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RohitRox/440459564644b0559894 to your computer and use it in GitHub Desktop.
Save RohitRox/440459564644b0559894 to your computer and use it in GitHub Desktop.
Ruby Refactoring with Meta and Modules
class Project < ActiveRecord::Base
STATUS_TRANSITIONS =
{
initial: :not_started,
not_started: { value: "On the board" },
recommendation_sent: { value: "Recs: Recommendations Sent", event: :recommend},
restarted: { event: :restart, to: :not_started }
}
after_initialize :default_status
def default_status
self.status ||= STATUS_TRANSITIONS[STATUS_TRANSITIONS[:initial]][:value]
end
STATUS_TRANSITIONS.except(:initial).each do |k,v|
value = v[:to] ? STATUS_TRANSITIONS[v[:to]][:value] : v[:value]
if value.present?
define_method "#{k}?" do
self.status == value
end
end
if v[:event].present?
define_method v[:event] do
self.status = value
end
define_method "#{v[:event]}!" do
self.send(v[:event])
self.save
end
end
end
def status_class
if self.not_started?
"label-info"
elsif self.recommendation_sent?
"label-warning"
else
"label-primary"
end
end
end
class Project < ActiveRecord::Base
include StatusMachine
status_machine initial: :not_started do
transition :not_started, value: "On the Desk", css: "label-info"
transition :recommendation_sent, value: "Recs: Recommendations Sent", event: "recommend", css: "label-success"
transition :restarted, to: :not_started, event: "restart"
end
end
module StatusMachine
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
@@states = {}
@@initial = nil
def transition t, opts
if opts[:to]
to = @@states[opts[:to]]
value = to[:value]
css = to[:css]
state = { value: value, event: opts[:event], to: opts[:to], css: css }
else
state = { value: opts[:value], event: opts[:event], to: opts[:to], css: opts[:css] }
end
@@states[t] = state
value = state[:value]
self.class_eval do
if value.present?
define_method "#{t}?" do
self.status == value
end
end
if opts[:event].present?
define_method opts[:event] do
self.status = value
end
define_method "#{opts[:event]}!" do
self.send(opts[:event])
self.save
end
end
end
end
def status_machine opts
yield
@@initial = @@states[opts[:initial]][:value]
self.class_eval do
after_initialize :default_status
def default_status
self.status ||= @@initial
end
def status_css
@@states.values.find{|e| e[:value] == self.status }[:css]
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment