holidays 5.4.0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Makefile +1 -1
  4. data/README.md +6 -6
  5. data/Rakefile +7 -8
  6. data/lib/generated_definitions/REGIONS.rb +3 -1
  7. data/lib/generated_definitions/ar.rb +0 -6
  8. data/lib/generated_definitions/at.rb +0 -6
  9. data/lib/generated_definitions/au.rb +6 -9
  10. data/lib/generated_definitions/be_fr.rb +0 -6
  11. data/lib/generated_definitions/be_nl.rb +0 -6
  12. data/lib/generated_definitions/bg.rb +0 -6
  13. data/lib/generated_definitions/br.rb +0 -6
  14. data/lib/generated_definitions/ca.rb +0 -6
  15. data/lib/generated_definitions/ch.rb +0 -6
  16. data/lib/generated_definitions/cl.rb +0 -6
  17. data/lib/generated_definitions/cr.rb +0 -6
  18. data/lib/generated_definitions/cz.rb +0 -6
  19. data/lib/generated_definitions/de.rb +0 -6
  20. data/lib/generated_definitions/dk.rb +0 -6
  21. data/lib/generated_definitions/ecb_target.rb +0 -6
  22. data/lib/generated_definitions/el.rb +0 -6
  23. data/lib/generated_definitions/es.rb +0 -6
  24. data/lib/generated_definitions/europe.rb +0 -6
  25. data/lib/generated_definitions/federal_reserve.rb +0 -6
  26. data/lib/generated_definitions/fedex.rb +0 -6
  27. data/lib/generated_definitions/fi.rb +0 -6
  28. data/lib/generated_definitions/fr.rb +0 -6
  29. data/lib/generated_definitions/gb.rb +0 -6
  30. data/lib/generated_definitions/hk.rb +0 -6
  31. data/lib/generated_definitions/hr.rb +0 -6
  32. data/lib/generated_definitions/hu.rb +0 -6
  33. data/lib/generated_definitions/ie.rb +0 -6
  34. data/lib/generated_definitions/is.rb +0 -6
  35. data/lib/generated_definitions/it.rb +0 -6
  36. data/lib/generated_definitions/jp.rb +0 -6
  37. data/lib/generated_definitions/kr.rb +15 -225
  38. data/lib/generated_definitions/li.rb +0 -6
  39. data/lib/generated_definitions/lt.rb +0 -6
  40. data/lib/generated_definitions/lu.rb +0 -6
  41. data/lib/generated_definitions/ma.rb +0 -6
  42. data/lib/generated_definitions/mx.rb +0 -6
  43. data/lib/generated_definitions/my.rb +0 -6
  44. data/lib/generated_definitions/nerc.rb +0 -6
  45. data/lib/generated_definitions/nl.rb +0 -6
  46. data/lib/generated_definitions/no.rb +0 -6
  47. data/lib/generated_definitions/north_america.rb +0 -6
  48. data/lib/generated_definitions/nyse.rb +1 -7
  49. data/lib/generated_definitions/nz.rb +0 -6
  50. data/lib/generated_definitions/pe.rb +0 -6
  51. data/lib/generated_definitions/ph.rb +0 -6
  52. data/lib/generated_definitions/pl.rb +0 -6
  53. data/lib/generated_definitions/pt.rb +0 -6
  54. data/lib/generated_definitions/ro.rb +0 -6
  55. data/lib/generated_definitions/scandinavia.rb +0 -6
  56. data/lib/generated_definitions/se.rb +0 -6
  57. data/lib/generated_definitions/sg.rb +0 -6
  58. data/lib/generated_definitions/si.rb +0 -6
  59. data/lib/generated_definitions/sk.rb +0 -6
  60. data/lib/generated_definitions/tn.rb +0 -6
  61. data/lib/generated_definitions/united_nations.rb +0 -6
  62. data/lib/generated_definitions/ups.rb +0 -6
  63. data/lib/generated_definitions/us.rb +0 -6
  64. data/lib/generated_definitions/ve.rb +0 -6
  65. data/lib/generated_definitions/vi.rb +5 -10
  66. data/lib/generated_definitions/za.rb +0 -6
  67. data/lib/holidays.rb +0 -1
  68. data/lib/holidays/date_calculator/lunar_date.rb +371 -0
  69. data/lib/holidays/definition/context/function_processor.rb +20 -15
  70. data/lib/holidays/definition/context/generator.rb +0 -6
  71. data/lib/holidays/definition/context/load.rb +29 -0
  72. data/lib/holidays/definition/context/merger.rb +0 -4
  73. data/lib/holidays/definition/generator/regions.rb +50 -0
  74. data/lib/holidays/definition/repository/cache.rb +20 -7
  75. data/lib/holidays/definition/repository/proc_result_cache.rb +1 -1
  76. data/lib/holidays/definition/repository/regions.rb +23 -13
  77. data/lib/holidays/definition/validator/custom_method.rb +1 -1
  78. data/lib/holidays/definition/validator/region.rb +2 -9
  79. data/lib/holidays/factory/date_calculator.rb +5 -0
  80. data/lib/holidays/factory/definition.rb +17 -1
  81. data/lib/holidays/factory/finder.rb +1 -1
  82. data/lib/holidays/finder/context/between.rb +3 -0
  83. data/lib/holidays/finder/context/parse_options.rb +53 -52
  84. data/lib/holidays/finder/context/search.rb +23 -6
  85. data/lib/holidays/finder/rules/in_region.rb +1 -1
  86. data/lib/holidays/load_all_definitions.rb +9 -0
  87. data/lib/holidays/version.rb +1 -1
  88. data/test/data/test_invalid_region.rb +15 -0
  89. data/test/data/test_region.rb +15 -0
  90. data/test/defs/test_defs_au.rb +11 -1
  91. data/test/defs/test_defs_kr.rb +15 -12
  92. data/test/defs/test_defs_nyse.rb +5 -0
  93. data/test/defs/test_defs_vi.rb +6 -4
  94. data/test/holidays/date_calculator/test_lunar_date.rb +89 -0
  95. data/test/holidays/definition/context/test_function_processor.rb +47 -23
  96. data/test/holidays/definition/context/test_generator.rb +3 -3
  97. data/test/holidays/definition/context/test_load.rb +37 -0
  98. data/test/holidays/definition/generator/test_regions.rb +97 -0
  99. data/test/holidays/definition/repository/test_cache.rb +47 -6
  100. data/test/holidays/definition/repository/test_proc_result_cache.rb +7 -0
  101. data/test/holidays/definition/repository/test_regions.rb +31 -13
  102. data/test/holidays/definition/validator/test_custom_method.rb +5 -0
  103. data/test/holidays/definition/validator/test_region.rb +7 -12
  104. data/test/holidays/factory/test_date_calculator.rb +5 -0
  105. data/test/holidays/factory/test_definition.rb +9 -0
  106. data/test/holidays/finder/context/test_parse_options.rb +102 -33
  107. data/test/holidays/finder/context/test_search.rb +45 -16
  108. data/test/integration/test_available_regions.rb +1 -1
  109. data/test/integration/test_custom_year_range_holidays.rb +0 -1
  110. data/test/integration/test_holidays.rb +3 -3
  111. data/test/integration/test_multiple_regions.rb +0 -1
  112. metadata +16 -3
