holidays 7.1.0 → 8.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/README.md +3 -4
  4. data/doc/CONTRIBUTING.md +2 -1
  5. data/holidays.gemspec +5 -5
  6. data/lib/generated_definitions/MANIFEST +3 -0
  7. data/lib/generated_definitions/REGIONS.rb +2 -2
  8. data/lib/generated_definitions/au.rb +8 -2
  9. data/lib/generated_definitions/ca.rb +14 -13
  10. data/lib/generated_definitions/ch.rb +13 -1
  11. data/lib/generated_definitions/cl.rb +5 -5
  12. data/lib/generated_definitions/de.rb +5 -4
  13. data/lib/generated_definitions/es.rb +4 -2
  14. data/lib/generated_definitions/europe.rb +83 -23
  15. data/lib/generated_definitions/gb.rb +6 -4
  16. data/lib/generated_definitions/hr.rb +8 -6
  17. data/lib/generated_definitions/hu.rb +3 -2
  18. data/lib/generated_definitions/it.rb +14 -5
  19. data/lib/generated_definitions/jp.rb +26 -21
  20. data/lib/generated_definitions/kz.rb +38 -0
  21. data/lib/generated_definitions/lu.rb +2 -0
  22. data/lib/generated_definitions/lv.rb +52 -0
  23. data/lib/generated_definitions/mx.rb +3 -3
  24. data/lib/generated_definitions/ng.rb +33 -0
  25. data/lib/generated_definitions/northamerica.rb +21 -21
  26. data/lib/generated_definitions/ro.rb +5 -2
  27. data/lib/generated_definitions/southamerica.rb +5 -5
  28. data/lib/generated_definitions/tr.rb +5 -3
  29. data/lib/generated_definitions/ua.rb +6 -6
  30. data/lib/generated_definitions/us.rb +5 -6
  31. data/lib/holidays.rb +2 -0
  32. data/lib/holidays/definition/context/generator.rb +20 -34
  33. data/lib/holidays/definition/repository/holidays_by_month.rb +9 -1
  34. data/lib/holidays/finder/context/search.rb +34 -31
  35. data/lib/holidays/finder/rules/year_range.rb +30 -54
  36. data/lib/holidays/version.rb +1 -1
  37. data/test/coverage_report.rb +23 -5
  38. data/test/data/test_custom_year_range_holiday_defs.yaml +6 -10
  39. data/test/data/test_multiple_regions_with_conflicts_region_1.yaml +38 -0
  40. data/test/data/test_multiple_regions_with_conflicts_region_2.yaml +38 -0
  41. data/test/defs/test_defs_ca.rb +27 -5
  42. data/test/defs/test_defs_ch.rb +4 -0
  43. data/test/defs/test_defs_co.rb +3 -3
  44. data/test/defs/test_defs_de.rb +2 -0
  45. data/test/defs/test_defs_es.rb +2 -0
  46. data/test/defs/test_defs_europe.rb +156 -11
  47. data/test/defs/test_defs_federalreservebanks.rb +20 -0
  48. data/test/defs/test_defs_gb.rb +16 -0
  49. data/test/defs/test_defs_hr.rb +6 -6
  50. data/test/defs/test_defs_hu.rb +12 -4
  51. data/test/defs/test_defs_it.rb +20 -0
  52. data/test/defs/test_defs_jp.rb +5 -3
  53. data/test/defs/test_defs_kz.rb +39 -0
  54. data/test/defs/test_defs_lu.rb +6 -0
  55. data/test/defs/test_defs_lv.rb +90 -0
  56. data/test/defs/test_defs_ng.rb +29 -0
  57. data/test/defs/test_defs_northamerica.rb +33 -15
  58. data/test/defs/test_defs_ro.rb +14 -0
  59. data/test/defs/test_defs_southamerica.rb +3 -3
  60. data/test/defs/test_defs_tr.rb +7 -0
  61. data/test/defs/test_defs_us.rb +6 -10
  62. data/test/holidays/core_extensions/test_date.rb +3 -2
  63. data/test/holidays/definition/context/test_generator.rb +5 -18
  64. data/test/holidays/definition/repository/test_holidays_by_month.rb +121 -1
  65. data/test/holidays/finder/rules/test_year_range.rb +43 -47
  66. data/test/integration/test_available_regions.rb +1 -1
  67. data/test/integration/test_custom_year_range_holidays.rb +0 -7
  68. data/test/integration/test_holidays.rb +1 -23
  69. data/test/integration/test_holidays_between.rb +10 -0
  70. data/test/integration/test_multiple_regions_with_conflict.rb +29 -0
  71. metadata +28 -14
