texpJim Weirich开发的Ruby临时表达式库,提供了模块化、可扩展的序列化语言。

临时表达式提供了一种精炼地表达重复性事件的方式。例如,每年的12月25日是圣诞节。一个代表圣诞节的临时表达式会返回真,如果日期是12月25日。

dec25 = Date.parse("Dec 25, 2008")
christmas_texp.includes?(dec25)      # => true
christmas_texp.includes?(dec25 + 1)  # => false

可以使用运算符组合临时表达式。例如,如果我有一个圣诞节的临时表达式和一个感恩节的临时表达式,我可以将它们合并成一个假日表达式:

holidays_texp = christmas_texp + thanksgiving_texp

TExp特性

  • 基本表达式

    • DayOfWeek
    • DayOfMonth
    • Week
    • Month
    • Year
  • 复合表达式

    • AND
    • OR
    • NOT
    • 时间窗口
  • inspect的描述人类可读

  • 紧凑、可解析的编码

  • 可由用户扩展的临时表达式类型

  • 建构临时表达式的DSL

例子

以下的例子使用了TExp DSL。DSL默认未开启,可以通过以下方式开启:

  • 使用全局texp方法和块

    te = texp { day(1) * month("Jan") }
    
  • 在类中includeTExp::DSL模块

    include TExp::DSL
    te = day(1) * month("Jan")
    

查看TExp::DSL模块获取所有DSL命令的完整描述。

匹配周一

te = dow(:monday)
te.includes?(Date.parse("Mar 3, 2008"))    # => true
te.includes?(Date.parse("Mar 4, 2008"))    # => false
te.includes?(Date.parse("Mar 10, 2008"))   # => true

# 等价于
te = TExp::DayOfWeek.new(Date::DAYNAMES.index("Monday"))

# 变体
dow("Mon", "Tues")     # 周一或周二

匹配三月的任意一天

te = month(:march)
te.includes?(Date.parse("Mar 1, 2008"))    # => true
te.includes?(Date.parse("Mar 31, 2008"))   # => true
te.includes?(Date.parse("Mar 15, 1995"))   # => true
te.includes?(Date.parse("Feb 28, 2008"))   # => false

# 等价于
te = TExp::Month.new(3)

# 变体
month(1,2,3)         # 一月、二月、三月
month("Nov", "Dec")  # 十一月或十二月

匹配情人节

如果你将临时表达式看成日期的集合,那么你可以以有趣的方式组合这些集合。例如,*运算符会创建两个日期集合的交集,只匹配同时满足两个表达式的日期。

te = day(14) * month("Feb")

te.includes?(Date.parse("Feb 14, 2008"))  # => true
te.includes?(Date.parse("Feb 14, 2007"))  # => true

# 等价于
te = TExp::And.new(
       TExp::DayOfMonth.new(14),
       TExp::Month.new(2))

匹配2008年的情人节

te = day(14) * month("Feb") * year(2008)

te.includes?(Date.parse("Feb 14, 2008"))  # => true
te.includes?(Date.parse("Feb 14, 2007"))  # => false

# 等价于
te = TExp::And.new(
       TExp::DayOfMonth.new(14),
       TExp::Month.new(2),
       TExp::Year.new(2008))

匹配多个日期

交集之外,我们可以请求两个临时表达式的并集。下面我们构建一个匹配圣诞节和新年的临时表达式:

christmas = day(25) * month("Dec")
new_years = day(1) * month("Jan")

holidays = christmas + new_years

holidays.includes?(Date.parse("Jan 1, 2008"))   # => true
holidays.includes?(Date.parse("Dec 25, 2008"))  # => true
holidays.includes?(Date.parse("Jan 1, 2009"))   # => true

holidays.includes?(Date.parse("Feb 14, 2008"))  # => false

# 等价于
holidays = TExp::Or.new(
  TExp::And.new( TExp::DayOfMonth.new(25), TExp::Month(12) ),
  TExp::And.new( TExp::DayOfMonth.new(1),  TExp::Month(1)  ))

排除日期

除了月末的周五之外的其他周五都是Casual Friday:

fridays = dow(:fri)
last_friday = week(:last) * dow(:fri)
casual_fridays = fridays - last_friday

casual_fridays.includes?(Date.new(2013, 6, 21))  # => true
casual_fridays.includes?(Date.new(2013, 6, 28))  # => false

相关链接

Jim Weirich


编译 SegmentFault


weakish
24.6k 声望844 粉丝

a vigorously lazy deadbeat with matured immaturity