Class: BankingCalendar::Calendar

Inherits:
Object
  • Object
show all
Defined in:
lib/banking_calendar/calendar.rb

Constant Summary collapse

DEFAULT_BANKING_DAYS =
%w[mon tue wed thu fri].freeze
DEFAULT_BANKING_HOURS =
(9..16).to_a.freeze
VALID_CALENDAR_KEYS =
%i[
  banking_days
  bank_holidays
  banking_hours
].freeze
VALID_BANKING_HOURS_KEYS =
%i[start end].freeze
VALID_DAYS =
%w[sun mon tue wed thu fri sat].freeze

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Calendar

Returns a new instance of Calendar.



55
56
57
58
# File 'lib/banking_calendar/calendar.rb', line 55

def initialize(config)
  @config = config
  validate_config
end

Class Attribute Details

.additional_load_pathsObject

Returns the value of attribute additional_load_paths.



8
9
10
# File 'lib/banking_calendar/calendar.rb', line 8

def additional_load_paths
  @additional_load_paths
end

Class Method Details

.load(calendar) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/banking_calendar/calendar.rb', line 10

def load(calendar)
  file_name = "#{calendar}.yml"

  directory = calendars.find do |d|
    File.exist?(File.join(d, file_name))
  end
  raise "Cannot find calendar #{calendar}" unless directory

  yaml = YAML.load_file(
    File.join(directory, file_name)
  ).transform_keys(&:to_sym)

  new(yaml)
end

.load_calendar(calendar) ⇒ Object



25
26
27
28
29
30
31
32
33
# File 'lib/banking_calendar/calendar.rb', line 25

def load_calendar(calendar)
  @semaphore.synchronize do
    @cached_calendars ||= {}
    unless @cached_calendars.include?(calendar)
      @cached_calendars[calendar] = load(calendar)
    end
    @cached_calendars[calendar]
  end
end

Instance Method Details

#after_banking_hours?(date) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
153
154
155
# File 'lib/banking_calendar/calendar.rb', line 150

def after_banking_hours?(date)
  time_or_datetime? date
  return true unless banking_day?(date)

  date.hour > banking_hours.max
end

#banking_day?(date) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
125
126
127
128
129
130
# File 'lib/banking_calendar/calendar.rb', line 122

def banking_day?(date)
  date = date.to_date
  day = date.strftime('%a').downcase

  return false if bank_holidays.include?(date)
  return false unless banking_days.include?(day)

  true
end

#banking_days_after(date, interval) ⇒ Object

Given a date, add interval number of banking days.

If the given date is not a banking day, counting starts from the next banking day.

If banking hours are provided, returned date and time will be normalized to the end of banking day. If given date falls after banking hours, counting starts from the next banking day.



92
93
94
95
96
97
98
99
100
101
# File 'lib/banking_calendar/calendar.rb', line 92

def banking_days_after(date, interval)
  date = normalize_date(date, :after) if with_banking_hours?
  date = next_banking_day(date) unless banking_day?(date)

  interval.times do
    date = next_banking_day(date)
  end

  date
end

#banking_days_before(date, interval) ⇒ Object

Given a date, subtract interval number of banking days.

If the given date is not a banking day, counting starts from the previous banking day.

If banking hours are provided, returned date and time will be normalized to the end of banking day. If given date falls before banking hours, counting starts from the prior banking day.



111
112
113
114
115
116
117
118
119
120
# File 'lib/banking_calendar/calendar.rb', line 111

def banking_days_before(date, interval)
  date = normalize_date(date, :before) if with_banking_hours?
  date = previous_banking_day(date) unless banking_day?(date)

  interval.times do
    date = previous_banking_day(date)
  end

  date
end

#banking_hour?(date) ⇒ Boolean

Returns:

  • (Boolean)


132
133
134
135
136
137
138
139
140
141
# File 'lib/banking_calendar/calendar.rb', line 132

def banking_hour?(date)
  time_or_datetime?(date)

  hour = date.hour

  return false unless banking_day?(date)
  return false unless banking_hours.include?(hour)

  true
end

#before_banking_hours?(date) ⇒ Boolean

Returns:

  • (Boolean)


143
144
145
146
147
148
# File 'lib/banking_calendar/calendar.rb', line 143

def before_banking_hours?(date)
  time_or_datetime? date
  return false unless banking_day?(date)

  date.hour < banking_hours.min
end

#end_of_banking_day(date) ⇒ Object



157
158
159
160
161
162
163
164
165
# File 'lib/banking_calendar/calendar.rb', line 157

def end_of_banking_day(date)
  date.class.new(
    date.year,
    date.month,
    date.day,
    banking_hours.max + 1,
    0
  )
end

#next_banking_day(date) ⇒ Object



66
67
68
69
70
71
72
73
# File 'lib/banking_calendar/calendar.rb', line 66

def next_banking_day(date)
  loop do
    date += duration_for(date)
    break if banking_day?(date)
  end

  date
end

#previous_banking_day(date) ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/banking_calendar/calendar.rb', line 75

def previous_banking_day(date)
  loop do
    date -= duration_for(date)
    break if banking_day?(date)
  end

  date
end

#validate_configObject



60
61
62
63
64
# File 'lib/banking_calendar/calendar.rb', line 60

def validate_config
  unless (@config.keys - VALID_CALENDAR_KEYS).empty?
    raise "Only the following keys are valid: #{VALID_CALENDAR_KEYS.join(', ')}"
  end
end