Class: NOTAM::Schedule

Inherits:
Object
  • Object
show all
Defined in:
lib/notam/schedule.rb

Overview

Structure to accommodate individual schedules used on D items

Defined Under Namespace

Classes: Dates, Days, ScheduleArray, Times

Constant Summary collapse

EVENTS =
{ 'SR' => :sunrise, 'SS' => :sunset }.freeze
EVENT_HOURS =
{ sunrise: AIXM.time('06:00'), sunset: AIXM.time('18:00') }.freeze
OPERATIONS =
{ 'PLUS' => 1, 'MINUS' => -1 }.freeze
MONTHS =
{ 'JAN' => 1, 'FEB' => 2, 'MAR' => 3, 'APR' => 4, 'MAY' => 5, 'JUN' => 6, 'JUL' => 7, 'AUG' => 8, 'SEP' => 9, 'OCT' => 10, 'NOV' => 11, 'DEC' => 12 }.freeze
DAYS =
{ 'MON' => :monday, 'TUE' => :tuesday, 'WED' => :wednesday, 'THU' => :thursday, 'FRI' => :friday, 'SAT' => :saturday, 'SUN' => :sunday, 'DAILY' => :any, 'DLY' => :any }.freeze
DATE_RE =
/[0-2]\d|3[01]/.freeze
DAY_RE =
/#{DAYS.keys.join('|')}/.freeze
MONTH_RE =
/#{MONTHS.keys.join('|')}/.freeze
HCODE_RE =
/(?<hcode>H24|HJ|HN)/.freeze
HOUR_RE =
/(?<hour>[01]\d|2[0-4])(?<minute>[0-5]\d)/.freeze
OPERATIONS_RE =
/#{OPERATIONS.keys.join('|')}/.freeze
EVENT_RE =
/(?<event>SR|SS)(?:\s(?<operation>#{OPERATIONS_RE})(?<delta>\d+))?/.freeze
TIME_RE =
/#{HOUR_RE}|#{EVENT_RE}/.freeze
TIME_RANGE_RE =
/#{TIME_RE}-#{TIME_RE}|#{HCODE_RE}/.freeze
DATETIME_RE =
/(?:(?<month>#{MONTH_RE}) )?(?<date>#{DATE_RE}) (?<time>#{TIME_RE})/.freeze
DATETIME_RANGE_RE =
/#{DATETIME_RE}-#{DATETIME_RE}/.freeze
H24 =
(AIXM::BEGINNING_OF_DAY..AIXM::END_OF_DAY).freeze
HJ =
(AIXM.time(:sunrise)..AIXM.time(:sunset)).freeze
HN =
(AIXM.time(:sunset)..AIXM.time(:sunrise)).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#activesArray<NOTAM::Schedule::Dates>, Array<NOTAM::Schedule::Days> (readonly)

Note:

If #actives lists dates, then #inactives must list days and vice versa.

Active dates or days

Returns:



37
38
39
# File 'lib/notam/schedule.rb', line 37

def actives
  @actives
end

#inactivesArray<NOTAM::Schedule::Dates>, Array<NOTAM::Schedule::Days> (readonly)

Note:

If #inactives lists dates, then #actives must list days and vice versa.

Inactive dates or days

Returns:



50
51
52
# File 'lib/notam/schedule.rb', line 50

def inactives
  @inactives
end

#timesArray<NOTAM::Schedule::Times> (readonly)

Active times

Returns:



42
43
44
# File 'lib/notam/schedule.rb', line 42

def times
  @times
end

Class Method Details

.parse(string, base_date:) ⇒ Array<NOTAM::Schedule>

Parse the schedule part of a D item.

Parameters:

  • string (String)

    raw schedule string

  • base_date (Date)

    month and year to assume when missing (day is force set to 1)

Returns:



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/notam/schedule.rb', line 66

def parse(string, base_date:)
  @rules, @exceptions = cleanup(string).split(/ EXC /).map(&:strip)
  @base_date = base_date.at(day: 1)
  case @rules
  when /^#{DATETIME_RANGE_RE}$/
    parse_datetimes
  when /^(#{DAY_RE}|#{TIME_RANGE_RE})/
    parse_days
  when /^(#{DATE_RE}|#{MONTH_RE})/
    parse_dates
  else
    fail! "unrecognized schedule"
  end
end

Instance Method Details

#active?(at:, xy:) ⇒ NOTAM::Schedule

Whether the schedule is active at the given time.

Parameters:

  • at (Time)
  • xy (AIXM::XY)

    geographic location

Returns:

See Also:

  • AIXM::Schedule::Time#resolve


274
275
276
277
# File 'lib/notam/schedule.rb', line 274

def active?(at:, xy:)
  date = AIXM.date(at)
  resolve(on: date, xy: xy).slice(date).times.cover? AIXM.time(at)
end

#empty?Boolean

Whether the schedule contains any actives

Returns:

  • (Boolean)


227
228
229
# File 'lib/notam/schedule.rb', line 227

def empty?
  actives.empty?
end

#inspectString Also known as: to_s

Returns:

  • (String)


218
219
220
221
# File 'lib/notam/schedule.rb', line 218

def inspect
  attr = %i(actives times inactives).map { "#{_1}: #{send(_1)}" }
  %Q(#<#{self.class} #{attr.join(', ')}>)
end

#last_dateAIXM::Date?

Last actives date of the schedule (inatives are ignored).

Returns:

  • (AIXM::Date, nil)

    last date or nil if schedule actives are days



282
283
284
285
286
287
# File 'lib/notam/schedule.rb', line 282

def last_date
  actives.last.then do |active|
    active = active.last if active.respond_to? :last
    active if active.instance_of? AIXM::Schedule::Date
  end
end

#resolve(on:, xy:) ⇒ NOTAM::Schedule

Note:

The resolved times are rounded up (sunrise) or down (sunset) to the next 5 minutes.

Resolve all events in #times for the given date and geographic location.

Parameters:

  • on (AIXM::Date)

    date

  • xy (AIXM::XY)

    geographic location

Returns:

See Also:

  • AIXM::Schedule::Time#resolve


256
257
258
259
260
261
262
263
264
265
266
# File 'lib/notam/schedule.rb', line 256

def resolve(on:, xy:)
  resolved_times = times.map do |time|
    case time
    when Range
      (time.first.resolve(on: on, xy: xy, round: 5)..time.last.resolve(on: on, xy: xy, round: 5))
    else
      time.resolve(on: on, xy: xy, round: 5)
    end
  end
  self.class.send(:new, actives, Times.new(resolved_times), inactives, base_date: @base_date)
end

#slice(from, to = nil) ⇒ NOTAM::Schedule

Note:

#inactives of sub-schedules are always empty which guarantees they can be translated to AIXM or OFMX.

Extract a sub-schedule for the given time window.

Parameters:

  • from (AIXM::Schedule::Date)

    beginning date

  • to (AIXM::Schedule::Date) (defaults to: nil)

    end date (defaults to from)

Returns:



239
240
241
242
243
244
245
# File 'lib/notam/schedule.rb', line 239

def slice(from, to=nil)
  sliced_actives = Dates.new
  (from..(to || from)).each do |date|
    sliced_actives << date if actives.cover?(date) && !inactives.cover?(date)
  end
  self.class.send(:new, sliced_actives.cluster, times, Days.new, base_date: @base_date)
end