holidays 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +22 -8
- data/Rakefile +26 -8
- data/bin/console +7 -0
- data/bin/setup +5 -0
- data/{data → definitions}/SYNTAX.rdoc +0 -0
- data/{data → definitions}/ar.yaml +0 -0
- data/{data → definitions}/at.yaml +1 -1
- data/{data → definitions}/au.yaml +80 -51
- data/{data → definitions}/be.yaml +0 -0
- data/{data → definitions}/br.yaml +0 -0
- data/{data → definitions}/ca.yaml +0 -0
- data/{data → definitions}/ch.yaml +0 -0
- data/{data → definitions}/cl.yaml +0 -0
- data/{data → definitions}/cr.yaml +0 -0
- data/{data → definitions}/cz.yaml +0 -0
- data/{data → definitions}/de.yaml +25 -34
- data/{data → definitions}/dk.yaml +0 -0
- data/{data → definitions}/ecb_target.yaml +2 -2
- data/{data → definitions}/el.yaml +0 -0
- data/{data → definitions}/es.yaml +37 -26
- data/{data → definitions}/federal_reserve.yaml +0 -0
- data/{data → definitions}/fedex.yaml +9 -3
- data/{data → definitions}/fi.yaml +0 -0
- data/{data → definitions}/fr.yaml +0 -0
- data/{data → definitions}/gb.yaml +19 -19
- data/{data → definitions}/hr.yaml +0 -0
- data/{data → definitions}/hu.yaml +1 -1
- data/{data → definitions}/ie.yaml +0 -0
- data/{data → definitions}/index.yaml +0 -0
- data/{data → definitions}/is.yaml +0 -0
- data/{data → definitions}/it.yaml +0 -0
- data/{data → definitions}/jp.yaml +3 -3
- data/{data → definitions}/li.yaml +3 -3
- data/{data → definitions}/lt.yaml +0 -0
- data/{data → definitions}/ma.yaml +0 -0
- data/{data → definitions}/mx.yaml +0 -0
- data/{data → definitions}/nerc.yaml +0 -0
- data/{data → definitions}/nl.yaml +0 -0
- data/{data → definitions}/no.yaml +0 -0
- data/{data → definitions}/north_america_informal.yaml +0 -0
- data/{data → definitions}/nyse.yaml +0 -0
- data/{data → definitions}/nz.yaml +21 -10
- data/{data → definitions}/ph.yaml +0 -0
- data/{data → definitions}/pl.yaml +0 -0
- data/{data → definitions}/pt.yaml +0 -0
- data/{data → definitions}/ro.yaml +1 -2
- data/{data → definitions}/se.yaml +0 -0
- data/{data → definitions}/sg.yaml +0 -0
- data/{data → definitions}/si.yaml +6 -6
- data/{data → definitions}/sk.yaml +0 -0
- data/{data → definitions}/united_nations.yaml +0 -0
- data/{data → definitions}/ups.yaml +17 -11
- data/{data → definitions}/us.yaml +20 -15
- data/{data → definitions}/ve.yaml +0 -0
- data/{data → definitions}/vi.yaml +0 -0
- data/{data → definitions}/za.yaml +0 -0
- data/holidays.gemspec +2 -1
- data/lib/generated_definitions/MANIFEST +56 -0
- data/lib/generated_definitions/REGIONS.rb +4 -0
- data/lib/{holidays → generated_definitions}/ar.rb +2 -2
- data/lib/{holidays → generated_definitions}/at.rb +2 -2
- data/lib/{holidays → generated_definitions}/au.rb +19 -10
- data/lib/{holidays → generated_definitions}/be.rb +2 -2
- data/lib/{holidays → generated_definitions}/br.rb +2 -2
- data/lib/{holidays → generated_definitions}/ca.rb +2 -2
- data/lib/{holidays → generated_definitions}/ch.rb +2 -2
- data/lib/{holidays → generated_definitions}/cl.rb +2 -2
- data/lib/{holidays → generated_definitions}/cr.rb +2 -2
- data/lib/{holidays → generated_definitions}/cz.rb +2 -2
- data/lib/{holidays → generated_definitions}/de.rb +5 -4
- data/lib/{holidays → generated_definitions}/dk.rb +2 -2
- data/lib/{holidays → generated_definitions}/ecb_target.rb +2 -2
- data/lib/{holidays → generated_definitions}/el.rb +2 -2
- data/lib/{holidays → generated_definitions}/es.rb +6 -6
- data/lib/{holidays → generated_definitions}/europe.rb +7 -6
- data/lib/{holidays → generated_definitions}/fed_ex.rb +8 -3
- data/lib/{holidays → generated_definitions}/federal_reserve.rb +2 -2
- data/lib/{holidays → generated_definitions}/fi.rb +2 -2
- data/lib/{holidays → generated_definitions}/fr.rb +2 -2
- data/lib/{holidays → generated_definitions}/gb.rb +2 -2
- data/lib/{holidays → generated_definitions}/hr.rb +2 -2
- data/lib/{holidays → generated_definitions}/hu.rb +2 -2
- data/lib/{holidays → generated_definitions}/ie.rb +2 -2
- data/lib/{holidays → generated_definitions}/is.rb +2 -2
- data/lib/{holidays → generated_definitions}/it.rb +2 -2
- data/lib/{holidays → generated_definitions}/jp.rb +5 -5
- data/lib/{holidays → generated_definitions}/li.rb +2 -2
- data/lib/{holidays → generated_definitions}/lt.rb +2 -2
- data/lib/{holidays → generated_definitions}/ma.rb +2 -2
- data/lib/{holidays → generated_definitions}/mx.rb +2 -2
- data/lib/{holidays → generated_definitions}/nerc.rb +2 -2
- data/lib/{holidays → generated_definitions}/nl.rb +2 -2
- data/lib/{holidays → generated_definitions}/no.rb +2 -2
- data/lib/{holidays → generated_definitions}/north_america.rb +8 -3
- data/lib/{holidays → generated_definitions}/nyse.rb +2 -2
- data/lib/{holidays → generated_definitions}/nz.rb +5 -5
- data/lib/{holidays → generated_definitions}/ph.rb +2 -2
- data/lib/{holidays → generated_definitions}/pl.rb +2 -2
- data/lib/{holidays → generated_definitions}/pt.rb +2 -2
- data/lib/{holidays → generated_definitions}/ro.rb +2 -2
- data/lib/{holidays → generated_definitions}/scandinavia.rb +2 -2
- data/lib/{holidays → generated_definitions}/se.rb +2 -2
- data/lib/{holidays → generated_definitions}/sg.rb +2 -2
- data/lib/{holidays → generated_definitions}/si.rb +2 -2
- data/lib/{holidays → generated_definitions}/sk.rb +2 -2
- data/lib/{holidays → generated_definitions}/united_nations.rb +2 -2
- data/lib/{holidays → generated_definitions}/ups.rb +8 -3
- data/lib/{holidays → generated_definitions}/us.rb +8 -3
- data/lib/{holidays → generated_definitions}/ve.rb +2 -2
- data/lib/{holidays → generated_definitions}/vi.rb +2 -2
- data/lib/{holidays → generated_definitions}/za.rb +2 -2
- data/lib/holidays.rb +120 -665
- data/lib/holidays/core_extensions/date.rb +39 -0
- data/lib/holidays/date_calculator/day_of_month.rb +68 -0
- data/lib/holidays/date_calculator/easter.rb +58 -0
- data/lib/holidays/date_calculator/weekend_modifier.rb +49 -0
- data/lib/holidays/date_calculator_factory.rb +21 -0
- data/lib/holidays/definition/context/generator.rb +216 -0
- data/lib/holidays/definition/context/merger.rb +26 -0
- data/lib/holidays/definition/repository/cache.rb +33 -0
- data/lib/holidays/definition/repository/holidays_by_month.rb +49 -0
- data/lib/holidays/definition/repository/proc_cache.rb +36 -0
- data/lib/holidays/definition/repository/regions.rb +36 -0
- data/lib/holidays/definition/validator/region.rb +45 -0
- data/lib/holidays/definition_factory.rb +50 -0
- data/lib/holidays/option/context/parse_options.rb +96 -0
- data/lib/holidays/option_factory.rb +14 -0
- data/lib/holidays/use_case/context/between.rb +105 -0
- data/lib/holidays/use_case/context/dates_driver_builder.rb +64 -0
- data/lib/holidays/use_case_factory.rb +20 -0
- data/lib/holidays/version.rb +1 -1
- data/test/defs/test_defs_ar.rb +1 -1
- data/test/defs/test_defs_at.rb +2 -2
- data/test/defs/test_defs_au.rb +61 -43
- data/test/defs/test_defs_be.rb +1 -1
- data/test/defs/test_defs_br.rb +1 -1
- data/test/defs/test_defs_ca.rb +1 -1
- data/test/defs/test_defs_ch.rb +1 -1
- data/test/defs/test_defs_cl.rb +1 -1
- data/test/defs/test_defs_cr.rb +1 -1
- data/test/defs/test_defs_cz.rb +1 -1
- data/test/defs/test_defs_de.rb +18 -30
- data/test/defs/test_defs_dk.rb +1 -1
- data/test/defs/test_defs_ecb_target.rb +3 -3
- data/test/defs/test_defs_el.rb +1 -1
- data/test/defs/test_defs_es.rb +36 -25
- data/test/defs/test_defs_europe.rb +82 -84
- data/test/defs/test_defs_fed_ex.rb +4 -1
- data/test/defs/test_defs_federal_reserve.rb +1 -1
- data/test/defs/test_defs_fi.rb +1 -1
- data/test/defs/test_defs_fr.rb +1 -1
- data/test/defs/test_defs_gb.rb +20 -20
- data/test/defs/test_defs_hr.rb +1 -1
- data/test/defs/test_defs_hu.rb +2 -2
- data/test/defs/test_defs_ie.rb +1 -1
- data/test/defs/test_defs_is.rb +1 -1
- data/test/defs/test_defs_it.rb +1 -1
- data/test/defs/test_defs_jp.rb +1 -1
- data/test/defs/test_defs_li.rb +4 -4
- data/test/defs/test_defs_lt.rb +1 -1
- data/test/defs/test_defs_ma.rb +1 -1
- data/test/defs/test_defs_mx.rb +1 -1
- data/test/defs/test_defs_nerc.rb +1 -1
- data/test/defs/test_defs_nl.rb +1 -1
- data/test/defs/test_defs_no.rb +1 -1
- data/test/defs/test_defs_north_america.rb +5 -3
- data/test/defs/test_defs_nyse.rb +1 -1
- data/test/defs/test_defs_nz.rb +19 -9
- data/test/defs/test_defs_ph.rb +1 -1
- data/test/defs/test_defs_pl.rb +1 -1
- data/test/defs/test_defs_pt.rb +1 -1
- data/test/defs/test_defs_ro.rb +2 -3
- data/test/defs/test_defs_scandinavia.rb +1 -1
- data/test/defs/test_defs_se.rb +1 -1
- data/test/defs/test_defs_sg.rb +1 -1
- data/test/defs/test_defs_si.rb +7 -7
- data/test/defs/test_defs_sk.rb +1 -1
- data/test/defs/test_defs_united_nations.rb +1 -1
- data/test/defs/test_defs_ups.rb +5 -2
- data/test/defs/test_defs_us.rb +5 -3
- data/test/defs/test_defs_ve.rb +1 -1
- data/test/defs/test_defs_vi.rb +1 -1
- data/test/defs/test_defs_za.rb +1 -1
- data/test/{test_date.rb → holidays/core_extensions/test_date.rb} +8 -2
- data/test/holidays/date_calculator/test_day_of_month.rb +27 -0
- data/test/holidays/date_calculator/test_easter.rb +29 -0
- data/test/holidays/date_calculator/test_weekend_modifier.rb +33 -0
- data/test/holidays/definition/context/test_generator.rb +84 -0
- data/test/holidays/definition/context/test_merger.rb +22 -0
- data/test/holidays/definition/repository/test_cache.rb +82 -0
- data/test/holidays/definition/repository/test_holidays_by_month.rb +187 -0
- data/test/holidays/definition/repository/test_proc_cache.rb +29 -0
- data/test/holidays/definition/repository/test_regions.rb +86 -0
- data/test/holidays/definition/validator/test_region.rb +50 -0
- data/test/holidays/option/context/test_parse_options.rb +69 -0
- data/test/holidays/test_date_calculator_factory.rb +21 -0
- data/test/holidays/test_definition_factory.rb +34 -0
- data/test/holidays/test_option_factory.rb +9 -0
- data/test/holidays/test_use_case_factory.rb +13 -0
- data/test/holidays/use_case/context/test_between.rb +75 -0
- data/test/holidays/use_case/context/test_dates_driver_builder.rb +91 -0
- data/test/test_all_regions.rb +14 -3
- data/test/test_helper.rb +2 -1
- data/test/test_holidays.rb +19 -24
- data/test/test_holidays_between.rb +85 -0
- data/test/test_multiple_regions.rb +2 -2
- data/test/test_parse_definitions.rb +10 -4
- metadata +181 -111
- data/.coveralls.yml +0 -1
- data/lib/holidays/MANIFEST +0 -55
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Holidays
|
|
2
|
+
module CoreExtensions
|
|
3
|
+
module Date
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Get holidays on the current date.
|
|
9
|
+
#
|
|
10
|
+
# Returns an array of hashes or nil. See Holidays#between for options
|
|
11
|
+
# and the output format.
|
|
12
|
+
#
|
|
13
|
+
# Date.civil('2008-01-01').holidays(:ca_)
|
|
14
|
+
# => [{:name => 'New Year\'s Day',...}]
|
|
15
|
+
#
|
|
16
|
+
# Also available via Holidays#on.
|
|
17
|
+
def holidays(*options)
|
|
18
|
+
Holidays.on(self, options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Check if the current date is a holiday.
|
|
22
|
+
#
|
|
23
|
+
# Returns true or false.
|
|
24
|
+
#
|
|
25
|
+
# Date.civil('2008-01-01').holiday?(:ca)
|
|
26
|
+
# => true
|
|
27
|
+
def holiday?(*options)
|
|
28
|
+
holidays = self.holidays(options)
|
|
29
|
+
holidays && !holidays.empty?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module ClassMethods
|
|
33
|
+
def calculate_mday(year, month, week, wday)
|
|
34
|
+
Holidays::DateCalculatorFactory.day_of_month_calculator.call(year, month, week, wday)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Holidays
|
|
2
|
+
module DateCalculator
|
|
3
|
+
# Calculate day of the month based on the week number and the day of the
|
|
4
|
+
# week.
|
|
5
|
+
#
|
|
6
|
+
# ==== Parameters
|
|
7
|
+
# [<tt>year</tt>] Integer.
|
|
8
|
+
# [<tt>month</tt>] Integer from 1-12.
|
|
9
|
+
# [<tt>week</tt>] One of <tt>:first</tt>, <tt>:second</tt>, <tt>:third</tt>,
|
|
10
|
+
# <tt>:fourth</tt>, <tt>:fifth</tt> or <tt>:last</tt>.
|
|
11
|
+
# [<tt>wday</tt>] Day of the week as an integer from 0 (Sunday) to 6
|
|
12
|
+
# (Saturday) or as a symbol (e.g. <tt>:monday</tt>).
|
|
13
|
+
#
|
|
14
|
+
# Returns an integer.
|
|
15
|
+
#
|
|
16
|
+
# ===== Examples
|
|
17
|
+
# First Monday of January, 2008:
|
|
18
|
+
# Date.calculate_mday(2008, 1, :first, :monday)
|
|
19
|
+
# => 7
|
|
20
|
+
#
|
|
21
|
+
# Third Thursday of December, 2008:
|
|
22
|
+
# Date.calculate_mday(2008, 12, :third, :thursday)
|
|
23
|
+
# => 18
|
|
24
|
+
#
|
|
25
|
+
# Last Monday of January, 2008:
|
|
26
|
+
# Date.calculate_mday(2008, 1, :last, 1)
|
|
27
|
+
# => 28
|
|
28
|
+
#--
|
|
29
|
+
# see http://www.irt.org/articles/js050/index.htm
|
|
30
|
+
class DayOfMonth
|
|
31
|
+
def call(year, month, week, wday)
|
|
32
|
+
raise ArgumentError, "Week parameter must be one of Holidays::WEEKS (provided #{week})." unless weeks.include?(week) or weeks.has_value?(week)
|
|
33
|
+
|
|
34
|
+
unless wday.kind_of?(Numeric) and wday.between?(0,6) or day_symbols.index(wday)
|
|
35
|
+
raise ArgumentError, "Wday parameter must be an integer between 0 and 6 or one of Holidays::DAY_SYMBOLS."
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
week = weeks[week] if week.kind_of?(Symbol)
|
|
39
|
+
wday = day_symbols.index(wday) if wday.kind_of?(Symbol)
|
|
40
|
+
|
|
41
|
+
# :first, :second, :third, :fourth or :fifth
|
|
42
|
+
if week > 0
|
|
43
|
+
return ((week - 1) * 7) + 1 + ((wday - Date.civil(year, month,(week-1)*7 + 1).wday) % 7)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
days = month_lengths[month-1]
|
|
47
|
+
|
|
48
|
+
days = 29 if month == 2 and Date.leap?(year)
|
|
49
|
+
|
|
50
|
+
return days - ((Date.civil(year, month, days).wday - wday + 7) % 7) - (7 * (week.abs - 1))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def weeks
|
|
56
|
+
Holidays::WEEKS
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def day_symbols
|
|
60
|
+
Holidays::DAY_SYMBOLS
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def month_lengths
|
|
64
|
+
Holidays::MONTH_LENGTHS
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Holidays
|
|
2
|
+
module DateCalculator
|
|
3
|
+
class Easter
|
|
4
|
+
# Get the date of Easter Sunday in a given year. From Easter Sunday, it is
|
|
5
|
+
# possible to calculate many traditional holidays in Western countries.
|
|
6
|
+
# Returns a Date object.
|
|
7
|
+
def calculate_easter_for(year)
|
|
8
|
+
y = year
|
|
9
|
+
a = y % 19
|
|
10
|
+
b = y / 100
|
|
11
|
+
c = y % 100
|
|
12
|
+
d = b / 4
|
|
13
|
+
e = b % 4
|
|
14
|
+
f = (b + 8) / 25
|
|
15
|
+
g = (b - f + 1) / 3
|
|
16
|
+
h = (19 * a + b - d - g + 15) % 30
|
|
17
|
+
i = c / 4
|
|
18
|
+
k = c % 4
|
|
19
|
+
l = (32 + 2 * e + 2 * i - h - k) % 7
|
|
20
|
+
m = (a + 11 * h + 22 * l) / 451
|
|
21
|
+
|
|
22
|
+
month = (h + l - 7 * m + 114) / 31
|
|
23
|
+
day = ((h + l - 7 * m + 114) % 31) + 1
|
|
24
|
+
|
|
25
|
+
Date.civil(year, month, day)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# A method to calculate the orthodox easter date, returns date in the Gregorian (western) calendar
|
|
29
|
+
# Safe until appr. 4100 AD, when one leap day will be removed.
|
|
30
|
+
# Returns a Date object.
|
|
31
|
+
def calculate_orthodox_easter_for(year)
|
|
32
|
+
y = year
|
|
33
|
+
g = y % 19
|
|
34
|
+
i = (19 * g + 15) % 30
|
|
35
|
+
j = (year + year/4 + i) % 7
|
|
36
|
+
j_month = 3 + (i - j + 40) / 44
|
|
37
|
+
j_day = i - j + 28 - 31 * (j_month / 4)
|
|
38
|
+
j_date = Date.civil(year, j_month, j_day)
|
|
39
|
+
|
|
40
|
+
case
|
|
41
|
+
# up until 1582, julian and gregorian easter dates were identical
|
|
42
|
+
when year <= 1582
|
|
43
|
+
offset = 0
|
|
44
|
+
# between the years 1583 and 1699 10 days are added to the julian day count
|
|
45
|
+
when (year >= 1583 and year <= 1699)
|
|
46
|
+
offset = 10
|
|
47
|
+
# after 1700, 1 day is added for each century, except if the century year is exactly divisible by 400 (in which case no days are added).
|
|
48
|
+
# Safe until 4100 AD, when one leap day will be removed.
|
|
49
|
+
when year >= 1700
|
|
50
|
+
offset = (year - 1700).divmod(100)[0] + ((year - year.divmod(100)[1]).divmod(400)[1] == 0 ? 0 : 1) - (year - year.divmod(100)[1] - 1700).divmod(400)[0] + 10
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# add offset to the julian day
|
|
54
|
+
return Date.jd(j_date.jd + offset)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
module Holidays
|
|
4
|
+
module DateCalculator
|
|
5
|
+
class WeekendModifier
|
|
6
|
+
# Move date to Monday if it occurs on a Saturday on Sunday.
|
|
7
|
+
# Used as a callback function.
|
|
8
|
+
def to_monday_if_weekend(date)
|
|
9
|
+
date += 1 if date.wday == 0
|
|
10
|
+
date += 2 if date.wday == 6
|
|
11
|
+
date
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Move date to Monday if it occurs on a Sunday.
|
|
15
|
+
# Used as a callback function.
|
|
16
|
+
def to_monday_if_sunday(date)
|
|
17
|
+
date += 1 if date.wday == 0
|
|
18
|
+
date
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Move Boxing Day if it falls on a weekend, leaving room for Christmas.
|
|
22
|
+
# Used as a callback function.
|
|
23
|
+
def to_weekday_if_boxing_weekend(date)
|
|
24
|
+
if date.wday == 6 || date.wday == 0
|
|
25
|
+
date += 2
|
|
26
|
+
elsif date.wday == 1
|
|
27
|
+
date += 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
date
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Call to_weekday_if_boxing_weekend but first get date based on year
|
|
34
|
+
# Used as a callback function.
|
|
35
|
+
def to_weekday_if_boxing_weekend_from_year(year)
|
|
36
|
+
to_weekday_if_boxing_weekend(Date.civil(year, 12, 26))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Move date to Monday if it occurs on a Sunday or to Friday if it occurs on a
|
|
40
|
+
# Saturday.
|
|
41
|
+
# Used as a callback function.
|
|
42
|
+
def to_weekday_if_weekend(date)
|
|
43
|
+
date += 1 if date.wday == 0
|
|
44
|
+
date -= 1 if date.wday == 6
|
|
45
|
+
date
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'holidays/date_calculator/easter'
|
|
2
|
+
require 'holidays/date_calculator/weekend_modifier'
|
|
3
|
+
require 'holidays/date_calculator/day_of_month'
|
|
4
|
+
|
|
5
|
+
module Holidays
|
|
6
|
+
module DateCalculatorFactory
|
|
7
|
+
class << self
|
|
8
|
+
def easter_calculator
|
|
9
|
+
DateCalculator::Easter.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def weekend_modifier
|
|
13
|
+
DateCalculator::WeekendModifier.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def day_of_month_calculator
|
|
17
|
+
DateCalculator::DayOfMonth.new
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module Holidays
|
|
4
|
+
module Definition
|
|
5
|
+
module Context
|
|
6
|
+
class Generator
|
|
7
|
+
|
|
8
|
+
def parse_definition_files(files)
|
|
9
|
+
raise ArgumentError, "Must have at least one file to parse" if files.nil? || files.empty?
|
|
10
|
+
|
|
11
|
+
all_regions = []
|
|
12
|
+
all_rules_by_month = {}
|
|
13
|
+
all_custom_methods = {}
|
|
14
|
+
all_tests = []
|
|
15
|
+
|
|
16
|
+
files.flatten!
|
|
17
|
+
|
|
18
|
+
files.each do |file|
|
|
19
|
+
definition_file = YAML.load_file(file)
|
|
20
|
+
|
|
21
|
+
regions, rules_by_month = parse_month_definitions(definition_file['months'])
|
|
22
|
+
|
|
23
|
+
all_regions << regions.flatten
|
|
24
|
+
|
|
25
|
+
all_rules_by_month.merge!(rules_by_month) { |month, existing, new|
|
|
26
|
+
existing << new
|
|
27
|
+
existing.flatten!
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
custom_methods = parse_method_definitions(definition_file['methods'])
|
|
31
|
+
all_custom_methods.merge!(custom_methods)
|
|
32
|
+
|
|
33
|
+
all_tests << parse_test_definitions(definition_file['tests'])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
all_regions.flatten!.uniq!
|
|
37
|
+
|
|
38
|
+
[all_regions, all_rules_by_month, all_custom_methods, all_tests]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def generate_definition_source(module_name, files, regions, rules_by_month, custom_methods, tests)
|
|
42
|
+
month_strings = generate_month_definition_strings(rules_by_month)
|
|
43
|
+
|
|
44
|
+
# Build the custom methods string
|
|
45
|
+
custom_method_string = ''
|
|
46
|
+
custom_methods.each do |key, code|
|
|
47
|
+
custom_method_string << code + "\n\n"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module_src = generate_module_src(module_name, files, regions, month_strings, custom_method_string)
|
|
51
|
+
test_src = generate_test_src(module_name, files, tests)
|
|
52
|
+
|
|
53
|
+
return module_src, test_src || ''
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def parse_month_definitions(month_definitions)
|
|
59
|
+
regions = []
|
|
60
|
+
rules_by_month = {}
|
|
61
|
+
|
|
62
|
+
if month_definitions
|
|
63
|
+
month_definitions.each do |month, definitions|
|
|
64
|
+
rules_by_month[month] = [] unless rules_by_month[month]
|
|
65
|
+
definitions.each do |definition|
|
|
66
|
+
rule = {}
|
|
67
|
+
|
|
68
|
+
definition.each do |key, val|
|
|
69
|
+
rule[key.to_sym] = val
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
rule[:regions] = rule[:regions].collect { |r| r.to_sym }
|
|
73
|
+
|
|
74
|
+
regions << rule[:regions]
|
|
75
|
+
|
|
76
|
+
exists = false
|
|
77
|
+
rules_by_month[month].each do |ex|
|
|
78
|
+
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]
|
|
79
|
+
ex[:regions] << rule[:regions].flatten
|
|
80
|
+
exists = true
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
unless exists
|
|
85
|
+
rules_by_month[month] << rule
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
[regions, rules_by_month]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def parse_method_definitions(methods)
|
|
95
|
+
custom_methods = {}
|
|
96
|
+
|
|
97
|
+
if methods
|
|
98
|
+
methods.each do |name, code|
|
|
99
|
+
custom_methods[name] = code
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
custom_methods
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def parse_test_definitions(tests)
|
|
107
|
+
test_strings = []
|
|
108
|
+
|
|
109
|
+
if tests
|
|
110
|
+
test_strings << tests
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
test_strings
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def generate_month_definition_strings(rules_by_month)
|
|
117
|
+
month_strings = []
|
|
118
|
+
|
|
119
|
+
rules_by_month.each do |month, rules|
|
|
120
|
+
month_string = " #{month.to_s} => ["
|
|
121
|
+
rule_strings = []
|
|
122
|
+
rules.each do |rule|
|
|
123
|
+
string = '{'
|
|
124
|
+
if rule[:mday]
|
|
125
|
+
string << ":mday => #{rule[:mday]}, "
|
|
126
|
+
elsif rule[:function]
|
|
127
|
+
string << ":function => lambda { |year| Holidays.#{rule[:function]} }, "
|
|
128
|
+
string << ":function_id => \"#{rule[:function].to_s}\", "
|
|
129
|
+
else
|
|
130
|
+
string << ":wday => #{rule[:wday]}, :week => #{rule[:week]}, "
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
if rule[:observed]
|
|
134
|
+
string << ":observed => lambda { |date| Holidays.#{rule[:observed]}(date) }, "
|
|
135
|
+
string << ":observed_id => \"#{rule[:observed].to_s}\", "
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
if rule[:type]
|
|
139
|
+
string << ":type => :#{rule[:type]}, "
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# shouldn't allow the same region twice
|
|
143
|
+
string << ":name => \"#{rule[:name]}\", :regions => [:" + rule[:regions].uniq.join(', :') + "]}"
|
|
144
|
+
rule_strings << string
|
|
145
|
+
end
|
|
146
|
+
month_string << rule_strings.join(",\n ") + "]"
|
|
147
|
+
month_strings << month_string
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
return month_strings
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def generate_module_src(module_name, files, regions, month_strings, custom_methods)
|
|
154
|
+
module_src = ""
|
|
155
|
+
|
|
156
|
+
module_src =<<-EOM
|
|
157
|
+
# encoding: utf-8
|
|
158
|
+
module Holidays
|
|
159
|
+
# This file is generated by the Ruby Holidays gem.
|
|
160
|
+
#
|
|
161
|
+
# Definitions loaded: #{files.join(', ')}
|
|
162
|
+
#
|
|
163
|
+
# To use the definitions in this file, load it right after you load the
|
|
164
|
+
# Holiday gem:
|
|
165
|
+
#
|
|
166
|
+
# require 'holidays'
|
|
167
|
+
# require '#{DEFINITIONS_PATH}/#{module_name.to_s.downcase}'
|
|
168
|
+
#
|
|
169
|
+
# All the definitions are available at https://github.com/alexdunae/holidays
|
|
170
|
+
module #{module_name.to_s.upcase} # :nodoc:
|
|
171
|
+
def self.defined_regions
|
|
172
|
+
[:#{regions.join(', :')}]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def self.holidays_by_month
|
|
176
|
+
{
|
|
177
|
+
#{month_strings.join(",\n")}
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
#{custom_methods}
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
Holidays.merge_defs(Holidays::#{module_name.to_s.upcase}.defined_regions, Holidays::#{module_name.to_s.upcase}.holidays_by_month)
|
|
186
|
+
EOM
|
|
187
|
+
|
|
188
|
+
return module_src
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def generate_test_src(module_name, files, tests)
|
|
192
|
+
unless tests.empty?
|
|
193
|
+
test_src = ""
|
|
194
|
+
|
|
195
|
+
test_src =<<-EndOfTests
|
|
196
|
+
# encoding: utf-8
|
|
197
|
+
require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
|
|
198
|
+
|
|
199
|
+
# This file is generated by the Ruby Holiday gem.
|
|
200
|
+
#
|
|
201
|
+
# Definitions loaded: #{files.join(', ')}
|
|
202
|
+
class #{module_name.to_s.capitalize}DefinitionTests < Test::Unit::TestCase # :nodoc:
|
|
203
|
+
|
|
204
|
+
def test_#{module_name.to_s.downcase}
|
|
205
|
+
#{tests.join("\n\n")}
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
EndOfTests
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
return test_src
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|