@@ -9,54 +9,59 @@ module Holidays
9
9
  @proc_result_cache_repo = proc_result_cache_repo
10
10
  end
11
11
 
12
- def call(year, month, day, func_id, desired_func_args, func_modifier = nil)
13
- validate!(year, month, day, func_id, desired_func_args)
12
+ def call(input, func_id, desired_func_args, func_modifier = nil)
13
+ validate!(input, func_id, desired_func_args)
14
14
 
15
15
  function = @custom_methods_repo.find(func_id)
16
16
  raise Holidays::FunctionNotFound.new("Unable to find function with id '#{func_id}'") if function.nil?
17
17
 
18
- calculate(year, month, function, parse_arguments(year, month, day, desired_func_args), func_modifier)
18
+ calculate(input, function, parse_arguments(input, desired_func_args), func_modifier)
19
19
  end
20
20
 
21
21
  private
22
22
 
23
- VALID_ARGUMENTS = [:year, :month, :day, :date]
23
+ VALID_ARGUMENTS = [:year, :month, :day, :date, :region]
24
24
 
25
- def validate!(year, month, day, func_id, desired_func_args)
25
+ def validate!(input, func_id, desired_func_args)
26
26
  raise ArgumentError if desired_func_args.nil? || desired_func_args.empty?
27
27
 
28
28
  desired_func_args.each do |name|
29
29
  raise ArgumentError unless VALID_ARGUMENTS.include?(name)
30
30
  end
31
31
 
