opening_hours_converter 0.0.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,8 @@
1
+ require 'opening_hours_converter/constants'
2
+
1
3
  module OpeningHoursConverter
2
4
  class OpeningHoursRule
5
+ include Constants
3
6
  attr_accessor :date, :time
4
7
 
5
8
  def initialize
@@ -8,14 +11,10 @@ module OpeningHoursConverter
8
11
  end
9
12
 
10
13
  def get
14
+ get_wide_selector if @date.length > 1
11
15
  result = ""
12
- if @date.length > 1 || @date[0]&.wide != ""
13
- @date.each_with_index do |d, i|
14
- if (i > 0)
15
- result += ","
16
- end
17
- result += d.wide
18
- end
16
+ if @date.length > 0
17
+ result += get_wide_selector
19
18
  end
20
19
 
21
20
  if @date.length > 0
@@ -36,13 +35,493 @@ module OpeningHoursConverter
36
35
  else
37
36
  result += " off"
38
37
  end
39
- if result.strip == "00:00-24:00"
40
- result = "24/7"
38
+
39
+ rgx_day = /(Mo|Tu|We|Th|Fr|Sa|Su)/
40
+
41
+ if result.strip == "00:00-24:00" || (!(result =~ /00:00-24:00/).nil? && (result =~ rgx_day).nil?)
42
+ result.gsub!("00:00-24:00", "24/7")
41
43
  end
42
44
 
45
+
46
+ result = clean(result)
43
47
  result.strip
44
48
  end
45
49
 
