holidays 3.3.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/CONTRIBUTING.md +37 -0
  4. data/README.md +16 -25
  5. data/REFERENCES +4 -1
  6. data/Rakefile +38 -8
  7. data/benchmark.rb +8 -0
  8. data/definitions/README.md +187 -8
  9. data/definitions/ar.yaml +2 -1
  10. data/definitions/at.yaml +17 -13
  11. data/definitions/au.yaml +65 -60
  12. data/definitions/be_fr.yaml +14 -10
  13. data/definitions/be_nl.yaml +8 -4
  14. data/definitions/bg.yaml +12 -6
  15. data/definitions/br.yaml +6 -3
  16. data/definitions/ca.yaml +8 -6
  17. data/definitions/ch.yaml +21 -15
  18. data/definitions/cl.yaml +4 -2
  19. data/definitions/cr.yaml +5 -3
  20. data/definitions/cz.yaml +4 -2
  21. data/definitions/de.yaml +25 -14
  22. data/definitions/dk.yaml +26 -17
  23. data/definitions/ecb_target.yaml +4 -2
  24. data/definitions/el.yaml +23 -18
  25. data/definitions/es.yaml +31 -28
  26. data/definitions/federal_reserve.yaml +12 -12
  27. data/definitions/fedex.yaml +6 -6
  28. data/definitions/fi.yaml +26 -25
  29. data/definitions/fr.yaml +8 -4
  30. data/definitions/gb.yaml +9 -7
  31. data/definitions/hr.yaml +8 -6
  32. data/definitions/hu.yaml +8 -6
  33. data/definitions/ie.yaml +17 -16
  34. data/definitions/index.yaml +1 -1
  35. data/definitions/is.yaml +29 -19
  36. data/definitions/it.yaml +10 -9
  37. data/definitions/jp.yaml +92 -44
  38. data/definitions/li.yaml +25 -20
  39. data/definitions/lt.yaml +2 -1
  40. data/definitions/ma.yaml +7 -7
  41. data/definitions/mx.yaml +11 -11
  42. data/definitions/nerc.yaml +6 -6
  43. data/definitions/nl.yaml +22 -18
  44. data/definitions/no.yaml +19 -11
  45. data/definitions/north_america_informal.yaml +6 -6
  46. data/definitions/nyse.yaml +9 -8
  47. data/definitions/nz.yaml +33 -29
  48. data/definitions/ph.yaml +15 -8
  49. data/definitions/pl.yaml +27 -17
  50. data/definitions/pt.yaml +4 -2
  51. data/definitions/ro.yaml +21 -18
  52. data/definitions/se.yaml +24 -18
  53. data/definitions/sg.yaml +10 -9
  54. data/definitions/si.yaml +4 -2
  55. data/definitions/sk.yaml +4 -2
  56. data/definitions/united_nations.yaml +12 -12
  57. data/definitions/ups.yaml +6 -6
  58. data/definitions/us.yaml +12 -11
  59. data/definitions/ve.yaml +8 -4
  60. data/definitions/vi.yaml +6 -6
  61. data/definitions/za.yaml +26 -24
  62. data/holidays.gemspec +3 -1
  63. data/lib/generated_definitions/MANIFEST +1 -1
  64. data/lib/generated_definitions/ar.rb +8 -6
  65. data/lib/generated_definitions/at.rb +11 -9
  66. data/lib/generated_definitions/au.rb +75 -99
  67. data/lib/generated_definitions/be.rb +12 -10
  68. data/lib/generated_definitions/be_fr.rb +12 -10
  69. data/lib/generated_definitions/be_nl.rb +12 -10
  70. data/lib/generated_definitions/bg.rb +14 -13
  71. data/lib/generated_definitions/br.rb +11 -9
  72. data/lib/generated_definitions/ca.rb +20 -20
  73. data/lib/generated_definitions/ch.rb +41 -44
  74. data/lib/generated_definitions/cl.rb +9 -7
  75. data/lib/generated_definitions/cr.rb +9 -7
  76. data/lib/generated_definitions/cz.rb +9 -6
  77. data/lib/generated_definitions/de.rb +25 -25
  78. data/lib/generated_definitions/dk.rb +17 -15
  79. data/lib/generated_definitions/ecb_target.rb +9 -7
  80. data/lib/generated_definitions/el.rb +13 -11
  81. data/lib/generated_definitions/es.rb +35 -33
  82. data/lib/generated_definitions/europe.rb +234 -247
  83. data/lib/generated_definitions/federal_reserve.rb +11 -9
  84. data/lib/generated_definitions/fedex.rb +42 -0
  85. data/lib/generated_definitions/fi.rb +32 -36
  86. data/lib/generated_definitions/fr.rb +12 -10
  87. data/lib/generated_definitions/gb.rb +15 -13
  88. data/lib/generated_definitions/hr.rb +10 -8
  89. data/lib/generated_definitions/hu.rb +9 -7
  90. data/lib/generated_definitions/ie.rb +17 -17
  91. data/lib/generated_definitions/is.rb +26 -26
  92. data/lib/generated_definitions/it.rb +9 -7
  93. data/lib/generated_definitions/jp.rb +112 -89
  94. data/lib/generated_definitions/li.rb +14 -12
  95. data/lib/generated_definitions/lt.rb +9 -7
  96. data/lib/generated_definitions/ma.rb +7 -5
  97. data/lib/generated_definitions/mx.rb +7 -5
  98. data/lib/generated_definitions/nerc.rb +10 -8
  99. data/lib/generated_definitions/nl.rb +15 -13
  100. data/lib/generated_definitions/no.rb +16 -14
  101. data/lib/generated_definitions/north_america.rb +34 -37
  102. data/lib/generated_definitions/nyse.rb +10 -8
  103. data/lib/generated_definitions/nz.rb +40 -40
  104. data/lib/generated_definitions/ph.rb +17 -13
  105. data/lib/generated_definitions/pl.rb +25 -27
  106. data/lib/generated_definitions/pt.rb +10 -8
  107. data/lib/generated_definitions/ro.rb +11 -9
  108. data/lib/generated_definitions/scandinavia.rb +92 -102
  109. data/lib/generated_definitions/se.rb +25 -27
  110. data/lib/generated_definitions/sg.rb +11 -9
  111. data/lib/generated_definitions/si.rb +10 -8
  112. data/lib/generated_definitions/sk.rb +9 -7
  113. data/lib/generated_definitions/united_nations.rb +7 -5
  114. data/lib/generated_definitions/ups.rb +13 -12
  115. data/lib/generated_definitions/us.rb +20 -21
  116. data/lib/generated_definitions/ve.rb +11 -9
  117. data/lib/generated_definitions/vi.rb +7 -5
  118. data/lib/generated_definitions/za.rb +19 -17
  119. data/lib/holidays.rb +20 -83
  120. data/lib/holidays/date_calculator/weekend_modifier.rb +22 -5
  121. data/lib/holidays/definition/context/generator.rb +67 -29
  122. data/lib/holidays/definition/context/merger.rb +8 -8
  123. data/lib/holidays/definition/decorator/custom_method_proc.rb +28 -0
  124. data/lib/holidays/definition/decorator/custom_method_source.rb +30 -0
  125. data/lib/holidays/definition/entity/custom_method.rb +11 -0
  126. data/lib/holidays/definition/parser/custom_method.rb +69 -0
  127. data/lib/holidays/definition/repository/custom_methods.rb +27 -0
  128. data/lib/holidays/definition/repository/holidays_by_month.rb +1 -1
  129. data/lib/holidays/definition/repository/{proc_cache.rb → proc_result_cache.rb} +19 -4
  130. data/lib/holidays/definition/validator/custom_method.rb +31 -0
  131. data/lib/holidays/definition_factory.rb +42 -6
  132. data/lib/holidays/errors.rb +6 -0
  133. data/lib/holidays/load_all_definitions.rb +57 -0
  134. data/lib/holidays/option/context/parse_options.rb +26 -16
  135. data/lib/holidays/option_factory.rb +1 -0
  136. data/lib/holidays/use_case/context/between.rb +41 -14
  137. data/lib/holidays/use_case_factory.rb +2 -1
  138. data/lib/holidays/version.rb +1 -1
  139. data/test/data/test_single_custom_holiday_with_custom_procs.yaml +24 -0
  140. data/test/defs/test_defs_at.rb +1 -1
  141. data/test/defs/test_defs_au.rb +3 -2
  142. data/test/defs/test_defs_cr.rb +1 -0
  143. data/test/defs/test_defs_cz.rb +1 -0
  144. data/test/defs/test_defs_dk.rb +2 -2
  145. data/test/defs/test_defs_el.rb +7 -6
  146. data/test/defs/test_defs_europe.rb +40 -33
  147. data/test/defs/test_defs_fedex.rb +24 -0
  148. data/test/defs/test_defs_fi.rb +4 -3
  149. data/test/defs/test_defs_hr.rb +2 -2
  150. data/test/defs/test_defs_hu.rb +2 -2
  151. data/test/defs/test_defs_is.rb +2 -1
  152. data/test/defs/test_defs_it.rb +2 -1
  153. data/test/defs/test_defs_jp.rb +1 -1
  154. data/test/defs/test_defs_li.rb +1 -1
  155. data/test/defs/test_defs_ma.rb +2 -1
  156. data/test/defs/test_defs_mx.rb +4 -3
  157. data/test/defs/test_defs_nl.rb +7 -6
  158. data/test/defs/test_defs_no.rb +1 -0
  159. data/test/defs/test_defs_north_america.rb +4 -3
  160. data/test/defs/test_defs_nyse.rb +2 -1
  161. data/test/defs/test_defs_pl.rb +1 -0
  162. data/test/defs/test_defs_ro.rb +11 -11
  163. data/test/defs/test_defs_scandinavia.rb +12 -8
  164. data/test/defs/test_defs_se.rb +3 -2
  165. data/test/defs/test_defs_sg.rb +2 -1
  166. data/test/defs/test_defs_vi.rb +1 -1
  167. data/test/defs/test_defs_za.rb +3 -2
  168. data/test/holidays/date_calculator/test_weekend_modifier.rb +11 -0
  169. data/test/holidays/definition/context/test_generator.rb +64 -5
  170. data/test/holidays/definition/context/test_merger.rb +5 -2
  171. data/test/holidays/definition/decorator/test_custom_method_proc.rb +113 -0
  172. data/test/holidays/definition/decorator/test_custom_method_source.rb +96 -0
  173. data/test/holidays/definition/parser/test_custom_method.rb +79 -0
  174. data/test/holidays/definition/repository/test_custom_methods.rb +43 -0
  175. data/test/holidays/definition/repository/test_holidays_by_month.rb +0 -32
  176. data/test/holidays/definition/repository/test_proc_result_cache.rb +84 -0
  177. data/test/holidays/definition/validator/test_custom_method.rb +89 -0
  178. data/test/holidays/option/context/test_parse_options.rb +5 -0
  179. data/test/holidays/test_definition_factory.rb +17 -2
  180. data/test/holidays/use_case/context/test_between.rb +2 -0
  181. data/test/test_all_regions.rb +7 -49
  182. data/test/test_custom_holidays.rb +8 -2
  183. data/test/test_helper.rb +9 -2
  184. data/test/test_holidays.rb +9 -29
  185. metadata +46 -11
  186. data/lib/generated_definitions/fed_ex.rb +0 -41
  187. data/test/holidays/definition/repository/test_proc_cache.rb +0 -29
  188. data/test/test_parse_definitions.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 314e234058d757423c0e873ac27f9ce001a54fa0
