Updated data/ca.yaml

Started documentation in CUSTOM DATES
master
Alex Dunae 2007-11-22 00:35:56 +00:00
parent 99874179df
commit 1da5732747
8 changed files with 307 additions and 75 deletions

104
CUSTOM DATES Normal file
View File

@ -0,0 +1,104 @@
= Custom dates with the Ruby Holidays Gem
It's easy to add your own custom holiday definitions to the Holidays gem. In a nutshell:
1. Build a definition file
2. Run a <tt>rake</tt> to make a custom module
3. <tt>require</tt> your new module
== Building the YAML file
Definition files have two main parts: *months* and *methods*. Before you start, you may want to look some of the existing files at http://code.dunae.ca/svn/holidays/trunk/data.
=== Months
Holidays are grouped by month from 1 through 12. Each entry within a month can have several fields.
[<tt>name</tt>] The name of the holiday.
[<tt>regions</tt>] One or more region codes.
===== Dates defined by a fixed date (e.g. January 1st)
[<tt>wday</tt>] Integer representing day of the month (1 through 31).
For example, the following holiday is on the first of the month and available in the <tt>ca</tt>, <tt>us</tt> and <tt>au</tt> regions.
- name: New Year's Day
regions: [ca,us,au]
mday: 1
===== Dates defined by a week number (e.g. first Monday of a month)
[<tt>wday</tt>] Integer representing day of the week (0 = Sunday through 6 = Saturday).
[<tt>week</tt>] Integer representing week number (1 = first week, 3 = third week, -1 = last week),
For example, the following holiday is on the first Monday of the month and available in the <tt>ca</tt> region.
- name: Labour Day
regions: [ca]
week: 1
wday: 1
=== Calculating dates with methods
In addition to defining holidays by day or week, you can create custom methods to calculate a date.
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.
methods:
ca_victoria_day: |
def self.ca_victoria_day(year)
date = Date.civil(year,5,24)
if date.wday > 1
date -= (date.wday - 1)
elsif date.wday == 0
date -= 6
end
date
end
This would be represented in the <tt>months</tt> section as:
5:
- name: Victoria Day
regions: [ca]
function: lambda { |year| ca_victoria_day(year) }
Functions called in this manner must return either a Date object or an integer representing the day of the month.
== Building the definition module
Once you have your YAML definition file you need to generate a Ruby module using <tt>rake</tt>.
To build the module for school holidays
rake generate Custom custom.yaml
Your module can include definitions from multiple YAML files.
rake generate Custom ca.yaml us.yaml mx.yaml custom.yaml
Your custom module is ready to use.
require 'holidays'
require 'path/to/custom'
Holidays.by_day(date, :your_region)
=== Sharing
If you've built a definition file that others might enjoy, why not share it?
Send any definition files to 'code' at 'dunae.ca'.

View File

