active-icalendar-events 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee9cc0c47ee4498afaf37e853db464fca142261bbf29aaa17439f66508c2610c
4
- data.tar.gz: a3e5972072dbb410c1949cc2d53a7e7db741e55d9619ed628cc97c2ed2a3d1bf
3
+ metadata.gz: 2c58972dd8113dffe13dc9434ac99480bf4bbffcc6013e8bbc082a38e0487729
4
+ data.tar.gz: 29e515e96bad5067907bcf7b43bf375ce2a01df43de0d743f7bb31c52566f483
5
5
  SHA512:
6
- metadata.gz: 4f9dbc20940280b719b5d4770e2e2de94544d5671a4b9aa1b6eceb41a126077d44e8d101eabd599f9885de7112d658000b199d8e305900d730b1f173565e94f8
7
- data.tar.gz: f269876565330984d37d22c592dbef52102d774c387399698af734136347bb90387bea64a6dd25e6b0f64745a946e48d1efb593576966d31e7ec281d3e17cf34
6
+ metadata.gz: dea7414593d274bdb9c3f20e27e3ae12c1eca6764e8ef0cee122c21562edc36ab67977d4809d3fe19abd0fb9c771aaf4a491db8ae0aaed2279598a7be0daeac1
7
+ data.tar.gz: c9c1321759cd3080f79572e3ddc595f8b066a8422215dc27479ef1c547e84d1e10ae05e24f0a0687cc8a81ceffa2d5f477d308ebd24a8a6ffb8cef08de6e9adf
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'active_support'
4
5
  require 'active_support/core_ext'
@@ -51,36 +52,36 @@ module ActiveIcalendarEvents
51
52
  active_events = Set.new
52
53
 
53
54
  format_icalendar_data(icalendar_data).each do |_, events|
54
- recurrence_definition = events.select { |e|
55
+ recurrence_definition = events.select do |e|
55
56
  !e[:recurrence_rule].empty? || !e[:recurrence_dates].empty?
56
- }
57
+ end
57
58
  if recurrence_definition.size > 1
58
- raise RuntimeError, 'Should only have one event that defines the recurrence in a group'
59
+ raise 'Should only have one event that defines the recurrence in a group'
59
60
  elsif recurrence_definition.size == 1
60
61
  r = recurrence_definition.first
61
62
  if r[:recurrence_rule].size > 1
62
- raise RuntimeError, 'Multiple recurrence rules not supported'
63
+ raise 'Multiple recurrence rules not supported'
63
64
  elsif r[:recurrence_rule].size == 1
64
65
  # TODO: Validate the overrides
65
66
  active_events << get_active_event_for_datetime(
66
- :datetime => datetime,
67
- :name => r[:name],
68
- :event_start => r[:event_start],
69
- :event_end => r[:event_end],
70
- :recurrence_rule => r[:recurrence_rule].first,
71
- :recurrence_dates => r[:recurrence_dates],
72
- :excluding_dates => r[:excluding_dates],
73
- :overrides => events.reject { |e| e == r }.group_by { |e| e[:recurrence_id] }
67
+ datetime: datetime,
68
+ name: r[:name],
69
+ event_start: r[:event_start],
70
+ event_end: r[:event_end],
71
+ recurrence_rule: r[:recurrence_rule].first,
72
+ recurrence_dates: r[:recurrence_dates],
73
+ excluding_dates: r[:excluding_dates],
74
+ overrides: events.reject { |e| e == r }.group_by { |e| e[:recurrence_id] }
74
75
  )
75
76
  else
76
77
  # TODO: Haven't bothered implementing this as Google Calendar doesn't seem to use these
77
- raise RuntimeError, 'Not yet implemented when only recurrence_dates are provided'
78
+ raise 'Not yet implemented when only recurrence_dates are provided'
78
79
  end
79
80
  else
80
81
  # Non reccurring events
81
- events.each { |e|
82
- active_events.add(e[:name]) if is_event_active?(datetime, e[:event_start].to_time, e[:event_end].to_time)
83
- }
82
+ events.each do |e|
83
+ active_events.add(e[:name]) if event_active?(datetime, e[:event_start], e[:event_end])
84
+ end
84
85
  end
85
86
  end
86
87
 