4
- data.tar.gz: f827b9614cd1037c20153fa2b316d000b784e2f4
3
+ metadata.gz: a3ae038d2ecc81231efdb1dfb62b8aa5f8a9a08b
4
+ data.tar.gz: 0ee05da812d8db5409bad033938d44d127c5a9a7
5
5
  SHA512:
6
- metadata.gz: 3fbe210da7f49b7e8c5d5693e230ee2b5bb46190656be2c99bd28f795bc9e8e8ede109e699ebd87ed7b024ca76cfa6cc34220d2853603296700c8feaf3e95562
7
- data.tar.gz: 66f1d44e7a7fc1c10b84f959dccc5c0710a10f802d0ee9bcdd8b74e7bf526d3be95ee1c36dc4dd2a756086bc3753218d7b87b6f8c872cc252e5cf8ba4e04c21e
6
+ metadata.gz: d89718606e9235afedb475611e069cc5cfeae83951f28881418df6299287cd947bff46df32ee6fbec68eb3794f42622c90ca8d69b4fc764bc9a0464542a1e36f
7
+ data.tar.gz: 1005849766e633f5fad96e4cdc37f8d5ab021c63b5a50c921bd066239eedd69d07d22f0b83474af958fc32db75cfee83ff7216f6d8a146b4788466e05702fc1b
@@ -1,5 +1,49 @@
1
1
  # Ruby Holidays Gem CHANGELOG
