This is my initial class. (I am not trying to reinvent state-flows again, just practicing)As you can see straight forward, it dynamically generates methods like .recommend,.recommend!, .recommendation_sent?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  endendNow, I would like to clean up my model and extract behavior to a separate module and would like to present a pleasant dsl like this: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, color: label-success    transition :restarted, to: :not_started, event: restart  end endMy solution looks like this: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  endendBeing quite new to meta world, I am not sure if this is the way to do such stuffs so I would like to see comments on my implementation. And also the transition method is ugly. I tried to refactor that, extracting to a separate method, but I don't want to add another class method to expose. And if I do private class method, things will be way more complicated. How can I approach this?
Extracting dynamic behaviors of state machines to modules
ruby;state machine;active record;meta programming;mixins