@@ -90,44 +91,52 @@ module ActiveIcalendarEvents
90
91
  active_events.to_a
91
92
  end
92
93
 
94
+ def timezone_for_event(event)
95
+ if event.parent.timezones.empty?
96
+ ActiveSupport::TimeZone.new(event.parent.custom_properties['x_wr_timezone'].first.to_s)
97
+ else
98
+ ActiveSupport::TimeZone.new(event.parent.timezones.first.tzid.to_s)
99
+ end
100
+ end
101
+
93
102
  def format_icalendar_data(icalendar_data)
94
- icalendar_data.first.events.map { |e|
103
+ icalendar_data.first.events.map do |e|
95
104
  event_start = e.dtstart
96
105
  if event_start.is_a?(Icalendar::Values::Date)
97
- timezone ||= ActiveSupport::TimeZone.new(e.parent.timezones.first.tzid.to_s)
106
+ timezone ||= timezone_for_event(e)
98
107
  event_start = timezone.local(event_start.year, event_start.month, event_start.day)
99
108
  end
100
109
 
101
110
  event_end = e.dtend
102
111
  if event_end.is_a?(Icalendar::Values::Date)
103
- timezone ||= ActiveSupport::TimeZone.new(e.parent.timezones.first.tzid.to_s)
112
+ timezone ||= timezone_for_event(e)
104
113
  event_end = timezone.local(event_end.year, event_end.month, event_end.day)
105
114
  end
106
115
 
107
- excluding_dates = e.exdate.map { |d|
116
+ excluding_dates = e.exdate.map do |d|
108
117
  if d.is_a?(Icalendar::Values::Date)
109
- timezone ||= ActiveSupport::TimeZone.new(e.parent.timezones.first.tzid.to_s)
118
+ timezone ||= timezone_for_event(e)
110
119
  timezone.local(d.year, d.month, d.day)
111
120
  else
112
121
  d
113
122
  end
114
- }
123
+ end
115
124
 
116
- recurrence_dates = e.rdate.map { |d|
125
+ recurrence_dates = e.rdate.map do |d|
117
126
  if d.is_a?(Icalendar::Values::Date)
118
- timezone ||= ActiveSupport::TimeZone.new(e.parent.timezones.first.tzid.to_s)
127
+ timezone ||= timezone_for_event(e)
119
128
  timezone.local(d.year, d.month, d.day)
120
129
  else
121
130
  d
122
131
  end
123
- }
132
+ end
124
133
 
125
- e.rrule.each { |rrule|
126
- if !rrule.until.nil?
127
- timezone ||= ActiveSupport::TimeZone.new(e.parent.timezones.first.tzid.to_s)
134
+ e.rrule.each do |rrule|
135
+ unless rrule.until.nil?
136
+ timezone ||= timezone_for_event(e)
128
137
  rrule.until = timezone.parse(rrule.until)
129
138
  end
130
- }
139
+ end
131
140
 
132
141
  {
133
142
  name: e.summary,
@@ -139,10 +148,10 @@ module ActiveIcalendarEvents
139
148
  recurrence_id: e.recurrence_id,
140
149
  uid: e.uid
141
150
  }
142
- }.group_by { |e| e[:uid] }
151
+ end.group_by { |e| e[:uid] }
143
152
  end
144
153
 
145
- def is_event_active?(datetime, event_start, event_end)
154
+ def event_active?(datetime, event_start, event_end)
146
155
  event_start <= datetime.to_time &&
147
156
  event_end > datetime.to_time
148
157
  end
@@ -155,14 +164,14 @@ module ActiveIcalendarEvents
155
164
  !count.nil? && considered_count > count
156
165
  end
157
166
 
158
- def is_daily_event_active_for_datetime?(datetime,
159
- event_start,
160
- event_end,
161
- until_datetime,
162
- count,
163
- interval,
164
- excluding_dates,
165
- overridden_dates)
167
+ def daily_event_active_for_datetime?(datetime,
168
+ event_start,
169
+ event_end,
170
+ until_datetime,
171
+ count,
172
+ interval,
173
+ excluding_dates,
174
+ overridden_dates)
166
175
  event_start_considered = event_start
167
176
  event_end_considered = event_end
168
177
  considered_count = 1
@@ -170,7 +179,7 @@ module ActiveIcalendarEvents
170
179
  !instance_count_exceeded?(considered_count, count) &&
