module VestalVersions # Allows version creation to occur conditionally based on given :if and/or # :unless options. module Conditions extend ActiveSupport::Concern # Class methods on ActiveRecord::Base to prepare the :if and :unless options. module ClassMethods # After the original +prepare_versioned_options+ method cleans the given options, this alias # also extracts the :if and :unless options, chaning them into arrays # and converting any symbols to procs. Procs are called with the ActiveRecord model instance # as the sole argument. # # If all of the :if conditions are met and none of the :unless conditions # are unmet, than version creation will proceed, assuming all other conditions are also met. def prepare_versioned_options(options) result = super(options) vestal_versions_options[:if] = Array(options.delete(:if)).map(&:to_proc) vestal_versions_options[:unless] = Array(options.delete(:unless)).map(&:to_proc) result end end # Instance methods that determine based on the :if and :unless conditions, # whether a version is to be create or updated. private # After first determining whether the :if and :unless conditions are # satisfied, the original, unaliased +create_version?+ method is called to determine # whether a new version should be created upon update of the ActiveRecord::Base instance. def create_version? version_conditions_met? && super end # After first determining whether the :if and :unless conditions are # satisfied, the original, unaliased +update_version?+ method is called to determine # whther the last version should be updated to include changes merged from the current # ActiveRecord::Base instance update. # # The overridden +update_version?+ method simply returns false, effectively delegating # the decision to whether the :if and :unless conditions are met. def update_version? version_conditions_met? && super end # Simply checks whether the :if and :unless conditions given in the # +versioned+ options are met: meaning that all procs in the :if array must # evaluate to a non-false, non-nil value and that all procs in the :unless array # must all evaluate to either false or nil. def version_conditions_met? vestal_versions_options[:if].all?{|p| p.call(self) } && !vestal_versions_options[:unless].any?{|p| p.call(self) } end end end