holidays 4.2.0 → 8.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitmodules +3 -0
- data/CHANGELOG.md +195 -0
- data/Makefile +45 -0
- data/README.md +253 -77
- data/Rakefile +10 -11
- data/bin/console +0 -0
- data/bin/setup +1 -0
- data/doc/CONTRIBUTING.md +72 -0
- data/doc/MAINTAINERS.md +81 -0
- data/{REFERENCES → doc/REFERENCES} +0 -0
- data/holidays.gemspec +9 -9
- data/lib/generated_definitions/MANIFEST +26 -4
- data/lib/generated_definitions/REGIONS.rb +3 -1
- data/lib/generated_definitions/ar.rb +4 -10
- data/lib/generated_definitions/at.rb +3 -9
- data/lib/generated_definitions/au.rb +32 -25
- data/lib/generated_definitions/be_fr.rb +2 -8
- data/lib/generated_definitions/be_nl.rb +2 -8
- data/lib/generated_definitions/bg.rb +2 -8
- data/lib/generated_definitions/br.rb +2 -8
- data/lib/generated_definitions/ca.rb +33 -32
- data/lib/generated_definitions/ch.rb +17 -11
- data/lib/generated_definitions/cl.rb +38 -12
- data/lib/generated_definitions/co.rb +121 -0
- data/lib/generated_definitions/cr.rb +2 -8
- data/lib/generated_definitions/cz.rb +2 -8
- data/lib/generated_definitions/de.rb +11 -14
- data/lib/generated_definitions/dk.rb +2 -8
- data/lib/generated_definitions/{ecb_target.rb → ecbtarget.rb} +10 -16
- data/lib/generated_definitions/ee.rb +36 -0
- data/lib/generated_definitions/el.rb +2 -8
- data/lib/generated_definitions/es.rb +8 -11
- data/lib/generated_definitions/europe.rb +121 -51
- data/lib/generated_definitions/federalreserve.rb +34 -0
- data/lib/generated_definitions/{federal_reserve.rb → federalreservebanks.rb} +14 -20
- data/lib/generated_definitions/fedex.rb +3 -9
- data/lib/generated_definitions/fi.rb +2 -8
- data/lib/generated_definitions/fr.rb +6 -10
- data/lib/generated_definitions/gb.rb +12 -16
- data/lib/generated_definitions/ge.rb +41 -0
- data/lib/generated_definitions/hk.rb +106 -0
- data/lib/generated_definitions/hr.rb +10 -14
- data/lib/generated_definitions/hu.rb +4 -9
- data/lib/generated_definitions/ie.rb +3 -17
- data/lib/generated_definitions/is.rb +3 -9
- data/lib/generated_definitions/it.rb +16 -13
- data/lib/generated_definitions/jp.rb +47 -36
- data/lib/generated_definitions/kr.rb +40 -0
- data/lib/generated_definitions/kz.rb +38 -0
- data/lib/generated_definitions/li.rb +2 -8
- data/lib/generated_definitions/lt.rb +2 -8
- data/lib/generated_definitions/lu.rb +35 -0
- data/lib/generated_definitions/lv.rb +52 -0
- data/lib/generated_definitions/ma.rb +2 -8
- data/lib/generated_definitions/mt_en.rb +38 -0
- data/lib/generated_definitions/mt_mt.rb +38 -0
- data/lib/generated_definitions/mx.rb +6 -12
- data/lib/generated_definitions/my.rb +30 -0
- data/lib/generated_definitions/nerc.rb +2 -8
- data/lib/generated_definitions/ng.rb +33 -0
- data/lib/generated_definitions/nl.rb +2 -8
- data/lib/generated_definitions/no.rb +2 -8
- data/lib/generated_definitions/northamerica.rb +223 -0
- data/lib/generated_definitions/nyse.rb +3 -9
- data/lib/generated_definitions/nz.rb +2 -9
- data/lib/generated_definitions/pe.rb +43 -0
- data/lib/generated_definitions/ph.rb +4 -10
- data/lib/generated_definitions/pl.rb +2 -8
- data/lib/generated_definitions/pt.rb +12 -12
- data/lib/generated_definitions/ro.rb +6 -9
- data/lib/generated_definitions/rs_cyrl.rb +39 -0
- data/lib/generated_definitions/rs_la.rb +39 -0
- data/lib/generated_definitions/ru.rb +37 -0
- data/lib/generated_definitions/scandinavia.rb +3 -9
- data/lib/generated_definitions/se.rb +2 -8
- data/lib/generated_definitions/sg.rb +2 -8
- data/lib/generated_definitions/si.rb +2 -8
- data/lib/generated_definitions/sk.rb +2 -8
- data/lib/generated_definitions/southamerica.rb +228 -0
- data/lib/generated_definitions/th.rb +36 -0
- data/lib/generated_definitions/tn.rb +32 -0
- data/lib/generated_definitions/tr.rb +64 -0
- data/lib/generated_definitions/ua.rb +37 -0
- data/lib/generated_definitions/{united_nations.rb → unitednations.rb} +61 -67
- data/lib/generated_definitions/ups.rb +3 -9
- data/lib/generated_definitions/us.rb +113 -23
- data/lib/generated_definitions/ve.rb +2 -8
- data/lib/generated_definitions/vi.rb +6 -11
- data/lib/generated_definitions/za.rb +2 -8
- data/lib/holidays/core_extensions/date.rb +21 -3
- data/lib/holidays/core_extensions/time.rb +23 -0
- data/lib/holidays/date_calculator/day_of_month.rb +3 -3
- data/lib/holidays/date_calculator/lunar_date.rb +371 -0
- data/lib/holidays/date_calculator/weekend_modifier.rb +0 -7
- data/lib/holidays/definition/context/function_processor.rb +91 -0
- data/lib/holidays/definition/context/generator.rb +37 -96
- data/lib/holidays/definition/context/load.rb +29 -0
- data/lib/holidays/definition/context/merger.rb +0 -4
- data/lib/holidays/definition/decorator/test.rb +37 -0
- data/lib/holidays/definition/entity/test.rb +11 -0
- data/lib/holidays/definition/generator/module.rb +54 -0
- data/lib/holidays/definition/generator/regions.rb +55 -0
- data/lib/holidays/definition/generator/test.rb +51 -0
- data/lib/holidays/definition/parser/custom_method.rb +3 -5
- data/lib/holidays/definition/parser/test.rb +86 -0
- data/lib/holidays/definition/repository/cache.rb +23 -9
- data/lib/holidays/definition/repository/holidays_by_month.rb +10 -2
- data/lib/holidays/definition/repository/proc_result_cache.rb +1 -1
- data/lib/holidays/definition/repository/regions.rb +23 -13
- data/lib/holidays/definition/validator/custom_method.rb +1 -1
- data/lib/holidays/definition/validator/region.rb +2 -11
- data/lib/holidays/definition/validator/test.rb +71 -0
- data/lib/holidays/errors.rb +5 -0
- data/lib/holidays/factory/date_calculator.rb +42 -0
- data/lib/holidays/factory/definition.rb +143 -0
- data/lib/holidays/factory/finder.rb +70 -0
- data/lib/holidays/finder/context/between.rb +45 -0
- data/lib/holidays/{use_case → finder}/context/dates_driver_builder.rb +11 -15
- data/lib/holidays/finder/context/next_holiday.rb +57 -0
- data/lib/holidays/finder/context/parse_options.rb +104 -0
- data/lib/holidays/finder/context/search.rb +110 -0
- data/lib/holidays/finder/context/year_holiday.rb +57 -0
- data/lib/holidays/finder/rules/in_region.rb +31 -0
- data/lib/holidays/finder/rules/year_range.rb +58 -0
- data/lib/holidays/load_all_definitions.rb +16 -17
- data/lib/holidays/version.rb +1 -1
- data/lib/holidays.rb +50 -125
- data/test/coverage_report.rb +26 -0
- data/test/data/test_custom_informal_holidays_defs.yaml +11 -0
- data/test/data/test_custom_year_range_holiday_defs.yaml +13 -10
- data/test/data/test_invalid_region.rb +15 -0
- data/test/data/test_multiple_custom_holiday_defs.yaml +7 -4
- 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/data/test_region.rb +15 -0
- data/test/data/test_single_custom_holiday_defs.yaml +7 -4
- data/test/data/test_single_custom_holiday_with_custom_procs.yaml +11 -7
- data/test/defs/test_defs_ar.rb +41 -19
- data/test/defs/test_defs_at.rb +18 -11
- data/test/defs/test_defs_au.rb +185 -126
- data/test/defs/test_defs_be_fr.rb +33 -14
- data/test/defs/test_defs_be_nl.rb +33 -14
- data/test/defs/test_defs_bg.rb +29 -17
- data/test/defs/test_defs_br.rb +33 -19
- data/test/defs/test_defs_ca.rb +246 -136
- data/test/defs/test_defs_ch.rb +35 -23
- data/test/defs/test_defs_cl.rb +57 -27
- data/test/defs/test_defs_co.rb +113 -0
- data/test/defs/test_defs_cr.rb +17 -11
- data/test/defs/test_defs_cz.rb +25 -15
- data/test/defs/test_defs_de.rb +60 -59
- data/test/defs/test_defs_dk.rb +31 -19
- data/test/defs/test_defs_ecbtarget.rb +27 -0
- data/test/defs/test_defs_ee.rb +41 -0
- data/test/defs/test_defs_el.rb +29 -17
- data/test/defs/test_defs_es.rb +116 -52
- data/test/defs/test_defs_europe.rb +1382 -701
- data/test/defs/test_defs_federalreserve.rb +113 -0
- data/test/defs/test_defs_federalreservebanks.rb +247 -0
- data/test/defs/test_defs_fedex.rb +19 -12
- data/test/defs/test_defs_fi.rb +47 -27
- data/test/defs/test_defs_fr.rb +31 -18
- data/test/defs/test_defs_gb.rb +120 -51
- data/test/defs/test_defs_ge.rb +53 -0
- data/test/defs/test_defs_hk.rb +59 -0
- data/test/defs/test_defs_hr.rb +32 -18
- data/test/defs/test_defs_hu.rb +34 -16
- data/test/defs/test_defs_ie.rb +41 -25
- data/test/defs/test_defs_is.rb +39 -22
- data/test/defs/test_defs_it.rb +43 -14
- data/test/defs/test_defs_jp.rb +141 -55
- data/test/defs/test_defs_kr.rb +37 -0
- data/test/defs/test_defs_kz.rb +39 -0
- data/test/defs/test_defs_li.rb +20 -20
- data/test/defs/test_defs_lt.rb +51 -30
- data/test/defs/test_defs_lu.rb +35 -0
- data/test/defs/test_defs_lv.rb +90 -0
- data/test/defs/test_defs_ma.rb +17 -11
- data/test/defs/test_defs_mt_en.rb +41 -0
- data/test/defs/test_defs_mt_mt.rb +41 -0
- data/test/defs/test_defs_mx.rb +34 -23
- data/test/defs/test_defs_my.rb +23 -0
- data/test/defs/test_defs_nerc.rb +17 -11
- data/test/defs/test_defs_ng.rb +29 -0
- data/test/defs/test_defs_nl.rb +21 -13
- data/test/defs/test_defs_no.rb +31 -18
- data/test/defs/test_defs_northamerica.rb +644 -0
- data/test/defs/test_defs_nyse.rb +27 -11
- data/test/defs/test_defs_nz.rb +47 -28
- data/test/defs/test_defs_pe.rb +47 -0
- data/test/defs/test_defs_ph.rb +17 -13
- data/test/defs/test_defs_pl.rb +200 -119
- data/test/defs/test_defs_pt.rb +35 -15
- data/test/defs/test_defs_ro.rb +53 -24
- data/test/defs/test_defs_rs_cyrl.rb +46 -0
- data/test/defs/test_defs_rs_la.rb +46 -0
- data/test/defs/test_defs_ru.rb +34 -0
- data/test/defs/test_defs_scandinavia.rb +193 -116
- data/test/defs/test_defs_se.rb +47 -28
- data/test/defs/test_defs_sg.rb +13 -9
- data/test/defs/test_defs_si.rb +93 -24
- data/test/defs/test_defs_sk.rb +29 -17
- data/test/defs/test_defs_southamerica.rb +307 -0
- data/test/defs/test_defs_th.rb +33 -0
- data/test/defs/test_defs_tn.rb +27 -0
- data/test/defs/test_defs_tr.rb +60 -0
- data/test/defs/test_defs_ua.rb +41 -0
- data/test/defs/{test_defs_united_nations.rb → test_defs_unitednations.rb} +3 -4
- data/test/defs/test_defs_ups.rb +19 -12
- data/test/defs/test_defs_us.rb +370 -30
- data/test/defs/test_defs_ve.rb +23 -16
- data/test/defs/test_defs_vi.rb +10 -6
- data/test/defs/test_defs_za.rb +23 -14
- data/test/holidays/core_extensions/test_date.rb +3 -2
- data/test/holidays/core_extensions/test_date_time.rb +60 -0
- data/test/holidays/date_calculator/test_lunar_date.rb +89 -0
- data/test/holidays/definition/context/test_function_processor.rb +199 -0
- data/test/holidays/definition/context/test_generator.rb +66 -35
- data/test/holidays/definition/context/test_load.rb +37 -0
- data/test/holidays/definition/decorator/test_test.rb +123 -0
- data/test/holidays/definition/generator/test_module.rb +268 -0
- data/test/holidays/definition/generator/test_regions.rb +97 -0
- data/test/holidays/definition/generator/test_test.rb +113 -0
- data/test/holidays/definition/parser/test_custom_method.rb +6 -6
- data/test/holidays/definition/parser/test_test.rb +142 -0
- data/test/holidays/definition/repository/test_cache.rb +47 -6
- data/test/holidays/definition/repository/test_holidays_by_month.rb +121 -1
- data/test/holidays/definition/repository/test_proc_result_cache.rb +8 -1
- data/test/holidays/definition/repository/test_regions.rb +31 -13
- data/test/holidays/definition/validator/test_custom_method.rb +5 -0
- data/test/holidays/definition/validator/test_region.rb +16 -12
- data/test/holidays/definition/validator/test_test.rb +60 -0
- data/test/holidays/finder/context/test_between.rb +172 -0
- data/test/holidays/{use_case → finder}/context/test_dates_driver_builder.rb +2 -2
- data/test/holidays/finder/context/test_next_holiday.rb +156 -0
- data/test/holidays/finder/context/test_parse_options.rb +141 -0
- data/test/holidays/finder/context/test_search.rb +232 -0
- data/test/holidays/finder/context/test_year_holiday.rb +202 -0
- data/test/holidays/finder/rules/test_in_region.rb +42 -0
- data/test/holidays/finder/rules/test_year_range.rb +166 -0
- data/test/integration/README.md +9 -0
- data/test/{test_all_regions.rb → integration/test_all_regions.rb} +18 -4
- data/test/integration/test_any_holidays_during_work_week.rb +90 -0
- data/test/integration/test_available_regions.rb +23 -0
- data/test/{test_custom_holidays.rb → integration/test_custom_holidays.rb} +6 -6
- data/test/integration/test_custom_informal_holidays.rb +15 -0
- data/test/{test_custom_year_range_holidays.rb → integration/test_custom_year_range_holidays.rb} +1 -9
- data/test/{test_holidays.rb → integration/test_holidays.rb} +100 -69
- data/test/{test_holidays_between.rb → integration/test_holidays_between.rb} +19 -17
- data/test/integration/test_multiple_regions.rb +71 -0
- data/test/integration/test_multiple_regions_with_conflict.rb +29 -0
- data/test/integration/test_nonstandard_regions.rb +25 -0
- data/test/test_helper.rb +7 -3
- metadata +204 -132
- data/CONTRIBUTING.md +0 -41
- data/benchmark.rb +0 -8
- data/definitions/README.md +0 -353
- data/definitions/ar.yaml +0 -93
- data/definitions/at.yaml +0 -72
- data/definitions/au.yaml +0 -375
- data/definitions/be_fr.yaml +0 -69
- data/definitions/be_nl.yaml +0 -69
- data/definitions/bg.yaml +0 -127
- data/definitions/br.yaml +0 -77
- data/definitions/ca.yaml +0 -302
- data/definitions/ch.yaml +0 -193
- data/definitions/cl.yaml +0 -94
- data/definitions/cr.yaml +0 -65
- data/definitions/cz.yaml +0 -73
- data/definitions/de.yaml +0 -209
- data/definitions/dk.yaml +0 -130
- data/definitions/ecb_target.yaml +0 -44
- data/definitions/el.yaml +0 -84
- data/definitions/es.yaml +0 -203
- data/definitions/federal_reserve.yaml +0 -114
- data/definitions/fedex.yaml +0 -62
- data/definitions/fi.yaml +0 -115
- data/definitions/fr.yaml +0 -79
- data/definitions/gb.yaml +0 -151
- data/definitions/hr.yaml +0 -79
- data/definitions/hu.yaml +0 -63
- data/definitions/ie.yaml +0 -89
- data/definitions/index.yaml +0 -57
- data/definitions/is.yaml +0 -146
- data/definitions/it.yaml +0 -67
- data/definitions/jp.yaml +0 -316
- data/definitions/li.yaml +0 -107
- data/definitions/lt.yaml +0 -89
- data/definitions/ma.yaml +0 -52
- data/definitions/mx.yaml +0 -106
- data/definitions/nerc.yaml +0 -51
- data/definitions/nl.yaml +0 -73
- data/definitions/no.yaml +0 -90
- data/definitions/north_america_informal.yaml +0 -61
- data/definitions/nyse.yaml +0 -64
- data/definitions/nz.yaml +0 -163
- data/definitions/ph.yaml +0 -94
- data/definitions/pl.yaml +0 -320
- data/definitions/pt.yaml +0 -69
- data/definitions/ro.yaml +0 -78
- data/definitions/se.yaml +0 -120
- data/definitions/sg.yaml +0 -56
- data/definitions/si.yaml +0 -86
- data/definitions/sk.yaml +0 -80
- data/definitions/united_nations.yaml +0 -189
- data/definitions/ups.yaml +0 -62
- data/definitions/us.yaml +0 -103
- data/definitions/ve.yaml +0 -74
- data/definitions/vi.yaml +0 -29
- data/definitions/za.yaml +0 -80
- data/lib/generated_definitions/north_america.rb +0 -126
- data/lib/holidays/date_calculator_factory.rb +0 -35
- data/lib/holidays/definition_factory.rb +0 -86
- data/lib/holidays/option/context/parse_options.rb +0 -106
- data/lib/holidays/option_factory.rb +0 -15
- data/lib/holidays/use_case/context/between.rb +0 -45
- data/lib/holidays/use_case/context/context_common.rb +0 -123
- data/lib/holidays/use_case/context/next_holiday.rb +0 -54
- data/lib/holidays/use_case_factory.rb +0 -31
- data/test/defs/test_defs_ecb_target.rb +0 -23
- data/test/defs/test_defs_federal_reserve.rb +0 -69
- data/test/defs/test_defs_north_america.rb +0 -195
- data/test/holidays/option/context/test_parse_options.rb +0 -74
- data/test/holidays/test_date_calculator_factory.rb +0 -27
- data/test/holidays/test_definition_factory.rb +0 -49
- data/test/holidays/test_option_factory.rb +0 -9
- data/test/holidays/test_use_case_factory.rb +0 -13
- data/test/holidays/use_case/context/test_between.rb +0 -77
- data/test/test_multiple_regions.rb +0 -24
@@ -0,0 +1,58 @@
|
|
1
|
+
module Holidays
|
2
|
+
module Finder
|
3
|
+
module Rules
|
4
|
+
class YearRange
|
5
|
+
class << self
|
6
|
+
UNTIL = :until
|
7
|
+
FROM = :from
|
8
|
+
LIMITED = :limited
|
9
|
+
BETWEEN = :between
|
10
|
+
|
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
|
28
|
+
end
|
29
|
+
|
30
|
+
matched
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def validate!(target_year, year_ranges)
|
36
|
+
raise ArgumentError.new("target_year must be a number") unless target_year.is_a?(Integer)
|
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
|
39
|
+
|
40
|
+
operator = year_ranges.keys.first
|
41
|
+
value = year_ranges[operator]
|
42
|
+
|
43
|
+
raise ArgumentError.new("Invalid operator found: '#{operator}'") unless [UNTIL, FROM, LIMITED, BETWEEN].include?(operator)
|
44
|
+
|
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)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,22 +1,14 @@
|
|
1
1
|
module Holidays
|
2
|
+
#TODO This file should be renamed. It's no longer about definitions, really.
|
2
3
|
class LoadAllDefinitions
|
3
4
|
class << self
|
4
5
|
def call
|
5
|
-
path = File.expand_path(File.dirname(__FILE__)) + "/../#{Holidays::DEFINITIONS_PATH}/"
|
6
|
-
|
7
|
-
Dir.foreach(path) do |item|
|
8
|
-
next if item == '.' or item == '..'
|
9
|
-
|
10
|
-
target = path+item
|
11
|
-
next if File.extname(target) != '.rb'
|
12
|
-
|
13
|
-
require target
|
14
|
-
end
|
15
|
-
|
16
6
|
#FIXME I need a better way to do this. I'm thinking of putting these 'common' methods
|
17
7
|
# into some kind of definition file so it can be loaded automatically but I'm afraid
|
18
8
|
# of making that big of a breaking API change since these are public. For the time
|
19
9
|
# being I'll load them manually like this.
|
10
|
+
#
|
11
|
+
# NOTE: These are no longer public! We can do whatever we want here!
|
20
12
|
global_methods = {
|
21
13
|
"easter(year)" => gregorian_easter.method(:calculate_easter_for).to_proc,
|
22
14
|
"orthodox_easter(year)" => gregorian_easter.method(:calculate_orthodox_easter_for).to_proc,
|
@@ -28,29 +20,36 @@ module Holidays
|
|
28
20
|
"to_weekday_if_weekend(date)" => weekend_modifier.method(:to_weekday_if_weekend).to_proc,
|
29
21
|
"calculate_day_of_month(year, month, day, wday)" => day_of_month_calculator.method(:call).to_proc,
|
30
22
|
"to_weekday_if_boxing_weekend_from_year_or_to_tuesday_if_monday(year)" => weekend_modifier.method(:to_weekday_if_boxing_weekend_from_year_or_to_tuesday_if_monday).to_proc,
|
31
|
-
"xmas_to_weekday_if_weekend(year)" => weekend_modifier.method(:xmas_to_weekday_if_weekend).to_proc,
|
32
23
|
"to_tuesday_if_sunday_or_monday_if_saturday(date)" => weekend_modifier.method(:to_tuesday_if_sunday_or_monday_if_saturday).to_proc,
|
24
|
+
"lunar_to_solar(year, month, day, region)" => lunar_date.method(:to_solar).to_proc,
|
33
25
|
}
|
34
26
|
|
35
|
-
|
27
|
+
Factory::Definition.custom_methods_repository.add(global_methods)
|
28
|
+
|
29
|
+
static_regions_definition = "#{Holidays::DEFINITIONS_PATH}/REGIONS.rb"
|
30
|
+
require static_regions_definition
|
36
31
|
end
|
37
32
|
|
38
33
|
private
|
39
34
|
|
40
35
|
def gregorian_easter
|
41
|
-
|
36
|
+
Factory::DateCalculator::Easter::Gregorian.easter_calculator
|
42
37
|
end
|
43
38
|
|
44
39
|
def julian_easter
|
45
|
-
|
40
|
+
Factory::DateCalculator::Easter::Julian.easter_calculator
|
46
41
|
end
|
47
42
|
|
48
43
|
def weekend_modifier
|
49
|
-
|
44
|
+
Factory::DateCalculator.weekend_modifier
|
50
45
|
end
|
51
46
|
|
52
47
|
def day_of_month_calculator
|
53
|
-
|
48
|
+
Factory::DateCalculator.day_of_month_calculator
|
49
|
+
end
|
50
|
+
|
51
|
+
def lunar_date
|
52
|
+
Factory::DateCalculator.lunar_date
|
54
53
|
end
|
55
54
|
end
|
56
55
|
end
|
data/lib/holidays/version.rb
CHANGED
data/lib/holidays.rb
CHANGED
@@ -3,51 +3,12 @@ $:.unshift File.dirname(__FILE__)
|
|
3
3
|
|
4
4
|
require 'date'
|
5
5
|
require 'digest/md5'
|
6
|
-
require 'holidays/
|
7
|
-
require 'holidays/
|
8
|
-
require 'holidays/
|
9
|
-
require 'holidays/use_case_factory'
|
6
|
+
require 'holidays/factory/definition'
|
7
|
+
require 'holidays/factory/date_calculator'
|
8
|
+
require 'holidays/factory/finder'
|
10
9
|
require 'holidays/errors'
|
11
10
|
require 'holidays/load_all_definitions'
|
12
11
|
|
13
|
-
# == Region options
|
14
|
-
# Holidays can be defined as belonging to one or more regions and sub regions.
|
15
|
-
# The Holidays#on, Holidays#between, Date#holidays and Date#holiday? methods
|
16
|
-
# each allow you to specify a specific region.
|
17
|
-
#
|
18
|
-
# There are several different ways that you can specify a region:
|
19
|
-
#
|
20
|
-
# [<tt>:region</tt>]
|
21
|
-
# By region. For example, return holidays in the Canada with <tt>:ca</tt>.
|
22
|
-
# [<tt>:region_</tt>]
|
23
|
-
# By region and sub regions. For example, return holidays in Germany
|
24
|
-
# and all its sub regions with <tt>:de_</tt>.
|
25
|
-
# [<tt>:region_sub</tt>]
|
26
|
-
# By sub region. Return national holidays in Spain plus holidays in Spain's
|
27
|
-
# Valencia region with <tt>:es_v</tt>.
|
28
|
-
# [<tt>:any</tt>]
|
29
|
-
# Any region. Return holidays from any loaded region.
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# You can load all the available holiday definition sets by running
|
33
|
-
# Holidays.load_all
|
34
|
-
# == Other options
|
35
|
-
# [<tt>:observed</tt>] Return holidays on the day they are observed (e.g. on a Monday if they fall on a Sunday).
|
36
|
-
# [<tt>:informal</tt>] Include informal holidays (e.g. Valentine's Day)
|
37
|
-
#
|
38
|
-
# == Examples
|
39
|
-
# Return all holidays in the <tt>:ca</tt> and <tt>:us</tt> regions on the day that they are
|
40
|
-
# observed.
|
41
|
-
#
|
42
|
-
# Holidays.between(from, to, :ca, :us, :observed)
|
43
|
-
#
|
44
|
-
# Return all holidays in <tt>:ca</tt> and any <tt>:ca</tt> sub-region.
|
45
|
-
#
|
46
|
-
# Holidays.between(from, to, :ca_)
|
47
|
-
#
|
48
|
-
# Return all holidays in <tt>:ca_bc</tt> sub-region (which includes the <tt>:ca</tt>), including informal holidays.
|
49
|
-
#
|
50
|
-
# Holidays.between(from, to, :ca_bc, :informal)
|
51
12
|
module Holidays
|
52
13
|
WEEKS = {:first => 1, :second => 2, :third => 3, :fourth => 4, :fifth => 5, :last => -1, :second_last => -2, :third_last => -3}
|
53
14
|
MONTH_LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
@@ -57,52 +18,19 @@ module Holidays
|
|
57
18
|
FULL_DEFINITIONS_PATH = File.expand_path(File.dirname(__FILE__) + "/#{DEFINITIONS_PATH}")
|
58
19
|
|
59
20
|
class << self
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
#
|
68
|
-
# Also available via Date#holidays.
|
69
|
-
def on(date, *options)
|
70
|
-
between(date, date, options)
|
21
|
+
def any_holidays_during_work_week?(date, *options)
|
22
|
+
monday = date - (date.wday - 1)
|
23
|
+
friday = date + (5 - date.wday)
|
24
|
+
|
25
|
+
holidays = between(monday, friday, *options)
|
26
|
+
|
27
|
+
holidays && holidays.count > 0
|
71
28
|
end
|
72
29
|
|
73
|
-
|
74
|
-
|
75
|
-
# [<tt>date</tt>] A Date object.
|
76
|
-
# [<tt>:options</tt>] One or more region symbols, and/or <tt>:informal</tt>. Automatically includes <tt>:observed</tt>. If you don't want this, pass <tt>:no_observed</tt>
|
77
|
-
#
|
78
|
-
# The given Date can be any day of the week.
|
79
|
-
# Returns true if any holidays fall on Monday - Friday of the given week.
|
80
|
-
def any_holidays_during_work_week?(date, *options)
|
81
|
-
days_to_monday = date.wday - 1
|
82
|
-
days_to_friday = 5 - date.wday
|
83
|
-
start_date = date - days_to_monday
|
84
|
-
end_date = date + days_to_friday
|
85
|
-
options += [:observed] unless options.include?(:no_observed)
|
86
|
-
options.delete(:no_observed)
|
87
|
-
between(start_date, end_date, options).empty?
|
30
|
+
def on(date, *options)
|
31
|
+
between(date, date, *options)
|
88
32
|
end
|
89
33
|
|
90
|
-
# Get all holidays occuring between two dates, inclusively.
|
91
|
-
#
|
92
|
-
# Returns an array of hashes or nil.
|
93
|
-
#
|
94
|
-
# Each holiday is returned as a hash with the following fields:
|
95
|
-
# [<tt>start_date</tt>] Ruby Date object.
|
96
|
-
# [<tt>end_date</tt>] Ruby Date object.
|
97
|
-
# [<tt>options</tt>] One or more region symbols, <tt>:informal</tt> and/or <tt>:observed</tt>.
|
98
|
-
#
|
99
|
-
# ==== Example
|
100
|
-
# from = Date.civil(2008,7,1)
|
101
|
-
# to = Date.civil(2008,7,31)
|
102
|
-
#
|
103
|
-
# Holidays.between(from, to, :ca, :us)
|
104
|
-
# => [{:name => 'Canada Day', :regions => [:ca]...}
|
105
|
-
# {:name => 'Independence Day'', :regions => [:us], ...}]
|
106
34
|
def between(start_date, end_date, *options)
|
107
35
|
raise ArgumentError unless start_date && end_date
|
108
36
|
|
@@ -112,35 +40,18 @@ module Holidays
|
|
112
40
|
|
113
41
|
start_date, end_date = get_date(start_date), get_date(end_date)
|
114
42
|
|
115
|
-
if
|
43
|
+
raise ArgumentError if end_date < start_date
|
44
|
+
|
45
|
+
if cached_holidays = Factory::Definition.cache_repository.find(start_date, end_date, options)
|
116
46
|
return cached_holidays
|
117
47
|
end
|
118
48
|
|
119
|
-
|
120
|
-
date_driver_hash = UseCaseFactory.dates_driver_builder.call(start_date, end_date)
|
121
|
-
|
122
|
-
UseCaseFactory.between.call(start_date, end_date, date_driver_hash, regions, observed, informal)
|
49
|
+
Factory::Finder.between.call(start_date, end_date, options)
|
123
50
|
end
|
124
51
|
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
# Incoming arguments are below:
|
130
|
-
# [<tt>holidays_count</tt>] Ruby Numeric object. This is the number of holidays to return
|
131
|
-
# [<tt>options</tt>] One or more region symbols, <tt>:informal</tt> and/or <tt>:observed</tt>.
|
132
|
-
# [<tt>from_date</tt>] Ruby Date object. This is an optional param, defaulted today.
|
133
|
-
#
|
134
|
-
# ==== Example
|
135
|
-
# Date.today
|
136
|
-
# => Tue, 23 Feb 2016
|
137
|
-
#
|
138
|
-
# regions = [:us, :informal]
|
139
|
-
#
|
140
|
-
# Holidays.next_holidays(3, regions)
|
141
|
-
# => [{:name => "St. Patrick's Day",...},
|
142
|
-
# {:name => "Good Friday",...},
|
143
|
-
# {:name => "Easter Sunday",...}]
|
52
|
+
#FIXME All other methods start with a date and require a date. For the next
|
53
|
+
# major version bump we should take the opportunity to change this
|
54
|
+
# signature to match, e.g. next_holidays(from_date, count, options)
|
144
55
|
def next_holidays(holidays_count, options, from_date = Date.today)
|
145
56
|
raise ArgumentError unless holidays_count
|
146
57
|
raise ArgumentError if options.empty?
|
@@ -150,42 +61,60 @@ module Holidays
|
|
150
61
|
from_date = from_date.new_offset(0) + from_date.offset if from_date.respond_to?(:new_offset)
|
151
62
|
|
152
63
|
from_date = get_date(from_date)
|
153
|
-
regions, observed, informal = OptionFactory.parse_options.call(options)
|
154
64
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
65
|
+
Factory::Finder.next_holiday.call(holidays_count, from_date, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
#FIXME All other methods start with a date and require a date. For the next
|
69
|
+
# major version bump we should take the opportunity to change this
|
70
|
+
# signature to match, e.g. year_holidays(from_date, options)
|
71
|
+
def year_holidays(options, from_date = Date.today)
|
72
|
+
raise ArgumentError if options.empty?
|
73
|
+
raise ArgumentError unless options.is_a?(Array)
|
74
|
+
|
75
|
+
# remove the timezone
|
76
|
+
from_date = from_date.new_offset(0) + from_date.offset if from_date.respond_to?(:new_offset)
|
77
|
+
from_date = get_date(from_date)
|
159
78
|
|
160
|
-
|
79
|
+
Factory::Finder.year_holiday.call(from_date, options)
|
161
80
|
end
|
162
81
|
|
163
|
-
# Allows a developer to explicitly calculate and cache holidays within a given period
|
164
82
|
def cache_between(start_date, end_date, *options)
|
165
83
|
start_date, end_date = get_date(start_date), get_date(end_date)
|
166
84
|
cache_data = between(start_date, end_date, *options)
|
167
85
|
|
168
|
-
|
86
|
+
Factory::Definition.cache_repository.cache_between(start_date, end_date, cache_data, options)
|
169
87
|
end
|
170
88
|
|
171
|
-
# Returns an array of symbols of all the available holiday regions.
|
172
89
|
def available_regions
|
173
90
|
Holidays::REGIONS
|
174
91
|
end
|
175
92
|
|
176
|
-
# Parses provided holiday definition file(s) and loads them so that they are immediately available.
|
177
93
|
def load_custom(*files)
|
178
|
-
regions, rules_by_month, custom_methods,
|
94
|
+
regions, rules_by_month, custom_methods, _ = Factory::Definition.file_parser.parse_definition_files(files)
|
179
95
|
|
180
96
|
custom_methods.each do |method_key, method_entity|
|
181
|
-
custom_methods[method_key] =
|
97
|
+
custom_methods[method_key] = Factory::Definition.custom_method_proc_decorator.call(method_entity)
|
182
98
|
end
|
183
99
|
|
184
|
-
|
100
|
+
Factory::Definition.merger.call(regions, rules_by_month, custom_methods)
|
185
101
|
|
186
102
|
rules_by_month
|
187
103
|
end
|
188
104
|
|
105
|
+
def load_all
|
106
|
+
path = FULL_DEFINITIONS_PATH + "/"
|
107
|
+
|
108
|
+
Dir.foreach(path) do |item|
|
109
|
+
next if item == '.' or item == '..'
|
110
|
+
|
111
|
+
target = path+item
|
112
|
+
next if File.extname(target) != '.rb'
|
113
|
+
|
114
|
+
require target
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
189
118
|
private
|
190
119
|
|
191
120
|
def get_date(date)
|
@@ -195,10 +124,6 @@ module Holidays
|
|
195
124
|
Date.civil(date.year, date.mon, date.mday)
|
196
125
|
end
|
197
126
|
end
|
198
|
-
|
199
|
-
def definition_cache_repository
|
200
|
-
DefinitionFactory.cache_repository
|
201
|
-
end
|
202
127
|
end
|
203
128
|
end
|
204
129
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
# For reasons I don't understand jruby implementations report lower coverage
|
4
|
+
# than other ruby versions. Ruby 2.5.3, for instance, is at 92%.
|
5
|
+
#
|
6
|
+
# We set the floor based on jruby so that all automated tests pass on Travis CI.
|
7
|
+
SimpleCov.minimum_coverage 89
|
8
|
+
|
9
|
+
SimpleCov.add_filter [
|
10
|
+
# Apparently simplecov doesn't automatically filter 'spec' or 'test' so we
|
11
|
+
# have to do it manually.
|
12
|
+
'test',
|
13
|
+
|
14
|
+
# Only filtered because I tend to not see value in testing factories.
|
15
|
+
'lib/holidays/factory/',
|
16
|
+
|
17
|
+
# jruby coverage flips out here and doesn't count much of the large date
|
18
|
+
# arrays used by this class. This results in an extremely low reported
|
19
|
+
# coverage for this specific file but only in jruby, not other ruby versions.
|
20
|
+
# Since it obliterates coverage percentages I'll filter it until I can come
|
21
|
+
# up with a solution.
|
22
|
+
'lib/holidays/date_calculator/lunar_date.rb',
|
23
|
+
]
|
24
|
+
|
25
|
+
SimpleCov.coverage_dir 'reports/coverage'
|
26
|
+
SimpleCov.start
|
@@ -4,25 +4,28 @@ months:
|
|
4
4
|
regions: [custom_year_range_file]
|
5
5
|
mday: 1
|
6
6
|
year_ranges:
|
7
|
-
|
7
|
+
from: 2016
|
8
8
|
- name: before_year
|
9
9
|
regions: [custom_year_range_file]
|
10
10
|
mday: 2
|
11
11
|
year_ranges:
|
12
|
-
|
12
|
+
until: 2017
|
13
13
|
- name: between_year
|
14
14
|
regions: [custom_year_range_file]
|
15
15
|
mday: 3
|
16
16
|
year_ranges:
|
17
|
-
|
17
|
+
between:
|
18
|
+
start: 2016
|
19
|
+
end: 2018
|
18
20
|
- name: limited_year
|
19
21
|
regions: [custom_year_range_file]
|
20
22
|
mday: 4
|
21
23
|
year_ranges:
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
limited: [2016,2018,2019]
|
25
|
+
|
26
|
+
tests:
|
27
|
+
- given:
|
28
|
+
date: '2017-01-01'
|
29
|
+
regions: [custom_year_range_file]
|
30
|
+
expect:
|
31
|
+
name: "after_year"
|
@@ -3,7 +3,10 @@ months:
|
|
3
3
|
- name: Company Founding!
|
4
4
|
regions: [custom_multiple_files]
|
5
5
|
mday: 5
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
|
7
|
+
tests:
|
8
|
+
- given:
|
9
|
+
date: "2013-10-5"
|
10
|
+
regions: ["custom_multiple_files"]
|
11
|
+
expect:
|
12
|
+
name: "Company Founding!"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
months:
|
2
|
+
0:
|
3
|
+
- name: With Function Modifier
|
4
|
+
regions: [multiple_with_conflict_1]
|
5
|
+
function: easter(year)
|
6
|
+
function_modifier: 60
|
7
|
+
- name: With Function Only Different Function Name
|
8
|
+
regions: [multiple_with_conflict_1]
|
9
|
+
function: conflict_custom_method_1(year)
|
10
|
+
- name: With Function Only Same Function Name
|
11
|
+
regions: [multiple_with_conflict_1]
|
12
|
+
function: conflict_custom_method_identical_name_between_regions(year)
|
13
|
+
- name: With Function Only Same Function Name - Region 1
|
14
|
+
regions: [multiple_with_conflict_1]
|
15
|
+
function: conflict_custom_method_identical_name_between_regions_but_different_holiday_names(year)
|
16
|
+
1:
|
17
|
+
- name: New Year's Day
|
18
|
+
regions: [multiple_with_conflict_1]
|
19
|
+
mday: 1
|
20
|
+
observed: to_monday_if_weekend(date)
|
21
|
+
10:
|
22
|
+
- name: Testing Conflict Month 10
|
23
|
+
regions: [multiple_with_conflict_1]
|
24
|
+
mday: 5
|
25
|
+
|
26
|
+
methods:
|
27
|
+
conflict_custom_method_1:
|
28
|
+
arguments: year
|
29
|
+
ruby: |
|
30
|
+
Date.civil(year, 8, 1)
|
31
|
+
conflict_custom_method_identical_name_between_regions:
|
32
|
+
arguments: year
|
33
|
+
ruby: |
|
34
|
+
Date.civil(year, 9, 1)
|
35
|
+
conflict_custom_method_identical_name_between_regions_but_different_holiday_names:
|
36
|
+
arguments: year
|
37
|
+
ruby: |
|
38
|
+
Date.civil(year, 9, 15)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
months:
|
2
|
+
0:
|
3
|
+
- name: With Function Modifier
|
4
|
+
regions: [multiple_with_conflict_2]
|
5
|
+
function: easter(year)
|
6
|
+
function_modifier: 64
|
7
|
+
- name: With Function Only Different Function Name
|
8
|
+
regions: [multiple_with_conflict_2]
|
9
|
+
function: conflict_custom_method_2(year)
|
10
|
+
- name: With Function Only Same Function Name
|
11
|
+
regions: [multiple_with_conflict_2]
|
12
|
+
function: conflict_custom_method_identical_name_between_regions(year)
|
13
|
+
- name: With Function Only Same Function Name - Region 2
|
14
|
+
regions: [multiple_with_conflict_2]
|
15
|
+
function: conflict_custom_method_identical_name_between_regions_but_different_holiday_names(year)
|
16
|
+
1:
|
17
|
+
- name: New Year's Day
|
18
|
+
regions: [multiple_with_conflict_2]
|
19
|
+
mday: 1
|
20
|
+
observed: to_tuesday_if_sunday_or_monday_if_saturday(date)
|
21
|
+
10:
|
22
|
+
- name: Testing Conflict Month 10
|
23
|
+
regions: [multiple_with_conflict_2]
|
24
|
+
mday: 7
|
25
|
+
|
26
|
+
methods:
|
27
|
+
conflict_custom_method_2:
|
28
|
+
arguments: year
|
29
|
+
ruby: |
|
30
|
+
Date.civil(year, 12, 1)
|
31
|
+
conflict_custom_method_identical_name_between_regions:
|
32
|
+
arguments: year
|
33
|
+
ruby: |
|
34
|
+
Date.civil(year, 11, 1)
|
35
|
+
conflict_custom_method_identical_name_between_regions_but_different_holiday_names:
|
36
|
+
arguments: year
|
37
|
+
ruby: |
|
38
|
+
Date.civil(year, 11, 15)
|
@@ -3,7 +3,10 @@ months:
|
|
3
3
|
- name: Company Founding
|
4
4
|
regions: [custom_single_file]
|
5
5
|
mday: 20
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
|
7
|
+
tests:
|
8
|
+
- given:
|
9
|
+
date: '2013-06-20'
|
10
|
+
regions: [custom_single_file]
|
11
|
+
expect:
|
12
|
+
name: "Company Founding"
|
@@ -14,11 +14,15 @@ methods:
|
|
14
14
|
source: |
|
15
15
|
d = Date.civil(year, month, 1)
|
16
16
|
d + 2
|
17
|
-
tests: |
|
18
|
-
{Date.civil(2013,6,20) => 'Company Founding'}.each do |date, name|
|
19
|
-
assert_equal name, (Holidays.on(date, :custom_single_file)[0] || {})[:name]
|
20
|
-
end
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
tests:
|
19
|
+
- given:
|
20
|
+
date: '2013-06-20'
|
21
|
+
regions: [custom_single_file]
|
22
|
+
expect:
|
23
|
+
name: "Company Founding"
|
24
|
+
- given:
|
25
|
+
date: '2015-01-01'
|
26
|
+
regions: [custom_single_file]
|
27
|
+
expect:
|
28
|
+
name: "Custom Holiday"
|