171
180
  event_start_considered <= datetime
172
181
 
173
- if is_event_active?(datetime, event_start_considered, event_end_considered)
182
+ if event_active?(datetime, event_start_considered, event_end_considered)
174
183
  return !excluding_dates.include?(event_start_considered) &&
175
184
  !overridden_dates.include?(event_start_considered)
176
185
  end
@@ -178,34 +187,35 @@ module ActiveIcalendarEvents
178
187
  # We consider both active dates and excluded dates for the recurrence count
179
188
  considered_count += 1
180
189
 
181
- event_start_considered = event_start_considered + interval.days
182
- event_end_considered = event_end_considered + interval.days
190
+ event_start_considered += interval.days
191
+ event_end_considered += interval.days
183
192
  end
184
193
 
185
194
  false
186
195
  end
187
196
 
188
- def is_weekly_event_active_for_datetime?(datetime,
189
- event_start,
190
- event_end,
191
- until_datetime,
192
- count,
193
- interval,
194
- by_day,
195
- excluding_dates,
196
- overridden_dates)
197
+ def weekly_event_active_for_datetime?(datetime,
198
+ event_start,
199
+ event_end,
200
+ until_datetime,
201
+ count,
202
+ interval,
203
+ by_day,
204
+ excluding_dates,
205
+ overridden_dates)
197
206
  event_start_considered = event_start
198
207
  event_end_considered = event_end
199
208
  considered_count = 1
200
- while !instance_count_exceeded?(considered_count, count)
209
+ until instance_count_exceeded?(considered_count, count)
201
210
 
211
+ # NOTE: Google Calendar does not appear to produce weekly events that do not specify a "by_day" array, so this path is untested
202
212
  if by_day.empty?
203
213
  if until_datetime_passed?(event_start_considered, until_datetime) ||
204
214
  event_start_considered > datetime
205
215
  return false
206
216
  end
207
217
 
208
- if is_event_active?(datetime, event_start_considered, event_end_considered)
218
+ if event_active?(datetime, event_start_considered, event_end_considered)
209
219
  return !excluding_dates.include?(event_start_considered) &&
210
220
  !overridden_dates.include?(event_start_considered)
211
221
  end
@@ -214,11 +224,14 @@ module ActiveIcalendarEvents
214
224
  considered_count += 1
215
225
  else
216
226
  week_event_start_considered =
217
- event_start_considered.monday? ? event_start_considered :
218
- event_start_considered.prev_occurring(:monday)
227
+ if event_start_considered.monday?
228
+ event_start_considered
229
+ else
230
+ event_start_considered.prev_occurring(:monday)
231
+ end
219
232
  week_event_end_considered = week_event_start_considered + (event_end.to_time - event_start.to_time).seconds
220
233
 
221
- (1..7).each { |_|
234
+ (1..7).each do |_|
222
235
  if week_event_start_considered >= event_start
223
236
  if until_datetime_passed?(week_event_start_considered, until_datetime) ||
224
237
  instance_count_exceeded?(considered_count, count) ||
@@ -226,10 +239,10 @@ module ActiveIcalendarEvents
226
239
  return false
227
240
  end
228
241
 
229
- day_code = week_event_start_considered.strftime("%^a").chop
242
+ day_code = week_event_start_considered.strftime('%^a').chop
230
243
 
231
244
  if by_day.include?(day_code)
232
- if is_event_active?(datetime, week_event_start_considered, week_event_end_considered)
245
+ if event_active?(datetime, week_event_start_considered, week_event_end_considered)
233
246
  return !excluding_dates.include?(week_event_start_considered) &&
234
247
  !overridden_dates.include?(week_event_start_considered)
235
248
  end
@@ -239,13 +252,13 @@ module ActiveIcalendarEvents
239
252
  end
240
253
  end
241
254
 
242
- week_event_start_considered = week_event_start_considered + 1.days
243
- week_event_end_considered = week_event_end_considered + 1.days
244
- }
255
+ week_event_start_considered += 1.days
256
+ week_event_end_considered += 1.days
257
+ end
245
258
  end
246
259
 
247
- event_start_considered = event_start_considered + interval.weeks
248
- event_end_considered = event_end_considered + interval.weeks
260
+ event_start_considered += interval.weeks
261
+ event_end_considered += interval.weeks
249
262
  end
