bjeanes-holidays 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/CHANGELOG +15 -0
  2. data/LICENSE +21 -0
  3. data/README.rdoc +77 -0
  4. data/REFERENCES +16 -0
  5. data/data/SYNTAX +111 -0
  6. data/data/au.yaml +111 -0
  7. data/data/build_defs.rb +152 -0
  8. data/data/ca.yaml +141 -0
  9. data/data/de.yaml +111 -0
  10. data/data/dk.yaml +117 -0
  11. data/data/es.yaml +161 -0
  12. data/data/fr.yaml +70 -0
  13. data/data/gb.yaml +106 -0
  14. data/data/ie.yaml +58 -0
  15. data/data/index.yaml +23 -0
  16. data/data/is.yaml +136 -0
  17. data/data/it.yaml +66 -0
  18. data/data/mx.yaml +106 -0
  19. data/data/nl.yaml +67 -0
  20. data/data/north_america_informal.yaml +49 -0
  21. data/data/nyse.yaml +63 -0
  22. data/data/pt.yaml +85 -0
  23. data/data/se.yaml +91 -0
  24. data/data/united_nations.yaml +188 -0
  25. data/data/ups.yaml +56 -0
  26. data/data/us.yaml +81 -0
  27. data/data/za.yaml +78 -0
  28. data/lib/holidays.rb +404 -0
  29. data/lib/holidays/MANIFEST +25 -0
  30. data/lib/holidays/au.rb +42 -0
  31. data/lib/holidays/ca.rb +68 -0
  32. data/lib/holidays/de.rb +50 -0
  33. data/lib/holidays/dk.rb +47 -0
  34. data/lib/holidays/es.rb +52 -0
  35. data/lib/holidays/europe.rb +214 -0
  36. data/lib/holidays/fr.rb +36 -0
  37. data/lib/holidays/gb.rb +40 -0
  38. data/lib/holidays/ie.rb +32 -0
  39. data/lib/holidays/is.rb +61 -0
  40. data/lib/holidays/it.rb +35 -0
  41. data/lib/holidays/mx.rb +51 -0
  42. data/lib/holidays/nl.rb +36 -0
  43. data/lib/holidays/north_america.rb +107 -0
  44. data/lib/holidays/nyse.rb +32 -0
  45. data/lib/holidays/pt.rb +43 -0
  46. data/lib/holidays/scandinavia.rb +114 -0
  47. data/lib/holidays/se.rb +52 -0
  48. data/lib/holidays/united_nations.rb +24 -0
  49. data/lib/holidays/ups.rb +31 -0
  50. data/lib/holidays/us.rb +48 -0
  51. data/lib/holidays/za.rb +35 -0
  52. data/rakefile.rb +150 -0
  53. data/test/defs/test_defs_au.rb +36 -0
  54. data/test/defs/test_defs_ca.rb +29 -0
  55. data/test/defs/test_defs_de.rb +49 -0
  56. data/test/defs/test_defs_dk.rb +30 -0
  57. data/test/defs/test_defs_es.rb +57 -0
  58. data/test/defs/test_defs_europe.rb +243 -0
  59. data/test/defs/test_defs_fr.rb +26 -0
  60. data/test/defs/test_defs_gb.rb +36 -0
  61. data/test/defs/test_defs_ie.rb +21 -0
  62. data/test/defs/test_defs_is.rb +33 -0
  63. data/test/defs/test_defs_it.rb +25 -0
  64. data/test/defs/test_defs_mx.rb +22 -0
  65. data/test/defs/test_defs_nl.rb +24 -0
  66. data/test/defs/test_defs_north_america.rb +54 -0
  67. data/test/defs/test_defs_nyse.rb +22 -0
  68. data/test/defs/test_defs_pt.rb +56 -0
  69. data/test/defs/test_defs_scandinavia.rb +75 -0
  70. data/test/defs/test_defs_se.rb +32 -0
  71. data/test/defs/test_defs_ups.rb +21 -0
  72. data/test/defs/test_defs_us.rb +23 -0
  73. data/test/defs/test_defs_za.rb +25 -0
  74. metadata +132 -0