2
2
 
3
+ ## 4.0.0
4
+
5
+ Major refactor with breaking changes! Sorry for the wall of text but there is a lot of info here.
6
+
7
+ * Fixes issue 144 (loading custom defs with methods). This was the refactor catalyst. Changes highlights include:
8
+ - Allow for custom methods added via the `load_custom` method to be used immediately as expected
9
+ - Consolidate and clarify custom method parsing and validation
10
+ - Change nearly every definition to use new 'custom method' YAML format. See `definitions/README.md` for more info.
11
+ - Remove `require` functionality when loading new definitions, instead using in-memory repositories. See below for info.
12
+ - Now loads all generated definitions when `require 'holidays'` is called. See below for performance info.
13
+ * Add `rake console` command for easier local testing
14
+ * Remove or rename many public methods that were never intended for public use:
15
+ - Remove following date calculation helper methods (definitions must now directly call factory):
16
+ - `easter`
17
+ - `orthodox_easter`
18
+ - `orthodox_easter_julian`
19
+ - `to_monday_if_sunday`
20
+ - `to_monday_if_weekend`
21
+ - `to_weekday_if_boxing_weekend`
22
+ - `to_weekday_if_boxing_weekend_from_year`
23
+ - `to_weekday_if_weekend`
24
+ - `calculate_day_of_month`
25
+ - Remove `available` method. This was only intended for internal use
26
+ - Remove `parse_definition_files_and_return_source`. This was only intended for internal use
27
+ - Remove `load_all` method. This was only intended for internal use
28
+ - Rename `regions` to `available_regions` for clarity
29
+ - Rename `full_week?` to `any_holidays_during_work_week?` for clarity
30
+ * Following methods now constitute the 'public API' of this gem:
31
+ - `on`
32
+ - `any_holidays_during_work_week?` (renamed method, was originally `full_week?`, same behavior as before)
33
+ - `between`
34
+ - `cache_between`
35
+ - `available_regions` (renamed method, was originally `regions`, same behavior as before)
36
+ - `load_custom`
37
+ * All generated definitions are now loaded when `require 'holidays'` is called
38
+ - Previously files were required 'on the fly' when a specific region was specified. By requiring all definitions upon
39
+ startup we greatly simplify the handling of regions, definitions, and custom methods internally
40
+ - This results in a performance hit when calling `require 'holidays'`. Here is an example based on my benchmarking:
41
+ - old: `0.045537`
42
+ - new: `0.145125`
43
+
44
+ I decided that this performance hit on startup is acceptable. All other performance should remain the same. If performance is
45
+ a major concern please open an issue so we can discuss your use case.
46
+
3
47
  ## 3.3.0
