diff --git a/create_defs.rb b/create_defs.rb index 547d28d..d9b5fc2 100644 --- a/create_defs.rb +++ b/create_defs.rb @@ -1,9 +1,14 @@ require 'yaml' -module_name = 'NorthAmerica' +#module_name = 'NorthAmerica' +#files = ['data/ca.yaml', 'data/mx.yaml', 'data/us.yaml', 'data/common_methods.yaml', 'data/north_america_informal.yaml'] + +#module_name = 'Europe' +#files = ['data/dk.yaml', 'data/es.yaml', 'data/fr.yaml', 'data/gb.yaml', 'data/ie.yaml', 'data/is.yaml', 'data/common_methods.yaml'] + +module_name = 'CA' +files = ['data/ca.yaml', 'data/common_methods.yaml', 'data/north_america_informal.yaml'] -# Load the data files -files = ['data/ca.yaml', 'data/mx.yaml', 'data/us.yaml', 'data/common_methods.yaml', 'data/north_america_informal.yaml'] regions = [] rules_by_month = {} custom_methods = {} @@ -106,24 +111,7 @@ module Holidays 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::#{module_name}::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::#{module_name}::HOLIDAYS_BY_MONTH)) - const_set(:HOLIDAYS_BY_MONTH, Holidays::#{module_name}::HOLIDAYS_BY_MONTH) - - include Holidays::#{module_name} -end +Holidays.merge_defs(Holidays::#{module_name}::DEFINED_REGIONS, Holidays::#{module_name}::HOLIDAYS_BY_MONTH) EOC File.open("test_file.rb","w") do |file| diff --git a/data/fr.yaml b/data/fr.yaml index b9d4aa4..c034ee7 100644 --- a/data/fr.yaml +++ b/data/fr.yaml @@ -44,8 +44,8 @@ months: - name: Armistice 1918 regions: [fr] mday: 11 - 12: - - name: Noël + 12: + - name: Nöel regions: [fr] mday: 25 diff --git a/data/is.yaml b/data/is.yaml index 2f273af..1b05cbd 100644 --- a/data/is.yaml +++ b/data/is.yaml @@ -1,29 +1,35 @@ -# Islandic holiday definitions for the Ruby Holiday gem. +# Icelandic holiday definitions for the Ruby Holiday gem. # -# Updated: 2008-11-22. +# Updated: 2008-11-23. # Sources: +# - http://www.simnet.is/gardarj/folk/days.htm#days # - http://www.iceland.is/history-and-culture/Traditions/IcelandicHolidays/ # - http://en.wikipedia.org/wiki/Public_holidays_in_Iceland --- months: 0: - - name: Fastelavn + - name: Bolludagur regions: [is] - function: lambda { |year| easter(year)-49 } - type: informal - - name: Palmesøndag + function: lambda { |year| easter(year)-48 } + - name: Sprengidagur + regions: [is] + function: lambda { |year| easter(year)-47 } + - name: Öskudagur + regions: [is] + function: lambda { |year| easter(year)-46 } + - name: Pálmasunnudagur regions: [is] function: lambda { |year| easter(year)-7 } - - name: Skærtorsdag + - name: Skírdagur regions: [is] function: lambda { |year| easter(year)-3 } - - name: Langfredag + - name: Föstudaginn langi regions: [is] function: lambda { |year| easter(year)-2 } - - name: Påskedag + - name: Páskadagur regions: [is] function: lambda { |year| easter(year) } - - name: 2. påskedag + - name: Annar í páskum regions: [is] function: lambda { |year| easter(year)+1 } - name: Store Bededag @@ -64,4 +70,45 @@ months: - name: Mæðradagurinn regions: [is] mday: 13 - \ No newline at end of file + 5: + - name: Sjómannadagurinn + regions: [is] + mday: 3 + type: informal + - name: Lýðveldisdagurinn + regions: [is] + mday: 17 + 8: + - name: Frídagur verslunarmanna + regions: [is] + week: 1 + wday: 1 + 11: + - name: Dagur íslenskrar tungu + regions: [is] + mday: 16 + 12: + - name: Jól + regions: [is] + mday: 24 + - name: Jól + regions: [is] + mday: 25 + - name: Jól + regions: [is] + mday: 26 + - name: Gamlárskvöld + regions: [is] + mday: 31 +methods: + is_sumardagurinn_fyrsti: | + # Iceland: first day of summer (Thursday after 18 April) + def self.is_sumardagurinn_fyrsti(year) + date = Date.civil(year,4,18) + if date.wday < 4 + date += (4 - date.wday) + else date + date += (11 - date.wday) + end + date + end \ No newline at end of file diff --git a/lib/holidays.rb b/lib/holidays.rb index 092eea9..082c7aa 100644 --- a/lib/holidays.rb +++ b/lib/holidays.rb @@ -6,6 +6,9 @@ module Holidays VERSION = '0.9.0' + @@regions = [] + @@holidays_by_month = {} + 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] @@ -53,7 +56,7 @@ module Holidays dates.each do |year, months| months.each do |month| - next unless hbm = HOLIDAYS_BY_MONTH[month] + next unless hbm = @@holidays_by_month[month] hbm.each do |h| next unless in_region?(regions, h[:regions]) @@ -80,6 +83,22 @@ module Holidays holidays end + # Merge a new set of definitions into the Holidays module. + # + # This method is automatically called when including holiday definition + # files. + def self.merge_defs(regions, holidays) + @@regions = @@regions | regions + @@regions.uniq! + + holidays.each do |month, holiday_defs| + @@holidays_by_month[month] = [] unless @@holidays_by_month[month] + holiday_defs.each do |holiday_def| + @@holidays_by_month[month] << holiday_def + end + end + end + private # Check regions against list of supported regions and return an array of # symbols. @@ -87,7 +106,7 @@ private regions = [regions] unless regions.kind_of?(Array) regions = regions.collect { |r| r.to_sym } - raise UnkownRegionError unless regions.all? { |r| r == :any or DEFINED_REGIONS.include?(r) } + raise UnkownRegionError unless regions.all? { |r| r == :any or @@regions.include?(r) } regions end diff --git a/lib/holidays/ca.rb b/lib/holidays/ca.rb index cb55c39..9df600f 100644 --- a/lib/holidays/ca.rb +++ b/lib/holidays/ca.rb @@ -1,7 +1,7 @@ module Holidays # This file is generated by the Ruby Holiday gem. # - # Definitions loaded: data/ca.yaml, data/common_methods.yaml + # Definitions loaded: data/ca.yaml, data/common_methods.yaml, data/north_america_informal.yaml # # To use the definitions in the file, load them right after you load the # Holiday gem: @@ -11,12 +11,13 @@ module Holidays # # More definitions are available at http://code.dunae.ca/holidays. module CA # :nodoc: - DEFINED_REGIONS = [:ca, :ca_qc, :ca_nf, :ca_nt, :ca_nu, :ca_ab, :ca_on, :ca_sk, :ca_mb, :ca_bc, :ca_ns, :ca_yk] + DEFINED_REGIONS = [:ca, :ca_qc, :us, :ca_nf, :ca_nt, :ca_nu, :ca_ab, :ca_on, :ca_sk, :ca_mb, :ca_bc, :ca_ns, :ca_yk] 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| ca_victoria_day(year) }, :name => "National Patriotes Day", :regions => [:ca_qc]}, + {:wday => 0, :week => 3, :name => "Father's Day", :regions => [:us, :ca]}], + 0 => [{:function => lambda { |year| easter(year)-2 }, :name => "Good Friday", :regions => [:ca, :us]}, {: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]}, @@ -30,16 +31,22 @@ module Holidays {:mday => 12, :name => "Orangemen's Day", :regions => [:ca_nf]}, {: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]}], + {:wday => 1, :week => 3, :name => "Louis Riel Day", :regions => [:ca_mb]}, + {:mday => 2, :name => "Groundhog Day", :regions => [:us, :ca]}, + {:mday => 14, :name => "Valentine's Day", :regions => [:us, :ca]}], 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]}], + 3 => [{:mday => 23, :name => "St. George's Day", :regions => [:ca_nf]}, + {:mday => 17, :name => "St. Patrick's Day", :regions => [:us, :ca]}], 9 => [{:wday => 1, :week => 1, :name => "Labour Day", :regions => [:ca]}], - 10 => [{:wday => 1, :week => 2, :name => "Thanksgiving", :regions => [:ca]}] + 4 => [{:mday => 1, :name => "April Fool's Day", :regions => [:us, :ca]}, + {:mday => 22, :name => "Earth Day", :regions => [:us, :ca]}], + 10 => [{:wday => 1, :week => 2, :name => "Thanksgiving", :regions => [:ca]}, + {:mday => 31, :name => "Halloween", :regions => [:us, :ca]}] } # Get the date of Easter in a given year. @@ -85,21 +92,4 @@ 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::CA::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::CA::HOLIDAYS_BY_MONTH)) - const_set(:HOLIDAYS_BY_MONTH, Holidays::CA::HOLIDAYS_BY_MONTH) - - include Holidays::CA -end +Holidays.merge_defs(Holidays::CA::DEFINED_REGIONS, Holidays::CA::HOLIDAYS_BY_MONTH) diff --git a/lib/holidays/gb.rb b/lib/holidays/gb.rb new file mode 100644 index 0000000..83d1d5d --- /dev/null +++ b/lib/holidays/gb.rb @@ -0,0 +1,67 @@ +module Holidays + # This file is generated by the Ruby Holiday gem. + # + # Definitions loaded: data/gb.yaml, data/common_methods.yaml + # + # To use the definitions in the file, load them right after you load the + # Holiday gem: + # + # require 'holidays' + # require 'path/to/gb' + # + # More definitions are available at http://code.dunae.ca/holidays. + module GB # :nodoc: + DEFINED_REGIONS = [:gb, :je, :gb_jsy, :gg, :gb_gsy, :gb_eng, :gb_wls, :gb_eaw, :gb_nir, :gb_sct, :im, :gb_iom, :gb_con] + + HOLIDAYS_BY_MONTH = { + 5 => [{:wday => 1, :week => 1, :name => "May Day", :regions => [:gb]}, + {:mday => 9, :name => "Liberation Day", :regions => [:je, :gb_jsy, :gg, :gb_gsy]}, + {:wday => 1, :week => -1, :name => "Bank Holiday", :regions => [:gb]}], + 0 => [{:function => lambda { |year| easter(year)-2 }, :name => "Good Friday", :regions => [:gb]}, + {:function => lambda { |year| easter(year) }, :name => "Easter Sunday", :regions => [:gb]}, + {:function => lambda { |year| easter(year)+1 }, :name => "Easter Monday", :regions => [:gb_eng, :gb_wls, :gb_eaw, :gb_nir]}], + 1 => [{:mday => 1, :name => "New Year's Day", :regions => [:gb]}, + {:mday => 2, :name => "New Year's", :regions => [:gb_sct]}], + 12 => [{:mday => 25, :name => "Christmas Day", :regions => [:gb]}, + {:mday => 26, :name => "Boxing Day", :regions => [:gb]}], + 7 => [{:mday => 5, :name => "Tynwald Day", :regions => [:im, :gb_iom]}, + {:mday => 12, :name => "Battle of the Boyne", :regions => [:gb_nir]}], + 8 => [{:wday => 1, :week => 1, :name => "Bank Holiday", :regions => [:gb_sct]}, + {:wday => 1, :week => -1, :name => "Bank Holiday", :regions => [:gb_eng, :gb_wls, :gb_eaw]}], + 3 => [{:mday => 5, :name => "St. Piran's Day", :regions => [:gb_con]}, + {:mday => 17, :name => "St. Patrick's Day", :regions => [:gb_nir]}] + } + +# Get the date of Easter in a given year. +# +# +year+ must be a valid Gregorian year. +# +# Returns a Date object. +#-- +# from http://snippets.dzone.com/posts/show/765 +# TODO: check year to ensure Gregorian +def self.easter(year) + y = year + a = y % 19 + b = y / 100 + c = y % 100 + d = b / 4 + e = b % 4 + f = (b + 8) / 25 + g = (b - f + 1) / 3 + h = (19 * a + b - d - g + 15) % 30 + i = c / 4 + k = c % 4 + l = (32 + 2 * e + 2 * i - h - k) % 7 + m = (a + 11 * h + 22 * l) / 451 + month = (h + l - 7 * m + 114) / 31 + day = ((h + l - 7 * m + 114) % 31) + 1 + Date.civil(year, month, day) +end + + + + end +end + +Holidays.merge_defs(Holidays::GB::DEFINED_REGIONS, Holidays::GB::HOLIDAYS_BY_MONTH) diff --git a/lib/holidays/ie.rb b/lib/holidays/ie.rb new file mode 100644 index 0000000..c338f8e --- /dev/null +++ b/lib/holidays/ie.rb @@ -0,0 +1,60 @@ +module Holidays + # This file is generated by the Ruby Holiday gem. + # + # Definitions loaded: data/ie.yaml, data/common_methods.yaml + # + # To use the definitions in the file, load them right after you load the + # Holiday gem: + # + # require 'holidays' + # require 'path/to/ie' + # + # More definitions are available at http://code.dunae.ca/holidays. + module IE # :nodoc: + DEFINED_REGIONS = [:ie] + + HOLIDAYS_BY_MONTH = { + 5 => [{:wday => 1, :week => 1, :name => "May Day", :regions => [:ie]}], + 0 => [{:function => lambda { |year| easter(year)+1 }, :name => "Easter Monday", :regions => [:ie]}], + 6 => [{:wday => 1, :week => 1, :name => "Labour Day/May Day", :regions => [:ie]}], + 1 => [{:mday => 1, :name => "New Year's Day", :regions => [:ie]}], + 12 => [{:mday => 25, :name => "Christmas Day", :regions => [:ie]}, + {:mday => 26, :name => "St. Stephen's Day", :regions => [:ie]}], + 8 => [{:wday => 1, :week => 1, :name => "August Holiday", :regions => [:ie]}], + 3 => [{:mday => 17, :name => "St. Patrick's Day", :regions => [:ie]}], + 10 => [{:wday => 1, :week => -1, :name => "October Holiday", :regions => [:ie]}] + } + +# Get the date of Easter in a given year. +# +# +year+ must be a valid Gregorian year. +# +# Returns a Date object. +#-- +# from http://snippets.dzone.com/posts/show/765 +# TODO: check year to ensure Gregorian +def self.easter(year) + y = year + a = y % 19 + b = y / 100 + c = y % 100 + d = b / 4 + e = b % 4 + f = (b + 8) / 25 + g = (b - f + 1) / 3 + h = (19 * a + b - d - g + 15) % 30 + i = c / 4 + k = c % 4 + l = (32 + 2 * e + 2 * i - h - k) % 7 + m = (a + 11 * h + 22 * l) / 451 + month = (h + l - 7 * m + 114) / 31 + day = ((h + l - 7 * m + 114) % 31) + 1 + Date.civil(year, month, day) +end + + + + end +end + +Holidays.merge_defs(Holidays::IE::DEFINED_REGIONS, Holidays::IE::HOLIDAYS_BY_MONTH) diff --git a/test/test_common_methods.rb b/test/test_common_methods.rb index 50c048f..4f386f9 100644 --- a/test/test_common_methods.rb +++ b/test/test_common_methods.rb @@ -3,7 +3,6 @@ require File.dirname(__FILE__) + '/test_helper' class CommonMethodsTests < Test::Unit::TestCase def test_inclusion - assert Holidays.include?(Holidays::CA) flunk assert_equal '1800-04-13', Holidays.easter(1800).to_s assert_equal '1899-04-02', Holidays.easter(1899).to_s diff --git a/test/test_holidays.rb b/test/test_holidays.rb index a313e5c..1cb1006 100644 --- a/test/test_holidays.rb +++ b/test/test_holidays.rb @@ -50,22 +50,22 @@ class HolidaysTests < Test::Unit::TestCase end def test_any_region - # Should return Victoria Day + # Should return Victoria Day and Father's Day holidays = Holidays.between(Date.civil(2008,5,1), Date.civil(2008,5,31), :ca) - assert_equal 1, holidays.length - - # Should return Victoria Day and National Patriotes Day - holidays = Holidays.between(Date.civil(2008,5,1), Date.civil(2008,5,31), :any) assert_equal 2, holidays.length + + # Should return Victoria Day, Father's Day and National Patriotes Day + holidays = Holidays.between(Date.civil(2008,5,1), Date.civil(2008,5,31), :any) + assert_equal 3, holidays.length end def test_sub_regions - # Should return Victoria Day + # Should return Victoria Day and Father's Day holidays = Holidays.between(Date.civil(2008,5,1), Date.civil(2008,5,31), :ca) - assert_equal 1, holidays.length - - # Should return Victoria Day and National Patriotes Day - holidays = Holidays.between(Date.civil(2008,5,1), Date.civil(2008,5,31), :ca_qc) assert_equal 2, holidays.length + + # Should return Victoria Day, Father's Day and National Patriotes Day + holidays = Holidays.between(Date.civil(2008,5,1), Date.civil(2008,5,31), :ca_qc) + assert_equal 3, holidays.length end end diff --git a/test/test_multiple_regions.rb b/test/test_multiple_regions.rb new file mode 100644 index 0000000..486eb95 --- /dev/null +++ b/test/test_multiple_regions.rb @@ -0,0 +1,27 @@ +require File.dirname(__FILE__) + '/test_helper' +require 'holidays/gb' +require 'holidays/ie' + + +class MultipleRegionsTests < Test::Unit::TestCase + def setup + @date = Date.civil(2008,1,1) + end + + def test_defining_regions + #assert Holidays::DEFINED_REGIONS.include?(:gb) + #assert Holidays::DEFINED_REGIONS.include?(:ie) + #assert Holidays::DEFINED_REGIONS.include?(:gb_con) + end + + def test_defining_holidays + h = Holidays.on(Date.civil(2008,12,26), :ie) + assert_equal 'St. Stephen\'s Day', h[0][:name] + + h = Holidays.on(Date.civil(2008,5,9), :je) + assert_equal 'Liberation Day', h[0][:name] + + h = Holidays.on(Date.civil(2008,5,9), :gb) + assert h.empty? + end +end