@@ -12,13 +12,16 @@ module Holidays
12
12
 
13
13
  def self.holidays_by_month
14
14
  {
15
- 0 => [{:function => "orthodox_easter(year)", :function_arguments => [:year], :name => "Paștele - duminică", :regions => [:ro]},
15
+ 0 => [{:function => "orthodox_easter(year)", :function_arguments => [:year], :function_modifier => -2, :year_ranges => { :from => 2018 },:name => "Paștele - Vinerea Mare", :regions => [:ro]},
16
+ {:function => "orthodox_easter(year)", :function_arguments => [:year], :name => "Paștele - duminică", :regions => [:ro]},
16
17
  {:function => "orthodox_easter(year)", :function_arguments => [:year], :function_modifier => 1, :name => "Paștele - luni", :regions => [:ro]},
17
18
  {:function => "orthodox_easter(year)", :function_arguments => [:year], :function_modifier => 49, :name => "Rusaliile - 50", :regions => [:ro]},
18
19
  {:function => "orthodox_easter(year)", :function_arguments => [:year], :function_modifier => 50, :name => "Rusaliile - 51", :regions => [:ro]}],
19
20
  1 => [{:mday => 1, :name => "Anul nou", :regions => [:ro]},
20
- {:mday => 2, :name => "Anul nou", :regions => [:ro]}],
21
+ {:mday => 2, :name => "Anul nou", :regions => [:ro]},
22
+ {:mday => 24, :year_ranges => { :from => 2017 },:name => "Unirea Principatelor Române", :regions => [:ro]}],
21
23
  5 => [{:mday => 1, :name => "Ziua muncii", :regions => [:ro]}],
24
+ 6 => [{:mday => 1, :year_ranges => { :from => 2017 },:name => "Ziua Copilului", :regions => [:ro]}],
22
25
  8 => [{:mday => 15, :name => "Adormirea Maicii Domnului", :regions => [:ro]}],
23
26
  11 => [{:mday => 30, :name => "Sfântul Apostol Andrei", :regions => [:ro]}],
24
27
  12 => [{:mday => 1, :name => "Ziua Națională", :regions => [:ro]},
@@ -21,8 +21,8 @@ module Holidays
21
21
  {:function => "easter(year)", :function_arguments => [:year], :function_modifier => 60, :name => "Corpus Christi", :regions => [:br]},
22
22
  {:function => "easter(year)", :function_arguments => [:year], :function_modifier => -2, :name => "Viernes Santo", :regions => [:cl]},
23
23
  {:function => "easter(year)", :function_arguments => [:year], :function_modifier => -1, :name => "Sábado Santo", :regions => [:cl]},
24
- {:function => "st_peter_st_paul_cl(year)", :function_arguments => [:year], :year_ranges => [{:after => 2000}],:name => "San Pedro y San Pablo", :regions => [:cl]},
25
- {:function => "other_churches_day_cl(year)", :function_arguments => [:year], :year_ranges => [{:after => 2008}],:name => "Día de las Iglesias Evangélicas y Protestantes", :regions => [:cl]},
24
+ {:function => "st_peter_st_paul_cl(year)", :function_arguments => [:year], :year_ranges => { :from => 2000 },:name => "San Pedro y San Pablo", :regions => [:cl]},
25
+ {:function => "other_churches_day_cl(year)", :function_arguments => [:year], :year_ranges => { :from => 2008 },:name => "Día de las Iglesias Evangélicas y Protestantes", :regions => [:cl]},
26
26
  {:function => "easter(year)", :function_arguments => [:year], :function_modifier => -3, :name => "Jueves Santo", :regions => [:co]},
27
27
  {:function => "easter(year)", :function_arguments => [:year], :function_modifier => -2, :name => "Viernes Santo", :regions => [:co]},
28
28
  {:function => "easter(year)", :function_arguments => [:year], :function_modifier => 43, :name => "Día de la Ascensión", :regions => [:co]},
@@ -58,7 +58,7 @@ module Holidays
58
58
  {:wday => 0, :week => 2, :type => :informal, :name => "Día de la Madre", :regions => [:pe]},
59
59
  {:mday => 1, :name => "Día del Trabajador", :regions => [:ve]}],
60
60
  6 => [{:mday => 20, :name => "Día de la Bandera", :regions => [:ar]},
61
- {:mday => 29, :year_ranges => [{:before => 1999}],:name => "San Pedro y San Pablo", :regions => [:cl]},
61
+ {:mday => 29, :year_ranges => { :until => 1999 },:name => "San Pedro y San Pablo", :regions => [:cl]},
62
62
  {:function => "saint_peter_and_saint_paul(year)", :function_arguments => [:year], :name => "San Pedro y San Pablo", :regions => [:co]},
63
63
  {:mday => 7, :type => :informal, :name => "Día de la Bandera", :regions => [:pe]},
64
64
  {:wday => 0, :week => 3, :type => :informal, :name => "Día del Padre", :regions => [:pe]},
@@ -80,8 +80,8 @@ module Holidays
80
80
  {:mday => 30, :name => "Santa Rosa de Lima", :regions => [:pe]}],
81
81
  10 => [{:mday => 12, :name => "Día del Respeto a la Diversidad Cultural", :regions => [:ar]},
82
82
  {:mday => 12, :name => "Dia de Nossa Senhora Aparecida", :regions => [:br]},
83
- {:mday => 12, :year_ranges => [{:before => 1999}],:name => "Encuentro de Dos Mundos", :regions => [:cl]},
84
- {:function => "columbus_day_cl(year)", :function_arguments => [:year], :year_ranges => [{:after => 2000}],:name => "Encuentro de Dos Mundos", :regions => [:cl]},
83
+ {:mday => 12, :year_ranges => { :until => 1999 },:name => "Encuentro de Dos Mundos", :regions => [:cl]},
84
+ {:function => "columbus_day_cl(year)", :function_arguments => [:year], :year_ranges => { :from => 2000 },:name => "Encuentro de Dos Mundos", :regions => [:cl]},
85
85
  {:function => "columbus_day(year)", :function_arguments => [:year], :name => "Día de la Raza", :regions => [:co]},
86
86
  {:mday => 8, :name => "Batalla de Angamos", :regions => [:pe]},
87
87
  {:mday => 12, :name => "Día de la Resistencia Indígena", :regions => [:ve]}],
@@ -23,7 +23,7 @@ module Holidays
23
23
  4 => [{:mday => 23, :name => "Ulusal Egemenlik ve Çocuk Bayramı", :regions => [:tr]}],
24
24
  5 => [{:mday => 1, :name => "Emek ve Dayanışma Günü", :regions => [:tr]},
25
25
  {:mday => 19, :name => "Atatürk'ü Anma Gençlik ve Spor Bayramı", :regions => [:tr]}],
26
- 7 => [{:mday => 15, :year_ranges => [{:after => 2016}],:name => "Demokrasi ve Milli Birlik Günü", :regions => [:tr]}],
26
+ 7 => [{:mday => 15, :year_ranges => { :from => 2016 },:name => "Demokrasi ve Milli Birlik Günü", :regions => [:tr]}],
27
27
  8 => [{:mday => 30, :name => "Zafer Bayramı", :regions => [:tr]}],
28
28
  10 => [{:mday => 29, :name => "Cumhuriyet Bayramı", :regions => [:tr]}]
29
29
  }
