13

我想为我的项目找到一个 ruby​​ gem 来处理符合以下要求的重复事件:

  • 可以处理“每周周二和周三”或“每月最后一个周二”等模式
  • 可以计算下一次出现
  • 可以将模式序列化/反序列化为字符串以存储在数据库中
  • 序列化格式稳定(ei即使升级后也能加载)
  • 至少使用以下模式组件:时间、星期几、月份日期、一个月中的第 n 天;
  • 可以每天、每周、每月或以 n 天、几周或几个月的间隔重复
  • 可以用自然英语表示一种模式
  • 可以从英语中解析模式(可选)
  • 可以导出为 iCal 等流行格式(可选)
  • 可以与其他 gem/系统集成以进行日历和任务管理(可选)
  • 支持 Active Record - 参数解析、验证(可选)
  • 有足够的测试,很少有错误,超过 1 个用户 :)
  • 有合理的表现

我找到了两个相关的候选人:

  • Tickle - 好处是它可以解析英语。
  • Ice_Cube(+Schedule-Attributes) - 好处是它最受欢迎并且可以导出到 iCal

你能推荐一颗宝石并描述它的正面和负面经历吗?

也许您也可以添加一些我没有提到的相关标准/要求。

PS 用 1,5K+ 添加 recurring_events 标签的人。谢谢

4

4 回答 4

8

我最终使用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
于 2011-04-19T19:39:18.110 回答
7

与 Ice_Cube 一样可爱,它似乎不适合大型调度应用程序,您可能需要过滤 100,000 多个事件以查看当天出现的内容。想想meetup.com

因为它都被序列化为规则字符串,所以过滤主要列表的唯一方法似乎是这样的:

def self.entries_on(date)
    entries = TimetableEntry.all
    entries.reject{|te|!te.schedule.occurs_on?(date)}
end

效率不是很高。有人请纠正我!希望我错过了一个技巧?

还可以使用未来 100 年的日期尝试上述方法......看起来 ice_cube 会随着您查询距离当前日期的距离越远而减慢速度。

于 2011-08-09T09:36:58.110 回答
2

我不知道有一个插件可以处理您的所有要求,但是rufus-schedulerchronic的组合应该会让您走得很远。

Rufus 调度程序使用类似 cron 的格式处理调度,该格式也适应本地时区。Chronic 进行自然语言解析。将它们放在一起应该可以解决您的大部分需求。

Rufus 文档有一些关于配对这两种解决方案的说明。

于 2011-03-15T16:10:57.577 回答
2

我建议看一下 RubyToolbox 的Recurring Events gems。它应该是最新的并且包括前面提到的 ice_cube。

于 2012-03-27T03:51:38.507 回答