250
263
 
251
264
  false
@@ -257,10 +270,8 @@ module ActiveIcalendarEvents
257
270
  end
258
271
 
259
272
  def get_nth_day_in_month(datetime, day)
260
- matches = day.match /^([0-9]+)([A-Z]+)$/
261
- if matches.nil?
262
- raise RuntimeError, "Unexpected by_day format found"
263
- end
273
+ matches = day.match(/^([0-9]+)([A-Z]+)$/)
274
+ raise 'Unexpected by_day format found' if matches.nil?
264
275
 
265
276
  number, day_code = matches.captures
266
277
 
@@ -280,32 +291,30 @@ module ActiveIcalendarEvents
280
291
  when 'SU'
281
292
  :sunday
282
293
  else
283
- raise RuntimeError, "Unexpected day code used"
294
+ raise 'Unexpected day code used'
284
295
  end
285
296
 
286
297
  target_day = beginning_of_month(datetime)
287
298
 
288
- if target_day.strftime("%^a").chop != day_code
289
- target_day = target_day.next_occurring(day_label)
290
- end
299
+ target_day = target_day.next_occurring(day_label) if target_day.strftime('%^a').chop != day_code
291
300
 
292
- (2..number.to_i).each { |_|
301
+ (2..number.to_i).each do |_|
293
302
  target_day = target_day.next_occurring(day_label)
294
- }
303
+ end
295
304
 
296
305
  target_day
297
306
  end
298
307
 
299
- def is_monthly_event_active_for_datetime?(datetime,
300
- event_start,
301
- event_end,
302
- until_datetime,
303
- count,
304
- interval,
305
- by_day,
306
- by_month_day,
307
- excluding_dates,
308
- overridden_dates)
308
+ def monthly_event_active_for_datetime?(datetime,
309
+ event_start,
310
+ event_end,
311
+ until_datetime,
312
+ count,
313
+ interval,
314
+ by_day,
315
+ by_month_day,
316
+ excluding_dates,
317
+ overridden_dates)
309
318
  # TODO: We will ignore the contents of "by_month_day" for now and assume
310
319
  # always contains one number which is the same as the day of
311
320
  # "event_start". We additionally assume that "by_day" will only contain
@@ -318,7 +327,7 @@ module ActiveIcalendarEvents
318
327
  !instance_count_exceeded?(considered_count, count) &&
319
328
  event_start_considered <= datetime
320
329
 
321
- if is_event_active?(datetime, event_start_considered, event_end_considered)
330
+ if event_active?(datetime, event_start_considered, event_end_considered)
322
331
  return !excluding_dates.include?(event_start_considered) &&
323
332
  !overridden_dates.include?(event_start_considered)
324
333
  end
@@ -327,8 +336,8 @@ module ActiveIcalendarEvents
327
336
  considered_count += 1
328
337
 
329
338
  if by_day.nil? || by_day.empty?
330
- event_start_considered = event_start_considered + interval.month
331
- event_end_considered = event_end_considered + interval.month
339
+ event_start_considered += interval.month
340
+ event_end_considered += interval.month
332
341
  else
333
342
  event_start_considered =
334
343
  get_nth_day_in_month(beginning_of_month(event_start_considered) + interval.month,
@@ -340,14 +349,14 @@ module ActiveIcalendarEvents
340
349
  false
341
350
  end
342
351
 
343
- def is_yearly_event_active_for_datetime?(datetime,
344
- event_start,
345
- event_end,
346
- until_datetime,
347
- count,
348
- interval,
349
- excluding_dates,
350
- overridden_dates)
352
+ def yearly_event_active_for_datetime?(datetime,
353
+ event_start,
354
+ event_end,
355
+ until_datetime,
356
+ count,
357
+ interval,
358
+ excluding_dates,
359
+ overridden_dates)
351
360
  event_start_considered = event_start
352
361
  event_end_considered = event_end
353
362
  considered_count = 1
@@ -355,7 +364,7 @@ module ActiveIcalendarEvents
355
364
  !instance_count_exceeded?(considered_count, count) &&
356
365
  event_start_considered <= datetime
357
366
 
358
- if is_event_active?(datetime, event_start_considered, event_end_considered)
367
+ if event_active?(datetime, event_start_considered, event_end_considered)
359
368
  return !excluding_dates.include?(event_start_considered) &&
360
369
  !overridden_dates.include?(event_start_considered)
361
370
  end
@@ -363,8 +372,8 @@ module ActiveIcalendarEvents
363
372
  # We consider both active dates and excluded dates for the recurrence count
364
373
  considered_count += 1
365
374
 
366
- event_start_considered = event_start_considered + interval.years
367
- event_end_considered = event_end_considered + interval.years
375
+ event_start_considered += interval.years
376
+ event_end_considered += interval.years
368
377
  end
369
378
 
370
379
  false
@@ -379,22 +388,21 @@ module ActiveIcalendarEvents
379
388
  excluding_dates: [],
380
389
  overrides:)
