revised_holidays 9.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.
Files changed (382) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +25 -0
  3. data/CHANGELOG.md +446 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +21 -0
  7. data/Makefile +45 -0
  8. data/README.md +337 -0
  9. data/Rakefile +109 -0
  10. data/bin/console +7 -0
  11. data/bin/setup +6 -0
  12. data/definitions/.github/workflows/ruby.yml +25 -0
  13. data/definitions/.gitignore +5 -0
  14. data/definitions/CHANGELOG.md +352 -0
  15. data/definitions/Gemfile +6 -0
  16. data/definitions/LICENSE +21 -0
  17. data/definitions/METHODS.yml +26 -0
  18. data/definitions/Makefile +9 -0
  19. data/definitions/README.md +22 -0
  20. data/definitions/ar.yaml +268 -0
  21. data/definitions/at.yaml +116 -0
  22. data/definitions/au.yaml +907 -0
  23. data/definitions/be_fr.yaml +153 -0
  24. data/definitions/be_nl.yaml +153 -0
  25. data/definitions/bg.yaml +186 -0
  26. data/definitions/br.yaml +178 -0
  27. data/definitions/ca.yaml +969 -0
  28. data/definitions/ch.yaml +277 -0
  29. data/definitions/cl.yaml +294 -0
  30. data/definitions/co.yaml +437 -0
  31. data/definitions/cr.yaml +100 -0
  32. data/definitions/cz.yaml +137 -0
  33. data/definitions/de.yaml +401 -0
  34. data/definitions/dk.yaml +220 -0
  35. data/definitions/doc/CONTRIBUTING.md +44 -0
  36. data/definitions/doc/MAINTAINERS.md +39 -0
  37. data/definitions/doc/SYNTAX.md +435 -0
  38. data/definitions/doc/architecture/README.md +15 -0
  39. data/definitions/doc/architecture/adr-001.md +86 -0
  40. data/definitions/doc/architecture/adr-002.md +64 -0
  41. data/definitions/ecbtarget.yaml +74 -0
  42. data/definitions/ee.yaml +123 -0
  43. data/definitions/es.yaml +495 -0
  44. data/definitions/federalreserve.yaml +389 -0
  45. data/definitions/federalreservebanks.yaml +821 -0
  46. data/definitions/fedex.yaml +102 -0
  47. data/definitions/fi.yaml +234 -0
  48. data/definitions/fr.yaml +157 -0
  49. data/definitions/gb.yaml +565 -0
  50. data/definitions/ge.yaml +158 -0
  51. data/definitions/gr.yaml +158 -0
  52. data/definitions/hk.yaml +287 -0
  53. data/definitions/hr.yaml +171 -0
  54. data/definitions/hu.yaml +156 -0
  55. data/definitions/ie.yaml +172 -0
  56. data/definitions/index.yaml +80 -0
  57. data/definitions/is.yaml +247 -0
  58. data/definitions/it.yaml +246 -0
  59. data/definitions/jp.yaml +761 -0
  60. data/definitions/ke.yaml +107 -0
  61. data/definitions/kr.yaml +166 -0
  62. data/definitions/kz.yaml +128 -0
  63. data/definitions/li.yaml +154 -0
  64. data/definitions/lib/validation/custom_method_validator.rb +38 -0
  65. data/definitions/lib/validation/definition_validator.rb +35 -0
  66. data/definitions/lib/validation/error.rb +11 -0
  67. data/definitions/lib/validation/month_validator.rb +58 -0
  68. data/definitions/lib/validation/run.rb +66 -0
  69. data/definitions/lib/validation/test_validator.rb +83 -0
  70. data/definitions/lt.yaml +198 -0
  71. data/definitions/lu.yaml +123 -0
  72. data/definitions/lv.yaml +229 -0
  73. data/definitions/ma.yaml +96 -0
  74. data/definitions/mt_en.yaml +131 -0
  75. data/definitions/mt_mt.yaml +131 -0
  76. data/definitions/mx.yaml +160 -0
  77. data/definitions/my.yaml +79 -0
  78. data/definitions/nerc.yaml +94 -0
  79. data/definitions/ng.yaml +97 -0
  80. data/definitions/nl.yaml +127 -0
  81. data/definitions/no.yaml +169 -0
  82. data/definitions/northamericainformal.yaml +105 -0
  83. data/definitions/nyse.yaml +137 -0
  84. data/definitions/nz.yaml +346 -0
  85. data/definitions/pe.yaml +208 -0
  86. data/definitions/ph.yaml +130 -0
  87. data/definitions/pl.yaml +796 -0
  88. data/definitions/pt.yaml +187 -0
  89. data/definitions/ro.yaml +240 -0
  90. data/definitions/rs_cyrl.yaml +129 -0
  91. data/definitions/rs_la.yaml +129 -0
  92. data/definitions/ru.yaml +108 -0
  93. data/definitions/se.yaml +238 -0
  94. data/definitions/sg.yaml +89 -0
  95. data/definitions/si.yaml +162 -0
  96. data/definitions/sk.yaml +154 -0
  97. data/definitions/spec/coverage_report.rb +7 -0
  98. data/definitions/spec/data/invalid/months/malformed/bad.yaml +15 -0
  99. data/definitions/spec/data/invalid/months/missing/no_months.yaml +9 -0
  100. data/definitions/spec/data/valid/simple.yaml +15 -0
  101. data/definitions/spec/spec_helper.rb +7 -0
  102. data/definitions/spec/validation/custom_method_validator_spec.rb +60 -0
  103. data/definitions/spec/validation/definition_validator_spec.rb +43 -0
  104. data/definitions/spec/validation/month_validator_spec.rb +175 -0
  105. data/definitions/spec/validation/test_validator_spec.rb +169 -0
  106. data/definitions/th.yaml +111 -0
  107. data/definitions/tn.yaml +83 -0
  108. data/definitions/tr.yaml +174 -0
  109. data/definitions/ua.yaml +161 -0
  110. data/definitions/unitednations.yaml +189 -0
  111. data/definitions/ups.yaml +102 -0
  112. data/definitions/us.yaml +965 -0
  113. data/definitions/ve.yaml +118 -0
  114. data/definitions/vi.yaml +54 -0
  115. data/definitions/za.yaml +139 -0
  116. data/doc/CONTRIBUTING.md +72 -0
  117. data/doc/MAINTAINERS.md +81 -0
  118. data/doc/REFERENCES +19 -0
  119. data/lib/generated_definitions/MANIFEST +83 -0
  120. data/lib/generated_definitions/REGIONS.rb +6 -0
  121. data/lib/generated_definitions/ar.rb +60 -0
  122. data/lib/generated_definitions/at.rb +37 -0
  123. data/lib/generated_definitions/au.rb +177 -0
  124. data/lib/generated_definitions/be.rb +42 -0
  125. data/lib/generated_definitions/be_fr.rb +36 -0
  126. data/lib/generated_definitions/be_nl.rb +36 -0
  127. data/lib/generated_definitions/bg.rb +53 -0
  128. data/lib/generated_definitions/br.rb +37 -0
  129. data/lib/generated_definitions/ca.rb +88 -0
  130. data/lib/generated_definitions/ch.rb +95 -0
  131. data/lib/generated_definitions/cl.rb +71 -0
  132. data/lib/generated_definitions/co.rb +121 -0
  133. data/lib/generated_definitions/cr.rb +35 -0
  134. data/lib/generated_definitions/cz.rb +37 -0
  135. data/lib/generated_definitions/de.rb +65 -0
  136. data/lib/generated_definitions/dk.rb +48 -0
  137. data/lib/generated_definitions/ecbtarget.rb +30 -0
  138. data/lib/generated_definitions/ee.rb +36 -0
  139. data/lib/generated_definitions/el.rb +38 -0
  140. data/lib/generated_definitions/es.rb +56 -0
  141. data/lib/generated_definitions/europe.rb +638 -0
  142. data/lib/generated_definitions/federalreserve.rb +35 -0
  143. data/lib/generated_definitions/federalreservebanks.rb +35 -0
  144. data/lib/generated_definitions/fedex.rb +36 -0
  145. data/lib/generated_definitions/fi.rb +61 -0
  146. data/lib/generated_definitions/fr.rb +39 -0
  147. data/lib/generated_definitions/gb.rb +51 -0
  148. data/lib/generated_definitions/ge.rb +41 -0
  149. data/lib/generated_definitions/gr.rb +38 -0
  150. data/lib/generated_definitions/hk.rb +106 -0
  151. data/lib/generated_definitions/hr.rb +40 -0
  152. data/lib/generated_definitions/hu.rb +35 -0
  153. data/lib/generated_definitions/ie.rb +33 -0
  154. data/lib/generated_definitions/is.rb +60 -0
  155. data/lib/generated_definitions/it.rb +45 -0
  156. data/lib/generated_definitions/jp.rb +166 -0
  157. data/lib/generated_definitions/ke.rb +34 -0
  158. data/lib/generated_definitions/kr.rb +40 -0
  159. data/lib/generated_definitions/kz.rb +38 -0
  160. data/lib/generated_definitions/li.rb +44 -0
  161. data/lib/generated_definitions/lt.rb +38 -0
  162. data/lib/generated_definitions/lu.rb +35 -0
  163. data/lib/generated_definitions/lv.rb +56 -0
  164. data/lib/generated_definitions/ma.rb +33 -0
  165. data/lib/generated_definitions/mt_en.rb +38 -0
  166. data/lib/generated_definitions/mt_mt.rb +38 -0
  167. data/lib/generated_definitions/mx.rb +54 -0
  168. data/lib/generated_definitions/my.rb +30 -0
  169. data/lib/generated_definitions/nerc.rb +30 -0
  170. data/lib/generated_definitions/ng.rb +33 -0
  171. data/lib/generated_definitions/nl.rb +37 -0
  172. data/lib/generated_definitions/no.rb +40 -0
  173. data/lib/generated_definitions/northamerica.rb +229 -0
  174. data/lib/generated_definitions/nyse.rb +34 -0
  175. data/lib/generated_definitions/nz.rb +105 -0
  176. data/lib/generated_definitions/pe.rb +43 -0
  177. data/lib/generated_definitions/ph.rb +50 -0
  178. data/lib/generated_definitions/pl.rb +73 -0
  179. data/lib/generated_definitions/pt.rb +40 -0
  180. data/lib/generated_definitions/ro.rb +39 -0
  181. data/lib/generated_definitions/rs_cyrl.rb +39 -0
  182. data/lib/generated_definitions/rs_la.rb +39 -0
  183. data/lib/generated_definitions/ru.rb +37 -0
  184. data/lib/generated_definitions/scandinavia.rb +166 -0
  185. data/lib/generated_definitions/se.rb +53 -0
  186. data/lib/generated_definitions/sg.rb +31 -0
  187. data/lib/generated_definitions/si.rb +39 -0
  188. data/lib/generated_definitions/sk.rb +39 -0
  189. data/lib/generated_definitions/southamerica.rb +248 -0
  190. data/lib/generated_definitions/th.rb +36 -0
  191. data/lib/generated_definitions/tn.rb +32 -0
  192. data/lib/generated_definitions/tr.rb +64 -0
  193. data/lib/generated_definitions/ua.rb +37 -0
  194. data/lib/generated_definitions/unitednations.rb +81 -0
  195. data/lib/generated_definitions/ups.rb +36 -0
  196. data/lib/generated_definitions/us.rb +153 -0
  197. data/lib/generated_definitions/ve.rb +36 -0
  198. data/lib/generated_definitions/vi.rb +29 -0
  199. data/lib/generated_definitions/za.rb +36 -0
  200. data/lib/holidays/core_extensions/date.rb +57 -0
  201. data/lib/holidays/core_extensions/time.rb +23 -0
  202. data/lib/holidays/date_calculator/day_of_month.rb +68 -0
  203. data/lib/holidays/date_calculator/easter.rb +91 -0
  204. data/lib/holidays/date_calculator/lunar_date.rb +371 -0
  205. data/lib/holidays/date_calculator/weekend_modifier.rb +80 -0
  206. data/lib/holidays/definition/context/function_processor.rb +91 -0
  207. data/lib/holidays/definition/context/generator.rb +209 -0
  208. data/lib/holidays/definition/context/load.rb +29 -0
  209. data/lib/holidays/definition/context/merger.rb +22 -0
  210. data/lib/holidays/definition/decorator/custom_method_proc.rb +28 -0
  211. data/lib/holidays/definition/decorator/custom_method_source.rb +30 -0
  212. data/lib/holidays/definition/decorator/test.rb +37 -0
  213. data/lib/holidays/definition/entity/custom_method.rb +11 -0
  214. data/lib/holidays/definition/entity/test.rb +11 -0
  215. data/lib/holidays/definition/generator/module.rb +54 -0
  216. data/lib/holidays/definition/generator/regions.rb +55 -0
  217. data/lib/holidays/definition/generator/test.rb +51 -0
  218. data/lib/holidays/definition/parser/custom_method.rb +67 -0
  219. data/lib/holidays/definition/parser/test.rb +86 -0
  220. data/lib/holidays/definition/repository/cache.rb +47 -0
  221. data/lib/holidays/definition/repository/custom_methods.rb +27 -0
  222. data/lib/holidays/definition/repository/holidays_by_month.rb +57 -0
  223. data/lib/holidays/definition/repository/proc_result_cache.rb +51 -0
  224. data/lib/holidays/definition/repository/regions.rb +46 -0
  225. data/lib/holidays/definition/validator/custom_method.rb +31 -0
  226. data/lib/holidays/definition/validator/region.rb +36 -0
  227. data/lib/holidays/definition/validator/test.rb +71 -0
  228. data/lib/holidays/errors.rb +11 -0
  229. data/lib/holidays/factory/date_calculator.rb +42 -0
  230. data/lib/holidays/factory/definition.rb +143 -0
  231. data/lib/holidays/factory/finder.rb +70 -0
  232. data/lib/holidays/finder/context/between.rb +45 -0
  233. data/lib/holidays/finder/context/dates_driver_builder.rb +64 -0
  234. data/lib/holidays/finder/context/next_holiday.rb +57 -0
  235. data/lib/holidays/finder/context/parse_options.rb +104 -0
  236. data/lib/holidays/finder/context/search.rb +111 -0
  237. data/lib/holidays/finder/context/year_holiday.rb +57 -0
  238. data/lib/holidays/finder/rules/in_region.rb +31 -0
  239. data/lib/holidays/finder/rules/year_range.rb +58 -0
  240. data/lib/holidays/load_all_definitions.rb +56 -0
  241. data/lib/holidays/version.rb +3 -0
  242. data/lib/holidays.rb +130 -0
  243. data/lib/revised_holidays.rb +1 -0
  244. data/revised_holidays.gemspec +31 -0
  245. data/test/coverage_report.rb +26 -0
  246. data/test/data/test_custom_govt_holiday_defs.yaml +5 -0
  247. data/test/data/test_custom_informal_holidays_defs.yaml +11 -0
  248. data/test/data/test_custom_year_range_holiday_defs.yaml +31 -0
  249. data/test/data/test_invalid_region.rb +15 -0
  250. data/test/data/test_multiple_custom_holiday_defs.yaml +12 -0
  251. data/test/data/test_multiple_regions_with_conflicts_region_1.yaml +38 -0
  252. data/test/data/test_multiple_regions_with_conflicts_region_2.yaml +38 -0
  253. data/test/data/test_region.rb +15 -0
  254. data/test/data/test_single_custom_holiday_defs.yaml +12 -0
  255. data/test/data/test_single_custom_holiday_with_custom_procs.yaml +28 -0
  256. data/test/defs/test_defs_ar.rb +69 -0
  257. data/test/defs/test_defs_at.rb +31 -0
  258. data/test/defs/test_defs_au.rb +233 -0
  259. data/test/defs/test_defs_be_fr.rb +45 -0
  260. data/test/defs/test_defs_be_nl.rb +45 -0
  261. data/test/defs/test_defs_bg.rb +41 -0
  262. data/test/defs/test_defs_br.rb +49 -0
  263. data/test/defs/test_defs_ca.rb +289 -0
  264. data/test/defs/test_defs_ch.rb +51 -0
  265. data/test/defs/test_defs_cl.rb +69 -0
  266. data/test/defs/test_defs_co.rb +113 -0
  267. data/test/defs/test_defs_cr.rb +29 -0
  268. data/test/defs/test_defs_cz.rb +37 -0
  269. data/test/defs/test_defs_de.rb +89 -0
  270. data/test/defs/test_defs_dk.rb +47 -0
  271. data/test/defs/test_defs_ecbtarget.rb +27 -0
  272. data/test/defs/test_defs_ee.rb +41 -0
  273. data/test/defs/test_defs_es.rb +137 -0
  274. data/test/defs/test_defs_europe.rb +1522 -0
  275. data/test/defs/test_defs_fed_ex.rb +24 -0
  276. data/test/defs/test_defs_federalreserve.rb +119 -0
  277. data/test/defs/test_defs_federalreservebanks.rb +251 -0
  278. data/test/defs/test_defs_fedex.rb +31 -0
  279. data/test/defs/test_defs_fi.rb +59 -0
  280. data/test/defs/test_defs_fr.rb +43 -0
  281. data/test/defs/test_defs_gb.rb +159 -0
  282. data/test/defs/test_defs_ge.rb +53 -0
  283. data/test/defs/test_defs_gr.rb +41 -0
  284. data/test/defs/test_defs_hk.rb +59 -0
  285. data/test/defs/test_defs_hr.rb +45 -0
  286. data/test/defs/test_defs_hu.rb +47 -0
  287. data/test/defs/test_defs_ie.rb +53 -0
  288. data/test/defs/test_defs_is.rb +51 -0
  289. data/test/defs/test_defs_it.rb +55 -0
  290. data/test/defs/test_defs_jp.rb +159 -0
  291. data/test/defs/test_defs_ke.rb +31 -0
  292. data/test/defs/test_defs_kr.rb +37 -0
  293. data/test/defs/test_defs_kz.rb +39 -0
  294. data/test/defs/test_defs_li.rb +35 -0
  295. data/test/defs/test_defs_lt.rb +65 -0
  296. data/test/defs/test_defs_lu.rb +35 -0
  297. data/test/defs/test_defs_lv.rb +98 -0
  298. data/test/defs/test_defs_ma.rb +29 -0
  299. data/test/defs/test_defs_mt_en.rb +41 -0
  300. data/test/defs/test_defs_mt_mt.rb +41 -0
  301. data/test/defs/test_defs_mx.rb +49 -0
  302. data/test/defs/test_defs_my.rb +23 -0
  303. data/test/defs/test_defs_nerc.rb +29 -0
  304. data/test/defs/test_defs_ng.rb +29 -0
  305. data/test/defs/test_defs_nl.rb +33 -0
  306. data/test/defs/test_defs_no.rb +43 -0
  307. data/test/defs/test_defs_northamerica.rb +667 -0
  308. data/test/defs/test_defs_nyse.rb +46 -0
  309. data/test/defs/test_defs_nz.rb +67 -0
  310. data/test/defs/test_defs_pe.rb +47 -0
  311. data/test/defs/test_defs_ph.rb +29 -0
  312. data/test/defs/test_defs_pl.rb +229 -0
  313. data/test/defs/test_defs_pt.rb +47 -0
  314. data/test/defs/test_defs_ro.rb +65 -0
  315. data/test/defs/test_defs_rs_cyrl.rb +46 -0
  316. data/test/defs/test_defs_rs_la.rb +46 -0
  317. data/test/defs/test_defs_ru.rb +34 -0
  318. data/test/defs/test_defs_scandinavia.rb +215 -0
  319. data/test/defs/test_defs_se.rb +59 -0
  320. data/test/defs/test_defs_sg.rb +25 -0
  321. data/test/defs/test_defs_si.rb +105 -0
  322. data/test/defs/test_defs_sk.rb +41 -0
  323. data/test/defs/test_defs_southamerica.rb +327 -0
  324. data/test/defs/test_defs_th.rb +33 -0
  325. data/test/defs/test_defs_tn.rb +27 -0
  326. data/test/defs/test_defs_tr.rb +60 -0
  327. data/test/defs/test_defs_ua.rb +41 -0
  328. data/test/defs/test_defs_unitednations.rb +11 -0
  329. data/test/defs/test_defs_ups.rb +31 -0
  330. data/test/defs/test_defs_us.rb +387 -0
  331. data/test/defs/test_defs_ve.rb +35 -0
  332. data/test/defs/test_defs_vi.rb +22 -0
  333. data/test/defs/test_defs_za.rb +35 -0
  334. data/test/holidays/core_extensions/test_date.rb +122 -0
  335. data/test/holidays/core_extensions/test_date_time.rb +60 -0
  336. data/test/holidays/date_calculator/test_day_of_month.rb +27 -0
  337. data/test/holidays/date_calculator/test_easter_gregorian.rb +30 -0
  338. data/test/holidays/date_calculator/test_easter_julian.rb +36 -0
  339. data/test/holidays/date_calculator/test_lunar_date.rb +89 -0
  340. data/test/holidays/date_calculator/test_weekend_modifier.rb +54 -0
  341. data/test/holidays/definition/context/test_function_processor.rb +199 -0
  342. data/test/holidays/definition/context/test_generator.rb +226 -0
  343. data/test/holidays/definition/context/test_load.rb +37 -0
  344. data/test/holidays/definition/context/test_merger.rb +25 -0
  345. data/test/holidays/definition/decorator/test_custom_method_proc.rb +113 -0
  346. data/test/holidays/definition/decorator/test_custom_method_source.rb +96 -0
  347. data/test/holidays/definition/decorator/test_test.rb +123 -0
  348. data/test/holidays/definition/generator/test_module.rb +268 -0
  349. data/test/holidays/definition/generator/test_regions.rb +97 -0
  350. data/test/holidays/definition/generator/test_test.rb +113 -0
  351. data/test/holidays/definition/parser/test_custom_method.rb +79 -0
  352. data/test/holidays/definition/parser/test_test.rb +142 -0
  353. data/test/holidays/definition/repository/test_cache.rb +123 -0
  354. data/test/holidays/definition/repository/test_custom_methods.rb +43 -0
  355. data/test/holidays/definition/repository/test_holidays_by_month.rb +275 -0
  356. data/test/holidays/definition/repository/test_proc_result_cache.rb +91 -0
  357. data/test/holidays/definition/repository/test_regions.rb +104 -0
  358. data/test/holidays/definition/validator/test_custom_method.rb +94 -0
  359. data/test/holidays/definition/validator/test_region.rb +54 -0
  360. data/test/holidays/definition/validator/test_test.rb +60 -0
  361. data/test/holidays/finder/context/test_between.rb +172 -0
  362. data/test/holidays/finder/context/test_dates_driver_builder.rb +91 -0
  363. data/test/holidays/finder/context/test_next_holiday.rb +156 -0
  364. data/test/holidays/finder/context/test_parse_options.rb +141 -0
  365. data/test/holidays/finder/context/test_search.rb +232 -0
  366. data/test/holidays/finder/context/test_year_holiday.rb +202 -0
  367. data/test/holidays/finder/rules/test_in_region.rb +42 -0
  368. data/test/holidays/finder/rules/test_year_range.rb +166 -0
  369. data/test/integration/README.md +9 -0
  370. data/test/integration/test_all_regions.rb +49 -0
  371. data/test/integration/test_any_holidays_during_work_week.rb +90 -0
  372. data/test/integration/test_available_regions.rb +23 -0
  373. data/test/integration/test_custom_holidays.rb +41 -0
  374. data/test/integration/test_custom_informal_holidays.rb +15 -0
  375. data/test/integration/test_custom_year_range_holidays.rb +35 -0
  376. data/test/integration/test_holidays.rb +243 -0
  377. data/test/integration/test_holidays_between.rb +87 -0
  378. data/test/integration/test_multiple_regions.rb +71 -0
  379. data/test/integration/test_multiple_regions_with_conflict.rb +29 -0
  380. data/test/integration/test_nonstandard_regions.rb +25 -0
  381. data/test/test_helper.rb +37 -0
  382. metadata +649 -0