data/CHANGELOG ADDED
@@ -0,0 +1,15 @@
1
+ = Ruby Holidays Gem CHANGELOG
2
+
3
+ == 0.9.3
4
+ * Added New York Stock Exchange holidays (thank you Alan Larkin).
5
+ * Added UPS holidays (thank you Tim Anglade).
6
+ * Fixed rakefile to force lower case definition file names.
7
+
8
+ == 0.9.2
9
+ * Included rakefile in Gem (thank you James Herdman).
10
+
11
+ == 0.9.1
12
+ * au.yaml was being included incorrectly in US holiday definitions. Thanks to Glenn Vanderburg (http://vanderburg.org/) for the fix.
13
+
14
+ == 0.9.0
15
+ * Initial release.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ ==== Ruby Holidays Gem License
2
+
3
+ Copyright (c) 2007-08 Alex Dunae
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,77 @@
1
+ = Ruby Holidays Gem
2
+
3
+ A set of functions to deal with holidays in Ruby.
4
+
5
+ Extends Ruby's built-in Date class and supports custom holiday definition lists.
6
+
7
+ === Installation
8
+
9
+ To install the gem from GitHub:
10
+
11
+ gem sources -a http://gems.github.com
12
+ gem install alexdunae-holidays
13
+
14
+ Or, download the source <tt>.tgz</tt> file from http://rubyforge.org/holidays and
15
+ extract it somewhere in your include path.
16
+
17
+ === Examples
18
+
19
+ For more information, see the notes at the top of the Holidays module.
20
+
21
+ ==== Using the Holidays class
22
+ Get all holidays on April 25, 2008 in Australia.
23
+ date = Date.civil(2008,4,25)
24
+
25
+ Holidays.on(date, :au)
26
+ => [{:name => 'ANZAC Day',...}]
27
+
28
+ Get holidays that are observed on July 2, 2007 in British Columbia, Canada.
29
+ date = Date.civil(2007,7,2)
30
+
31
+ Holidays.on(date, :ca_bc, :observed)
32
+ => [{:name => 'Canada Day',...}]
33
+
34
+ Get all holidays in July, 2008 in Canada and the US.
35
+ from = Date.civil(2008,7,1)
36
+ to = Date.civil(2008,7,31)
37
+
38
+ Holidays.between(from, to, :ca, :us)
39
+ => [{:name => 'Canada Day',...}
40
+ {:name => 'Independence Day',...}]
41
+
42
+ Get informal holidays in February.
43
+ from = Date.civil(2008,2,1)
44
+ to = Date.civil(2008,2,15)
45
+
46
+ Holidays.between(from, to)
47
+ => [{:name => 'Valentine\'s Day',...}]
48
+
49
+
50
+ ==== Extending Ruby's Date class
51
+ Check which holidays occur in Iceland on January 1, 2008.
52
+ d = Date.civil(2008,7,1)
53
+
54
+ d.holidays(:is)
55
+ => [{:name => 'Nýársdagur'}...]
56
+
57
+ Lookup Canada Day in different regions.
58
+ d = Date.civil(2008,7,1)
59
+
60
+ d.holiday?(:ca) # Canada
61
+ => true
62
+
63
+ d.holiday?(:ca_bc) # British Columbia, Canada
64
+ => true
65
+
66
+ d.holiday?(:fr) # France
67
+ => false
68
+
69
+ === Credits and code
70
+
71
+ * Project page: http://code.dunae.ca/holidays
72
+ * Source: http://github.com/alexdunae/holidays
73
+ * Docs: http://code.dunae.ca/holidays/doc
74
+
75
+ By Alex Dunae (dunae.ca, e-mail 'code' at the same domain), 2007-08.
76
+
77
+ Made on Vancouver Island.
data/REFERENCES ADDED
@@ -0,0 +1,16 @@
1
+ === References
2
+
3
+ I am grateful to the following sources.
4
+
5
+ ==== Date calculations
6
+ * http://michaelthompson.org/technikos/holidays.php
7
+
8
+ ==== Easter calculations
9
+ * http://www.assa.org.au/edm.html
10
+ * http://www.smart.net/~mmontes/ec-cal.html
11
+
12
+ ==== World dates
13
+ * http://www.un.org/geninfo/faq/factsheets/FS18.HTM
14
+ * http://en.wikipedia.org/wiki/List_of_holidays_by_country
15
+
16
+
data/data/SYNTAX ADDED
@@ -0,0 +1,111 @@
1
+ == Holiday Gem Definition Syntax
2
+
3
+ All holidays are defined in YAML files in the <tt>data/</tt> directory. These definition files have three main parts: *months*, *methods* and *tests*. Before you start, you may want to look some of the existing files at http://code.dunae.ca/svn/holidays/trunk/data.
4
+
5
+ === Months
6
+
7
+ Holidays are grouped by month from 1 through 12. Each entry within a month can have several fields.
8
+
9
+ [<tt>name</tt>] The name of the holiday.
10
+ [<tt>regions</tt>] One or more region codes.
11
+
12
+ ===== Dates defined by a fixed date (e.g. January 1st)
13
+
14
+ [<tt>wday</tt>] Integer representing day of the month (1 through 31).
15
+
16
+ For example, the following holiday is on the first of January and available in the <tt>ca</tt>, <tt>us</tt> and <tt>au</tt> regions.
17
+
18
+ 1:
19
+ - name: New Year's Day
20
+ regions: [ca, us, au]
21
+ mday: 1
22
+
23
+ ===== Dates defined by a week number (e.g. first Monday of a month)
24
+
25
+ [<tt>wday</tt>] Integer representing day of the week (0 = Sunday through 6 = Saturday).
26
+ [<tt>week</tt>] Integer representing week number (1 = first week, 3 = third week, -1 = last week),
27
+
28
+
29
+ For example, the following holiday is on the first Monday of September and available in the <tt>ca</tt> region.
30
+
31
+ 9:
32
+ - name: Labour Day
33
+ regions: [ca]
34
+ week: 1
35
+ wday: 1
36
+
37
+ === Calculating dates with methods
38
+
39
+ In addition to defining holidays by day or week, you can create custom methods to calculate a date.
40
+
41
+ For example, Canada celebrates Victoria Day, which falls on the Monday on or before May 24. So, under the <tt>methods</tt> section we could create a custom method that returns a Date object.
42
+
43
+ methods:
44
+ ca_victoria_day: |
45
+ def self.ca_victoria_day(year)
46
+ date = Date.civil(year,5,24)
47
+ if date.wday > 1
48
+ date -= (date.wday - 1)
49
+ elsif date.wday == 0
50
+ date -= 6
51
+ end
52
+ date
53
+ end
54
+
55
+ This would be represented in the <tt>months</tt> section as:
56
+
57
+ 5:
58
+ - name: Victoria Day
59
+ regions: [ca]
60
+ function: ca_victoria_day(year)
61
+
62
+ If a holiday can occur in different months (e.g. Easter) it can go in the '0' month.
63
+
64
+ 0:
65
+ - name: Easter Monday
66
+ regions: [ca]
67
+ function: easter(year)+1
68
+
69
+ Calculated-date functions take the year (integer) as a parameter and must return either a Date object or an integer representing the day of the month.
70
+
71
+
72
+ === Calculating observed dates
73
+
74
+ Several built-in methods are available for holidays that are observed on varying dates. For example, for a holiday that is observed on Monday if it falls on a weekend you could write:
75
+
76
+ 7:
77
+ - name: Canada Day
78
+ regions: [ca]
79
+ mday: 1
80
+ observed: to_monday_if_weekend(date)
81
+
82
+ Methods included in the Holidays module are:
83
+
84
+ * Holidays#to_monday_if_sunday
85
+ * Holidays#to_monday_if_weekend
86
+ * Holidays#to_weekday_if_boxing_weekend
87
+ * Holidays#to_weekday_if_weekend
88
+
89
+ Observed-date functions take a Date object as a parameter and must return either a Date object or an integer representing the day of the month.
90
+
91
+
92
+
93
+ === Tests
94
+
95
+ All definition files should have tests included. In the YAML file, tests are just a block of Ruby code.
96
+
97
+ tests: |
98
+ {Date.civil(2008,1,1) => 'New Year\'s Day',
99
+ Date.civil(2008,3,21) => 'Good Friday',
100
+ Date.civil(2008,3,24) => 'Easter Monday',
101
+ Date.civil(2008,9,1) => 'Labour Day',
102
+ Date.civil(2008,12,25) => 'Christmas Day',
103
+ Date.civil(2008,12,26) => 'Boxing Day'}.each do |date, name|
104
+ assert_equal name, Holidays.on(date, :ca, :informal)[0][:name]
105
+ end
106
+
107
+ # Victoria Day
108
+ [Date.civil(2004,5,24), Date.civil(2005,5,23), Date.civil(2006,5,22),
109
+ Date.civil(2007,5,21), Date.civil(2008,5,19)].each do |date|
110
+ assert_equal 'Victoria Day', Holidays.on(date, :ca)[0][:name]
111
+ end
data/data/au.yaml ADDED
@@ -0,0 +1,111 @@
1
+ # Australian holiday definitions for the Ruby Holiday gem.
2
+ # Updated: 2008-11-29.
3
+ # Sources:
4
+ # - http://en.wikipedia.org/wiki/Australian_public_holidays
5
+ # - http://www.docep.wa.gov.au/lr/LabourRelations/Content/Wages%20and%20Conditions/Public%20Holidays/Public_Holidays.html
6
+ # - http://www.wst.tas.gov.au/employment_info/public_holidays
7
+ # TODO: missing some regional holidays
8
+ ---
9
+ months:
10
+ 0:
11
+ - name: Good Friday
12
+ regions: [au]
13
+ function: easter(year)-2
14
+ - name: Easter Saturday
15
+ regions: [au]
16
+ function: easter(year)-1
17
+ - name: Easter Monday
18
+ regions: [au]
19
+ function: easter(year)+1
20
+ - name: Easter Monday
21
+ regions: [au_tas]
22
+ function: easter(year)+2
23
+ 1:
24
+ - name: New Year's Day
25
+ regions: [au]
26
+ mday: 1
27
+ - name: Australia Day
28
+ regions: [au]
29
+ mday: 26
30
+ 3:
31
+ - name: Labour Day
32
+ regions: [au_wa]
33
+ week: 1
34
+ wday: 1
35
+ - name: Eight Hours Day
36
+ regions: [au_tas]
37
+ week: 2
38
+ wday: 1
39
+ - name: Labour Day
40
+ regions: [au_vic]
41
+ week: 2
42
+ wday: 1
43
+ 4:
44
+ - name: ANZAC Day
45
+ regions: [au]
46
+ mday: 25
47
+ 5:
48
+ - name: Labour Day
49
+ regions: [au_qld]
50
+ week: 1
51
+ wday: 1
52
+ - name: May Day
53
+ regions: [au_nt]
54
+ week: 1
55
+ wday: 1
56
+ 6:
57
+ - name: Foundation Day
58
+ regions: [au_wa]
59
+ week: 1
60
+ wday: 1
61
+ - name: Queen's Birthday
62
+ regions: [au_act, au_nsw, au_sa, au_tas, au_nt, au_qld, au_vic]
63
+ week: 2
64
+ wday: 1
65
+ - name: Queensland Day
66
+ regions: [au_qld]
67
+ mday: 6
68
+ type: informal
69
+ 8:
70
+ - name: Ekka
71
+ regions: [au_qld_brisbane]
72
+ week: -3
73
+ wday: 3
74
+ 10:
75
+ - name: Labour Day
76
+ regions: [au_act, au_nsw, au_sa]
77
+ week: 1
78
+ wday: 1
79
+ 12:
80
+ - name: Christmas Day
81
+ regions: [au]
82
+ mday: 25
83
+ - name: Boxing Day
84
+ regions: [au]
85
+ mday: 26
86
+ tests: |
87
+ {Date.civil(2007,1,1) => 'New Year\'s Day',
88
+ Date.civil(2007,1,26) => 'Australia Day',
89
+ Date.civil(2007,4,6) => 'Good Friday',
90
+ Date.civil(2007,4,9) => 'Easter Monday',
91
+ Date.civil(2007,4,25) => 'ANZAC Day',
92
+ Date.civil(2007,12,25) => 'Christmas Day',
93
+ Date.civil(2007,12,26) => 'Boxing Day'}.each do |date, name|
94
+ assert_equal name, Holidays.on(date, :au, :informal)[0][:name]
95
+ end
96
+
97
+ [:au_sa, :au_act, :au_nsw, :au_].each do |r|
98
+ assert_equal 'Labour Day', Date.civil(2007,10,1).holidays(r)[0][:name]
99
+ end
100
+
101
+ [:au_sa, :au_act, :au_nsw, :au_vic, :au_tas, :au_qld, :au_nt, :au_].each do |r|
102
+ assert_equal 'Queen\'s Birthday', Date.civil(2007,6,11).holidays(r)[0][:name]
103
+ end
104
+
105
+ assert_equal 'Labour Day', Date.civil(2007,3,5).holidays(:au_wa)[0][:name]
106
+ assert_equal 'Labour Day', Date.civil(2007,3,12).holidays(:au_vic)[0][:name]
107
+ assert_equal 'Labour Day', Date.civil(2007,5,7).holidays(:au_qld)[0][:name]
108
+
109
+ assert_equal 'May Day', Date.civil(2007,5,7).holidays(:au_nt)[0][:name]
110
+
111
+ assert_equal 'Eight Hours Day', Date.civil(2007,3,12).holidays(:au_tas)[0][:name]
@@ -0,0 +1,152 @@
1
+ require 'yaml'
2
+
3
+ # Functions are stored in generated files as both Procs (:function) and
4
+ # Strings (:function_id). The String version makes comparisons of Procs much
5
+ # easier.
6
+ #
7
+ # TODO:
8
+ # - better comparison of existing rules
9
+ def parse_holiday_defs(module_name, files)
10
+ regions = []
11
+ rules_by_month = {}
12
+ custom_methods = {}
13
+ test_strs = []
14
+
15
+ files.each do |file|
16
+ def_file = YAML.load_file(file)
17
+ puts " Loading #{file}"
18
+ if def_file['months']
19
+ puts " - importing dates..."
20
+ def_file['months'].each do |month, definitions|
21
+ rules_by_month[month] = [] unless rules_by_month[month]
22
+ definitions.each do |definition|
23
+ rule = {}
24
+ definition.each do |key, val|
25
+ rule[key] = val
26
+ end
27
+
28
+ rule['regions'] = rule['regions'].collect { |r| r.to_sym }
29
+
30
+ regions << rule['regions']
31
+
32
+ exists = false
33
+ rules_by_month[month].each do |ex|
34
+ 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']
35
+ ex['regions'] << rule['regions'].flatten
36
+ exists = true
37
+ end
38
+ end
39
+ unless exists
40
+ rules_by_month[month] << rule
41
+ end
42
+
43
+ end # /defs.each
44
+ end
45
+ end
46
+
47
+ if def_file['methods']
48
+ puts " - importing methods..."
49
+ def_file['methods'].each do |name, code|
50
+ custom_methods[name] = code
51
+ end # /methods.each
52
+ end
53
+
54
+ if def_file['tests']
55
+ puts " - importing testings..."
56
+ test_strs << def_file['tests']
57
+ end
58
+ end
59
+
60
+ # Build the definitions
61
+ month_strs = []
62
+ rules_by_month.each do |month, rules|
63
+ month_str = " #{month.to_s} => ["
64
+ rule_strings = []
65
+ rules.each do |rule|
66
+ str = '{'
67
+ if rule['mday']
68
+ str << ":mday => #{rule['mday']}, "
69
+ elsif rule['function']
70
+ str << ":function => lambda { |year| Holidays.#{rule['function']} }, "
71
+ str << ":function_id => \"#{rule['function'].to_s}\", "
72
+ else
73
+ str << ":wday => #{rule['wday']}, :week => #{rule['week']}, "
74
+ end
75
+
76
+ if rule['observed']
77
+ str << ":observed => lambda { |date| Holidays.#{rule['observed']}(date) }, "
78
+ str << ":observed_id => \"#{rule['observed'].to_s}\", "
79
+ end
80
+
81
+ if rule['type']
82
+ str << ":type => :#{rule['type']}, "
83
+ end
84
+
85
+ # shouldn't allow the same region twice
86
+ str << ":name => \"#{rule['name']}\", :regions => [:" + rule['regions'].uniq.join(', :') + "]}"
87
+ rule_strings << str
88
+ end
89
+ month_str << rule_strings.join(",\n ") + "]"
90
+ month_strs << month_str
91
+ end
92
+
93
+ month_strs.join(",\n")
94
+
95
+
96
+ # Build the methods
97
+ method_str = ''
98
+ custom_methods.each do |key, code|
99
+ method_str << code + "\n\n"
100
+ end
101
+
102
+
103
+ # Build the module file
104
+ module_src =<<-EOM
105
+ module Holidays
106
+ # This file is generated by the Ruby Holiday gem.
107
+ #
108
+ # Definitions loaded: #{files.join(', ')}
109
+ #
110
+ # To use the definitions in this file, load them right after you load the
111
+ # Holiday gem:
112
+ #
113
+ # require 'holidays'
114
+ # require 'holidays/#{module_name.downcase}'
115
+ #
116
+ # More definitions are available at http://code.dunae.ca/holidays.
117
+ module #{module_name} # :nodoc:
118
+ DEFINED_REGIONS = [:#{regions.flatten.uniq.join(', :')}]
119
+
120
+ HOLIDAYS_BY_MONTH = {
121
+ #{month_strs.join(",\n")}
122
+ }
123
+ end
124
+
125
+ #{method_str}
126
+ end
127
+
128
+ Holidays.merge_defs(Holidays::#{module_name}::DEFINED_REGIONS, Holidays::#{module_name}::HOLIDAYS_BY_MONTH)
129
+ EOM
130
+
131
+
132
+ # Build the test file
133
+ unless test_strs.empty?
134
+ test_src =<<-EndOfTests
135
+ require File.dirname(__FILE__) + '/../test_helper'
136
+ require 'holidays/#{module_name.downcase}'
137
+
138
+ # This file is generated by the Ruby Holiday gem.
139
+ #
140
+ # Definitions loaded: #{files.join(', ')}
141
+ class #{module_name.capitalize}DefinitionTests < Test::Unit::TestCase # :nodoc:
142
+
143
+ def test_#{module_name.downcase}
144
+ #{test_strs.join("\n\n")}
145
+ end
146
+ end
147
+ EndOfTests
148
+ end
149
+
150
+ return module_src, test_src || ''
151
+
152
+ end