381
390
  # Can return early if one of the overrides matches as they always take precendence
382
- overrides.values.flatten.each { |e|
383
- return e[:name] if e[:event_start] <= datetime.to_time &&
384
- e[:event_end] > datetime.to_time
385
- }
391
+ overrides.values.flatten.each do |e|
392
+ return e[:name] if event_active?(datetime, e[:event_start], e[:event_end])
393
+ end
386
394
 
387
395
  # Can return early if one of the recurrence dates matches and is not overridden
388
396
  # Note: I've just made an assumption about how this data could be presented.
389
397
  # Google Calendar does not seem to create rdates, only rrules.
390
- (recurrence_dates - overrides.keys).each { |recurrence_event_start|
391
- recurrence_event_end = recurrence_event_start + (event_end.to_time - event_start.to_time)
392
- return name if is_event_active?(datetime, recurrence_event_start, recurrence_event_end)
393
- }
398
+ (recurrence_dates - overrides.keys).each do |recurrence_event_start|
399
+ recurrence_event_end = recurrence_event_start + (event_end.to_time - event_start.to_time).seconds
400
+ return name if event_active?(datetime, recurrence_event_start, recurrence_event_end)
401
+ end
394
402
 
395
403
  case recurrence_rule.frequency
396
- when "DAILY"
397
- return name if is_daily_event_active_for_datetime?(
404
+ when 'DAILY'
405
+ return name if daily_event_active_for_datetime?(
398
406
  datetime,
399
407
  event_start,
400
408
  event_end,
@@ -404,8 +412,8 @@ module ActiveIcalendarEvents
404
412
  excluding_dates,
405
413
  overrides.keys
406
414
  )
407
- when "WEEKLY"
408
- return name if is_weekly_event_active_for_datetime?(
415
+ when 'WEEKLY'
416
+ return name if weekly_event_active_for_datetime?(
409
417
  datetime,
410
418
  event_start,
411
419
  event_end,
@@ -416,8 +424,8 @@ module ActiveIcalendarEvents
416
424
  excluding_dates,
417
425
  overrides.keys
418
426
  )
419
- when "MONTHLY"
420
- return name if is_monthly_event_active_for_datetime?(
427
+ when 'MONTHLY'
428
+ return name if monthly_event_active_for_datetime?(
421
429
  datetime,
422
430
  event_start,
423
431
  event_end,
@@ -429,8 +437,8 @@ module ActiveIcalendarEvents
429
437
  excluding_dates,
430
438
  overrides.keys
431
439
  )
432
- when "YEARLY"
433
- return name if is_yearly_event_active_for_datetime?(
440
+ when 'YEARLY'
441
+ return name if yearly_event_active_for_datetime?(
434
442
  datetime,
435
443
  event_start,
436
444
  event_end,
@@ -441,7 +449,7 @@ module ActiveIcalendarEvents
441
449
  overrides.keys
442
450
  )
443
451
  else
444
- throw RuntimeError, "Invalid event frequency"
452
+ throw RuntimeError, 'Invalid event frequency'
445
453
  end
446
454
 
447
455
  nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active-icalendar-events
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Starling
@@ -44,7 +44,7 @@ executables: []
44
44
  extensions: []
45
45
  extra_rdoc_files: []
46
46
  files:
47
- - lib/active-icalendar-events.rb
47
+ - lib/active_icalendar_events.rb
48
48
  homepage: https://github.com/foygl/active-icalendar-events
49
49
  licenses:
50
50
  - MIT