@@ -0,0 +1,70 @@
1
+ require 'holidays/finder/context/between'
2
+ require 'holidays/finder/context/dates_driver_builder'
3
+ require 'holidays/finder/context/next_holiday'
4
+ require 'holidays/finder/context/parse_options'
5
+ require 'holidays/finder/context/search'
6
+ require 'holidays/finder/context/year_holiday'
7
+ require 'holidays/finder/rules/in_region'
8
+ require 'holidays/finder/rules/year_range'
9
+
10
+ module Holidays
11
+ module Factory
12
+ module Finder
13
+ class << self
14
+ def search
15
+ Holidays::Finder::Context::Search.new(
16
+ Factory::Definition.holidays_by_month_repository,
17
+ Factory::Definition.function_processor,
18
+ Factory::DateCalculator.day_of_month_calculator,
19
+ rules,
20
+ )
21
+ end
22
+
23
+ def between
24
+ Holidays::Finder::Context::Between.new(
25
+ search,
26
+ dates_driver_builder,
27
+ parse_options,
28
+ )
29
+ end
30
+
31
+ def next_holiday
32
+ Holidays::Finder::Context::NextHoliday.new(
33
+ search,
34
+ dates_driver_builder,
35
+ parse_options,
36
+ )
37
+ end
38
+
39
+ def year_holiday
40
+ Holidays::Finder::Context::YearHoliday.new(
41
+ search,
42
+ dates_driver_builder,
43
+ parse_options,
44
+ )
45
+ end
46
+
47
+ def parse_options
48
+ Holidays::Finder::Context::ParseOptions.new(
49
+ Factory::Definition.regions_repository,
50
+ Factory::Definition.region_validator,
51
+ Factory::Definition.loader,
52
+ )
53
+ end
54
+
55
+ private
56
+
57
+ def dates_driver_builder
58
+ Holidays::Finder::Context::DatesDriverBuilder.new
59
+ end
60
+
61
+ def rules
62
+ {
63
+ :in_region => Holidays::Finder::Rules::InRegion,
64
+ :year_range => Holidays::Finder::Rules::YearRange,
65
+ }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,45 @@
1
+ module Holidays
2
+ module Finder
3
+ module Context
4
+ class Between
5
+ def initialize(definition_search, dates_driver_builder, options_parser)
6
+ @definition_search = definition_search
7
+ @dates_driver_builder = dates_driver_builder
8
+ @options_parser = options_parser
9
+ end
10
+
11
+ def call(start_date, end_date, options)
12
+ validate!(start_date, end_date)
13
+
14
+ regions, observed, informal = @options_parser.call(options)
15
+ dates_driver = @dates_driver_builder.call(start_date, end_date)
16
+
17
+ #FIXME Why are we calling the options_parser to convert the observed/informal
18
+ # symbols to bool and then...converting them back? O_o
19
+ opts = gather_options(observed, informal)
20
+
21
+ @definition_search
22
+ .call(dates_driver, regions, opts)
23
+ .select { |holiday| holiday[:date].between?(start_date, end_date) }
24
+ .sort_by { |a| a[:date] }
25
+ end
26
+
27
+ private
28
+
29
+ def validate!(start_date, end_date)
30
+ raise ArgumentError unless start_date
31
+ raise ArgumentError unless end_date
32
+ end
33
+
34
+ def gather_options(observed, informal)
35
+ opts = []
36
+
37
+ opts << :observed if observed
38
+ opts << :informal if informal
39
+
40
+ opts
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,64 @@
1
+ # This context builds a hash that contains {:year => [<array of months>]}. The idea is that
2
+ # we will iterate over each year and then over each month internally and check to see if the
3
+ # supplied dates match any holidays for the region and date. So if we supply start_date of 2015/1/1
4
+ # and end_date of 2015/6/1 then we will return a date driver of {:2015 => [0, 1, 2, 5, 6, 7]}.
5
+ # In the logic in the various other 'finder' contexts we will iterate over this and compare dates
6
+ # in these months to the supplied range to determine whether they should be returned to the user.
7
+ module Holidays
8
+ module Finder
9
+ module Context
10
+ class DatesDriverBuilder
11
+ def call(start_date, end_date)
12
+ dates_driver = {}
13
+
14
+ (start_date..end_date).each do |date|
15
+ dates_driver[date.year] = [] unless dates_driver[date.year]
16
+ dates_driver[date.year] << date.month
17
+ dates_driver = add_border_months(date, dates_driver)
18
+ end
19
+ clean(dates_driver)
20
+ end
21
+
22
+ private
23
+
24
+ # As part of https://github.com/holidays/holidays/issues/146 I am returning
25
+ # additional months in an attempt to catch month-spanning date situations (i.e.
26
+ # dates falling on 2/1 but being observed on 1/31). By including the additional months
27
+ # we are increasing runtimes slightly but improving accuracy, which is more important
28
+ # to me at this stage.
29
+ def add_border_months(current_date, dates_driver)
30
+ if current_date.month == 1
31
+ dates_driver[current_date.year] << 2
32
+
33
+ prev_year = current_date.year - 1
34
+ dates_driver[prev_year] = [] unless dates_driver[prev_year]
35
+ dates_driver[prev_year] << 12
36
+ elsif current_date.month == 12
37
+ dates_driver[current_date.year] << 11
38
+
39
+ next_year = current_date.year + 1
40
+ dates_driver[next_year] = [] unless dates_driver[next_year]
41
+ dates_driver[next_year] << 1
42
+ else
43
+ dates_driver[current_date.year] << current_date.month - 1 << current_date.month + 1
44
+ end
45
+
46
+ dates_driver
47
+ end
48
+
49
+ def clean(dates_driver)
50
+ dates_driver.each do |year, months|
51
+ # Always add variable month '0' for proc calc purposes. For example, 'easter' lives in
52
+ # 'month 0' but is vital to calculating a lot of easter-related dates.
53
+ dates_driver[year] << 0
54
+
55
+ dates_driver[year].uniq!
56
+ dates_driver[year].sort!
57
+ end
58
+
59
+ dates_driver
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,57 @@
1
+ module Holidays
2
+ module Finder
3
+ module Context
4
+ class NextHoliday
5
+ def initialize(definition_search, dates_driver_builder, options_parser)
6
+ @definition_search = definition_search
7
+ @dates_driver_builder = dates_driver_builder
8
+ @options_parser = options_parser
9
+ end
10
+
11
+ def call(holidays_count, from_date, options)
12
+ validate!(holidays_count, from_date)
13
+
14
+ regions, observed, informal = @options_parser.call(options)
15
+
16
+ holidays = []
17
+ opts = gather_options(observed, informal)
18
+
19
+ # This could be smarter but I don't have any evidence that just checking for
20
+ # the next 12 months will cause us issues. If it does we can implement something
21
+ # smarter here to check in smaller increments.
22
+ dates_driver = @dates_driver_builder.call(from_date, from_date >> 12)
23
+
24
+ @definition_search
25
+ .call(dates_driver, regions, opts)
26
+ .sort_by { |a| a[:date] }
27
+ .each do |holiday|
28
+ if holiday[:date] >= from_date
29
+ holidays << holiday
30
+ holidays_count -= 1
31
+ break if holidays_count == 0
32
+ end
33
+ end
34
+
35
+ holidays.sort_by { |a| a[:date] }
36
+ end
37
+
38
+ private
39
+
40
+ def validate!(holidays_count, from_date)
41
+ raise ArgumentError unless holidays_count
42
+ raise ArgumentError if holidays_count <= 0
43
+ raise ArgumentError unless from_date
44
+ end
45
+
46
+ def gather_options(observed, informal)
47
+ opts = []
48
+
49
+ opts << :observed if observed
50
+ opts << :informal if informal
51
+
52
+ opts
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,104 @@
1
+ module Holidays
2
+ module Finder
3
+ module Context
4
+ class ParseOptions
5
+ def initialize(regions_repo, region_validator, definition_loader)
6
+ @regions_repo = regions_repo
7
+ @region_validator = region_validator
8
+ @definition_loader = definition_loader
9
+ end
10
+
11
+ # Returns [(arr)regions, (bool)observed, (bool)informal]
12
+ def call(*options)
13
+ options.flatten!
14
+
15
+ #TODO This is garbage. These two deletes MUST come before the
16
+ # parse_regions call, otherwise it thinks that :observed and :informal
17
+ # are regions to parse. We should be splitting these things out.
18
+ observed = options.delete(:observed) ? true : false
19
+ informal = options.delete(:informal) ? true : false
20
+ regions = parse_regions!(options)
21
+
22
+ return regions, observed, informal
23
+ end
24
+
25
+ private
26
+
27
+ # Check regions against list of supported regions and return an array of
28
+ # symbols.
29
+ #
30
+ # If a wildcard region is found (e.g. :ca_) it is expanded into all
31
+ # of its available sub regions.
32
+ def parse_regions!(regions)
33
+ regions = [regions] unless regions.kind_of?(Array)
34
+
35
+ if regions.empty?
36
+ regions = [:any]
37
+ else
38
+ regions = regions.collect { |r| r.to_sym }
39
+ end
40
+
41
+ validate!(regions)
42
+
43
+ loaded_regions = []
44
+
45
+ if regions.include?(:any)
46
+ @regions_repo.all_generated.each do |r|
47
+ if @regions_repo.loaded?(r)
48
+ loaded_regions << r
49
+ next
50
+ end
51
+
52
+ target = @regions_repo.parent_region_lookup(r)
53
+ load_region!(target)
54
+
55
+ loaded_regions << r
56
+ end
57
+ else
58
+ regions.each do |r|
59
+ if is_wildcard?(r)
60
+ loaded_regions << load_wildcard_parent!(r)
61
+ else
62
+ parent = @regions_repo.parent_region_lookup(r)
63
+
64
+ target = parent || r
65
+
66
+ if @regions_repo.loaded?(target)
67
+ loaded_regions << r
68
+ next
69
+ end
70
+
71
+ load_region!(target)
72
+
73
+ loaded_regions << r
74
+ end
75
+ end
76
+ end
77
+
78
+ loaded_regions.flatten.compact.uniq
79
+ end
80
+
81
+ def validate!(regions)
82
+ regions.each do |r|
83
+ raise InvalidRegion unless @region_validator.valid?(r)
84
+ end
85
+ end
86
+
87
+ def is_wildcard?(r)
88
+ r.to_s =~ /_$/
89
+ end
90
+
91
+ def load_wildcard_parent!(wildcard_region)
92
+ prefix = wildcard_region.to_s.split('_').first.to_sym
93
+ load_region!(prefix)
94
+ end
95
+
96
+ def load_region!(r)
97
+ @definition_loader.call(r)
98
+ rescue NameError, LoadError => e
99
+ raise UnknownRegionError.new(e), "Could not load region: #{r}"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,111 @@
1
+ module Holidays
2
+ module Finder
3
+ module Context
4
+ class Search
5
+ def initialize(holidays_by_month_repo, custom_method_processor, day_of_month_calculator, rules)
6
+ @holidays_by_month_repo = holidays_by_month_repo
7
+ @custom_method_processor = custom_method_processor
8
+ @day_of_month_calculator = day_of_month_calculator
9
+ @rules = rules
10
+ end
11
+
12
+ def call(dates_driver, regions, options)
13
+ validate!(dates_driver)
14
+
15
+ holidays = []
16
+ dates_driver.each do |year, months|
17
+ months.each do |month|
18
+ next unless hbm = @holidays_by_month_repo.find_by_month(month)
19
+ hbm.each do |h|
20
+ next if informal_type?(h[:type]) && !informal_set?(options)
21
+ next unless @rules[:in_region].call(regions, h[:regions])
22
+
23
+ if h[:year_ranges]
24
+ next unless @rules[:year_range].call(year, h[:year_ranges])
25
+ end
26
+
27
+ date = build_date(year, month, h)
28
+ next unless date
29
+
30
+ if observed_set?(options) && h[:observed]
31
+ date = build_observed_date(date, regions, h)
32
+ end
33
+
34
+ holidays << {:date => date, :name => h[:name], :regions => h[:regions]}
35
+ end
36
+ end
37
+ end
38
+
39
+ holidays
40
+ end
41
+
42
+ private
43
+
44
+ def validate!(dates_driver)
45
+ #FIXME This should give some kind of error message that indicates the
46
+ # problem.
47
+ raise ArgumentError if dates_driver.nil? || dates_driver.empty?
48
+
49
+ dates_driver.each do |year, months|
50
+ months.each do |month|
51
+ raise ArgumentError unless month >= 0 && month <= 12
52
+ end
53
+ end
54
+ end
55
+
56
+ def informal_type?(type)
57
+ type && [:informal, 'informal'].include?(type)
58
+ end
59
+
60
+ def informal_set?(options)
61
+ options && options.include?(:informal) == true
62
+ end
63
+
64
+ def observed_set?(options)
65
+ options && options.include?(:observed) == true
66
+ end
67
+
68
+ def build_date(year, month, h)
69
+ if h[:function]
70
+ holiday = custom_holiday(year, month, h)
71
+ #FIXME The result should always be present, see https://github.com/holidays/holidays/issues/204 for more information
72
+ current_month = holiday&.month
73
+ current_day = holiday&.mday
74
+ else
75
+ current_month = month
76
+ current_day = h[:mday] || @day_of_month_calculator.call(year, month, h[:week], h[:wday])
77
+ end
78
+
79
+ # Silently skip bad mdays
80
+ #TODO Should we be doing something different here? We have no concept of logging right now. Maybe we should add it?
81
+ Date.civil(year, current_month, current_day) rescue nil
82
+ end
83
+
84
+ def custom_holiday(year, month, h)
85
+ @custom_method_processor.call(
86
+ #FIXME This seems like a bug, we seem to expect the day in here in the au defs?
87
+ build_custom_method_input(year, month, h[:mday], h[:regions]),
88
+ h[:function], h[:function_arguments], h[:function_modifier],
89
+ )
90
+ end
91
+
92
+ def build_custom_method_input(year, month, day, regions)
93
+ {
94
+ year: year,
95
+ month: month,
96
+ day: day,
97
+ region: regions.first, #FIXME This isn't ideal but will work for our current use case...
98
+ }
99
+ end
100
+
101
+ def build_observed_date(date, regions, h)
102
+ @custom_method_processor.call(
103
+ build_custom_method_input(date.year, date.month, date.day, regions),
104
+ h[:observed],
105
+ [:date],
106
+ )
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,57 @@
1
+ module Holidays
2
+ module Finder
3
+ module Context
4
+ class YearHoliday
5
+ def initialize(definition_search, dates_driver_builder, options_parser)
6
+ @definition_search = definition_search
7
+ @dates_driver_builder = dates_driver_builder
8
+ @options_parser = options_parser
9
+ end
10
+
11
+ def call(from_date, options)
12
+ validate!(from_date)
13
+
14
+ regions, observed, informal = @options_parser.call(options)
15
+
16
+ # This could be smarter but I don't have any evidence that just checking for
17
+ # the next 12 months will cause us issues. If it does we can implement something
18
+ # smarter here to check in smaller increments.
19
+ #
20
+ #FIXME Could this be until the to_date instead? Save us some processing?
21
+ # This is matching what was in holidays.rb currently so I'm keeping it. -pp
22
+ dates_driver = @dates_driver_builder.call(from_date, from_date >> 12)
23
+
24
+ to_date = Date.civil(from_date.year, 12, 31)
25
+ holidays = []
26
+ ret_holidays = []
27
+ opts = gather_options(observed, informal)
28
+
29
+ ret_holidays = @definition_search.call(dates_driver, regions, opts)
30
+
31
+ ret_holidays.each do |holiday|
32
+ if holiday[:date] >= from_date && holiday[:date] <= to_date
33
+ holidays << holiday
34
+ end
35
+ end
36
+
37
+ holidays.sort{|a, b| a[:date] <=> b[:date] }
38
+ end
39
+
40
+ private
41
+
42
+ def validate!(from_date)
43
+ raise ArgumentError unless from_date && from_date.is_a?(Date)
44
+ end
45
+
46
+ def gather_options(observed, informal)
47
+ opts = []
48
+
49
+ opts << :observed if observed == true
50
+ opts << :informal if informal == true
51
+
52
+ opts
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ module Holidays
2
+ module Finder
3
+ module Rules
4
+ class InRegion
5
+ class << self
6
+ def call(requested, available)
7
+ return true if requested.include?(:any)
8
+
9
+ # When an underscore is encountered, derive the parent regions
10
+ # symbol and check for both.
11
+ requested = requested.collect do |r|
12
+ if r.to_s =~ /_/
13
+ chunks = r.to_s.split('_')
14
+
15
+ chunks.length.downto(1).map do |num|
16
+ chunks[0..-num].join('_').to_sym
17
+ end
18
+ else
19
+ r
20
+ end
21
+ end
22
+
23
+ requested = requested.flatten.uniq
24
+
25
+ available.any? { |avail| requested.include?(avail) }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,58 @@
1
+ module Holidays
2
+ module Finder
3
+ module Rules
4
+ class YearRange
5
+ class << self
6
+ UNTIL = :until
7
+ FROM = :from
8
+ LIMITED = :limited
9
+ BETWEEN = :between
10
+
11
+ def call(target_year, year_range_defs)
12
+ validate!(target_year, year_range_defs)
13
+
14
+ operator = year_range_defs.keys.first
15
+ rule_value = year_range_defs[operator]
16
+
17
+ case operator
18
+ when UNTIL
19
+ matched = target_year <= rule_value
20
+ when FROM
21
+ matched = target_year >= rule_value
22
+ when LIMITED
23
+ matched = rule_value.include?(target_year)
24
+ when BETWEEN
25
+ matched = rule_value.cover?(target_year)
26
+ else
27
+ matched = false
28
+ end
29
+
30
+ matched
31
+ end
32
+
33
+ private
34
+
35
+ def validate!(target_year, year_ranges)
36
+ raise ArgumentError.new("target_year must be a number") unless target_year.is_a?(Integer)
37
+ raise ArgumentError.new("year_ranges cannot be missing") if year_ranges.nil? || year_ranges.empty?
38
+ raise ArgumentError.new("year_ranges must contain a hash with a single operator") unless year_ranges.is_a?(Hash) && year_ranges.size == 1
39
+
40
+ operator = year_ranges.keys.first
41
+ value = year_ranges[operator]
42
+
43
+ raise ArgumentError.new("Invalid operator found: '#{operator}'") unless [UNTIL, FROM, LIMITED, BETWEEN].include?(operator)
44
+
45
+ case operator
46
+ when UNTIL, FROM
47
+ raise ArgumentError.new("#{UNTIL} and #{FROM} operator value must be a number, received: '#{value}'") unless value.is_a?(Integer)
48
+ when LIMITED
49
+ raise ArgumentError.new(":limited operator value must be an array containing at least one integer value, received: '#{value}'") unless value.is_a?(Array) && value.size >= 1 && value.all? { |v| v.is_a?(Integer) }
50
+ when BETWEEN
51
+ raise ArgumentError.new(":between operator value must be a range, received: '#{value}'") unless value.is_a?(Range)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,56 @@
1
+ module Holidays
2
+ #TODO This file should be renamed. It's no longer about definitions, really.
3
+ class LoadAllDefinitions
4
+ class << self
5
+ def call
6
+ #FIXME I need a better way to do this. I'm thinking of putting these 'common' methods
7
+ # into some kind of definition file so it can be loaded automatically but I'm afraid
8
+ # of making that big of a breaking API change since these are public. For the time
9
+ # being I'll load them manually like this.
10
+ #
11
+ # NOTE: These are no longer public! We can do whatever we want here!
12
+ global_methods = {
13
+ "easter(year)" => gregorian_easter.method(:calculate_easter_for).to_proc,
14
+ "orthodox_easter(year)" => gregorian_easter.method(:calculate_orthodox_easter_for).to_proc,
15
+ "orthodox_easter_julian(year)" => julian_easter.method(:calculate_orthodox_easter_for).to_proc,
16
+ "to_monday_if_sunday(date)" => weekend_modifier.method(:to_monday_if_sunday).to_proc,
17
+ "to_monday_if_weekend(date)" => weekend_modifier.method(:to_monday_if_weekend).to_proc,
18
+ "to_weekday_if_boxing_weekend(date)" => weekend_modifier.method(:to_weekday_if_boxing_weekend).to_proc,
19
+ "to_weekday_if_boxing_weekend_from_year(year)" => weekend_modifier.method(:to_weekday_if_boxing_weekend_from_year).to_proc,
20
+ "to_weekday_if_weekend(date)" => weekend_modifier.method(:to_weekday_if_weekend).to_proc,
21
+ "calculate_day_of_month(year, month, day, wday)" => day_of_month_calculator.method(:call).to_proc,
22
+ "to_weekday_if_boxing_weekend_from_year_or_to_tuesday_if_monday(year)" => weekend_modifier.method(:to_weekday_if_boxing_weekend_from_year_or_to_tuesday_if_monday).to_proc,
23
+ "to_tuesday_if_sunday_or_monday_if_saturday(date)" => weekend_modifier.method(:to_tuesday_if_sunday_or_monday_if_saturday).to_proc,
24
+ "lunar_to_solar(year, month, day, region)" => lunar_date.method(:to_solar).to_proc,
25
+ }
26
+
27
+ Factory::Definition.custom_methods_repository.add(global_methods)
28
+
29
+ static_regions_definition = "#{Holidays::DEFINITIONS_PATH}/REGIONS.rb"
30
+ require static_regions_definition
31
+ end
32
+
33
+ private
34
+
35
+ def gregorian_easter
36
+ Factory::DateCalculator::Easter::Gregorian.easter_calculator
37
+ end
38
+
39
+ def julian_easter
40
+ Factory::DateCalculator::Easter::Julian.easter_calculator
41
+ end
42
+
43
+ def weekend_modifier
44
+ Factory::DateCalculator.weekend_modifier
45
+ end
46
+
47
+ def day_of_month_calculator
48
+ Factory::DateCalculator.day_of_month_calculator
49
+ end
50
+
51
+ def lunar_date
52
+ Factory::DateCalculator.lunar_date
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Holidays
2
+ VERSION = '9.0.0'
3
+ end