32
- raise ArgumentError if desired_func_args.include?(:year) && !year.is_a?(Integer)
33
- raise ArgumentError if desired_func_args.include?(:month) && (month < 0 || month > 12)
34
- raise ArgumentError if desired_func_args.include?(:day) && (day < 1 || day > 31)
32
+ raise ArgumentError if desired_func_args.include?(:year) && !input[:year].is_a?(Integer)
33
+ raise ArgumentError if desired_func_args.include?(:month) && (input[:month] < 0 || input[:month] > 12)
34
+ raise ArgumentError if desired_func_args.include?(:day) && (input[:day] < 1 || input[:day] > 31)
35
+ raise ArgumentError if desired_func_args.include?(:region) && !input[:region].is_a?(Symbol)
35
36
  end
36
37
 
37
- def parse_arguments(year, month, day, target_args)
38
+ def parse_arguments(input, target_args)
38
39
  args = []
39
40
 
40
41
  if target_args.include?(:year)
41
- args << year
42
+ args << input[:year]
42
43
  end
43
44
 
44
45
  if target_args.include?(:month)
45
- args << month
46
+ args << input[:month]
46
47
  end
47
48
 
48
49
  if target_args.include?(:day)
49
- args << day
50
+ args << input[:day]
50
51
  end
51
52
 
52
53
  if target_args.include?(:date)
53
- args << Date.civil(year, month, day)
54
+ args << Date.civil(input[:year], input[:month], input[:day])
55
+ end
56
+
57
+ if target_args.include?(:region)
58
+ args << input[:region]
54
59
  end
55
60
 
56
61
  args
57
62
  end
58
63
 
59
- def calculate(year, month, id, args, modifier)
64
+ def calculate(input, id, args, modifier)
60
65
  result = @proc_result_cache_repo.lookup(id, *args)
61
66
  if result.kind_of?(Date)
62
67
  if modifier
@@ -64,7 +69,7 @@ module Holidays
64
69
  end
65
70
  elsif result.is_a?(Integer)
66
71
  begin
67
- result = Date.civil(year, month, result)
72
+ result = Date.civil(input[:year], input[:month], result)
68
73
  rescue ArgumentError
69
74
  raise Holidays::InvalidFunctionResponse.new("invalid day response from custom method call resulting in invalid date. Result: '#{result}'")
70
75
  end
@@ -235,12 +235,6 @@ module Holidays
235
235
  #
236
236
  # Definitions loaded: #{files.join(', ')}
237
237
  #
238
- # To use the definitions in this file, load it right after you load the
239
- # Holiday gem:
240
- #
241
- # require 'holidays'
242
- # require '#{DEFINITIONS_PATH}/#{module_name.to_s.downcase}'
243
- #
244
238
  # All the definitions are available at https://github.com/holidays/holidays
245
239
  module #{module_name.to_s.upcase} # :nodoc:
246
240
  def self.defined_regions
@@ -0,0 +1,29 @@
1
+ module Holidays
2
+ module Definition
3
+ module Context
4
+ class Load
5
+ def initialize(definition_merger, full_definitions_path)
6
+ @definition_merger = definition_merger
7
+ @full_definitions_path = full_definitions_path
8
+ end
9
+
10
+ def call(region)
11
+ region_definition_file = "#{@full_definitions_path}/#{region}"
12
+ require region_definition_file
13
+
14
+ target_region_module = Module.const_get("Holidays").const_get(region.upcase)
15
+
16
+ @definition_merger.call(
17
+ target_region_module.defined_regions,
18
+ target_region_module.holidays_by_month,
19
+ target_region_module.custom_methods,
20
+ )
21
+
22
+ target_region_module.defined_regions
23
+ rescue NameError, LoadError => e
24
+ raise UnknownRegionError.new(e), "Could not load region prefix: #{region.to_s}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,10 +2,6 @@ module Holidays
2
2
  module Definition
3
3
  module Context
4
4
  # Merge a new set of definitions into the Holidays module.
5
- #
6
- # This method is automatically called when including holiday definition
7
- # files. This is accomplished because the Generator class generates the
8
- # definition source with this class explicitly.
9
5
  class Merger
10
6
  def initialize(holidays_by_month_repo, regions_repo, custom_methods_repo)
11
7
  @holidays_repo = holidays_by_month_repo