@@ -38,7 +38,8 @@ begin_of_ramadan_feast = {
38
38
  '2016' => Date.civil(2016, 7, 5),
39
39
  '2017' => Date.civil(2017, 6, 25),
40
40
  '2018' => Date.civil(2018, 6, 15),
41
- '2019' => Date.civil(2019, 6, 4)
41
+ '2019' => Date.civil(2019, 6, 4),
42
+ '2020' => Date.civil(2020, 5, 24)
42
43
  }
43
44
  begin_of_ramadan_feast[year.to_s]
44
45
  },
@@ -50,7 +51,8 @@ begin_of_sacrifice_feast = {
50
51
  '2016' => Date.civil(2016, 9, 12),
51
52
  '2017' => Date.civil(2017, 9, 1),
52
53
  '2018' => Date.civil(2018, 8, 21),
53
- '2019' => Date.civil(2019, 8, 11)
54
+ '2019' => Date.civil(2019, 8, 11),
55
+ '2020' => Date.civil(2020, 7, 31)
54
56
  }
55
57
  begin_of_sacrifice_feast[year.to_s]
56
58
  },
@@ -18,13 +18,13 @@ module Holidays
18
18
  {:mday => 7, :observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "Різдво Христове", :regions => [:ua]}],
19
19
  3 => [{:mday => 8, :observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "Міжнародний жіночий день", :regions => [:ua]}],
