active-icalendar-events 0.1.4 → 0.2.0

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.
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