@@ -0,0 +1,50 @@
1
+ module Holidays
2
+ module Definition
3
+ module Generator
4
+ class Regions
5
+ def call(regions)
6
+ validate!(regions)
7
+
8
+ <<-EOF
9
+ # encoding: utf-8
10
+ module Holidays
11
+ REGIONS = #{to_array(regions)}
12
+
13
+ PARENT_REGION_LOOKUP = #{generate_parent_lookup(regions)}
14
+ end
15
+ EOF
16
+ end
17
+
18
+ private
19
+
20
+ def validate!(regions)
21
+ raise ArgumentError.new("regions cannot be missing") if regions.nil?
22
+ raise ArgumentError.new("regions must be a hash") unless regions.is_a?(Hash)
23
+ raise ArgumentError.new("regions cannot be empty") if regions.empty?
24
+ end
25
+
26
+ def to_array(regions)
27
+ all_regions = []
28
+
29
+ regions.each do |region, subregions|
30
+ all_regions << subregions
31
+ end
32
+
33
+ all_regions.flatten.uniq
34
+ end
35
+
36
+ def generate_parent_lookup(regions)
37
+ lookup = {}
38
+
39
+ regions.each do |region, subregions|
40
+ subregions.each do |s|
41
+ lookup[s] = region unless lookup.has_key?(s)
42
+ end
43
+ end
44
+
45
+ lookup
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -10,16 +10,18 @@ module Holidays
10
10
  raise ArgumentError unless cache_data
11
11
 
12
12
  @cache_range[options] = start_date..end_date
13
- @cache[options] = cache_data
13
+ @cache[options] = cache_data.group_by { |holiday| holiday[:date] }
14
14
  end
15
15
 
16
16
  def find(start_date, end_date, options)
17
- if range = @cache_range[options]
18
- if range.begin <= start_date && range.end >= end_date
19
- return @cache[options].select do |holiday|
20
- holiday[:date] >= start_date && holiday[:date] <= end_date
21
- end
22
- end
17
+ return nil unless in_cache_range?(start_date, end_date, options)
18
+
19
+ if start_date == end_date
20
+ @cache[options].fetch(start_date, [])
21
+ else
22
+ @cache[options].select do |date, holidays|
23
+ date >= start_date && date <= end_date
24
+ end.flat_map { |date, holidays| holidays }
23
25
  end
24
26
  end
25
27
 
@@ -27,6 +29,17 @@ module Holidays
27
29
  @cache = {}
28
30
  @cache_range = {}
29
31
  end
32
+
33
+ private
34
+
35
+ def in_cache_range?(start_date, end_date, options)
36
+ range = @cache_range[options]
37
+ if range
38
+ range.begin <= start_date && range.end >= end_date
39
+ else
40
+ false
41
+ end
42
+ end
30
43
  end
31
44
  end
32
45
  end
@@ -38,7 +38,7 @@ module Holidays
38
38
  def validate!(function, function_arguments)
39
39
  raise ArgumentError.new("function must be a proc") unless function.is_a?(Proc)
40
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)
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
42
  end
43
43
  end
44
44
 
@@ -2,12 +2,27 @@ module Holidays
2
2
  module Definition
3
3
  module Repository
4
4
  class Regions
5
- def initialize
6
- @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
7
9
  end
8
10
 
9
- def all
10
- @regions
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)
11
26
  end
12
27
 
13
28
  def add(regions)
@@ -17,18 +32,13 @@ module Holidays
17
32
  raise ArgumentError unless region.is_a?(Symbol)
18
33
  end
19
34
 
20
- @regions = @regions | regions
21
- @regions.uniq!
22
- end
23
-
24
- def exists?(region)
25
- raise ArgumentError unless region.is_a?(Symbol)
26
- @regions.include?(region)
35
+ @loaded_regions = @loaded_regions | regions
36
+ @loaded_regions.uniq!
27
37
  end
28
38
 
29
39
  def search(prefix)
30
- raise ArgumentError unless prefix.is_a?(String)
31
- @regions.select { |region| region.to_s =~ Regexp.new("^#{prefix}") }
40
+ raise ArgumentError unless prefix.is_a?(Symbol)
41
+ @loaded_regions.select { |region| region.to_s =~ Regexp.new("^#{prefix}") }
32
42
  end
33
43
  end
34
44
  end
@@ -2,7 +2,7 @@ module Holidays
2
2
  module Definition
3
3
  module Validator
4
4
  class CustomMethod
5
- VALID_ARGUMENTS = ["date", "year", "month", "day"]
5
+ VALID_ARGUMENTS = ["date", "year", "month", "day", "region"]
6
6
 
7
7
  def valid?(m)
8
8
  valid_name?(m[:name]) &&
@@ -12,8 +12,8 @@ module Holidays
12
12
  region = find_wildcard_base(r)
13
13
 
