eventual 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +3 -0
- data/VERSION +1 -1
- data/lib/eventual/es/event_parser.treetop +11 -3
- data/lib/eventual/es.rb +1 -0
- data/lib/eventual/syntax_nodes.rb +74 -63
- data/lib/eventual.rb +1 -1
- data/spec/es_eventual_spec.rb +55 -18
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -84,6 +84,7 @@ Ejemplos de formatos reconocidos:
|
|
84
84
|
* 21 de marzo
|
85
85
|
* 21 marzo
|
86
86
|
* domingo 21 de marzo
|
87
|
+
* domingo, 21 de marzo
|
87
88
|
* 1, 2 y 3 de marzo
|
88
89
|
* 1, 2 y 3 marzo
|
89
90
|
* lunes 1, martes 2 y miercoles 3 de marzo
|
@@ -101,6 +102,7 @@ Ejemplos de formatos reconocidos:
|
|
101
102
|
* los lunes y martes del 1 al 22 de marzo del '10
|
102
103
|
* los lunes y los martes del 1 al 22 de marzo del '10
|
103
104
|
* lunes y martes de diciembre a las 15
|
105
|
+
* lunes y martes, de diciembre a las 15
|
104
106
|
* lunes y martes de diciembre a las 15:30 hrs.
|
105
107
|
* lunes y martes de diciembre a las 15:00 y 16:00 horas
|
106
108
|
* lunes y martes de diciembre a las 3 am
|
@@ -111,6 +113,7 @@ Ejemplos de formatos reconocidos:
|
|
111
113
|
Formatos a reconocer
|
112
114
|
|
113
115
|
* todo el año
|
116
|
+
* lunes y martes de diciembre, 3:15 p.m.
|
114
117
|
|
115
118
|
== INSTALACIÓN:
|
116
119
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.4
|
@@ -33,7 +33,11 @@ grammar EsDates
|
|
33
33
|
|
34
34
|
##########
|
35
35
|
rule times
|
36
|
-
|
36
|
+
time_range / time_list
|
37
|
+
end
|
38
|
+
|
39
|
+
rule time_list
|
40
|
+
space 'a' space ('las' / 'la') (time_12 / time_24) ((space 'y' / ',') (time_12 / time_24))* <Eventual::TimeList>
|
37
41
|
end
|
38
42
|
|
39
43
|
rule time_24
|
@@ -41,7 +45,11 @@ grammar EsDates
|
|
41
45
|
end
|
42
46
|
|
43
47
|
rule time_12
|
44
|
-
space ('0' [0-9] / '1' [0-2] / [0-9]) (':' [0-5] [0-9])? space? period:(('a'/'p') '.'? space? 'm' '.'?
|
48
|
+
space ('0' [0-9] / '1' [0-2] / [0-9]) (':' [0-5] [0-9])? space? period:(('a'/'p') '.'? space? 'm' '.'? ) <Eventual::Time12>
|
49
|
+
end
|
50
|
+
|
51
|
+
rule time_range
|
52
|
+
space 'de' space ('las' / 'la') first:(time_12 / time_24) space 'a' space ('las' / 'la') last:(time_12 / time_24) <Eventual::TimeRange>
|
45
53
|
end
|
46
54
|
|
47
55
|
##########
|
@@ -58,7 +66,7 @@ grammar EsDates
|
|
58
66
|
end
|
59
67
|
|
60
68
|
rule weekday_constrain
|
61
|
-
wdays_node:weekday space <Eventual::WeekdayConstrain>
|
69
|
+
wdays_node:weekday ','? space <Eventual::WeekdayConstrain>
|
62
70
|
end
|
63
71
|
|
64
72
|
rule weekday_list
|
data/lib/eventual/es.rb
CHANGED
@@ -6,12 +6,12 @@ module Eventual
|
|
6
6
|
WdayListR = /\b(?:#{ WdaysR.join('|') })/.freeze
|
7
7
|
|
8
8
|
class WdayMatchError < StandardError #:nodoc:
|
9
|
-
def initialize value
|
10
|
-
@value
|
9
|
+
def initialize value
|
10
|
+
@value
|
11
11
|
end
|
12
12
|
|
13
13
|
def to_s
|
14
|
-
"El #{@value.day} de #{MonthNames[@value.month]} del #{@value.year} cae en #{Weekdays[@value.wday]}
|
14
|
+
"El #{@value.day} de #{MonthNames[@value.month]} del #{@value.year} cae en #{Weekdays[@value.wday]}"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -48,19 +48,13 @@ module Eventual
|
|
48
48
|
attr_accessor :times
|
49
49
|
|
50
50
|
# Returns last Date or DateTime of the encompassed period
|
51
|
-
def last
|
52
|
-
to_a.last
|
53
|
-
end
|
51
|
+
def last; to_a.last end
|
54
52
|
|
55
53
|
# Returns last Date or DateTime of the encompassed period
|
56
|
-
def first
|
57
|
-
to_a.first
|
58
|
-
end
|
54
|
+
def first; to_a.first end
|
59
55
|
|
60
56
|
# Returns an array with all the encompassed Dates or DateTimes
|
61
|
-
def to_a
|
62
|
-
map
|
63
|
-
end
|
57
|
+
def to_a; map end
|
64
58
|
|
65
59
|
# Returns true if the weekday (as number) correspons to any allowed weekday
|
66
60
|
def date_within_weekdays? date
|
@@ -78,15 +72,9 @@ module Eventual
|
|
78
72
|
result = false
|
79
73
|
walk { |elements| break result = true if elements.include? date }
|
80
74
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
check_against = ::Time.local date.year, date.month, date.day, time.hour, time.minute
|
85
|
-
time = ::Time.local date.year, date.month, date.day, date.hour, date.min
|
86
|
-
break true if time >= check_against && time < check_against + 60 * @time_span
|
87
|
-
}
|
88
|
-
end
|
89
|
-
result
|
75
|
+
return result if !result or date.class == Date or times.nil?
|
76
|
+
|
77
|
+
times.include? date
|
90
78
|
end
|
91
79
|
|
92
80
|
private
|
@@ -96,7 +84,7 @@ module Eventual
|
|
96
84
|
|
97
85
|
walk = lambda do |elements|
|
98
86
|
break unless elements
|
99
|
-
weekdays = elements.
|
87
|
+
weekdays = elements.shift.value if WeekdayConstrain === elements.first
|
100
88
|
|
101
89
|
elements.reverse.map do |element|
|
102
90
|
case element
|
@@ -105,7 +93,6 @@ module Eventual
|
|
105
93
|
element.year = year
|
106
94
|
element.month = month
|
107
95
|
element.times = @times
|
108
|
-
|
109
96
|
yield element
|
110
97
|
when Year
|
111
98
|
year = element.value
|
@@ -113,29 +100,37 @@ module Eventual
|
|
113
100
|
when MonthName
|
114
101
|
month = element.value
|
115
102
|
next nil
|
116
|
-
when
|
117
|
-
|
118
|
-
when Times
|
119
|
-
@times = element.map
|
103
|
+
when TimeList, TimeRange
|
104
|
+
@times = element
|
120
105
|
next nil
|
121
|
-
else
|
106
|
+
else
|
122
107
|
walk.call element.elements
|
123
108
|
end
|
124
109
|
end.reverse
|
125
110
|
end
|
126
111
|
walk.call(elements).flatten.compact
|
127
112
|
end
|
113
|
+
|
114
|
+
def make year, month, day
|
115
|
+
return Date.civil(year, month, day) unless times
|
116
|
+
times.make year, month, day
|
117
|
+
end
|
128
118
|
end
|
129
119
|
|
130
120
|
class Day < Node #:nodoc:
|
121
|
+
def value
|
122
|
+
Date.civil year, month, text_value.to_i
|
123
|
+
end
|
124
|
+
|
131
125
|
def map &block
|
132
|
-
dates =
|
133
|
-
|
134
|
-
dates.
|
126
|
+
dates = make(year, month, text_value.to_i)
|
127
|
+
dates = [dates] unless Array === dates
|
128
|
+
raise WdayMatchError.new(dates.first) unless date_within_weekdays? dates.first
|
129
|
+
dates.map &block
|
135
130
|
end
|
136
131
|
|
137
132
|
def include? date
|
138
|
-
map{ |e| e.strftime("%Y-%m-%d") }.include? date.strftime("%Y-%m-%d")
|
133
|
+
map { |element| [*element].map{ |e| e.strftime("%Y-%m-%d") } }.flatten.include? date.strftime("%Y-%m-%d")
|
139
134
|
end
|
140
135
|
end
|
141
136
|
|
@@ -152,33 +147,22 @@ module Eventual
|
|
152
147
|
alias node_map map
|
153
148
|
private :node_map
|
154
149
|
|
155
|
-
def map
|
156
|
-
|
157
|
-
range.each do |date|
|
150
|
+
def map &block
|
151
|
+
range.map do |date|
|
158
152
|
next unless date_within_weekdays? date
|
159
|
-
|
160
|
-
|
161
|
-
times.each do |time|
|
162
|
-
new_date = DateTime.civil date.year, date.month, date.day, time.hour, time.minute
|
163
|
-
array.push block_given? ? yield(new_date) : new_date
|
164
|
-
end
|
153
|
+
dates = times ? make(date.year, date.month, date.day) : [date]
|
154
|
+
dates.map &block
|
165
155
|
end
|
166
|
-
array
|
167
156
|
end
|
168
157
|
end
|
169
158
|
|
170
159
|
class MonthPeriod < Period #:nodoc:
|
171
160
|
def first
|
172
|
-
|
173
|
-
time = times.first
|
174
|
-
return DateTime.civil(year, month_name.value, 1, time.hour, time.minute)
|
161
|
+
Date.civil year, month_name.value
|
175
162
|
end
|
176
|
-
|
163
|
+
|
177
164
|
def last
|
178
|
-
|
179
|
-
return date unless times and !times.empty?
|
180
|
-
time = times.last
|
181
|
-
DateTime.civil(date.year, date.month, date.day, time.hour, time.minute)
|
165
|
+
Date.civil year, month_name.value, -1
|
182
166
|
end
|
183
167
|
end
|
184
168
|
|
@@ -192,32 +176,59 @@ module Eventual
|
|
192
176
|
end
|
193
177
|
end
|
194
178
|
|
195
|
-
class
|
179
|
+
class TimeList < Treetop::Runtime::SyntaxNode #:nodoc:
|
196
180
|
def map
|
197
181
|
walk_times = lambda do |elements|
|
198
182
|
break unless elements
|
199
|
-
elements.map
|
183
|
+
elements.map do |element|
|
184
|
+
next walk_times.call(element.elements) unless Time === element
|
185
|
+
block_given? ? yield(element) : element
|
186
|
+
end
|
200
187
|
end
|
201
|
-
walk_times.call(elements).flatten.compact
|
188
|
+
walk_times.call(elements).flatten.compact
|
189
|
+
end
|
190
|
+
|
191
|
+
def make year, month, day
|
192
|
+
map { |time| DateTime.civil year, month, day, time.hour, time.minute }.sort
|
193
|
+
end
|
194
|
+
|
195
|
+
def include? date
|
196
|
+
map { |time| time.to_i }.include? date.strftime("%H%M").to_i
|
202
197
|
end
|
203
198
|
end
|
204
|
-
|
199
|
+
|
205
200
|
class Time < Treetop::Runtime::SyntaxNode #:nodoc:
|
206
|
-
attr_accessor :hour, :minute
|
207
201
|
def value
|
208
|
-
@
|
209
|
-
@minute ||= 0
|
210
|
-
self
|
202
|
+
@value ||= text_value.scan(/\d+/).map(&:to_i)
|
211
203
|
end
|
212
204
|
|
213
|
-
|
205
|
+
def hour; value.first end
|
206
|
+
def minute; value[1] || 0 end
|
207
|
+
|
208
|
+
def to_i
|
209
|
+
("%02d%02d" % [hour, minute]).to_i
|
210
|
+
end
|
214
211
|
end
|
215
212
|
|
216
213
|
class Time12 < Time #:nodoc:
|
217
|
-
def
|
218
|
-
|
219
|
-
|
220
|
-
|
214
|
+
def pm?
|
215
|
+
@pm ||= true if period.text_value.include? 'pm'
|
216
|
+
end
|
217
|
+
|
218
|
+
def hour
|
219
|
+
pm? ? super + 12 : super
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
class TimeRange < Treetop::Runtime::SyntaxNode #:nodoc:
|
224
|
+
def make year, month, day
|
225
|
+
first_time = DateTime.civil year, month, day, first.hour, first.minute
|
226
|
+
last_time = DateTime.civil year, month, day, last.hour, last.minute
|
227
|
+
(first_time..last_time)
|
228
|
+
end
|
229
|
+
|
230
|
+
def include? date
|
231
|
+
(first.to_i..last.to_i).include? date.strftime("%H%M").to_i
|
221
232
|
end
|
222
233
|
end
|
223
234
|
end
|
data/lib/eventual.rb
CHANGED
@@ -13,7 +13,7 @@ module Eventual
|
|
13
13
|
#
|
14
14
|
# Options:
|
15
15
|
# +:lang+:
|
16
|
-
# Defaults to 'Es', the language to be used for parsing, currently only spanish is supported,
|
16
|
+
# Defaults to 'Es', the language to be used for parsing, currently only spanish is supported, please contribute.
|
17
17
|
# +:default_year+:
|
18
18
|
# The default year to be used in case year is not specified in the text, defaults to current year
|
19
19
|
# +:default_event_span+:
|
data/spec/es_eventual_spec.rb
CHANGED
@@ -9,7 +9,7 @@ describe Eventual, 'Es' do
|
|
9
9
|
describe 'proxy' do
|
10
10
|
it "should raise NotImplementedError if using not implemented language" do
|
11
11
|
lambda { Eventual.parse 'marzo', :lang => 'WP' }.should raise_error(NotImplementedError)
|
12
|
-
end
|
12
|
+
end
|
13
13
|
end
|
14
14
|
|
15
15
|
shared_examples_for 'correctly parses' do
|
@@ -137,6 +137,17 @@ describe Eventual, 'Es' do
|
|
137
137
|
lambda { Eventual.parse("lunes 21 de marzo").map }.should raise_error(Eventual::WdayMatchError)
|
138
138
|
end
|
139
139
|
end
|
140
|
+
|
141
|
+
describe 'date with wday and comma' do
|
142
|
+
describe "parsing 'domingo, 21 de marzo'" do
|
143
|
+
before { @result = Eventual.parse("domingo, 21 de marzo") }
|
144
|
+
it_should_behave_like 'correctly parses'
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should raise WdayMatchError if weekday doesn't correspond to date" do
|
148
|
+
lambda { Eventual.parse("lunes 21 de marzo").map }.should raise_error(Eventual::WdayMatchError)
|
149
|
+
end
|
150
|
+
end
|
140
151
|
end
|
141
152
|
|
142
153
|
describe 'day list' do
|
@@ -236,6 +247,14 @@ describe Eventual, 'Es' do
|
|
236
247
|
end
|
237
248
|
it_should_behave_like 'correctly parses'
|
238
249
|
end
|
250
|
+
|
251
|
+
describe "lunes y martes, del 1 de octubre al 2 de diciembre del 2008" do
|
252
|
+
before do
|
253
|
+
@result = Eventual.parse "lunes y martes, del 1 de octubre al 2 de diciembre del 2008"
|
254
|
+
@dates = (Date.parse('2008-10-1')..DateTime.parse('2008-12-2')).reject{ |day| not [1,2].include?(day.wday) }
|
255
|
+
end
|
256
|
+
it_should_behave_like 'correctly parses'
|
257
|
+
end
|
239
258
|
|
240
259
|
describe 'with weekday constrain' do
|
241
260
|
describe "wdays for 'lunes y martes del 1 al 22 de marzo del '10" do
|
@@ -337,6 +356,7 @@ describe Eventual, 'Es' do
|
|
337
356
|
@result = Eventual.parse('1 de enero del 2010 a las 15:00')
|
338
357
|
@dates = [DateTime.civil 2010, 1, 1, 15]
|
339
358
|
end
|
359
|
+
|
340
360
|
it_should_behave_like 'correctly parses'
|
341
361
|
it_should_behave_like 'outputs DateTime'
|
342
362
|
end
|
@@ -390,6 +410,24 @@ describe Eventual, 'Es' do
|
|
390
410
|
end
|
391
411
|
end
|
392
412
|
|
413
|
+
describe 'three times for month range' do
|
414
|
+
before do
|
415
|
+
@result = Eventual.parse('lunes y martes de diciembre a las 16:00, 17:00 y 15:00 horas')
|
416
|
+
@dates = (
|
417
|
+
(DateTime.parse('2010-12-1T15:00')..DateTime.parse('2010-12-31T15:00')).map +
|
418
|
+
(DateTime.parse('2010-12-1T16:00')..DateTime.parse('2010-12-31T16:00')).map +
|
419
|
+
(DateTime.parse('2010-12-1T17:00')..DateTime.parse('2010-12-31T17:00')).map
|
420
|
+
).reject{ |day| not [1,2].include?(day.wday) }
|
421
|
+
end
|
422
|
+
|
423
|
+
it_should_behave_like 'correctly parses'
|
424
|
+
it_should_behave_like 'outputs DateTime'
|
425
|
+
|
426
|
+
it "should not include other time" do
|
427
|
+
@result.should_not include(DateTime.parse('2010-12-06T14:00'))
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
393
431
|
describe 'range with time as 12 hours am' do
|
394
432
|
before do
|
395
433
|
@result = Eventual.parse('lunes y martes de diciembre a las 3 am')
|
@@ -423,14 +461,6 @@ describe Eventual, 'Es' do
|
|
423
461
|
end
|
424
462
|
it_should_behave_like 'correctly parses'
|
425
463
|
it_should_behave_like 'outputs DateTime'
|
426
|
-
|
427
|
-
it "should include time encompassed in 60 minutes from start" do
|
428
|
-
@result.should include(DateTime.civil(2010, 12, 1, 15, 30))
|
429
|
-
end
|
430
|
-
|
431
|
-
it "should not include time past 60 minutes from start" do
|
432
|
-
@result.should_not include(DateTime.civil(2010, 12, 1, 16, 00))
|
433
|
-
end
|
434
464
|
end
|
435
465
|
|
436
466
|
describe 'event defined timespan' do
|
@@ -440,21 +470,28 @@ describe Eventual, 'Es' do
|
|
440
470
|
end
|
441
471
|
it_should_behave_like 'correctly parses'
|
442
472
|
it_should_behave_like 'outputs DateTime'
|
443
|
-
|
444
|
-
|
445
|
-
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
describe "with time range" do
|
477
|
+
describe 'single day with time range' do
|
478
|
+
before do
|
479
|
+
@result = Eventual.parse('1 de enero del 2010 de las 15:00 a las 16:00')
|
480
|
+
@ranges = [(DateTime.civil 2010, 1, 1, 15)..(DateTime.civil 2010, 1, 1, 16)]
|
446
481
|
end
|
447
482
|
|
448
|
-
it
|
449
|
-
|
450
|
-
|
483
|
+
it { @result.should_not be_nil }
|
484
|
+
it { @result.to_a.size.should == @ranges.map.size }
|
485
|
+
it { @result.should map_dates *@ranges }
|
486
|
+
it { @ranges.each{ |range| range.each{ |date| @result.should include(date) } } }
|
487
|
+
# it { @result.should_not include(@dates.first - 1) }
|
488
|
+
# it { @result.should_not include(@dates.last + 1) }
|
489
|
+
# it { @dates.select{ |d| @result.include? d }.map{ |d| d.to_s }.should == @dates.map{ |r| r.to_s } }
|
451
490
|
|
452
|
-
it "should not include time past 60 minutes from start" do
|
453
|
-
@result.should_not include(DateTime.civil(2010, 12, 1, 17, 00))
|
454
|
-
end
|
455
491
|
end
|
456
492
|
end
|
457
493
|
|
494
|
+
|
458
495
|
describe 'Marshal dump' do
|
459
496
|
describe "month without year parsing 'marzo'" do
|
460
497
|
before do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 5
|
8
|
-
-
|
9
|
-
version: 0.5.
|
8
|
+
- 4
|
9
|
+
version: 0.5.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Macario Ortega
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-09-20 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|