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,86 @@
1
+ require 'holidays/definition/entity/test'
2
+
3
+ module Holidays
4
+ module Definition
5
+ module Parser
6
+ class Test
7
+ def initialize(validator)
8
+ @validator = validator
9
+ end
10
+
11
+ def call(tests)
12
+ return [] if tests.nil?
13
+
14
+ validate!(tests)
15
+
16
+ tests.map do |t|
17
+ given = t["given"]
18
+ expect = t["expect"]
19
+
20
+ Entity::Test.new(
21
+ dates: parse_dates(given["date"]),
22
+ regions: parse_regions(given["regions"]),
23
+ options: parse_options(given["options"]),
24
+ name: expect["name"],
25
+ holiday?: is_holiday?(expect["holiday"]),
26
+ )
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def validate!(tests)
33
+ raise ArgumentError unless tests.all? do |t|
34
+ dates = t["given"]["date"]
35
+ unless dates.is_a?(Array)
36
+ dates = [ dates ]
37
+ end
38
+
39
+ @validator.valid?(
40
+ {
41
+ :dates => dates,
42
+ :regions => t["given"]["regions"],
43
+ :options => t["given"]["options"],
44
+ :name => t["expect"]["name"],
45
+ :holiday => t["expect"]["holiday"],
46
+ }
47
+ )
48
+ end
49
+ end
50
+
51
+ def parse_dates(dates)
52
+ unless dates.is_a?(Array)
53
+ dates = [ dates ]
54
+ end
55
+
56
+ dates.map do |d|
57
+ DateTime.parse(d)
58
+ end
59
+ end
60
+
61
+ def parse_regions(regions)
62
+ regions.map do |r|
63
+ r.to_sym
64
+ end
65
+ end
66
+
67
+ def parse_options(options)
68
+ if options
69
+ if options.is_a?(Array)
70
+ options.map do |o|
71
+ o.to_sym
72
+ end
73
+ else
74
+ [ options.to_sym ]
75
+ end
76
+ end
77
+ end
78
+
79
+ # If flag is not present then default to 'true'
80
+ def is_holiday?(flag)
81
+ flag.nil? ? true : !!flag
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,47 @@
1
+ module Holidays
2
+ module Definition
3
+ module Repository
4
+ class Cache
5
+ def initialize
6
+ reset!
7
+ end
8
+
9
+ def cache_between(start_date, end_date, cache_data, options)
10
+ raise ArgumentError unless cache_data
11
+ raise ArgumentError unless start_date && end_date
12
+
13
+ @cache_range[options] = start_date..end_date
14
+ @cache[options] = cache_data.group_by { |holiday| holiday[:date] }
15
+ end
16
+
17
+ def find(start_date, end_date, options)
18
+ return nil unless in_cache_range?(start_date, end_date, options)
19
+
20
+ if start_date == end_date
21
+ @cache[options].fetch(start_date, [])
22
+ else
23
+ @cache[options].select do |date, holidays|
24
+ date >= start_date && date <= end_date
25
+ end.flat_map { |date, holidays| holidays }
26
+ end
27
+ end
28
+
29
+ def reset!
30
+ @cache = {}
31
+ @cache_range = {}
32
+ end
33
+
34
+ private
35
+
36
+ def in_cache_range?(start_date, end_date, options)
37
+ range = @cache_range[options]
38
+ if range
39
+ range.begin <= start_date && range.end >= end_date
40
+ else
41
+ false
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ module Holidays
2
+ module Definition
3
+ module Repository
4
+ class CustomMethods
5
+ def initialize
6
+ @custom_methods = {}
7
+ end
8
+
9
+ # This performs a merge that overwrites any conflicts.
10
+ # While this is not ideal I'm leaving it as-is since I have no
11
+ # evidence of any current definitions that will cause an issue.
12
+ #
13
+ # FIXME: this should probably return an error if a method with the
14
+ # same ID already exists.
15
+ def add(new_custom_methods)
16
+ raise ArgumentError if new_custom_methods.nil?
17
+ @custom_methods.merge!(new_custom_methods)
18
+ end
19
+
20
+ def find(method_id)
21
+ raise ArgumentError if method_id.nil? || method_id.empty?
22
+ @custom_methods[method_id]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ module Holidays
2
+ module Definition
3
+ module Repository
4
+ class HolidaysByMonth
5
+ def initialize
6
+ @holidays_by_month = {}
7
+ end
8
+
9
+ def all
10
+ @holidays_by_month
11
+ end
12
+
13
+ def find_by_month(month)
14
+ raise ArgumentError unless month >= 0 && month <= 12
15
+ @holidays_by_month[month]
16
+ end
17
+
18
+ def add(new_holidays)
19
+ new_holidays.each do |month, holiday_defs|
20
+ @holidays_by_month[month] = [] unless @holidays_by_month[month]
21
+
22
+ holiday_defs.each do |holiday_def|
23
+ exists = false
24
+ @holidays_by_month[month].each do |existing_def|
25
+ if definition_exists?(existing_def, holiday_def)
26
+ # append regions
27
+ existing_def[:regions] << holiday_def[:regions]
28
+
29
+ # Should do this once we're done
30
+ existing_def[:regions].flatten!
31
+ existing_def[:regions].uniq!
32
+ exists = true
33
+ end
34
+ end
35
+
36
+ @holidays_by_month[month] << holiday_def unless exists
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def definition_exists?(existing_def, target_def)
44
+ existing_def[:name] == target_def[:name] &&
45
+ existing_def[:wday] == target_def[:wday] &&
46
+ existing_def[:mday] == target_def[:mday] &&
47
+ existing_def[:week] == target_def[:week] &&
48
+ existing_def[:function] == target_def[:function] &&
49
+ existing_def[:function_modifier] == target_def[:function_modifier] &&
50
+ existing_def[:type] == target_def[:type] &&
51
+ existing_def[:observed] == target_def[:observed] &&
52
+ existing_def[:year_ranges] == target_def[:year_ranges]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,51 @@
1
+ module Holidays
2
+ module Definition
3
+ module Repository
4
+ # ==== Benchmarks
5
+ #
6
+ # Lookup Easter Sunday, with caching, by number of iterations:
7
+ #
8
+ # user system total real
9
+ # 0001 0.000000 0.000000 0.000000 ( 0.000000)
10
+ # 0010 0.000000 0.000000 0.000000 ( 0.000000)
11
+ # 0100 0.078000 0.000000 0.078000 ( 0.078000)
12
+ # 1000 0.641000 0.000000 0.641000 ( 0.641000)
13
+ # 5000 3.172000 0.015000 3.187000 ( 3.219000)
14
+ #
15
+ # Lookup Easter Sunday, without caching, by number of iterations:
16
+ #
17
+ # user system total real
18
+ # 0001 0.000000 0.000000 0.000000 ( 0.000000)
19
+ # 0010 0.016000 0.000000 0.016000 ( 0.016000)
20
+ # 0100 0.125000 0.000000 0.125000 ( 0.125000)
21
+ # 1000 1.234000 0.000000 1.234000 ( 1.234000)
22
+ # 5000 6.094000 0.031000 6.125000 ( 6.141000)
23
+ class ProcResultCache
24
+ def initialize
25
+ @proc_cache = {}
26
+ end
27
+
28
+ def lookup(function, *function_arguments)
29
+ validate!(function, function_arguments)
30
+
31
+ proc_key = build_proc_key(function, function_arguments)
32
+ @proc_cache[proc_key] = function.call(*function_arguments) unless @proc_cache[proc_key]
33
+ @proc_cache[proc_key]
34
+ end
35
+
36
+ private
37
+
38
+ def validate!(function, function_arguments)
39
+ raise ArgumentError.new("function must be a proc") unless function.is_a?(Proc)
40
+ function_arguments.each do |arg|
41
+ raise ArgumentError.new("function arguments '#{function_arguments}' must contain either integers or dates") unless arg.is_a?(Integer) || arg.is_a?(Date) || arg.is_a?(Symbol)
42
+ end
43
+ end
44
+
45
+ def build_proc_key(function, function_arguments)
46
+ Digest::MD5.hexdigest("#{function.to_s}_#{function_arguments.join('_')}")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,46 @@
1
+ module Holidays
2
+ module Definition
3
+ module Repository
4
+ class Regions
5
+ def initialize(all_generated_regions, parent_region_lookup)
6
+ @loaded_regions = []
7
+ @all_generated_regions = all_generated_regions
8
+ @parent_region_lookup = parent_region_lookup
9
+ end
10
+
11
+ def all_generated
12
+ @all_generated_regions
13
+ end
14
+
15
+ def parent_region_lookup(r)
16
+ @parent_region_lookup[r]
17
+ end
18
+
19
+ def all_loaded
20
+ @loaded_regions
21
+ end
22
+
23
+ def loaded?(region)
24
+ raise ArgumentError unless region.is_a?(Symbol)
25
+ @loaded_regions.include?(region)
26
+ end
27
+
28
+ def add(regions)
29
+ regions = [regions] unless regions.is_a?(Array)
30
+
31
+ regions.each do |region|
32
+ raise ArgumentError unless region.is_a?(Symbol)
33
+ end
34
+
35
+ @loaded_regions = @loaded_regions | regions
36
+ @loaded_regions.uniq!
37
+ end
38
+
39
+ def search(prefix)
40
+ raise ArgumentError unless prefix.is_a?(Symbol)
41
+ @loaded_regions.select { |region| region.to_s =~ Regexp.new("^#{prefix}") }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ module Holidays
2
+ module Definition
3
+ module Validator
4
+ class CustomMethod
5
+ VALID_ARGUMENTS = ["date", "year", "month", "day", "region"]
6
+
7
+ def valid?(m)
8
+ valid_name?(m[:name]) &&
9
+ valid_arguments?(m[:arguments]) &&
10
+ valid_source?(m[:source])
11
+ end
12
+
13
+ private
14
+
15
+ def valid_name?(name)
16
+ !name.nil? && !name.empty?
17
+ end
18
+
19
+ def valid_arguments?(arguments)
20
+ arguments.split(",").all? { |arg|
21
+ arg == arg.chomp && VALID_ARGUMENTS.include?(arg.strip)
22
+ }
23
+ end
24
+
25
+ def valid_source?(source)
26
+ !source.nil? && !source.empty?
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ module Holidays
2
+ module Definition
3
+ module Validator
4
+ class Region
5
+ def initialize(regions_repo)
6
+ @regions_repo = regions_repo
7
+ end
8
+
9
+ def valid?(r)
10
+ return false unless r.is_a?(Symbol)
11
+
12
+ region = find_wildcard_base(r)
13
+
14
+ (region == :any ||
15
+ @regions_repo.loaded?(region) ||
16
+ @regions_repo.all_generated.include?(region))
17
+ end
18
+
19
+ private
20
+
21
+ # Ex: :gb_ transformed to :gb
22
+ def find_wildcard_base(region)
23
+ r = region.to_s
24
+
25
+ if r =~ /_$/
26
+ base = r.split('_').first
27
+ else
28
+ base = r
29
+ end
30
+
31
+ base.to_sym
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,71 @@
1
+ module Holidays
2
+ module Definition
3
+ module Validator
4
+ class Test
5
+ def valid?(t)
6
+ valid_dates?(t[:dates]) &&
7
+ valid_regions?(t[:regions]) &&
8
+ valid_name?(t[:name]) &&
9
+ valid_holiday?(t[:holiday]) &&
10
+ valid_options?(t[:options]) &&
11
+ required_fields?(t)
12
+ end
13
+
14
+ private
15
+
16
+ def valid_dates?(dates)
17
+ return false unless dates
18
+
19
+ dates.all? do |d|
20
+ begin
21
+ DateTime.parse(d)
22
+ true
23
+ rescue TypeError, ArgumentError
24
+ false
25
+ end
26
+ end
27
+ end
28
+
29
+ def valid_regions?(regions)
30
+ return false unless regions
31
+
32
+ regions.all? do |r|
33
+ r.is_a?(String)
34
+ end
35
+ end
36
+
37
+ # Can be missing
38
+ def valid_name?(n)
39
+ return true unless n
40
+ n.is_a?(String)
41
+ end
42
+
43
+ # Can be missing
44
+ def valid_holiday?(h)
45
+ return true unless h
46
+ h.is_a?(TrueClass)
47
+ end
48
+
49
+ # Okay to be missing and can be either string or array of strings
50
+ def valid_options?(options)
51
+ return true unless options
52
+
53
+ if options.is_a?(Array)
54
+ options.all? do |o|
55
+ o.is_a?(String)
56
+ end
57
+ elsif options.is_a?(String)
58
+ true
59
+ else
60
+ false
61
+ end
62
+ end
63
+
64
+ def required_fields?(t)
65
+ return false if t[:name].nil? && t[:holiday].nil?
66
+ true
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,11 @@
1
+ module Holidays
2
+ class Error < StandardError; end
3
+
4
+ class FunctionNotFound < Error; end
5
+ class InvalidFunctionResponse < Error; end
6
+
7
+ class UnknownRegionError < Error ; end
8
+ class InvalidRegion < Error; end
9
+
10
+ class DefinitionTestError < Error; end
11
+ end
@@ -0,0 +1,42 @@
1
+ require 'holidays/date_calculator/easter'
2
+ require 'holidays/date_calculator/weekend_modifier'
3
+ require 'holidays/date_calculator/day_of_month'
4
+ require 'holidays/date_calculator/lunar_date'
5
+
6
+ module Holidays
7
+ module Factory
8
+ module DateCalculator
9
+ module Easter
10
+ module Gregorian
11
+ class << self
12
+ def easter_calculator
13
+ Holidays::DateCalculator::Easter::Gregorian.new
14
+ end
15
+ end
16
+ end
17
+
18
+ module Julian
19
+ class << self
20
+ def easter_calculator
21
+ Holidays::DateCalculator::Easter::Julian.new
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ class << self
28
+ def lunar_date
29
+ Holidays::DateCalculator::LunarDate.new
30
+ end
31
+
32
+ def weekend_modifier
33
+ Holidays::DateCalculator::WeekendModifier.new
34
+ end
35
+
36
+ def day_of_month_calculator
37
+ Holidays::DateCalculator::DayOfMonth.new
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,143 @@
1
+ require 'holidays/definition/context/generator'
2
+ require 'holidays/definition/context/merger'
3
+ require 'holidays/definition/context/function_processor'
4
+ require 'holidays/definition/context/load'
5
+ require 'holidays/definition/decorator/custom_method_proc'
6
+ require 'holidays/definition/decorator/custom_method_source'
7
+ require 'holidays/definition/decorator/test'
8
+ require 'holidays/definition/generator/module'
9
+ require 'holidays/definition/generator/regions'
10
+ require 'holidays/definition/generator/test'
11
+ require 'holidays/definition/parser/custom_method'
12
+ require 'holidays/definition/parser/test'
13
+ require 'holidays/definition/repository/holidays_by_month'
14
+ require 'holidays/definition/repository/regions'
15
+ require 'holidays/definition/repository/cache'
16
+ require 'holidays/definition/repository/proc_result_cache'
17
+ require 'holidays/definition/repository/custom_methods'
18
+ require 'holidays/definition/validator/custom_method'
19
+ require 'holidays/definition/validator/region'
20
+ require 'holidays/definition/validator/test'
21
+
22
+ module Holidays
23
+ module Factory
24
+ module Definition
25
+ class << self
26
+ def file_parser
27
+ Holidays::Definition::Context::Generator.new(
28
+ custom_method_parser,
29
+ custom_method_source_decorator,
30
+ custom_methods_repository,
31
+ test_parser,
32
+ test_generator,
33
+ module_generator,
34
+ )
35
+ end
36
+
37
+ def source_generator
38
+ Holidays::Definition::Context::Generator.new(
39
+ custom_method_parser,
40
+ custom_method_source_decorator,
41
+ custom_methods_repository,
42
+ test_parser,
43
+ test_generator,
44
+ module_generator,
45
+ )
46
+ end
47
+
48
+ def function_processor
49
+ Holidays::Definition::Context::FunctionProcessor.new(
50
+ custom_methods_repository,
51
+ proc_result_cache_repository,
52
+ )
53
+ end
54
+
55
+ def merger
56
+ Holidays::Definition::Context::Merger.new(
57
+ holidays_by_month_repository,
58
+ regions_repository,
59
+ custom_methods_repository,
60
+ )
61
+ end
62
+
63
+ def custom_method_parser
64
+ Holidays::Definition::Parser::CustomMethod.new(
65
+ custom_method_validator,
66
+ )
67
+ end
68
+
69
+ def custom_method_proc_decorator
70
+ Holidays::Definition::Decorator::CustomMethodProc.new
71
+ end
72
+
73
+ def custom_method_source_decorator
74
+ Holidays::Definition::Decorator::CustomMethodSource.new
75
+ end
76
+
77
+ def region_validator
78
+ Holidays::Definition::Validator::Region.new(
79
+ regions_repository
80
+ )
81
+ end
82
+
83
+ def custom_method_validator
84
+ Holidays::Definition::Validator::CustomMethod.new
85
+ end
86
+
87
+ def holidays_by_month_repository
88
+ @holidays_repo ||= Holidays::Definition::Repository::HolidaysByMonth.new
89
+ end
90
+
91
+ def regions_repository
92
+ @regions_repo ||= Holidays::Definition::Repository::Regions.new(
93
+ Holidays::REGIONS,
94
+ Holidays::PARENT_REGION_LOOKUP,
95
+ )
96
+ end
97
+
98
+ def cache_repository
99
+ @cache_repo ||= Holidays::Definition::Repository::Cache.new
100
+ end
101
+
102
+ def proc_result_cache_repository
103
+ @proc_result_cache_repo ||= Holidays::Definition::Repository::ProcResultCache.new
104
+ end
105
+
106
+ def custom_methods_repository
107
+ @custom_methods_repository ||= Holidays::Definition::Repository::CustomMethods.new
108
+ end
109
+
110
+ def regions_generator
111
+ Holidays::Definition::Generator::Regions.new
112
+ end
113
+
114
+ def loader
115
+ Holidays::Definition::Context::Load.new(
116
+ merger,
117
+ Holidays::FULL_DEFINITIONS_PATH,
118
+ )
119
+ end
120
+
121
+ def module_generator
122
+ Holidays::Definition::Generator::Module.new
123
+ end
124
+
125
+ def test_generator
126
+ Holidays::Definition::Generator::Test.new(
127
+ test_decorator,
128
+ )
129
+ end
130
+
131
+ def test_decorator
132
+ Holidays::Definition::Decorator::Test.new
133
+ end
134
+
135
+ def test_parser
136
+ Holidays::Definition::Parser::Test.new(
137
+ Holidays::Definition::Validator::Test.new,
138
+ )
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end