14
14
  (region == :any ||
15
- @regions_repo.exists?(region) ||
16
- region_in_static_definitions?(region))
15
+ @regions_repo.loaded?(region) ||
16
+ @regions_repo.all_generated.include?(region))
17
17
  end
18
18
 
19
19
  private
@@ -30,13 +30,6 @@ module Holidays
30
30
 
31
31
  base.to_sym
32
32
  end
33
-
34
- def region_in_static_definitions?(region)
35
- static_regions_definition = "#{DEFINITIONS_PATH}/REGIONS.rb"
36
- require static_regions_definition
37
-
38
- Holidays::REGIONS.include?(region)
39
- end
40
33
  end
41
34
  end
42
35
  end
@@ -1,6 +1,7 @@
1
1
  require 'holidays/date_calculator/easter'
2
2
  require 'holidays/date_calculator/weekend_modifier'
3
3
  require 'holidays/date_calculator/day_of_month'
4
+ require 'holidays/date_calculator/lunar_date'
4
5
 
5
6
  module Holidays
6
7
  module Factory
@@ -24,6 +25,10 @@ module Holidays
24
25
  end
25
26
 
26
27
  class << self
28
+ def lunar_date
29
+ Holidays::DateCalculator::LunarDate.new
30
+ end
31
+
27
32
  def weekend_modifier
28
33
  Holidays::DateCalculator::WeekendModifier.new
29
34
  end
@@ -1,8 +1,10 @@
1
1
  require 'holidays/definition/context/generator'
2
2
  require 'holidays/definition/context/merger'
3
3
  require 'holidays/definition/context/function_processor'
4
+ require 'holidays/definition/context/load'
4
5
  require 'holidays/definition/decorator/custom_method_proc'
5
6
  require 'holidays/definition/decorator/custom_method_source'
7
+ require 'holidays/definition/generator/regions'
6
8
  require 'holidays/definition/parser/custom_method'
7
9
  require 'holidays/definition/repository/holidays_by_month'
8
10
  require 'holidays/definition/repository/regions'
@@ -76,7 +78,10 @@ module Holidays
76
78
  end
77
79
 
78
80
  def regions_repository
79
- @regions_repo ||= Holidays::Definition::Repository::Regions.new
81
+ @regions_repo ||= Holidays::Definition::Repository::Regions.new(
82
+ Holidays::REGIONS,
83
+ Holidays::PARENT_REGION_LOOKUP,
84
+ )
80
85
  end
81
86
 
82
87
  def cache_repository
@@ -90,6 +95,17 @@ module Holidays
90
95
  def custom_methods_repository
91
96
  @custom_methods_repository ||= Holidays::Definition::Repository::CustomMethods.new
92
97
  end
98
+
99
+ def regions_generator
100
+ Holidays::Definition::Generator::Regions.new
101
+ end
102
+
103
+ def loader
104
+ Holidays::Definition::Context::Load.new(
105
+ merger,
106
+ Holidays::FULL_DEFINITIONS_PATH,
107
+ )
108
+ end
93
109
  end
94
110
  end
95
111
  end
@@ -48,7 +48,7 @@ module Holidays
48
48
  Holidays::Finder::Context::ParseOptions.new(
49
49
  Factory::Definition.regions_repository,
50
50
  Factory::Definition.region_validator,
51
- Factory::Definition.merger,
51
+ Factory::Definition.loader,
52
52
  )
53
53
  end
54
54
 
@@ -15,6 +15,9 @@ module Holidays
15
15
  dates_driver = @dates_driver_builder.call(start_date, end_date)
16
16
 
17
17
  holidays = []
18
+
19
+ #FIXME Why are we calling the options_parser to convert the observed/informal
20
+ # symbols to bool and then...converting them back? O_o
18
21
  opts = gather_options(observed, informal)
19
22
 
20
23
  holidays = @definition_search.call(dates_driver, regions, opts)
@@ -2,10 +2,10 @@ module Holidays
2
2
  module Finder
3
3
  module Context
4
4
  class ParseOptions
5
- def initialize(regions_repo, region_validator, definition_merger)
5
+ def initialize(regions_repo, region_validator, definition_loader)
6
6
  @regions_repo = regions_repo
7
7
  @region_validator = region_validator
8
- @definition_merger = definition_merger
8
+ @definition_loader = definition_loader
9
9
  end
10
10
 
11
11
  # Returns [(arr)regions, (bool)observed, (bool)informal]
@@ -31,42 +31,57 @@ module Holidays
31
31
  # of its available sub regions.