50
+ def get_wide_selector
51
+
52
+ years = build_day_array
53
+
54
+ year_start = -1
55
+ month_start = -1
56
+ day_start = -1
57
+
58
+ result = {}
59
+
60
+ if !years["always"].nil?
61
+
62
+ always = years.delete("always")
63
+
64
+ always.each_with_index do |month_array, month|
65
+ month_array.each_with_index do |day_bool, day|
66
+ if day_bool && month_start < 0
67
+ month_start = month
68
+ day_start = day
69
+ elsif day_bool && month_start >= 0 && month == 11 && day == 30
70
+ result["always"] ||= []
71
+ result["always"] << {start: { day: day_start, month: month_start }, end: { day: 30, month: 11 }}
72
+ month_start = -1
73
+ day_start = -1
74
+ elsif !day_bool && month_start >= 0
75
+ result["always"] ||= []
76
+ end_res = day == 0 ?
77
+ month == 0 ?
78
+ { day: 30, month: 11 } : { day: MONTH_END_DAY[month-1]-1, month: month-1 } :
79
+ { day: day-1, month: month }
80
+ result["always"] << { start: { day: day_start, month: month_start }, end: end_res }
81
+ month_start = -1
82
+ day_start = -1
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ # years {
89
+ # 2017: [
90
+ # {start: {}, end: {}}
91
+ # ],
92
+ # multi_year: [
93
+ # {start: {}, {}}
94
+ # ]
95
+ # }
96
+
97
+ years.each do |year, months|
98
+ months.each_with_index do |month_array, month|
99
+ month_array.each_with_index do |day_bool, day|
100
+ if day_bool && year_start < 0
101
+ year_start = year
102
+ month_start = month
103
+ day_start = day
104
+ elsif day_bool && year_start >= 0 && month == 11 && day == 30 && years[year+1].nil?
105
+ if year_start == year
106
+ result[year] ||= []
107
+ result[year] << { start: { day: day_start, month: month_start }, end: { day: 30, month: 11 } }
108
+ else
109
+ result["multi_year"] ||= {}
110
+ result["multi_year"]["#{year_start}-#{year}"] ||= []
111
+ result["multi_year"]["#{year_start}-#{year}"] << { start: { day: day_start, month: month_start, year: year_start },
112
+ end: { day: 30, month: 11, year: year } }
113
+ end
114
+ year_start = -1
115
+ month_start = -1
116
+ day_start = -1
117
+ elsif !day_bool && year_start >= 0
118
+ end_res = {}
119
+
120
+ if day == 0
121
+ if month == 0
122
+ end_res = { day: 30, month: 11 }
123
+ else
124
+ end_res = { day: MONTH_END_DAY[month-1]-1, month: month-1 }
125
+ end
126
+ else
127
+ end_res = { day: day-1, month: month }
128
+ end
129
+
130
+ if year_start == year
131
+ result[year] ||= []
132
+ result[year] << { start: { day: day_start, month: month_start }, end: end_res }
133
+ else
134
+ result["multi_year"] ||= {}
135
+ result["multi_year"]["#{year_start}-#{year}"] ||= []
136
+ end_res[:year] = year
137
+ result["multi_year"]["#{year_start}-#{year}"] << { start: { day: day_start, month: month_start, year: year_start },
138
+ end: end_res }
139
+ end
140
+ # end_res = day == 0 ?
141
+ # month == 0 ?
142
+ # { day: 30, month: 11, year: year } : { day: MONTH_END_DAY[month-1]-1, month: month-1, year: year } :
143
+ # { day: day-1, month: month, year: year }
144
+ # result << {start: {day: day_start, month: month_start, year: year_start}, end: end_res}
145
+ year_start = -1
146
+ month_start = -1
147
+ day_start = -1
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+
154
+ result_to_string(result)
155
+
156
+ end
157
+
158
+ def result_to_string(result)
159
+ str_result = ""
160
+ result.each do |selector, intervals|
161
+ if selector == "always"
162
+ intervals.each do |interval|
163
+ if str_result.length > 0
164
+ str_result += ","
165
+ end
166
+ if is_full_year?(interval)
167
+ elsif is_full_month?(interval)
168
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]}"
169
+ elsif starts_month?(interval) && ends_month?(interval)
170
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]}-#{OSM_MONTHS[interval[:end][:month]]}"
171
+ elsif is_same_month?(interval)
172
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day]+1 < 10 ? "0#{interval[:start][:day]+1}" : interval[:start][:day]+1}-#{interval[:end][:day]+1 < 10 ? "0#{interval[:end][:day]+1}" : interval[:end][:day]+1}"
173
+ else
174
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day]+1 < 10 ? "0#{interval[:start][:day]+1}" : interval[:start][:day]+1}-#{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day]+1 < 10 ? "0#{interval[:end][:day]+1}" : interval[:end][:day]+1}"
175
+ end
176
+ end
177
+ elsif selector == "multi_year"
178
+ intervals.each do |years, intervals|
179
+ intervals.each do |interval|
180
+ if str_result.length > 0
181
+ str_result += ","
182
+ end
183
+ if starts_year?(interval) && ends_year?(interval)
184
+ str_result += "#{interval[:start][:year]}-#{interval[:end][:year]}"
185
+ elsif starts_month?(interval) && ends_month?(interval)
186
+ str_result += "#{interval[:start][:year]} #{OSM_MONTHS[interval[:start][:month]]}-#{interval[:end][:year]} #{OSM_MONTHS[interval[:end][:month]]}"
187
+ else
188
+ str_result += "#{interval[:start][:year]} #{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day]+1 < 10 ? "0#{interval[:start][:day]+1}" : interval[:start][:day]+1}-#{interval[:end][:year]} #{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day]+1 < 10 ? "0#{interval[:end][:day]+1}" : interval[:end][:day]+1}"
189
+ end
190
+ end
191
+ end
192
+ else
193
+ str_result += "#{selector} "
194
+ intervals.each do |interval|
195
+ if is_full_year?(interval)
196
+ elsif is_full_month?(interval)
197
+ str_result += "#{str_result.length > 5 ? "," : ""}#{OSM_MONTHS[interval[:start][:month]]}"
198
+ elsif starts_month?(interval) && ends_month?(interval)
199
+ str_result += "#{str_result.length > 5 ? "," : ""}#{OSM_MONTHS[interval[:start][:month]]}-#{OSM_MONTHS[interval[:end][:month]]}"
200
+ elsif is_same_month?(interval)
201
+ str_result += "#{str_result.length > 5 ? "," : ""}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day]+1 < 10 ? "0#{interval[:start][:day]+1}" : interval[:start][:day]+1}-#{interval[:end][:day]+1 < 10 ? "0#{interval[:end][:day]+1}" : interval[:end][:day]+1}"
202
+ else
203
+ str_result += "#{str_result.length > 5 ? "," : ""}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day]+1 < 10 ? "0#{interval[:start][:day]+1}" : interval[:start][:day]+1}-#{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day]+1 < 10 ? "0#{interval[:end][:day]+1}" : interval[:end][:day]+1}"
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ str_result.strip
210
+ end
211
+
212
+ def is_full_year?(r)
213
+ starts_year?(r) && ends_year?(r)
214
+ end
215
+
216
+ def is_full_month?(r)
217
+ is_same_month?(r) && starts_month?(r) && ends_month?(r)
218
+ end
219
+
220
+ def is_same_year?(r)
221
+ r[:start][:year] == r[:end][:year]
222
+ end
223
+
224
+ def is_same_month?(r)
225
+ r[:start][:month] == r[:end][:month]
226
+ end
227
+
228
+ def starts_month?(r)
229
+ r[:start][:day] == 0
230
+ end
231
+
232
+ def ends_month?(r)
233
+ r[:end][:day] == MONTH_END_DAY[r[:end][:month]] - 1
234
+ end
235
+
236
+ def starts_year?(r)
237
+ r[:start][:month] == 0 && starts_month?(r)
238
+ end
239
+
240
+ def ends_year?(r)
241
+ r[:end][:month] == 11 && ends_month?(r)
242
+ end
243
+
244
+ def build_day_array
245
+ years = {}
246
+ @date.each do |date|
247
+ if !date.wide.start.nil? && !date.wide.start[:year].nil?
248
+ if date.wide.end.nil? || date.wide.end[:year].nil? || date.wide.start[:year] == date.wide.end[:year]
249
+ if !years[date.wide.start[:year]].nil?
250
+ years = process_single_year(date, years)
251
+ else
252
+ years[date.wide.start[:year]] = Array.new(OSM_MONTHS.length) { |i| Array.new(MONTH_END_DAY[i]) { false } }
253
+ years = process_single_year(date, years)
254
+ end
255
+ else
256
+ for year in date.wide.start[:year]..date.wide.end[:year]
257
+ years[year] ||= Array.new(OSM_MONTHS.length) { |i| Array.new(MONTH_END_DAY[i]) { false } }
258
+ end
259
+ process_multiple_years(date, years)
260
+ end
261
+ else
262
+ years["always"] ||= Array.new(OSM_MONTHS.length) { |i| Array.new(MONTH_END_DAY[i]) { false } }
263
+ years = process_always(date, years)
264
+ end
265
+ end
266
+ years
267
+ end
268
+
269
+ def process_always(date, years, get_iterator=false)
270
+ if !get_iterator
271
+ if date.wide.start.nil?
272
+ years["always"] = Array.new(OSM_MONTHS.length) { |i| Array.new(MONTH_END_DAY[i]) { true } }
273
+ elsif !date.wide.start[:day].nil?
274
+ if date.wide.end.nil? || (date.wide.end[:month].nil? && date.wide.end[:day].nil?) ||
275
+ (date.wide.start[:month] == date.wide.end[:month] && date.wide.start[:day] == date.wide.end[:day])
276
+ years["always"][date.wide.start[:month]-1][date.wide.start[:day]-1] = true
277
+ elsif date.wide.start[:month] == date.wide.end[:month]
278
+ for day in date.wide.start[:day]-1..date.wide.end[:day]-1
279
+ years["always"][date.wide.start[:month]-1][day] = true
280
+ end
281
+ elsif date.wide.start[:month] != date.wide.end[:month]
282
+ for month in date.wide.start[:month]-1..date.wide.end[:month]-1
283
+ if month == date.wide.start[:month]-1
284
+ for day in date.wide.start[:day]-1...MONTH_END_DAY[month]
285
+ years["always"][month][day] = true
286
+ end
287
+ elsif month == date.wide.end[:month]-1
288
+ for day in 0..date.wide.end[:day]-1
289
+ years["always"][month][day] = true
290
+ end
291
+ else
292
+ for day in 0...MONTH_END_DAY[month]
293
+ years["always"][month][day] = true
294
+ end
295
+ end
296
+ end
297
+ end
298
+ elsif !date.wide.start[:month].nil?
299
+ if date.wide.end.nil? || date.wide.end[:month].nil? || date.wide.start[:month] == date.wide.end[:month]
300
+ years["always"][date.wide.start[:month]-1].each_with_index do |month, i|
301
+ years["always"][date.wide.start[:month]-1][i] = true
302
+ end
303
+ else
304
+ for month in date.wide.start[:month]-1..date.wide.end[:month]-1
305
+ years["always"][month].each_with_index do |day, i|
306
+ years["always"][month][i] = true
307
+ end
308
+ end
309
+ end
310
+ end
311
+ else
312
+ for year in YEAR_MIN..YEAR_MAX
313
+ if years[year].nil?
314
+ years[year] = Array.new(OSM_MONTHS.length) { |i| Array.new(MONTH_END_DAY[i]) { false } }
315
+ end
316
+ if !date.wide.start[:day].nil?
317
+ if date.wide.end.nil? || (date.wide.end[:month].nil? && date.wide.end[:day].nil?) ||
318
+ (date.wide.start[:month] == date.wide.end[:month] && date.wide.start[:day] == date.wide.end[:day])
319
+ years[year][date.wide.start[:month]-1][date.wide.start[:day]-1] = true
320
+ elsif date.wide.start[:month] == date.wide.end[:month]
321
+ for day in date.wide.start[:day]-1..date.wide.end[:day]-1
322
+ years[year][date.wide.start[:month]-1][day] = true
323
+ end
324
+ elsif date.wide.start[:month] != date.wide.end[:month]
325
+ for month in date.wide.start[:month]-1..date.wide.end[:month]-1
326
+ if month == date.wide.start[:month]-1
327
+ for day in date.wide.start[:day]-1...MONTH_END_DAY[month]
328
+ years[year][month][day] = true
329
+ end
330
+ elsif month == date.wide.end[:month]-1
331
+ for day in 0..date.wide.end[:day]-1
332
+ years[year][month][day] = true
333
+ end
334
+ else
335
+ for day in 0...MONTH_END_DAY[month]
336
+ years[year][month][day] = true
337
+ end
338
+ end
339
+ end
340
+ end
341
+ elsif !date.wide.start[:month].nil?
342
+ if date.wide.end.nil? || date.wide.end[:month].nil? || date.wide.start[:month] == date.wide.end[:month]
343
+ years[year][date.wide.start[:month]-1].each_with_index do |month, i|
344
+ years[year][date.wide.start[:month]-1][i] = true
345
+ end
346
+ else
347
+ for month in date.wide.start[:month]-1..date.wide.end[:month]-1
348
+ years[year][month].each_with_index do |day, i|
349
+ years[year][month][i] = true
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end
355
+ end
356
+ return years
357
+ end
358
+
359
+ def process_multiple_years(date, years)
360
+ if date.wide.type == "year"
361
+ for year in date.wide.start[:year]..date.wide.end[:year]
362
+ years[year].each_with_index do |month,i|
363
+ month.each_with_index do |day,j|
364
+ years[year][i][j] = true
365
+ end
366
+ end
367
+ end
368
+ elsif date.wide.type == "month"
369
+ for year in date.wide.start[:year]..date.wide.end[:year]
370
+ if year == date.wide.start[:year]
371
+ for month in date.wide.start[:month]-1..11
372
+ years[year][month].each_with_index do |day, i|
373
+ years[year][month][i] = true
374
+ end
375
+ end
376
+ elsif year == date.wide.end[:year]
377
+ for month in 0..date.wide.end[:month]-1
378
+ years[year][month].each_with_index do |day, i|
379
+ years[year][month][i] = true
380
+ end
381
+ end
382
+ else
383
+ for month in 0..11
384
+ years[year][month].each_with_index do |day, i|
385
+ years[year][month][i] = true
386
+ end
387
+ end
388
+ end
389
+ end
390
+ elsif date.wide.type == "day"
391
+ for year in date.wide.start[:year]..date.wide.end[:year]
392
+ if year == date.wide.start[:year]
393
+ for month in date.wide.start[:month]-1..11
394
+ if month == date.wide.start[:month]-1
395
+ for day in date.wide.start[:day]-1...MONTH_END_DAY[month]
396
+ years[year][month][day] = true
397
+ end
398
+ else
399
+ for day in 0...MONTH_END_DAY[month]
400
+ years[year][month][day] = true
401
+ end
402
+ end
403
+ end
404
+ elsif year == date.wide.end[:year]
405
+ for month in 0..date.wide.end[:month]-1
406
+ if month == date.wide.end[:month]-1
407
+ for day in 0..date.wide.end[:day]-1
408
+ years[year][month][day] = true
409
+ end
410
+ else
411
+ for day in 0...MONTH_END_DAY[month]
412
+ years[year][month][day] = true
413
+ end
414
+ end
415
+ end
416
+ else
417
+ for month in 0..11
418
+ for day in 0...MONTH_END_DAY[month]
419
+ years[year][month][day] = true
420
+ end
421
+ end
422
+ end
423
+ end
424
+ end
425
+ return years
426
+ end
427
+
428
+ def process_single_year(date, years, always=false)
429
+ if date.wide.type == "year"
430
+ years[date.wide.start[:year]].each_with_index do |month,i|
431
+ month.each_with_index do |day,j|
432
+ years[date.wide.start[:year]][i][j] = true
433
+ end
434
+ end
435
+ elsif date.wide.type == "month"
436
+ if date.wide.end.nil? || date.wide.end[:month].nil? || date.wide.start[:month] == date.wide.end[:month]
437
+ years[date.wide.start[:year]][date.wide.start[:month]-1].each_with_index do |month, i|
438
+ years[date.wide.start[:year]][date.wide.start[:month]-1][i] = true
439
+ end
440
+ else
441
+ for month in date.wide.start[:month]-1..date.wide.end[:month]-1
442
+ years[date.wide.start[:year]][month].each_with_index do |day, i|
443
+ years[date.wide.start[:year]][month][i] = true
444
+ end
445
+ end
446
+ end
447
+ elsif date.wide.type == "day"
448
+ if date.wide.start[:month] == date.wide.end[:month] || date.wide.end[:month].nil?
449
+ if date.wide.start[:day] == date.wide.end[:day]
450
+ years[date.wide.start[:year]][date.wide.start[:month]-1][date.wide.start[:day]-1] = true
451
+ else
452
+ for day in date.wide.start[:day]-1..date.wide.end[:day]-1
453
+ years[date.wide.start[:year]][date.wide.start[:month]-1][day] = true
454
+ end
455
+ end
456
+ else
457
+ for month in date.wide.start[:month]-1..date.wide.end[:month]-1
458
+ if month == date.wide.start[:month]-1
459
+ for day in date.wide.start[:day]-1...MONTH_END_DAY[month]
460
+ years[date.wide.start[:year]][month][day] = true
461
+ end
462
+ elsif month == date.wide.end[:month]-1
463
+ for day in 0..date.wide.end[:day]-1
464
+ years[date.wide.start[:year]][month][day] = true
465
+ end
466
+ else
467
+ for day in 0...MONTH_END_DAY[month]
468
+ years[date.wide.start[:year]][month][day] = true
469
+ end
470
+ end
471
+ end
472
+ end
473
+ end
474
+ return years
475
+ end
476
+
477
+ def clean(result)
478
+ result = remove_duplicate_year(result)
479
+ result = remove_bad_spaces(result)
480
+ end
481
+
482
+ def remove_bad_spaces(result)
483
+ return result if (result =~ /\,\s/).nil?
484
+ return result.split(', ').join(',')
485
+ end
486
+
487
+ def remove_duplicate_year(result)
488
+ return result if (result =~ /(\d{4})[^;]+(\1)/).nil? && (result =~ /(\d{4}\-\d{4})[^;]+(\1)/).nil?
489
+ result_parts = result.split(';')
490
+ sanitized_parts = []
491
+ result_parts.each do |rp|
492
+
493
+ # string with year range repeating separated by a comma
494
+ if !(rp =~ /(\d{4}\-\d{4})\,(\1)/).nil?
495
+ first_occurence = (rp =~ /(\d{4}\-\d{4})/)
496
+ years = result[first_occurence...first_occurence + 9]
497
+
498
+ sanitized_parts << years + rp[first_occurence + 10, rp.length].split(year).join('')
499
+
500
+ # string with year repeating separrated by a comma
501
+ elsif !(rp =~ /(\d{4})\,(\1)/).nil?
502
+ first_occurence = (rp =~ /(\d{4})/)
503
+ year = result[first_occurence...first_occurence + 4]
504
+
505
+ sanitized_parts << year + rp[first_occurence + 5, rp.length].split(year).join('')
506
+
507
+ # string with year range repeating
508
+ elsif !(rp =~ /(\d{4}\-\d{4})[^;]+(\1)/).nil?
509
+ first_occurence = (rp =~ /(\d{4}\-\d{4})/)
510
+ years = result[first_occurence...first_occurence + 9]
511
+
512
+ sanitized_parts << years + rp[first_occurence + 9, rp.length].split(year).join('')
513
+
514
+ # string with year repeating
515
+ elsif !(rp =~ /(\d{4})[^;]+(\1)/).nil?
516
+ first_occurence = (rp =~ /(\d{4})/)
517
+ year = result[first_occurence...first_occurence + 4]
518
+
519
+ sanitized_parts << year + rp[first_occurence + 4, rp.length].split(year).join('')
520
+ end
521
+ end
522
+ sanitized_parts.join('')
523
+ end
524
+
46
525
  def same_time?(o)