4
48
 
5
49
  This is the final minor point release in v3.X.X. I am releasing it so that all of the latest definitions can be
@@ -0,0 +1,37 @@
1
+ # How to contribute
2
+
3
+ There are multiple ways to help! We rely on users around the world to help keep our definitions accurate and up to date. In addition, pull requests to address bugs or implement new features are always welcome.
4
+
5
+ ## For definition updates
6
+
7
+ Our definitions are written in YAML. You can find a complete guide to our format in the [definitions README](definitions/README.md). We take the YAML definitions and generate final ruby classes that are loaded at runtime for fast calculations.
8
+
9
+ Here are the steps to take once you have a good idea on what you want to change:
10
+
11
+ * Fork the repository
12
+ * Edit desired definition YAML file(s) located under `definitions/`. If you are adding a new region be sure to update `definitions/index.yaml` as well
13
+ * Run `bundle exec rake generate` to generate updated final definitions (they will be located under `lib/generated_definitions/` and `test/defs/`)
14
+ * Run `bundle exec rake test` to ensure your changes did not introduce errors
15
+ * Open a PR with *all* of these changes. You *MUST* include the generated definition files and tests in your PR. There is no automatic process to generate definitions at this time
16
+
17
+ Including documentation with your updates is very much appreciated. A simple Wikipedia entry or government link in the comments alongside your changes would be perfect.
18
+
19
+ Lastly, note that there are many 'meta' regions. For example, there are regions for Europe, Scandinavia, and North America. If your new region(s) falls into these areas consider adding them. You can find these 'meta' regions in `definitions/index.yaml`.
20
+
21
+ ## For non-definition functionality
22
+
23
+ * Fork the repository
24
+ * Make your changes
25
+ * Create a PR pointing back to `master`
26
+
27
+ Don't worry about versioning, we'll handle it on our end.
28
+
29
+ *Tests are required*. If your PR results in lower test coverage then it will not be accepted.
30
+
31
+ ## Local development helpers
32
+
33
+ We have included a few handy tasks to help you troubleshoot and test:
34
+
35
+ * `rake test` - runs the entire suite
36
+ * `rake test_region <region>` - runs the tests for just that region. Make sure to run `rake generate` after updating your YAML before running this!
37
+ * `rake console` - launches an IRB session with the 'holidays' gem loaded for quick testing
data/README.md CHANGED
@@ -14,7 +14,9 @@ To install the gem from RubyGems:
14
14
 
