我最终使用Ice_Cube的原因如下:
- 最受欢迎
- 可以计算下一次出现
- 可以将模式序列化/反序列化为字符串以存储在数据库中
- 序列化格式稳定(ei即使升级后也能加载)
- 至少使用以下模式组件:时间、星期几、月份日期、一个月中的第 n 天;
- 可以每天、每周、每月或以 n 天、几周或几个月的间隔重复
- 可以从英语中解析模式(可选)
- 可以导出为 iCal 等流行格式(可选)
我的标准没有满足这些条件:
- 可以用自然英语表示一种模式
- 支持 Active Record - 参数解析、验证(可选)
这个未经验证:
在 Rails 中从用户输入创建 Ice_Cube::Schedule 不是很方便,但可行:
class EntryForm < FormModel
include IceCube
class_eval &ValidatesTimelinessSupport[{:start_date => :datetime}]
Units = [Day = 'day', Week = 'week']
Intervals = %w[0 1 2 3 4 5 6 7 8 9]
Week_Days = [:sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday]
Days_With_Letters = Week_Days.zip(%w[S M T W T F S])
attr_accessible_accessors :interval, :unit, :start_date
attr_accessible_accessors *Week_Days
def_delegators :@model, :display_title, :schedule_yaml, :schedule_yaml=
validates_date :start_date, :allow_blank => true
validates_inclusion_of :unit, :in => Units
validates_inclusion_of :interval, :in => Intervals
validates_inclusion_of :complete, :in => %w[0 1], :allow_blank => true
Week_Days.each { |day| validates_inclusion_of day, :in => %w[0 1], :allow_blank => true }
before_edit {
if not schedule_yaml.blank? and hash = YAML::load(schedule_yaml)
schedule = Schedule.from_hash(hash)
end
if schedule and rule = schedule.rrules.first
@start_date = schedule.start_date
rule_hash = rule.to_hash
@interval = rule_hash[:interval]
case rule
when DailyRule
@unit = Day
when WeeklyRule
@unit = Week
rule_hash[:validations][:day].try :each do |day_index|
send "#{Week_Days[day_index]}=", 1
end
end
else
@start_date = Date.today
@interval = 1
@unit = Day
end
}
before_save {
sd = @start_date.blank? ?
Date.today.to_all_day :
@start_date.parse_date_in_timezone
i = @interval.to_i
schedule = Schedule.new(sd)
rule = case @unit
when Day
Rule.daily i
when Week
Rule.weekly(i).day(
*Week_Days.
select { |day| send(day).to_i == 1 } )
end
schedule.add_recurrence_rule(rule)
self.schedule_yaml = schedule.to_yaml
end
}
end