47
526
  if o.nil? || o.time.length != @time.length
48
527
  return false
@@ -54,6 +533,22 @@ module OpeningHoursConverter
54
533
  end
55
534
  end
56
535
 
536
+ def same_date?(o)
537
+ if o.nil? || o.date.length != @date.length
538
+ return false
539
+ else
540
+ @date.each_with_index do |d, i|
541
+ return false if !d.wide.equals(o.date[i].wide)
542
+ end
543
+ return true
544
+ end
545
+ end
546
+
547
+ def equals(o)
548
+ return false unless o.instance_of?(OpeningHoursConverter::OpeningHoursRule)
549
+ (same_time?(o) && same_date?(o))
550
+ end
551
+
57
552
  def is_off?
58
553
  @time.length == 0 || (@time.length == 1 && time[0].start.nil?)
59
554
  end
@@ -79,7 +574,7 @@ module OpeningHoursConverter
79
574
  raise ArgumentError
80
575
  end
81
576
 
82
- if @date.length == 0 || @date.first.wide_type != "always" && @date.first.same_kind_as?(date)
577
+ if @date.length == 0 || date.same_weekdays?(@date.first.weekdays)
83
578
  @date << date
84
579
  else
85
580
  if @date.length != 1 || @date.first.wide_type != "always" || !@date.first.same_weekdays?(date.weekdays)