Class: Symphony::Metronome::IntervalExpression
- Inherits:
-
Object
- Object
- Symphony::Metronome::IntervalExpression
- Extended by:
- Loggability
- Includes:
- Comparable, TimeFunctions
- Defined in:
- lib/symphony/metronome/intervalexpression.rb
Overview
Parse natural English expressions of times and intervals.
in 30 minutes
once an hour
every 15 minutes for 2 days
at 2014-05-01
at 2014-04-01 14:00:25
at 2pm
starting at 2pm once a day
start in 1 hour from now run every 5 seconds end at 11:15pm
every other hour
once a day ending in 1 week
run once a minute for an hour starting in 6 days
run each hour starting at 2010-01-05 09:00:00
10 times a minute for 2 days
run 45 times every hour
30 times per day
start at 2010-01-02 run 12 times and end on 2010-01-03
starting in an hour from now run 6 times a minute for 2 hours
beginning a day from now, run 30 times per minute and finish in 2 weeks
execute 12 times during the next 2 minutes
Constant Summary collapse
- COMMON_DECORATORS =
Words/phrases in the expression that we’ll strip/ignore before parsing.
[ 'and', 'then', /\s+from now/, 'the next' ]
Class Attribute Summary collapse
-
._interval_expression_eof_actions ⇒ Object
Returns the value of attribute _interval_expression_eof_actions.
-
._interval_expression_index_offsets ⇒ Object
Returns the value of attribute _interval_expression_index_offsets.
-
._interval_expression_key_offsets ⇒ Object
Returns the value of attribute _interval_expression_key_offsets.
-
._interval_expression_range_lengths ⇒ Object
Returns the value of attribute _interval_expression_range_lengths.
-
._interval_expression_single_lengths ⇒ Object
Returns the value of attribute _interval_expression_single_lengths.
-
._interval_expression_trans_actions ⇒ Object
Returns the value of attribute _interval_expression_trans_actions.
-
._interval_expression_trans_keys ⇒ Object
Returns the value of attribute _interval_expression_trans_keys.
-
._interval_expression_trans_targs ⇒ Object
Returns the value of attribute _interval_expression_trans_targs.
-
.interval_expression_en_main ⇒ Object
Returns the value of attribute interval_expression_en_main.
-
.interval_expression_error ⇒ Object
Returns the value of attribute interval_expression_error.
-
.interval_expression_first_final ⇒ Object
Returns the value of attribute interval_expression_first_final.
-
.interval_expression_start ⇒ Object
Returns the value of attribute interval_expression_start.
Instance Attribute Summary collapse
-
#ending ⇒ Object
readonly
The valid end time for the schedule (for recurring events).
-
#interval ⇒ Object
readonly
The interval to wait before the event should be acted on.
-
#multiplier ⇒ Object
readonly
An optional interval multipler for expressing counts.
-
#recurring ⇒ Object
readonly
Does this event repeat?.
-
#starting ⇒ Object
readonly
The valid start time for the schedule (for recurring events).
-
#valid ⇒ Object
readonly
Is the schedule expression parsable?.
Class Method Summary collapse
-
.parse(exp, time = nil) ⇒ Object
Parse a schedule expression
exp.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
Comparable interface, order by interval, ‘soonest’ first.
-
#fire? ⇒ Boolean
If this interval is on a stack somewhere and ready to fire, is it okay to do so based on the specified expression criteria?.
-
#initialize(expression, base) ⇒ IntervalExpression
constructor
:nodoc:.
-
#inspect ⇒ Object
Inspection string.
-
#to_s ⇒ Object
Just return the original event expression.
Constructor Details
#initialize(expression, base) ⇒ IntervalExpression
:nodoc:
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2172 def initialize( expression, base ) # :nodoc: @exp = expression @data = expression.to_s.unpack( 'c*' ) @base = base @valid = false @recurring = false @starting = nil @interval = nil @multiplier = nil @ending = nil end |
Class Attribute Details
._interval_expression_eof_actions ⇒ Object
Returns the value of attribute _interval_expression_eof_actions.
1767 1768 1769 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 1767 def _interval_expression_eof_actions @_interval_expression_eof_actions end |
._interval_expression_index_offsets ⇒ Object
Returns the value of attribute _interval_expression_index_offsets.
793 794 795 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 793 def _interval_expression_index_offsets @_interval_expression_index_offsets end |
._interval_expression_key_offsets ⇒ Object
Returns the value of attribute _interval_expression_key_offsets.
47 48 49 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 47 def _interval_expression_key_offsets @_interval_expression_key_offsets end |
._interval_expression_range_lengths ⇒ Object
Returns the value of attribute _interval_expression_range_lengths.
675 676 677 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 675 def _interval_expression_range_lengths @_interval_expression_range_lengths end |
._interval_expression_single_lengths ⇒ Object
Returns the value of attribute _interval_expression_single_lengths.
557 558 559 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 557 def _interval_expression_single_lengths @_interval_expression_single_lengths end |
._interval_expression_trans_actions ⇒ Object
Returns the value of attribute _interval_expression_trans_actions.
1339 1340 1341 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 1339 def _interval_expression_trans_actions @_interval_expression_trans_actions end |
._interval_expression_trans_keys ⇒ Object
Returns the value of attribute _interval_expression_trans_keys.
165 166 167 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 165 def _interval_expression_trans_keys @_interval_expression_trans_keys end |
._interval_expression_trans_targs ⇒ Object
Returns the value of attribute _interval_expression_trans_targs.
911 912 913 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 911 def _interval_expression_trans_targs @_interval_expression_trans_targs end |
.interval_expression_en_main ⇒ Object
Returns the value of attribute interval_expression_en_main.
1898 1899 1900 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 1898 def interval_expression_en_main @interval_expression_en_main end |
.interval_expression_error ⇒ Object
Returns the value of attribute interval_expression_error.
1893 1894 1895 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 1893 def interval_expression_error @interval_expression_error end |
.interval_expression_first_final ⇒ Object
Returns the value of attribute interval_expression_first_final.
1889 1890 1891 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 1889 def interval_expression_first_final @interval_expression_first_final end |
.interval_expression_start ⇒ Object
Returns the value of attribute interval_expression_start.
1885 1886 1887 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 1885 def interval_expression_start @interval_expression_start end |
Instance Attribute Details
#ending ⇒ Object (readonly)
The valid end time for the schedule (for recurring events)
2200 2201 2202 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2200 def ending @ending end |
#interval ⇒ Object (readonly)
The interval to wait before the event should be acted on.
2203 2204 2205 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2203 def interval @interval end |
#multiplier ⇒ Object (readonly)
An optional interval multipler for expressing counts.
2206 2207 2208 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2206 def multiplier @multiplier end |
#recurring ⇒ Object (readonly)
Does this event repeat?
2194 2195 2196 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2194 def recurring @recurring end |
#starting ⇒ Object (readonly)
The valid start time for the schedule (for recurring events)
2197 2198 2199 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2197 def starting @starting end |
#valid ⇒ Object (readonly)
Is the schedule expression parsable?
2191 2192 2193 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2191 def valid @valid end |
Class Method Details
.parse(exp, time = nil) ⇒ Object
Parse a schedule expression exp.
Parsing defaults to Time.now(), but if passed a time object, all contexual times (2pm) are relative to it. If you know when an expression was generated, you can ‘reconstitute’ an interval object this way.
1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 1919 def self::parse( exp, time=nil ) # Normalize the expression before parsing # exp = exp.downcase. gsub( /(?:[^[a-z][0-9][\.\-:]\s]+)/, '' ). # . : - a-z 0-9 only gsub( Regexp.union(COMMON_DECORATORS), '' ). # remove common decorator words gsub( /\s+/, ' ' ). # collapse whitespace gsub( /([:\-])+/, '\1' ). # collapse multiple - or : chars gsub( /\.+$/, '' ) # trailing periods event = new( exp, time || Time.now ) data = event.instance_variable_get( :@data ) # Ragel interface variables # key = '' mark = 0 begin p ||= 0 pe ||= data.length cs = interval_expression_start end eof = pe begin testEof = false _klen, _trans, _keys = nil _goto_level = 0 _resume = 10 _eof_trans = 15 _again = 20 _test_eof = 30 _out = 40 while true if _goto_level <= 0 if p == pe _goto_level = _test_eof next end if cs == 0 _goto_level = _out next end end if _goto_level <= _resume _keys = _interval_expression_key_offsets[cs] _trans = _interval_expression_index_offsets[cs] _klen = _interval_expression_single_lengths[cs] _break_match = false begin if _klen > 0 _lower = _keys _upper = _keys + _klen - 1 loop do break if _upper < _lower _mid = _lower + ( (_upper - _lower) >> 1 ) if data[p].ord < _interval_expression_trans_keys[_mid] _upper = _mid - 1 elsif data[p].ord > _interval_expression_trans_keys[_mid] _lower = _mid + 1 else _trans += (_mid - _keys) _break_match = true break end end # loop break if _break_match _keys += _klen _trans += _klen end _klen = _interval_expression_range_lengths[cs] if _klen > 0 _lower = _keys _upper = _keys + (_klen << 1) - 2 loop do break if _upper < _lower _mid = _lower + (((_upper-_lower) >> 1) & ~1) if data[p].ord < _interval_expression_trans_keys[_mid] _upper = _mid - 2 elsif data[p].ord > _interval_expression_trans_keys[_mid+1] _lower = _mid + 2 else _trans += ((_mid - _keys) >> 1) _break_match = true break end end # loop break if _break_match _trans += _klen end end while false cs = _interval_expression_trans_targs[_trans]; if _interval_expression_trans_actions[_trans] != 0 case _interval_expression_trans_actions[_trans] when 2 then begin mark = p end when 1 then begin event.instance_variable_set( :@valid, false ) end when 3 then begin event.instance_variable_set( :@recurring, true ) end when 4 then begin time = event.send( :extract, mark, p - mark ) event.send( :set_starting, time, :time ) end when 5 then begin interval = event.send( :extract, mark, p - mark ) event.send( :set_starting, interval, :interval ) end when 9 then begin interval = event.send( :extract, mark, p - mark ) event.send( :set_interval, interval, :interval ) end when 7 then begin multiplier = event.send( :extract, mark, p - mark ).sub( / times/, '' ) event.instance_variable_set( :@multiplier, multiplier.to_i ) end when 14 then begin time = event.send( :extract, mark, p - mark ) event.send( :set_ending, time, :time ) end when 15 then begin interval = event.send( :extract, mark, p - mark ) event.send( :set_ending, interval, :interval ) end end # action switch end end if _goto_level <= _again if cs == 0 _goto_level = _out next end p += 1 if p != pe _goto_level = _resume next end end if _goto_level <= _test_eof if p == eof begin case ( _interval_expression_eof_actions[cs] ) when 1 then begin event.instance_variable_set( :@valid, false ) end when 10 then begin time = event.send( :extract, mark, p - mark ) event.send( :set_starting, time, :time ) end begin event.instance_variable_set( :@valid, true ) end when 13 then begin interval = event.send( :extract, mark, p - mark ) event.send( :set_starting, interval, :interval ) end begin event.instance_variable_set( :@valid, true ) end when 16 then begin time = event.send( :extract, mark, p - mark ) event.send( :set_interval, time, :time ) end begin event.instance_variable_set( :@valid, true ) end when 8 then begin interval = event.send( :extract, mark, p - mark ) event.send( :set_interval, interval, :interval ) end begin event.instance_variable_set( :@valid, true ) end when 6 then begin multiplier = event.send( :extract, mark, p - mark ).sub( / times/, '' ) event.instance_variable_set( :@multiplier, multiplier.to_i ) end begin event.instance_variable_set( :@valid, true ) end when 11 then begin time = event.send( :extract, mark, p - mark ) event.send( :set_ending, time, :time ) end begin event.instance_variable_set( :@valid, true ) end when 12 then begin interval = event.send( :extract, mark, p - mark ) event.send( :set_ending, interval, :interval ) end begin event.instance_variable_set( :@valid, true ) end end end end end if _goto_level <= _out break end end end # Attach final time logic and sanity checks. event.send( :finalize ) return event end |
Instance Method Details
#<=>(other) ⇒ Object
Comparable interface, order by interval, ‘soonest’ first.
2257 2258 2259 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2257 def <=>( other ) return self.interval <=> other.interval end |
#fire? ⇒ Boolean
If this interval is on a stack somewhere and ready to fire, is it okay to do so based on the specified expression criteria?
Returns true if it should fire, false if it should not but could at a later attempt, and nil if the interval has expired.
2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2217 def fire? now = Time.now # Interval has expired. return nil if self.ending && now > self.ending # Interval is not yet in its current time window. return false if self.starting - now > 0 # Looking good. return true end |
#inspect ⇒ Object
Inspection string.
2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2240 def inspect return ( "<%s:0x%08x valid:%s recur:%s expression:%p " + "starting:%p interval:%p ending:%p>" ) % [ self.class.name, self.object_id * 2, self.valid, self.recurring, self.to_s, self.starting, self.interval, self.ending ] end |
#to_s ⇒ Object
Just return the original event expression.
2233 2234 2235 |
# File 'lib/symphony/metronome/intervalexpression.rb', line 2233 def to_s return @exp end |