module Shoulda module Whenever def schedule(task) ScheduleMatcher.new(task) end alias_method :schedule_rake, :schedule alias_method :schedule_runner, :schedule alias_method :schedule_command, :schedule class ScheduleMatcher attr_reader :duration, :time, :task, :roles def initialize(task) @task = task @duration = nil @time = nil @roles = nil end def matches?(subject) jobs = subject.instance_variable_get("@jobs") jobs = filter_jobs_by_duration(jobs) jobs = filter_jobs_by_time(jobs) jobs = filter_jobs_by_roles(jobs) jobs = filter_jobs_by_task(jobs) jobs.any? end def filter_jobs_by_duration(jobs) if duration.nil? jobs.values.flatten else duration_to_fetch = if duration.is_a?(String) || duration.is_a?(Symbol) duration else duration.to_i end jobs.fetch(duration_to_fetch) { [] } end end def filter_jobs_by_time(jobs) return jobs if time.nil? jobs.select { |job| job.at == time } end def filter_jobs_by_roles(jobs) return jobs if roles.nil? || roles.empty? jobs.select { |job| job.roles == roles } end def filter_jobs_by_task(jobs) jobs.select do |job| job.instance_variable_get("@options")[:task] == task end end def every(duration) @duration = duration self end def at(time) @time = time self end def with_roles(roles) @roles = Array(roles) self end alias_method :with_role, :with_roles def description [ base_description, duration_description, time_description, roles_description ].compact.join(' ') end def failure_message [ base_failure_message, duration_description, time_description, roles_description ].compact.join(' ') end def failure_message_when_negated [ base_failure_message_when_negated, duration_description, time_description, roles_description ].compact.join(' ') end private def base_description "schedule \"#{ task }\"" end def duration_description unless duration.nil? if duration.is_a?(String) || duration.is_a?(Symbol) "every \"#{ duration }\"" else "every #{ duration.to_i } seconds" end end end def time_description unless time.nil? "at \"#{ time }\"" end end def roles_description unless roles.nil? || roles.empty? role_names = roles.map { |role| "\"#{ role }\"" }.join(", ") "with #{ role_names } role(s)" end end def base_failure_message "expected to schedule \"#{ task }\"" end def base_failure_message_when_negated "expected not to schedule \"#{ task }\"" end end end end