Skip to content

Commit

Permalink
NOTAM::Schedule.parse returns array of one or more schedule objects
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven Schwyn committed Sep 1, 2022
1 parent 68bcd84 commit 12469cf
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
## Main

#### Breaking Changes
* `NOTAM::Schedule.parse` now returns an array of `NOTAM_Schedule` instances
instead of just a single one (to model date and time ranges across midnight).

#### Additions
* Wrap all exceptions raised while parsing items.

## 0.1.3
Expand Down
2 changes: 1 addition & 1 deletion lib/notam/item/d.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class D < Item
# @see NOTAM::Item#parse
def parse
base_date = AIXM.date(data[:effective_at])
@schedules = cleanup(text).split(',').map do |string|
@schedules = cleanup(text).split(',').flat_map do |string|
Schedule.parse(string, base_date: base_date)
end
self
Expand Down
3 changes: 2 additions & 1 deletion lib/notam/schedule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class << self
# @param string [String] raw schedule string
# @param base_date [Date] month and year to assume when missing (day is
# force set to 1)
# @return [Array<NOTAM::Schedule>] array of at least one schedule object
def parse(string, base_date:)
raw_actives, raw_times, raw_inactives = string.split(/((?: ?#{TIME_RANGE_RE.decapture})+)/).map(&:strip)
raw_inactives = raw_inactives&.sub(/^EXC /, '')
Expand All @@ -72,7 +73,7 @@ def parse(string, base_date:)
inactives = raw_inactives ? days_from(raw_inactives) : Days.new
end
initialize(actives, times, inactives, base_date: base_date)
self
[self]
end
end
end
Expand Down
63 changes: 46 additions & 17 deletions spec/lib/notam/schedule_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,46 @@
describe :parse do
it "must extract schedule :date_with_exception" do
subject = NOTAM::Schedule.parse(NOTAM::Factory.schedule[:date_with_exception], base_date: AIXM.date('2000-02-01'))
_(subject.actives).must_be_instance_of NOTAM::Schedule::Dates
_(subject.actives).must_equal [(AIXM.date('2000-02-01')..AIXM.date('2000-03-31'))]
_(subject.times).must_equal [(AIXM.time('07:00')..AIXM.time('11:00'))]
_(subject.inactives).must_be_instance_of NOTAM::Schedule::Days
_(subject.inactives).must_equal [AIXM.day(:friday)]
_(subject.count).must_equal 1
_(subject.first.actives).must_be_instance_of NOTAM::Schedule::Dates
_(subject.first.actives).must_equal [(AIXM.date('2000-02-01')..AIXM.date('2000-03-31'))]
_(subject.first.times).must_equal [(AIXM.time('07:00')..AIXM.time('11:00'))]
_(subject.first.inactives).must_be_instance_of NOTAM::Schedule::Days
_(subject.first.inactives).must_equal [AIXM.day(:friday)]
end

it "must extract schedule :day_with_exception" do
subject = NOTAM::Schedule.parse(NOTAM::Factory.schedule[:day_with_exception], base_date: AIXM.date('2000-02-01'))
_(subject.actives).must_be_instance_of NOTAM::Schedule::Days
_(subject.actives).must_equal [(AIXM.day(:monday)..AIXM.day(:tuesday))]
_(subject.times).must_equal [(AIXM.time('07:00')..AIXM.time('19:00'))]
_(subject.inactives).must_be_instance_of NOTAM::Schedule::Dates
_(subject.inactives).must_equal [AIXM.date('2000-02-15')]
_(subject.count).must_equal 1
_(subject.first.actives).must_be_instance_of NOTAM::Schedule::Days
_(subject.first.actives).must_equal [(AIXM.day(:monday)..AIXM.day(:tuesday))]
_(subject.first.times).must_equal [(AIXM.time('07:00')..AIXM.time('19:00'))]
_(subject.first.inactives).must_be_instance_of NOTAM::Schedule::Dates
_(subject.first.inactives).must_equal [AIXM.date('2000-02-15')]
end
end

# TODO: parse the following as well
#
# a) when the activity covers more than 24 hours (start date) (start time)-(end date) (end time);
# d) when entering a succession of activities that span midnight UTC (start date) (start time)-(end time).
#
# 08 2100-0400
# 30 2100-0400
# 08 30 2100-0400
# 08-09 2100-0400
# 08-09 30 2100-0400
# 08-09 29-30 2100-0400
# 08-09 29-30 2100-0400 EXC MON
#
# JUN 08 2100-0400
# JUN 30 2100-0400
# JUN 08 30 2100-0400
# JUN 08-09 2100-0400
# JUN 08-09 30 2100-0400
# 08-09 29-30 2100-0400
# 08-09 29-30 2100-0400 EXC MON

describe :empty? do
subject do
NOTAM::Schedule.send(:new,
Expand All @@ -46,28 +69,32 @@
describe :slice do
it "consolidates :date_with_exception" do
subject = NOTAM::Schedule.parse(NOTAM::Factory.schedule[:date_with_exception], base_date: AIXM.date('2000-02-02'))
_(subject.slice(AIXM.date('2000-02-02'), AIXM.date('2000-02-05')).to_s).must_equal(
_(subject.count).must_equal 1
_(subject.first.slice(AIXM.date('2000-02-02'), AIXM.date('2000-02-05')).to_s).must_equal(
"#<NOTAM::Schedule actives: [2000-02-02..2000-02-03, 2000-02-05], times: [07:00 UTC..11:00 UTC], inactives: []>"
)
end

it "consolidates :day_with_exception" do
subject = NOTAM::Schedule.parse(NOTAM::Factory.schedule[:day_with_exception], base_date: AIXM.date('2000-01-01'))
_(subject.slice(AIXM.date('2000-02-14'), AIXM.date('2000-02-27')).to_s).must_equal(
_(subject.count).must_equal 1
_(subject.first.slice(AIXM.date('2000-02-14'), AIXM.date('2000-02-27')).to_s).must_equal(
"#<NOTAM::Schedule actives: [2000-02-14, 2000-02-21..2000-02-22], times: [07:00 UTC..19:00 UTC], inactives: []>"
)
end

it "defaults to a time frame of one day" do
subject = NOTAM::Schedule.parse(NOTAM::Factory.schedule[:daytime], base_date: AIXM.date('2000-01-01'))
_(subject.slice(AIXM.date('2000-02-02')).to_s).must_equal(
_(subject.count).must_equal 1
_(subject.first.slice(AIXM.date('2000-02-02')).to_s).must_equal(
"#<NOTAM::Schedule actives: [2000-02-02], times: [sunrise..sunset], inactives: []>"
)
end

it "accepts custom time frames" do
subject = NOTAM::Schedule.parse(NOTAM::Factory.schedule[:daytime], base_date: AIXM.date('2000-01-01'))
_(subject.slice(AIXM.date('2000-02-02'), AIXM.date('2000-02-03')).to_s).must_equal(
_(subject.count).must_equal 1
_(subject.first.slice(AIXM.date('2000-02-02'), AIXM.date('2000-02-03')).to_s).must_equal(
"#<NOTAM::Schedule actives: [2000-02-02..2000-02-03], times: [sunrise..sunset], inactives: []>"
)
end
Expand All @@ -79,7 +106,7 @@
# rounded up (sunrise) or down (sunset) to the next 5 minutes.
describe :resolve do
subject do
NOTAM::Schedule.parse(NOTAM::Factory.schedule[:daytime], base_date: AIXM.date('2025-01-01')).slice(AIXM.date('2025-07-01'))
NOTAM::Schedule.parse(NOTAM::Factory.schedule[:daytime], base_date: AIXM.date('2025-01-01')).first.slice(AIXM.date('2025-07-01'))
end

it "resolves sunrise and sunset to clock times" do
Expand All @@ -99,11 +126,13 @@
end

it "returns true if the given time is covered by active times" do
_(subject.active?(at: Time.utc(2000, 1, 1, 12, 0), xy: AIXM.xy(lat: 49.01614, long: 2.54423))).must_equal true
_(subject.count).must_equal 1
_(subject.first.active?(at: Time.utc(2000, 1, 1, 12, 0), xy: AIXM.xy(lat: 49.01614, long: 2.54423))).must_equal true
end

it "returns false if the given time is not covered by active times" do
_(subject.active?(at: Time.utc(2000, 1, 1, 1, 0), xy: AIXM.xy(lat: 49.01614, long: 2.54423))).must_equal false
_(subject.count).must_equal 1
_(subject.first.active?(at: Time.utc(2000, 1, 1, 1, 0), xy: AIXM.xy(lat: 49.01614, long: 2.54423))).must_equal false
end
end
end
Expand Down

0 comments on commit 12469cf

Please sign in to comment.