@ -100,14 +100,22 @@ module Holidays
end
Holidays.class_eval do
new_regions = []
existing_regions = []
if const_defined?(:DEFINED_REGIONS)
new_regions = const_get(:DEFINED_REGIONS)
existing_regions = const_get(:DEFINED_REGIONS)
remove_const(:DEFINED_REGIONS)
end
const_set(:DEFINED_REGIONS, new_regions | Holidays::#{module_name}::DEFINED_REGIONS)
const_set(:DEFINED_REGIONS, existing_regions | Holidays::#{module_name}::DEFINED_REGIONS)
include Holidays::MixinModule
existing_defs = {}
if const_defined?(:HOLIDAYS_BY_MONTH)
existing_defs = const_get(:HOLIDAYS_BY_MONTH)
remove_const(:HOLIDAYS_BY_MONTH)
end
#const_set(:HOLIDAYS_BY_MONTH, existing_defs.merge(Holidays::#{module_name}::HOLIDAYS_BY_MONTH))
const_set(:HOLIDAYS_BY_MONTH, Holidays::#{module_name}::HOLIDAYS_BY_MONTH)
include Holidays::#{module_name}
end
EOC

View File

@ -6,22 +6,95 @@ months:
- name: Good Friday
regions: [ca]
function: lambda { |year| easter(year)-2 }
- name: Easter Sunday
regions: [ca]
function: lambda { |year| easter(year) }
- name: Easter Monday
regions: [ca_qc]
function: lambda { |year| easter(year)+1 }
1:
- name: New Year's Day
regions: [ca]
mday: 1
- name: New Year's
regions: [ca_qc]
mday: 2
2:
- name: Family Day
regions: [ca_ab, ca_on, ca_sk]
wday: 1
week: 3
- name: Louis Riel Day
regions: [ca_mb]
wday: 1
week: 3
3:
- name: St. Patrick's Day
regions: [ca_nf]
mday: 17
3:
- name: St. George's Day
regions: [ca_nf]
mday: 23
5:
- name: Victoria Day
regions: [ca]
function: lambda { |year| ca_victoria_day(year) }
- name: National Patriotes Day
regions: [ca_qc]
function: lambda { |year| ca_victoria_day(year) }
6:
- name: Discovery Day
regions: [ca_nf]
mday: 24
- name: Fête Nationale
regions: [ca_qc]
mday: 24
- name: National Aboriginal Day
regions: [ca_nt]
mday: 21
7:
- name: Canada Day
regions: [ca]
mday: 1
- name: Orangemen's Day
regions: [ca]
mday: 12
- name: Nunavut Day
regions: [ca_nu]
mday: 9
8:
- name: BC Day
week: 1
regions: [ca_bc]
wday: 1
- name: Saskatchewan Day
week: 1
regions: [ca_sk]
wday: 1
- name: Heritage Day
week: 1
regions: [ca_ab]
wday: 1
- name: Natal Day
week: 1
regions: [ca_ns]
wday: 1
- name: Civic Holiday
week: 1
regions: [ca_on]
wday: 1
- name: Discovery Day
week: 3
regions: [ca_yk]
wday: 1
9:
- name: Labour Day
week: 1
regions: [ca]
wday: 1
10:
- name: Thanksgiving
week: 2
regions: [ca]
wday: 1
11:
- name: Rememberance Day
regions: [ca]
@ -35,10 +108,17 @@ months:
mday: 26
methods:
easter: |
def easter(year)
def self.easter(year)
Date.civil(2008,1,1)
end
tester: |
def tester(year)
Date.civil(2005,1,1)
ca_victoria_day: |
# Monday on or before May 24
def self.ca_victoria_day(year)
date = Date.civil(year,5,24)
if date.wday > 1
date -= (date.wday - 1)
elsif date.wday == 0
date -= 6
end
date
end

View File

@ -12,7 +12,7 @@ module Holidays
WEEKS = {:first => 1, :second => 2, :third => 3, :fourth => 4, :fifth => 5, :last => -1}
MONTH_LENGTHS = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
DEFINED_REGIONS = [:ca, :us, :au, :gr, :fr, :christian]
DEFINED_REGIONS = [:us, :au]
HOLIDAYS_TYPES = [:bank, :statutory, :religious, :informal]
@ -22,35 +22,8 @@ module Holidays
# The month <tt>0</tt> is used to store events that require lambda calculations
# and may occur in more than one month.
HOLIDAYS_BY_MONTH = {
0 => [{:function => lambda { |year| easter(year) }, :name => 'Easter Sunday', :regions => [:christian, :ca, :us]},
{:function => lambda { |year| easter(year)-2 }, :name => 'Good Friday', :regions => [:christian, :ca, :us]}],
1 => [{:mday => 1, :name => 'New Year\'s Day', :regions => [:us, :ca, :au]},
{:mday => 1, :name => 'Australia Day', :regions => [:au]},
{:mday => 6, :name => 'Epiphany', :regions => [:christian]},
{:wday => 1, :week => :third, :name => 'Martin Luther King, Jr. Day', :regions => [:us]}],
3 => [{:wday => 1, :week => :third, :name => 'George Washington\'s Birthday', :regions => [:us]},
{:mday => 25, :name => 'Independence Day', :regions => [:gr]}],
4 => [{:mday => 25, :name => 'ANZAC Day', :regions => [:au]}],
5 => [{:mday => 1, :name => 'Labour Day', :regions => [:fr,:gr]},
{:mday => 8, :name => 'Victoria 1945', :regions => [:fr]},
{:wday => 6, :week => :third, :name => 'Armed Forces Day', :regions => [:us]},
{:wday => 1, :week => :last, :name => 'Memorial Day', :regions => [:us]}],
6 => [{:mday => 14, :name => 'Flag Day', :regions => [:us]},
{:wday => 1, :week => :second, :name => 'Queen\'s Birthday', :regions => [:au]}],
7 => [{:mday => 1, :name => 'Canada Day', :regions => [:ca]},
{:mday => 4, :name => 'Independence Day', :regions => [:us]},
{:mday => 14, :name => 'Ascension Day', :regions => [:fr]}],
8 => [{:mday => 15, :name => 'Assumption of Mary', :regions => [:fr, :gr, :christian]}],
9 => [{:wday => 1, :week => :first,:name => 'Labor Day', :regions => [:us]},
{:wday => 1, :week => :first,:name => 'Labour Day', :regions => [:ca]}],
10 => [{:wday => 1, :week => :second, :name => 'Columbus Day', :regions => [:us]},
{:mday => 28, :name => 'National Day', :regions => [:gr]}],
11 => [{:wday => 4, :week => :fourth, :name => 'Thanksgiving Day', :regions => [:us]},
{:mday => 11, :name => 'Rememberance Day', :regions => [:ca,:au]},
{:mday => 11, :name => 'Armistice 1918', :regions => [:fr]},
{:mday => 1, :name => 'Touissant', :regions => [:fr]}],
12 => [{:mday => 25, :name => 'Christmas Day', :regions => [:us,:ca,:christian,:au]},
{:mday => 26, :name => 'Boxing Day', :regions => [:ca,:gr,:au]}]
1 => [{:mday => 1, :name => 'New Year\'s Day', :regions => [:ca, :au]},
{:mday => 1, :name => 'Australia Day', :regions => [:au]}]
}
@ -130,7 +103,16 @@ module Holidays
hbm.each do |h|
next unless h[:regions].any?{ |reg| regions.include?(reg) }
unless h[:function]
if h[:function]
result = h[:function].call(year)
if result.kind_of?(Date) and result.mon == month
holidays << h.merge({:day => result.mday})
else #if result == mday
holidays << h
end
else
day = h[:mday] || Date.calculate_mday(year, month, h[:week], h[:wday])
holidays << {:month => month, :day => day, :year => year, :name => h[:name], :regions => h[:regions]}
end

View File

@ -21,6 +21,7 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.title = 'Ruby Holidays Gem'
rdoc.options << '--all' << '--inline-source' << '--line-numbers'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('CUSTOM DATES')
rdoc.rdoc_files.include('REFERENCES')
rdoc.rdoc_files.include('LICENSE')
rdoc.rdoc_files.include('lib/*.rb')
@ -41,7 +42,7 @@ spec = Gem::Specification.new do |s|
s.files = FileList["{lib}/**/*"].to_a
s.test_files = Dir.glob('test/test_*.rb')
s.has_rdoc = true
s.extra_rdoc_files = ['README', 'REFERENCES', 'LICENSE']
s.extra_rdoc_files = ['README', 'CUSTOM DATES', 'REFERENCES', 'LICENSE']
s.rdoc_options << '--all' << '--inline-source' << '--line-numbers'
end

82
test/fixtures/ca.rb vendored Normal file
View File

@ -0,0 +1,82 @@
# This file is generated by the Ruby Holiday gem.
#
# To use the definitions in the file, load them right after you load the
# Holiday gem:
#
# require 'holidays'
# require 'path/to/testmodule'
#
# More definitions are available at http://code.dunae.ca/holidays.
#
# Definitions loaded: data/ca.yaml
module Holidays
module TestModule
DEFINED_REGIONS = [:ca]
HOLIDAYS_BY_MONTH = {
5 => [{:function => lambda { |year| ca_victoria_day(year) }, :name => "Victoria Day", :regions => [:ca]},
{:function => lambda { |year| ca_victoria_day(year) }, :name => "National Patriotes Day", :regions => [:ca_qc]}],
0 => [{:function => lambda { |year| easter(year)-2 }, :name => "Good Friday", :regions => [:ca]},
{:function => lambda { |year| easter(year)+1 }, :name => "Easter Monday", :regions => [:ca_qc]}],
11 => [{:mday => 11, :name => "Rememberance Day", :regions => [:ca]}],
6 => [{:mday => 24, :name => "Discovery Day", :regions => [:ca_nf]},
{:mday => 24, :name => "Fête Nationale", :regions => [:ca_qc]},
{:mday => 21, :name => "National Aboriginal Day", :regions => [:ca_nt]}],
1 => [{:mday => 1, :name => "New Year's Day", :regions => [:ca]},
{:mday => 2, :name => "New Year's", :regions => [:ca_qc]}],
12 => [{:mday => 25, :name => "Christmas Day", :regions => [:ca]},
{:mday => 26, :name => "Boxing Day", :regions => [:ca]}],
7 => [{:mday => 1, :name => "Canada Day", :regions => [:ca]},
{:mday => 12, :name => "Orangemen's Day", :regions => [:ca]},
{:mday => 9, :name => "Nunavut Day", :regions => [:ca_nu]}],
2 => [{:wday => 1, :week => 3, :name => "Family Day", :regions => [:ca_ab, :ca_on, :ca_sk]},
{:wday => 1, :week => 3, :name => "Louis Riel Day", :regions => [:ca_mb]}],
8 => [{:wday => 1, :week => 1, :name => "BC Day", :regions => [:ca_bc]},
{:wday => 1, :week => 1, :name => "Saskatchewan Day", :regions => [:ca_sk]},
{:wday => 1, :week => 1, :name => "Heritage Day", :regions => [:ca_ab]},
{:wday => 1, :week => 1, :name => "Natal Day", :regions => [:ca_ns]},
{:wday => 1, :week => 1, :name => "Civic Holiday", :regions => [:ca_on]},
{:wday => 1, :week => 3, :name => "Discovery Day", :regions => [:ca_yk]}],
3 => [{:mday => 23, :name => "St. George's Day", :regions => [:ca_nf]}],
9 => [{:wday => 1, :week => 1, :name => "Labour Day", :regions => [:ca]}],
10 => [{:wday => 1, :week => 2, :name => "Thanksgiving", :regions => [:ca]}]
}
def self.easter(year)
Date.civil(2008,1,1)
end
# Monday on or before May 24
def self.ca_victoria_day(year)
date = Date.civil(year,5,24)
if date.wday > 1
date -= (date.wday - 1)
elsif date.wday == 0
date -= 6
end
date
end
end
end
Holidays.class_eval do
existing_regions = []
if const_defined?(:DEFINED_REGIONS)
existing_regions = const_get(:DEFINED_REGIONS)
remove_const(:DEFINED_REGIONS)
end
const_set(:DEFINED_REGIONS, existing_regions | Holidays::TestModule::DEFINED_REGIONS)
existing_defs = {}
if const_defined?(:HOLIDAYS_BY_MONTH)
existing_defs = const_get(:HOLIDAYS_BY_MONTH)
remove_const(:HOLIDAYS_BY_MONTH)
end
#const_set(:HOLIDAYS_BY_MONTH, existing_defs.merge(Holidays::TestModule::HOLIDAYS_BY_MONTH))
const_set(:HOLIDAYS_BY_MONTH, Holidays::TestModule::HOLIDAYS_BY_MONTH)
include Holidays::TestModule
end

View File

@ -1,21 +0,0 @@
module Holidays
module MixinModule
DEFINED_REGIONS = [:merged_a,:merged_b]
def test_lambda(year)
28
end
end
end
Holidays.class_eval do
# merge regions and holidays
new_regions = []
if const_defined?(:DEFINED_REGIONS)
new_regions = const_get(:DEFINED_REGIONS)
remove_const(:DEFINED_REGIONS)
end
const_set(:DEFINED_REGIONS, new_regions | Holidays::MixinModule::DEFINED_REGIONS)
include Holidays::MixinModule
end

View File

@ -1,15 +1,11 @@
require File.dirname(__FILE__) + '/test_helper'
require 'fixtures/mixin_module'
require 'fixtures/ca'
class MixinTests < Test::Unit::TestCase
def test_tester
#Holidays.append_features(Holidays::MixinModule)
puts Holidays.constants
puts Holidays::DEFINED_REGIONS.join(',')
assert Holidays.method_defined?(:test_lambda)
end
def test_adding_region_constants
class CATests < Test::Unit::TestCase
def test_ca_victoria_day
[Date.civil(2004,5,24), Date.civil(2005,5,23), Date.civil(2006,5,22),
Date.civil(2007,5,21), Date.civil(2008,5,19)].each do |date|
assert_equal 'Victoria Day', Holidays.by_day(date, :ca)[0][:name]
end
end
end