32
32
  def parse_regions!(regions)
33
33
  regions = [regions] unless regions.kind_of?(Array)
34
- return [:any] if regions.empty?
35
34
 
36
- regions = regions.collect { |r| r.to_sym }
35
+ if regions.empty?
36
+ regions = [:any]
37
+ else
38
+ regions = regions.collect { |r| r.to_sym }
39
+ end
37
40
 
38
41
  validate!(regions)
39
42
 
40
- # Found sub region wild-card
41
- regions.delete_if do |r|
42
- if r.to_s =~ /_$/
43
- load_containing_region(r.to_s)
44
- regions << @regions_repo.search(r.to_s)
45
- true
46
- end
47
- end
43
+ loaded_regions = []
44
+
45
+ #FIXME I don't know what this means or why we have it! I'm reluctant to remove it
46
+ # at this time without understanding more. -PP 2017/3/29
47
+ #
48
+ # special case for north_america/US cross-linking
49
+ load_region!(:north_america) if regions.include?(:us)
48
50
 
49
- regions.flatten!
50
-
51
- load_definition_data("north_america") if regions.include?(:us) # special case for north_america/US cross-linking
52
-
53
- regions.each do |region|
54
- unless region == :any || @regions_repo.exists?(region)
55
- begin
56
- load_definition_data(region.to_s)
57
- rescue NameError, LoadError => e
58
- # This could be a sub region that does not have any holiday
59
- # definitions of its own; try to load the containing region instead.
60
- if region.to_s =~ /_/
61
- load_containing_region(region.to_s)
62
- else
63
- raise UnknownRegionError.new(e), "Could not load #{region.to_s}"
51
+ if regions.include?(:any)
52
+ @regions_repo.all_generated.each do |r|
53
+ if @regions_repo.loaded?(r)
54
+ loaded_regions << r
55
+ next
56
+ end
57
+
58
+ target = @regions_repo.parent_region_lookup(r)
59
+ load_region!(target)
60
+
61
+ loaded_regions << r
62
+ end
63
+ else
64
+ regions.each do |r|
65
+ if is_wildcard?(r)
66
+ loaded_regions << load_wildcard_parent!(r)
67
+ else
68
+ parent = @regions_repo.parent_region_lookup(r)
69
+
70
+ target = parent || r
71
+
72
+ if @regions_repo.loaded?(target)
73
+ loaded_regions << r
74
+ next
64
75
  end
76
+
77
+ load_region!(target)
78
+
79
+ loaded_regions << r
65
80
  end
66
81
  end
67
82
  end
68
83
 
69
- regions
84
+ loaded_regions.flatten.compact.uniq
70
85
  end
71
86
 
72
87
  def validate!(regions)
@@ -75,33 +90,19 @@ module Holidays
75
90
  end
76
91
  end
77
92
 
78
- # Derive the containing region from a sub region wild-card or a sub region
79
- # and load its definition. (Common code factored out from parse_regions)
80
- def load_containing_region(sub_reg)
81
- prefix = sub_reg.split('_').first
82
-
83
- return if @regions_repo.exists?(prefix.to_sym)
84
-
85
- begin
86
- load_definition_data(prefix)
87
- rescue NameError, LoadError => e
88
- raise UnknownRegionError.new(e), "Could not load region prefix: #{prefix.to_s}, original subregion: #{sub_reg.to_s}"
89
- end
93
+ def is_wildcard?(r)
94
+ r.to_s =~ /_$/
90
95
  end
91
96
 
92
- def load_definition_data(region)
93
- # Lazy loading of definition files. We verify the region doesn't
94
- # contain malicious stuff in the initial validation.
95
- region_definition_file = "#{FULL_DEFINITIONS_PATH}/#{region}"
96
- require region_definition_file
97
-
98
- target_region_module = Module.const_get("Holidays").const_get(region.upcase)
97
+ def load_wildcard_parent!(wildcard_region)
98
+ prefix = wildcard_region.to_s.split('_').first.to_sym
99
+ load_region!(prefix)
100
+ end
99
101
 
100
- @definition_merger.call(
101
- target_region_module.defined_regions,
102
- target_region_module.holidays_by_month,
103
- target_region_module.custom_methods,
104
- )
102
+ def load_region!(r)
103
+ @definition_loader.call(r)
104
+ rescue NameError, LoadError => e
105
+ raise UnknownRegionError.new(e), "Could not load region: #{r}"
105
106
  end
106
107
  end
107
108
  end