holidays 7.1.0 → 8.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -1
- data/README.md +3 -4
- data/doc/CONTRIBUTING.md +2 -1
- data/holidays.gemspec +5 -5
- data/lib/generated_definitions/MANIFEST +3 -0
- data/lib/generated_definitions/REGIONS.rb +2 -2
- data/lib/generated_definitions/au.rb +8 -2
- data/lib/generated_definitions/ca.rb +14 -13
- data/lib/generated_definitions/ch.rb +13 -1
- data/lib/generated_definitions/cl.rb +5 -5
- data/lib/generated_definitions/de.rb +5 -4
- data/lib/generated_definitions/es.rb +4 -2
- data/lib/generated_definitions/europe.rb +83 -23
- data/lib/generated_definitions/gb.rb +6 -4
- data/lib/generated_definitions/hr.rb +8 -6
- data/lib/generated_definitions/hu.rb +3 -2
- data/lib/generated_definitions/it.rb +14 -5
- data/lib/generated_definitions/jp.rb +26 -21
- data/lib/generated_definitions/kz.rb +38 -0
- data/lib/generated_definitions/lu.rb +2 -0
- data/lib/generated_definitions/lv.rb +52 -0
- data/lib/generated_definitions/mx.rb +3 -3
- data/lib/generated_definitions/ng.rb +33 -0
- data/lib/generated_definitions/northamerica.rb +21 -21
- data/lib/generated_definitions/ro.rb +5 -2
- data/lib/generated_definitions/southamerica.rb +5 -5
- data/lib/generated_definitions/tr.rb +5 -3
- data/lib/generated_definitions/ua.rb +6 -6
- data/lib/generated_definitions/us.rb +5 -6
- data/lib/holidays.rb +2 -0
- data/lib/holidays/definition/context/generator.rb +20 -34
- data/lib/holidays/definition/repository/holidays_by_month.rb +9 -1
- data/lib/holidays/finder/context/search.rb +34 -31
- data/lib/holidays/finder/rules/year_range.rb +30 -54
- data/lib/holidays/version.rb +1 -1
- data/test/coverage_report.rb +23 -5
- data/test/data/test_custom_year_range_holiday_defs.yaml +6 -10
- data/test/data/test_multiple_regions_with_conflicts_region_1.yaml +38 -0
- data/test/data/test_multiple_regions_with_conflicts_region_2.yaml +38 -0
- data/test/defs/test_defs_ca.rb +27 -5
- data/test/defs/test_defs_ch.rb +4 -0
- data/test/defs/test_defs_co.rb +3 -3
- data/test/defs/test_defs_de.rb +2 -0
- data/test/defs/test_defs_es.rb +2 -0
- data/test/defs/test_defs_europe.rb +156 -11
- data/test/defs/test_defs_federalreservebanks.rb +20 -0
- data/test/defs/test_defs_gb.rb +16 -0
- data/test/defs/test_defs_hr.rb +6 -6
- data/test/defs/test_defs_hu.rb +12 -4
- data/test/defs/test_defs_it.rb +20 -0
- data/test/defs/test_defs_jp.rb +5 -3
- data/test/defs/test_defs_kz.rb +39 -0
- data/test/defs/test_defs_lu.rb +6 -0
- data/test/defs/test_defs_lv.rb +90 -0
- data/test/defs/test_defs_ng.rb +29 -0
- data/test/defs/test_defs_northamerica.rb +33 -15
- data/test/defs/test_defs_ro.rb +14 -0
- data/test/defs/test_defs_southamerica.rb +3 -3
- data/test/defs/test_defs_tr.rb +7 -0
- data/test/defs/test_defs_us.rb +6 -10
- data/test/holidays/core_extensions/test_date.rb +3 -2
- data/test/holidays/definition/context/test_generator.rb +5 -18
- data/test/holidays/definition/repository/test_holidays_by_month.rb +121 -1
- data/test/holidays/finder/rules/test_year_range.rb +43 -47
- data/test/integration/test_available_regions.rb +1 -1
- data/test/integration/test_custom_year_range_holidays.rb +0 -7
- data/test/integration/test_holidays.rb +1 -23
- data/test/integration/test_holidays_between.rb +10 -0
- data/test/integration/test_multiple_regions_with_conflict.rb +29 -0
- 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 -
|
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],
|
25
|
-
{:function => "other_churches_day_cl(year)", :function_arguments => [:year],
|
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,
|
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,
|
84
|
-
{:function => "columbus_day_cl(year)", :function_arguments => [:year],
|
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,
|
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,
|
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,
|
24
|
-
7 => [{:mday => 16,
|
25
|
-
8 => [{:mday => 24,
|
26
|
-
10 => [{:mday => 14,
|
27
|
-
12 => [{:mday => 25,
|
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, :
|
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 =>
|
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
|
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, :
|
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 => "
|
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
|
}
|
data/lib/holidays.rb
CHANGED
@@ -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[:
|
94
|
-
|
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
|
-
|
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
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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] &&
|
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
|
-
|
28
|
-
|
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 =
|
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
|
-
|
9
|
-
|
6
|
+
UNTIL = :until
|
7
|
+
FROM = :from
|
10
8
|
LIMITED = :limited
|
11
9
|
BETWEEN = :between
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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.
|
59
|
-
|
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
|
-
|
43
|
+
raise ArgumentError.new("Invalid operator found: '#{operator}'") unless [UNTIL, FROM, LIMITED, BETWEEN].include?(operator)
|
67
44
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
data/lib/holidays/version.rb
CHANGED