15
15
  The Holidays gem is tested on Ruby 2.0.0, 2.1.0, 2.2.0, 2.3.0 and JRuby.
16
16
 
17
- The Holidays gem follows [semantic versioning](http://semver.org/). Please take this into account when relying on this gem as a dependency.
17
+ This gem follows [semantic versioning](http://semver.org/). The only methods covered by this guarantee are under the
18
+ `Holidays` namespace specifically. Anything that is not a method off of `Holidays` or the core extension is not covered by
19
+ semver. Please take this into account when relying on this gem as a dependency.
18
20
 
19
21
  ## Time zones
20
22
 
@@ -53,6 +55,16 @@ Get informal holidays in February.
53
55
  Holidays.between(from, to, :informal)
54
56
  => [{:name => 'Valentine\'s Day',...}]
55
57
 
58
+ Return all available regions:
59
+
60
+ Holidays.available_regions
61
+ => [:ar, :at, ..., :sg] # this will be a big array
62
+
63
+ To check if there are any holidays taking place during a specified work week:
64
+
65
+ Holidays.any_holidays_during_work_week?(Date.civil(2016, 1, 1))
66
+ => true
67
+
56
68
  ### Loading Custom Definitions on the fly
57
69
 
58
70
  Load custom definitions file on the fly and use them immediately.
@@ -112,32 +124,11 @@ If you are checking holidays regularly you can cache your results for improved p
112
124
 
113
125
  Holidays.cache_between(Time.now, 2.years.from_now, :ca, :us, :observed)
114
126
 
115
- Holidays for the regions specified within the dates specified will be pre-calculated.
116
-
117
- See the [original pull request](https://github.com/alexdunae/holidays/pull/36) for more details.
127
+ Holidays for the regions specified within the dates specified will be pre-calculated and stored in-memory. Future lookups will be much faster.
118
128
 
119
129
  ### How to contribute
120
130
 
121
- #### For definition updates
122
-
123
- * Edit desired definition YAML file(s) located under `definitions/`. If you are adding a new region be sure to update `definitions/index.yaml` as well
124
- * Run `bundle exec rake generate` to generate updated final definitions (they will be located under `lib/generated_definitions/`)
125
- * Run `bundle exec rake test` to ensure your changes did not introduce errors
126
- * Open a PR with *all* of these changes. You *MUST* include the generated definition files in your PR. There is no automatic process to generated definitions at this time
127
-
128
- Including documentation with your updates is very much appreciated. A simple Wikipedia entry or government link in the comments alongside your changes would be perfect.
129
-
130
- Lastly, note that there are many 'meta' regions. For example, there are regions for Europe, Scandinavia, and North America. If your new region(s) falls into these areas consider adding them. You can find these 'meta' regions in `definitions/index.yaml`.
131
-
132
- #### For non-definition functionality
133
-
134
- * Fork the repository
135
- * Make your changes
136
- * Create a PR pointing back to `master`
137
-
138
- Don't worry about versioning, we'll handle it on our end.
139
-
140
- Tests are required. If your PR results in lower test coverage then it will not be accepted.
131
+ See our [contribution guidelines](CONTRIBUTING.md) for information on how to help out!
141
132
 
142
133
  ### Credits and code
143
134
 
@@ -145,4 +136,4 @@ Tests are required. If your PR results in lower test coverage then it will not b
145
136
  * Maintained by [Hana Wang](https://github.com/hahahana), 2013
146
137
  * Maintained by [Phil Trimble](https://github.com/ptrimble), 2014-present
147
138
 
148
- Plus all of these [wonderful contributors!](https://github.com/alexdunae/holidays/contributors)
139
+ Plus all of these [wonderful contributors!](https://github.com/holidays/holidays/contributors)
data/REFERENCES CHANGED
@@ -1,6 +1,6 @@
1
1
  === References
2
2
 
3
- I am grateful to the following sources.
3
+ We are eternally grateful to the following sources.
4
4
 
5
5
  ==== Date calculations
6
6
  * http://michaelthompson.org/technikos/holidays.php
@@ -8,9 +8,12 @@ I am grateful to the following sources.
8
8
  ==== Easter calculations
9
9
  * http://www.assa.org.au/edm.html
10
10
  * http://www.smart.net/~mmontes/ec-cal.html
11
+ * https://github.com/Loyolny/when_easter - graciously allowed by Michał Nierebiński
11
12
 
12
13
  ==== World dates
13
14
  * http://www.un.org/geninfo/faq/factsheets/FS18.HTM
14
15
  * http://en.wikipedia.org/wiki/List_of_holidays_by_country
15
16
 
17
+ Other sources for specific regions are noted in the definitions files themselves.
16
18
 
19
+ If a commit sneaks past the maintainers without attribution then please, let us know immediately! It was entirely unintentional.
data/Rakefile CHANGED
@@ -7,6 +7,9 @@ require 'yaml'
7
7
  require 'fileutils'
8
8
  require 'holidays'
9
9
 
10
+ DEFINITION_PATH = 'definitions'
11
+ DEFINITION_TESTS_PATH = 'test/defs'
12
+
10
13
  Rake::TestTask.new(:test) do |t|
11
14
  t.libs << 'test'
12
15
  t.test_files = FileList['test/**/test_*.rb']
@@ -14,30 +17,57 @@ end
14
17
 
15
18
  task :default => :test
16
19
 
17
- namespace :generate do
18
- DATA_PATH = 'definitions'
19
- TEST_DEFS_PATH = 'test/defs'
20
+ desc "Run tests for only a single region. Do not provide sub regions. Example (without quotes): 'rake test_region jp'"
21
+ task :test_region do
22
+ # Magic to define empty tasks on the fly so we have nicer arguments, see http://cobwwweb.com/4-ways-to-pass-arguments-to-a-rake-task
23
+ ARGV.each { |a| task a.to_sym do ; end }
24
+
25
+ if ARGV[1].nil? || ARGV[1].empty?
26
+ raise ArgumentError.new("You must provide a region. Example (without quotes): 'rake test_region us'")
27
+ end
20
28
 
29
+ region = ARGV[1].downcase
30
+
31
+ unless Holidays.available_regions.include?(region.to_sym)
32
+ raise ArgumentError.new("Region '#{region}' not recognized")
33
+ end
34
+
35
+ unless File.file?("#{DEFINITION_TESTS_PATH}/test_defs_#{region}.rb")
36
+ raise ArgumentError.new("Test file not found for region '#{region}'. Do not use sub regions, try the overall region instead. Example: 'us' instead of 'us_dc'")
37
+ end
38
+
39
+ sh "bundle exec ruby #{DEFINITION_TESTS_PATH}/test_defs_#{region}.rb"
40
+ end
41
+
42
+ desc 'Launch IRB session'
43
+ task :console do
44
+ sh "irb -rubygems -I lib -r holidays.rb"
45
+ end
46
+
47
+ desc 'Generate definitions and tests used in main holiday logic based on raw YAML definitions'
48
+ namespace :generate do
21
49
  desc 'Generate the holiday definition files'
22
50
  task :definitions do
23
51
  # load the index
24
- def_index = YAML.load_file("#{DATA_PATH}/index.yaml")
52
+ def_index = YAML.load_file("#{DEFINITION_PATH}/index.yaml")
25
53
 
26
54
  # create a dir for the generated tests
27
- FileUtils.mkdir_p(TEST_DEFS_PATH)
55
+ FileUtils.mkdir_p(DEFINITION_TESTS_PATH)
28
56
 
29
57
  all_regions = []
30
58
 
31
59
  def_index['defs'].each do |region, files|
32
60
  puts "Building #{region} definition module:"
33
- files = files.collect { |f| "#{DATA_PATH}/#{f}" }.uniq
61
+ files = files.collect { |f| "#{DEFINITION_PATH}/#{f}" }.uniq
62
+
63
+ regions, rules_by_month, custom_methods, tests = Holidays::DefinitionFactory.file_parser.parse_definition_files(files)
64
+ module_src, test_src = Holidays::DefinitionFactory.source_generator.generate_definition_source(region, files, regions, rules_by_month, custom_methods, tests)
34
65
 
35
- module_src, test_src, regions = Holidays.parse_definition_files_and_return_source(region, files)
36
66
  File.open("lib/#{Holidays::DEFINITIONS_PATH}/#{region.downcase.to_s}.rb","w") do |file|
37
67
  file.puts module_src
38
68
  end
39
69
  unless test_src.empty?
40
- File.open("#{TEST_DEFS_PATH}/test_defs_#{region.downcase.to_s}.rb","w") do |file|
70
+ File.open("#{DEFINITION_TESTS_PATH}/test_defs_#{region.downcase.to_s}.rb","w") do |file|
41
71
  file.puts test_src
42
72
  end
43
73
  end
@@ -0,0 +1,8 @@
1
+ require 'benchmark'
2
+
3
+ puts Benchmark.measure {
4
+ require 'holidays'
5
+ Holidays.between(
6
+ Date.civil(2016, 1, 1), Date.civil(2016, 12, 31), :us
7
+ )
8
+ }
@@ -51,7 +51,7 @@ The two required properties are:
51
51
 
52
52
  For example, the following holiday is on the first of January and available in the `:ca`, `:us` and `:au` regions:
53
53
 
54
- ```
54
+ ```yaml
55
55
  1:
56
56
  - name: New Year's Day
57
57
  regions: [ca, us, au]
@@ -65,7 +65,7 @@ For example, the following holiday is on the first of January and available in t
65
65
 
66
66
  For example, the following holiday is on the first Monday of September and available in the `:ca` region:
67
67
 
68
- ```
68
+ ```yaml
69
69
  9:
70
70
  - name: Labour Day
71
71
  regions: [ca]
@@ -73,6 +73,156 @@ For example, the following holiday is on the first Monday of September and avail
73
73
  wday: 1
74
74
  ```
75
75
 
76
+ ### 'Formal' vs 'Informal' types
77
+
78
+ As mentioned above you can specify two different types. By default a holiday is considered 'formal'. By adding a `type: informal` to a definition you will mark it as 'informal' and it will only show up if the user specifically asks for it.
79
+
80
+ Example:
81
+
82
+ ```yaml
83
+ 9:
84
+ - name: Some Holiday
85
+ regions: [fr]
86
+ mday: 1
87
+ type: informal
88
+ ```
89
+
90
+ If a user submits:
91
+
92
+ ```ruby
93
+ Holidays.on(Date.civil(2016, 9, 1), :fr)
94
+ ```
95
+
96
+ then they will not see the holiday. However, if they submit:
97
+
98
+ ```ruby
99
+ Holidays.on(Date.civil(2016, 9, 1), :fr, :informal)
100
+ ```
101
+
102
+ Then the holiday will be returned. This is especially useful for holidays like "Valentine's Day" in the USA, where it is commonly recognized as a holiday in society but not as a day that is celebrated by taking the day off.
103
+
104
+ ### Year ranges
105
+
106
+ Certain holidays in various countries are only in effect during specific year ranges. For example, a new holiday might come into effect that is only valid after a speciic year (say, 2017).
107
+
108
+ To address this we have the ability to specify these 'year ranges' in the definition. The gem will then only return a match on a date that adheres to these rules.
109
+
110
+ There are a total of four selectors that can be specified. All must be specified in terms of 'years'.
111
+
112
+ #### `before`
113
+
114
+ The 'before' selector will only find a match if the supplied date takes place
115
+ before or equal to the holiday.
116
+
117
+ Example:
118
+
119
+ ```yaml
120
+ 7:
121
+ name: 振替休日
122
+ regions: [jp]
123
+ mday: 1
124
+ year_ranges:
125
+ - before: 2002
126
+ ```
127
+
128
+ This will return successfully:
129
+
130
+ ```ruby
131
+ Holidays.on(Date.civil(2000, 7, 1), :jp)
132
+ ```
133
+
134
+ This will not:
135
+
136
+ ```ruby
137
+ Holidays.on(Date.civil(2016, 7, 1), :jp)
138
+ ```
139
+
140
+ #### `after`
141
+
142
+ The 'after' selector will only find a match if the supplied date takes place
143
+ after or equal to the holiday.
144
+
145
+ Example:
146
+
147
+ ```yaml
148
+ 7:
149
+ name: 振替休日
150
+ regions: [jp]
151
+ mday: 1
152
+ year_ranges:
153
+ - after: 2002
154
+ ```
155
+
156
+ This will return successfully:
157
+
158
+ ```ruby
159
+ Holidays.on(Date.civil(2016, 7, 1), :jp)
160
+ ```
161
+
162
+ This will not:
163
+
164
+ ```ruby
165
+ Holidays.on(Date.civil(2000, 7, 1), :jp)
166
+ ```
167
+
168
+ #### `limited`
169
+
170
+ The 'limited' selector will only find a match if the supplied date takes place during
171
+ one of the specified years. Multiple years can be specified.
172
+
173
+ An array of years *must* be supplied. Individual integers will result in an error.
174
+
175
+ Example:
176
+
177
+ ```yaml
178
+ 7:
179
+ name: 振替休日
180
+ regions: [jp]
181
+ mday: 1
182
+ year_ranges:
183
+ - limited: [2002]
184
+ ```
185
+
186
+ This will return successfully:
187
+
188
+ ```ruby
189
+ Holidays.on(Date.civil(2002, 7, 1), :jp)
190
+ ```
191
+
192
+ This will not:
193
+
194
+ ```ruby
195
+ Holidays.on(Date.civil(2000, 7, 1), :jp)
196
+ ```
197
+
198
+ #### `between`
199
+
200
+ The 'between' selector will only find a match if the supplied date takes place during the specified range of years. Only a single range is allowed at this time.
201
+
202
+ Example:
203
+
204
+ ```yaml
205
+ 7:
206
+ name: 振替休日
207
+ regions: [jp]
208
+ mday: 1
209
+ year_ranges:
210
+ - between: 1996..2002
211
+ ```
212
+
213
+ This will return successfully:
214
+
215
+ ```ruby
216
+ Holidays.on(Date.civil(2000, 7, 1), :jp)
217
+ ```
218
+
219
+ This will not:
220
+
221
+ ```ruby
222
+ Holidays.on(Date.civil(2003, 7, 1), :jp)
223
+ Holidays.on(Date.civil(1995, 7, 1), :jp)
224
+ ```
225
+
76
226
  ## Methods
77
227
 
78
228
  In addition to defining holidays by day or week, you can create custom methods to calculate a date. These should be placed under the `methods` property. Methods named in this way can then be referenced by entries in the `months` property.
@@ -81,16 +231,17 @@ For example, Canada celebrates Victoria Day, which falls on the Monday on or bef
81
231
 
82
232
  ```
83
233
  methods:
84
- ca_victoria_day: |
85
- def self.ca_victoria_day(year)
86
- date = Date.civil(year,5,24)
234
+ ca_victoria_day:
235
+ arguments: year
236
+ source: |
237
+ date = Date.civil(year, 5, 24)
87
238
  if date.wday > 1
88
239
  date -= (date.wday - 1)
89
240
  elsif date.wday == 0
90
241
  date -= 6
91
242
  end
243
+
92
244
  date
93
- end
94
245
  ```
95
246
 
96
247
  This would be represented in `months` entry as:
@@ -108,7 +259,7 @@ If a holiday can occur in different months (e.g. Easter) it can go in the '0' mo
108
259
  0:
109
260
  - name: Easter Monday
110
261
  regions: [ca]
111
- function: easter(year)+1
262
+ function: easter(year)
112
263
  ```
113
264
 
114
265
  There are pre-existing methods for highly-used calculations. They are:
@@ -127,10 +278,38 @@ There are pre-existing methods for highly-used calculations. They are:
127
278
  0:
128
279
  - name: Good Friday
129
280
  regions: [us]
130
- function: easter(year)-2
281
+ function: easter(year)
282
+ function_modifier: -2
131
283
  type: informal
132
284
  ```
133
285
 
286
+ Use the `function_modifier` property, which can be positive or negative, to modify the result of the function.
287
+
288
+ In addition, you may only specify the following values for arguments into a custom method: `date`, `year`, `month`, `day`.
289
+
290
+ If attempt to specify anything else then you will receive an error on definition generation. This is because these are the only values that are available to
291
+ call into the custom methods will calculating the result of a function.
292
+
293
+ Correct example:
294
+
295
+ ```
296
+ 1:
297
+ - name: Custom Method
298
+ regions: [us]
299
+ function: custom_method(year, month, day)
300
+ ```
301
+
302
+ If you do the following:
303
+
304
+ ```
305
+ 1:
306
+ - name: Custom Method
307
+ regions: [us]
308
+ function: custom_method(week)
309
+ ```
310
+
311
+ This will result in an error since `week` is not a recognized method argument.
312
+
134
313
  ### Calculating observed dates
135
314
 
136
315
  Users can specify that this gem only return holidays on their 'observed' day. This can be especially useful if they are using this gem for business-related logic. If you wish for your definitions to allow for this then you can add the `observed` property to your entry. This requires a method to help calculate the observed day.