20
20
  5 => [{:mday => 1, :observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День праці", :regions => [:ua]},
21
- {:mday => 2, :year_ranges => [{:before => 2017}],:name => "День міжнародної солідарності трудящих", :regions => [:ua]},
21
+ {:mday => 2, :year_ranges => { :until => 2017 },:name => "День міжнародної солідарності трудящих", :regions => [:ua]},
22
22
  {:mday => 9, :observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День перемоги над нацизмом у Другій світовій війні", :regions => [:ua]}],
23
- 6 => [{:mday => 28, :year_ranges => [{:after => 1997}],:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День Конституції", :regions => [:ua]}],
24
- 7 => [{:mday => 16, :year_ranges => [{:limited => [1991]}],:name => "День Незалежності України", :regions => [:ua]}],
25
- 8 => [{:mday => 24, :year_ranges => [{:after => 1992}],:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День Незалежності", :regions => [:ua]}],
26
- 10 => [{:mday => 14, :year_ranges => [{:after => 2015}],:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День захисника України", :regions => [:ua]}],
27
- 12 => [{:mday => 25, :year_ranges => [{:after => 2017}],:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "Різдво Христове", :regions => [:ua]}]
23
+ 6 => [{:mday => 28, :year_ranges => { :from => 1997 },:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День Конституції", :regions => [:ua]}],
24
+ 7 => [{:mday => 16, :year_ranges => { :limited => [1991] },:name => "День Незалежності України", :regions => [:ua]}],
25
+ 8 => [{:mday => 24, :year_ranges => { :from => 1992 },:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День Незалежності", :regions => [:ua]}],
26
+ 10 => [{:mday => 14, :year_ranges => { :from => 2015 },:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "День захисника України", :regions => [:ua]}],
27
+ 12 => [{:mday => 25, :year_ranges => { :from => 2017 },:observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "Різдво Христове", :regions => [:ua]}]
28
28
  }
29
29
  end
30
30
 
@@ -7,7 +7,7 @@ module Holidays
7
7
  # All the definitions are available at https://github.com/holidays/holidays
8
8
  module US # :nodoc:
9
9
  def self.defined_regions
10
- [:us_fl, :us_la, :us, :us_ct, :us_de, :us_gu, :us_hi, :us_in, :us_ky, :us_nj, :us_nc, :us_nd, :us_pr, :us_tn, :us_ms, :us_id, :us_ar, :us_tx, :us_dc, :us_md, :us_va, :us_il, :us_vt, :us_ak, :us_ca, :us_me, :us_ma, :us_al, :us_ga, :us_ne, :us_mo, :us_sc, :us_wv, :us_vi, :us_ut, :us_ri, :us_az, :us_co, :us_mt, :us_nm, :us_ny, :us_oh, :us_pa, :us_mi, :us_mn, :us_nv, :us_or, :us_sd, :us_wa, :us_wi, :us_wy, :us_ia, :us_ks, :us_nh, :us_ok, :ca]
10
+ [:us_fl, :us_la, :us, :us_ct, :us_de, :us_gu, :us_hi, :us_in, :us_ky, :us_nj, :us_nc, :us_nd, :us_pr, :us_tn, :us_ms, :us_id, :us_ar, :us_tx, :us_dc, :us_md, :us_va, :us_vt, :us_ak, :us_ca, :us_me, :us_ma, :us_al, :us_ga, :us_ne, :us_mo, :us_sc, :us_wv, :us_vi, :us_ut, :us_ri, :us_az, :us_co, :us_il, :us_mt, :us_nm, :us_ny, :us_oh, :us_pa, :us_mi, :us_mn, :us_nv, :us_or, :us_sd, :us_wa, :us_wi, :us_wy, :us_ia, :us_ks, :us_nh, :us_ok, :ca]
11
11
  end
12
12
 
13
13
  def self.holidays_by_month
@@ -28,14 +28,13 @@ module Holidays
28
28
  2 => [{:wday => 1, :week => 3, :name => "Presidents' Day", :regions => [:us]},
29
29
  {:mday => 2, :type => :informal, :name => "Groundhog Day", :regions => [:us, :ca]},
30
30
  {:mday => 14, :type => :informal, :name => "Valentine's Day", :regions => [:us, :ca]}],
31
- 3 => [{:wday => 1, :week => 1, :name => "Casimir Pulaski Day", :regions => [:us_il]},
32
- {:wday => 2, :week => 1, :name => "Town Meeting Day", :regions => [:us_vt]},
31
+ 3 => [{:wday => 2, :week => 1, :name => "Town Meeting Day", :regions => [:us_vt]},
33
32
  {:mday => 2, :name => "Texas Independence Day", :regions => [:us_tx]},
34
33
  {:mday => 26, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Prince Jonah Kuhio Kalanianaole Day", :regions => [:us_hi]},
35
34
  {:wday => 1, :week => -1, :name => "Seward's Day", :regions => [:us_ak]},
36
35
  {:mday => 31, :name => "César Chávez Day", :regions => [:us_ca]},
37
36
  {:mday => 17, :type => :informal, :name => "St. Patrick's Day", :regions => [:us, :ca]}],
38
- 4 => [{:mday => 16, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Emancipation Day", :regions => [:us_dc, :us_ca]},
37
+ 4 => [{:mday => 16, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Emancipation Day", :regions => [:us_dc]},
39
38
  {:wday => 1, :week => 3, :name => "Patriots' Day", :regions => [:us_me, :us_ma]},
40
39
  {:mday => 21, :name => "San Jacinto Day", :regions => [:us_tx]},
41
40
  {:wday => 1, :week => -1, :name => "Confederate Memorial Day", :regions => [:us_al, :us_ms]},
@@ -71,7 +70,7 @@ module Holidays
71
70
  {:mday => 18, :name => "Alaska Day", :regions => [:us_ak]},
72
71
  {:wday => 5, :week => -1, :name => "Nevada Day", :regions => [:us_nv]},
73
72
  {:mday => 31, :type => :informal, :name => "Halloween", :regions => [:us, :ca]}],
74
- 11 => [{:function => "election_day(year)", :function_arguments => [:year], :name => "Election Day", :regions => [:us_de, :us_hi, :us_il, :us_in, :us_mt, :us_nj, :us_ny, :us_pa, :us_ri]},
73
+ 11 => [{:function => "election_day(year)", :function_arguments => [:year], :name => "Election Day", :regions => [:us_de, :us_hi, :us_in, :us_mt, :us_nj, :us_ny, :us_pa, :us_ri]},
75
74
  {:mday => 11, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Veterans Day", :regions => [:us]},
76
75
  {:wday => 4, :week => 4, :name => "Thanksgiving", :regions => [:us]},
77
76
  {:function => "day_after_thanksgiving(year)", :function_arguments => [:year], :name => "Family Day", :regions => [:us_nv]},
@@ -82,7 +81,7 @@ module Holidays
82
81
  {:function => "day_after_thanksgiving(year)", :function_arguments => [:year], :name => "Day after Thanksgiving (Black Friday)", :regions => [:us_ca, :us_de, :us_fl, :us_ia, :us_il, :us_ks, :us_ky, :us_me, :us_mi, :us_mn, :us_ms, :us_ne, :us_nh, :us_nc, :us_pa, :us_sc, :us_ok, :us_tn, :us_tx, :us_va, :us_wa, :us_wv]}],
83
82
  12 => [{:mday => 24, :name => "Christmas Eve", :regions => [:us_ar, :us_mi, :us_nc, :us_sc, :us_tx, :us_wi]},
84
83
  {:mday => 24, :function => "christmas_eve_holiday(date)", :function_arguments => [:date], :name => "Christmas Eve (Holiday)", :regions => [:us_mi, :us_sc, :us_va]},
85
- {:mday => 25, :observed => "to_monday_if_weekend(date)", :observed_arguments => [:date], :name => "Christmas Day", :regions => [:us]},
84
+ {:mday => 25, :observed => "to_weekday_if_weekend(date)", :observed_arguments => [:date], :name => "Christmas Day", :regions => [:us]},
86
85
  {:mday => 26, :name => "Day after Christmas", :regions => [:us_ar, :us_nc, :us_ok, :us_sc, :us_tn, :us_tx]},
87
86
  {:mday => 31, :name => "New Year's Eve", :regions => [:us_mi, :us_wi]}]
88
87
  }
@@ -40,6 +40,8 @@ module Holidays
40
40
 
41
41
  start_date, end_date = get_date(start_date), get_date(end_date)
42
42
 
43
+ raise ArgumentError if end_date < start_date
44
+
43
45
  if cached_holidays = Factory::Definition.cache_repository.find(start_date, end_date, options)
44
46
  return cached_holidays
45
47
  end
@@ -87,16 +87,27 @@ module Holidays
87
87
  rule = {}
88
88
 
89
89
  definition.each do |key, val|
90
+ # Ruby 2.4 doesn't have the `transform_keys` method. Once we drop 2.4 support we can
91
+ # use `val.transform_keys!(&:to_sym) if val.is_a?(Hash)` instead of this `if` statement.
92
+ if val.is_a?(Hash)
93
+ val = val.keys.each_with_object({}) do |k, result|
94
+ result[k.to_sym] = val[k]
95
+ end
96
+ end
97
+
90
98
  rule[key.to_sym] = val
91
99
  end
92
100
 
93
- rule[:regions] = rule[:regions].collect { |r| r.to_sym }
94
- regions << rule[:regions]
101
+ if rule[:year_ranges] && rule[:year_ranges].key?(:between)
102
+ start_year = rule[:year_ranges][:between]["start"].to_i
103
+ end_year = rule[:year_ranges][:between]["end"].to_i
95
104
 
96
- if rule[:year_ranges]
97
- rule[:year_ranges] = clean_year_ranges(rule[:year_ranges])
105
+ rule[:year_ranges][:between] = Range.new(start_year, end_year)
98
106
  end
99
107
 
108
+ rule[:regions] = rule[:regions].collect { |r| r.to_sym }
109
+ regions << rule[:regions]
110
+
100
111
  exists = false
101
112
  rules_by_month[month].each do |ex|
102
113
  if ex[:name] == rule[:name] and ex[:wday] == rule[:wday] and ex[:mday] == rule[:mday] and ex[:week] == rule[:week] and ex[:type] == rule[:type] and ex[:function] == rule[:function] and ex[:observed] == rule[:observed] and ex[:year_ranges] == rule[:year_ranges]
@@ -121,23 +132,6 @@ module Holidays
121
132
  [regions, rules_by_month]
122
133
  end
123
134
 
124
- # In this case we end up parsing a range as "2006..2008" a string. This is codifying
125
- # what we already do...today we parse as a string but when writing out to our final
126
- # generated files it comes out as a range that Ruby interprets. This just puts it in stone
127
- # what we want to do.
128
- def clean_year_ranges(year_ranges)
129
- year_ranges.collect do |year_range|
130
- if year_range["between"]
131
- range = year_range["between"]
132
- if range.is_a?(String)
133
- year_range["between"] = Range.new(*range.split("..").map(&:to_i))
134
- end
135
- end
136
-
137
- year_range
138
- end
139
- end
140
-
141
135
  #FIXME This should really be split out and tested with its own unit tests.
142
136
  def generate_month_definition_strings(rules_by_month, parsed_custom_methods)
143
137
  month_strings = []
@@ -170,19 +164,11 @@ module Holidays
170
164
  string << ":wday => #{rule[:wday]}, :week => #{rule[:week]}, "
171
165
  end
172
166
 
173
- #FIXME I think this should be split out into its own file.
174
- if rule[:year_ranges] && rule[:year_ranges].kind_of?(Array)
175
- year_string = " :year_ranges => ["
176
- len = rule[:year_ranges].length
177
- rule[:year_ranges].each_with_index do |year,index|
178
- year_string << "{:#{year.keys.first} => #{year.values.first}}"
179
- if len == index + 1
180
- year_string << "],"
181
- else
182
- year_string << ","
183
- end
184
- end
185
- string << year_string
167
+ if rule[:year_ranges] && rule[:year_ranges].is_a?(Hash)
168
+ selector = rule[:year_ranges].keys.first
169
+ value = rule[:year_ranges][selector]
170
+
171
+ string << ":year_ranges => { :#{selector} => #{value} },"
186
172
  end
187
173
 
188
174
  if rule[:observed]
@@ -41,7 +41,15 @@ module Holidays
41
41
  private
42
42
 
43
43
  def definition_exists?(existing_def, target_def)
44
- existing_def[:name] == target_def[:name] && existing_def[:wday] == target_def[:wday] && existing_def[:mday] == target_def[:mday] && existing_def[:week] == target_def[:week] && existing_def[:function] == target_def[:function] && existing_def[:type] == target_def[:type] && existing_def[:observed] == target_def[:observed] && existing_def[:year_ranges] == target_def[:year_ranges]
44
+ existing_def[:name] == target_def[:name] &&
45
+ existing_def[:wday] == target_def[:wday] &&
46
+ existing_def[:mday] == target_def[:mday] &&
47
+ existing_def[:week] == target_def[:week] &&
48
+ existing_def[:function] == target_def[:function] &&
49
+ existing_def[:function_modifier] == target_def[:function_modifier] &&
50
+ existing_def[:type] == target_def[:type] &&
51
+ existing_def[:observed] == target_def[:observed] &&
52
+ existing_def[:year_ranges] == target_def[:year_ranges]
45
53
  end
46
54
  end
47
55
  end
@@ -24,39 +24,11 @@ module Holidays
24
24
  next unless @rules[:year_range].call(year, h[:year_ranges])
25
25
  end
26
26
 
27
- current_month = month
28
- current_day = h[:mday]
29
-
30
- if h[:function]
31
- result = @custom_method_processor.call(
32
- build_custom_method_input(year, current_month, current_day, h[:regions]),
33
- h[:function], h[:function_arguments], h[:function_modifier],
34
- )
35
-
36
- #FIXME The result should always be present, see https://github.com/holidays/holidays/issues/204 for more information
37
- if result
38
- current_month = result.month
39
- current_day = result.mday
40
- else
41
- current_month = nil
42
- current_day = nil
43
- end
44
- else
45
- current_day = h[:mday] || @day_of_month_calculator.call(year, current_month, h[:week], h[:wday])
46
- end
47
-
48
- # Silently skip bad mdays
49
- #TODO Should we be doing something different here? We have no concept of logging right now. Maybe we should add it?
50
- begin
51
- date = Date.civil(year, current_month, current_day)
52
- rescue; next; end
27
+ date = build_date(year, month, h)
28
+ next unless date
53
29
 
54
30
  if observed_set?(options) && h[:observed]
55
- date = @custom_method_processor.call(
56
- build_custom_method_input(date.year, date.month, date.day, regions),
57
- h[:observed],
58
- [:date],
59
- )
31
+ date = build_observed_date(date, regions, h)
60
32
  end
61
33
 
62
34
  holidays << {:date => date, :name => h[:name], :regions => h[:regions]}
@@ -93,6 +65,29 @@ module Holidays
93
65
  options && options.include?(:observed) == true
94
66
  end
95
67
 
68
+ def build_date(year, month, h)
69
+ if h[:function]
70
+ holiday = custom_holiday(year, month, h)
71
+ #FIXME The result should always be present, see https://github.com/holidays/holidays/issues/204 for more information
72
+ current_month = holiday&.month
73
+ current_day = holiday&.mday
74
+ else
75
+ current_month = month
76
+ current_day = h[:mday] || @day_of_month_calculator.call(year, month, h[:week], h[:wday])
77
+ end
78
+
79
+ # Silently skip bad mdays
80
+ #TODO Should we be doing something different here? We have no concept of logging right now. Maybe we should add it?
81
+ Date.civil(year, current_month, current_day) rescue nil
82
+ end
83
+
84
+ def custom_holiday(year, month, h)
85
+ @custom_method_processor.call(
86
+ build_custom_method_input(year, month, h[:mday], h[:regions]),
87
+ h[:function], h[:function_arguments], h[:function_modifier],
88
+ )
89
+ end
90
+
96
91
  def build_custom_method_input(year, month, day, regions)
97
92
  {
98
93
  year: year,
@@ -101,6 +96,14 @@ module Holidays
101
96
  region: regions.first, #FIXME This isn't ideal but will work for our current use case...
102
97
  }
103
98
  end
99
+
100
+ def build_observed_date(date, regions, h)
101
+ @custom_method_processor.call(
102
+ build_custom_method_input(date.year, date.month, date.day, regions),
103
+ h[:observed],
104
+ [:date],
105
+ )
106
+ end
104
107
  end
105
108
  end
106
109
  end
@@ -1,49 +1,30 @@
1
- # Please note that only one condition needs to match in order for `call` to return `true.
2
- # See the test file for this class for specific examples.
3
1
  module Holidays
4
2
  module Finder
5
3
  module Rules
6
4
  class YearRange
7
5
  class << self
8
- BEFORE = :before
9
- AFTER = :after
6
+ UNTIL = :until
7
+ FROM = :from
10
8
  LIMITED = :limited
11
9
  BETWEEN = :between
12
10
 
13
- #TODO Can we just accept symbols here? Why accept strings?
14
- VALID_OPERATORS = [
15
- BEFORE, BEFORE.to_s,
16
- AFTER, AFTER.to_s,
17
- LIMITED, LIMITED.to_s,
18
- BETWEEN, BETWEEN.to_s
19
- ]
20
-
21
- def call(target_year, year_range_definitions)
22
- validate!(target_year, year_range_definitions)
23
-
24
- matched = false
25
- year_range_definitions.each do |range_defs|
26
- next unless range_defs.is_a?(Hash) && range_defs.length == 1
27
-
28
- operator = range_defs.keys.first
29
- year_range = range_defs.values.first
30
-
31
- case operator
32
- when BEFORE, BEFORE.to_s
33
- matched = target_year <= year_range
34
- when AFTER, AFTER.to_s
35
- matched = target_year >= year_range
36
- when LIMITED, LIMITED.to_s
37
- if year_range.is_a?(Array)
38
- matched = year_range.include?(target_year)
39
- else
40
- matched = year_range == target_year
41
- end
42
- when BETWEEN, BETWEEN.to_s
43
- matched = year_range.cover?(target_year)
44
- end
45
-
46
- break if matched == true
11
+ def call(target_year, year_range_defs)
12
+ validate!(target_year, year_range_defs)
13
+
14
+ operator = year_range_defs.keys.first
15
+ rule_value = year_range_defs[operator]
16
+
17
+ case operator
18
+ when UNTIL
19
+ matched = target_year <= rule_value
20
+ when FROM
21
+ matched = target_year >= rule_value
22
+ when LIMITED
23
+ matched = rule_value.include?(target_year)
24
+ when BETWEEN
25
+ matched = rule_value.cover?(target_year)
26
+ else
27
+ matched = false
47
28
  end
48
29
 
49
30
  matched
@@ -54,25 +35,20 @@ module Holidays
54
35
  def validate!(target_year, year_ranges)
55
36
  raise ArgumentError.new("target_year must be a number") unless target_year.is_a?(Integer)
56
37
  raise ArgumentError.new("year_ranges cannot be missing") if year_ranges.nil? || year_ranges.empty?
38
+ raise ArgumentError.new("year_ranges must contain a hash with a single operator") unless year_ranges.is_a?(Hash) && year_ranges.size == 1
57
39
 
58
- year_ranges.each do |range|
59
- raise ArgumentError.new("year_ranges must include only hashes") unless range.is_a?(Hash)
60
- raise ArgumentError.new("year_ranges cannot include empty hashes") if range.empty?
61
- raise ArgumentError.new("year_ranges entries can only include one operator") unless range.count == 1
62
-
63
- operator = range.keys.first
64
- range = range.values.first
40
+ operator = year_ranges.keys.first
41
+ value = year_ranges[operator]
65
42
 
66
- raise ArgumentError.new("Invalid operator found: '#{operator}'") unless VALID_OPERATORS.include?(operator)
43
+ raise ArgumentError.new("Invalid operator found: '#{operator}'") unless [UNTIL, FROM, LIMITED, BETWEEN].include?(operator)
67
44
 
68
- case operator
69
- when BEFORE, BEFORE.to_s, AFTER, AFTER.to_s
70
- raise ArgumentError.new(":before and :after operator value must be a number, received: '#{range}'") unless range.is_a?(Integer)
71
- when LIMITED, LIMITED.to_s
72
- raise ArgumentError.new(":limited operator value must be an array, received: '#{range}'") unless range.is_a?(Array) || range.is_a?(Integer)
73
- when BETWEEN, BETWEEN.to_s
74
- raise ArgumentError.new(":between operator value must be a range, received: '#{range}'") unless range.is_a?(Range)
75
- end
45
+ case operator
46
+ when UNTIL, FROM
47
+ raise ArgumentError.new("#{UNTIL} and #{FROM} operator value must be a number, received: '#{value}'") unless value.is_a?(Integer)
48
+ when LIMITED
49
+ raise ArgumentError.new(":limited operator value must be an array containing at least one integer value, received: '#{value}'") unless value.is_a?(Array) && value.size >= 1 && value.all? { |v| v.is_a?(Integer) }
50
+ when BETWEEN
51
+ raise ArgumentError.new(":between operator value must be a range, received: '#{value}'") unless value.is_a?(Range)
76
52
  end
77
53
  end
78
54
  end
@@ -1,3 +1,3 @@
1
1
  module Holidays
2
- VERSION = '7.1.0'
2
+ VERSION = '8.4.0'
3
3
  end