go_transit 1.3.0 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84243aa4bc3cdb3d2a86f340ca75d60258e93e98bb9977f32d36ec05b2222932
4
- data.tar.gz: 40069a1839ae01fd8053053398ef33607ee4af557a9c1f8f7b891e2ee91807c1
3
+ metadata.gz: 751a393a6605bb8cdd61ef32add027a21a98525b8c7b915e0056e46b0a10d612
4
+ data.tar.gz: 78788276d6887bd958084f65da77d023f0a85f720da59d2906c949ce2946e4fc
5
5
  SHA512:
6
- metadata.gz: bcb8c6f390868672a075a961631c79762089e0bb84e9eace72be500174352b4b6120789377f7041b65aff7ea1e40a2f2450162939182ac94fe27c0ac055d2c87
7
- data.tar.gz: ac5a553ddd10f0225cb1a80088bed844c94f8ddc64c1ff2801cfaa9840373b1e52aa09a594f9c90e8c1dfd1625d9806ab96ccbaa06d94e1b4fb77ed11084f73e
6
+ metadata.gz: adce23e7e7328e4152b136e6871cea7785eeaaf74b6286fab12005375f9c0855a7f205efdadeb8ff26f105052f1371a425a00bf454ae03609d55ca7f4fce8530
7
+ data.tar.gz: cc544ca9e200e2de1227cb85b38d97328dffe690427d24a939b1a265e064e909646d20bd7016b8f731912c57e5d70480c89ccd8f3139fac337d4ef67ff032be0
@@ -8,17 +8,17 @@ module GoTransit
8
8
 
9
9
  def hydrate(params)
10
10
  params.each_pair do |key, value|
11
- if collection?(value)
11
+ if wrapped_collection?(value)
12
12
  sub_key, sub_value = value.first
13
- key = sub_key.pluralize
14
- value = build_object(sub_key.singularize, sub_value)
13
+ key = Inflector.pluralize(sub_key)
14
+ value = build_object(Inflector.singularize(sub_key), sub_value)
15
15
  elsif value.kind_of?(Hash)
16
16
  value = build_object(key, value)
17
17
  elsif value.kind_of?(Array)
18
- value = build_object(key.singularize, value)
19
- key = key.pluralize
18
+ value = build_object(Inflector.singularize(key), value)
19
+ key = Inflector.pluralize(key)
20
20
  end
21
- send("#{key.to_s.underscore}=", value)
21
+ send("#{Inflector.underscore(key)}=", value)
22
22
  end
23
23
  end
24
24
 
@@ -35,38 +35,46 @@ module GoTransit
35
35
  Object.const_get("#{self.class.name}::#{name}")
36
36
  end
37
37
 
38
- def collection?(value)
38
+ def wrapped_collection?(value)
39
39
  return false unless value.kind_of?(Hash)
40
40
  key, data = value.first
41
41
  data.kind_of?(Array)
42
42
  end
43
43
 
44
44
  def to_utc(date)
45
- to_local(date).utc
45
+ Zone.wall_clock_to_utc(date)
46
46
  end
47
47
 
48
- def to_local(date, timezone: "America/Toronto")
49
- date.in_time_zone(timezone)
48
+ def to_local(date, timezone: Zone::DEFAULT)
49
+ Zone.wall_clock_to_local(date, timezone)
50
50
  end
51
51
 
52
- def to_utc_from_anchor(time, trip_date, timezone: "America/Toronto")
53
- to_local_from_anchor(time, trip_date, timezone: timezone)&.utc
52
+ def to_utc_from_anchor(time, trip_date, timezone: Zone::DEFAULT)
53
+ wall_clock = anchored_wall_clock(time, trip_date)
54
+ wall_clock && Zone.wall_clock_to_utc(wall_clock, timezone)
54
55
  end
55
56
 
56
- def to_local_from_anchor(time, trip_date, timezone: "America/Toronto")
57
+ def to_local_from_anchor(time, trip_date, timezone: Zone::DEFAULT)
58
+ wall_clock = anchored_wall_clock(time, trip_date)
59
+ wall_clock && Zone.wall_clock_to_local(wall_clock, timezone)
60
+ end
61
+
62
+ def anchored_wall_clock(time, trip_date)
57
63
  raise MissingAnchorDateError if trip_date.nil?
58
- return nil if time.blank?
59
- hour = time.split(":").first.to_i
60
- date = determine_date(trip_date, hour)
61
- "#{date} #{time}".in_time_zone(timezone)
64
+ return nil if blank_value?(time)
65
+ "#{determine_date(trip_date, time.split(":").first.to_i)} #{time}"
62
66
  end
63
67
 
64
68
  def determine_date(date, hour)
65
69
  if hour < GoTransit.service_day_boundary_hour
66
- date + 1.day
70
+ date + 1
67
71
  else
68
72
  date
69
73
  end
70
74
  end
75
+
76
+ def blank_value?(value)
77
+ value.nil? || value.to_s.strip.empty?
78
+ end
71
79
  end
72
80
  end
@@ -0,0 +1,32 @@
1
+ module GoTransit
2
+ module Inflector
3
+ module_function
4
+
5
+ def underscore(word)
6
+ word.to_s.
7
+ gsub(/(?<=[A-Z\d])(?=[A-Z][a-z])/, "_").
8
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
9
+ tr("-", "_").
10
+ downcase
11
+ end
12
+
13
+ def pluralize(word)
14
+ plural_of_singular(singularize(word))
15
+ end
16
+
17
+ def singularize(word)
18
+ word = word.to_s
19
+ return "#{word[0..-4]}y" if word.match?(/[^aeiou]ies\z/i)
20
+ return word[0..-3] if word.match?(/(ss|x|z|ch|sh)es\z/i)
21
+ return word[0..-2] if word.match?(/[^s]s\z/i) && !word.match?(/(us|is)\z/i)
22
+ word
23
+ end
24
+
25
+ def plural_of_singular(singular)
26
+ return singular if singular.empty?
27
+ return "#{singular[0..-2]}ies" if singular.match?(/[^aeiou]y\z/i)
28
+ return "#{singular}es" if singular.match?(/(s|x|z|ch|sh)\z/i)
29
+ "#{singular}s"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,10 @@
1
+ module GoTransit
2
+ class Gtfs::Alert < Gtfs::Resource
3
+ attr_accessor :active_periods, :informed_entities, :cause, :effect, :url,
4
+ :header_text, :description_text
5
+
6
+ hydrate_as active_period: Gtfs::TimeRange, informed_entity: Gtfs::EntitySelector,
7
+ url: Gtfs::TranslatedString, header_text: Gtfs::TranslatedString,
8
+ description_text: Gtfs::TranslatedString
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module GoTransit
2
+ class Gtfs::EntitySelector < Gtfs::Resource
3
+ attr_accessor :agency_id, :route_id, :route_type, :trip, :stop_id
4
+
5
+ hydrate_as trip: Gtfs::TripDescriptor
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ module GoTransit
2
+ class Gtfs::Feed < Gtfs::Resource
3
+ include Enumerable
4
+
5
+ attr_accessor :header, :entities
6
+
7
+ hydrate_as header: Gtfs::FeedHeader, entity: Gtfs::FeedEntity
8
+
9
+ def self.alerts
10
+ request_feed("Alerts")
11
+ end
12
+
13
+ def self.trip_updates
14
+ request_feed("TripUpdates")
15
+ end
16
+
17
+ def self.vehicle_position
18
+ request_feed("VehiclePosition")
19
+ end
20
+
21
+ def self.endpoint_prefix
22
+ "Gtfs/Feed"
23
+ end
24
+
25
+ def self.request_feed(name)
26
+ client = Client.new
27
+ response = client.get("#{endpoint_prefix}/#{name}")
28
+ new(response.data)
29
+ end
30
+ private_class_method :request_feed
31
+
32
+ def each(&block)
33
+ entities.each(&block)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,7 @@
1
+ module GoTransit
2
+ class Gtfs::FeedEntity < Gtfs::Resource
3
+ attr_accessor :id, :is_deleted, :trip_update, :vehicle, :alert
4
+
5
+ hydrate_as trip_update: Gtfs::TripUpdate, vehicle: Gtfs::VehiclePosition, alert: Gtfs::Alert
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module GoTransit
2
+ class Gtfs::FeedHeader < Gtfs::Resource
3
+ attr_accessor :gtfs_realtime_version, :incrementality, :timestamp
4
+
5
+ epoch_time :timestamp
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module GoTransit
2
+ class Gtfs::Position < Gtfs::Resource
3
+ attr_accessor :latitude, :longitude, :bearing, :odometer, :speed
4
+ end
5
+ end
@@ -0,0 +1,40 @@
1
+ module GoTransit
2
+ class Gtfs::Resource < ApiResource
3
+ def self.hydrate_as(classes)
4
+ own_classes.merge!(classes)
5
+ end
6
+
7
+ def self.own_classes
8
+ @own_classes ||= {}
9
+ end
10
+
11
+ def self.class_for(key)
12
+ own_classes[key.to_sym] || (superclass.class_for(key) if superclass.respond_to?(:class_for))
13
+ end
14
+
15
+ def self.epoch_time(*fields)
16
+ fields.each do |field|
17
+ define_method("#{field}_utc") { epoch_utc(public_send(field)) }
18
+ define_method("#{field}_local") { epoch_local(public_send(field)) }
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def get_klass(name)
25
+ self.class.class_for(name) || raise(NameError, "#{self.class.name} has no class for #{name.inspect}")
26
+ end
27
+
28
+ def wrapped_collection?(_value)
29
+ false
30
+ end
31
+
32
+ def epoch_utc(epoch)
33
+ Time.at(epoch).utc if epoch
34
+ end
35
+
36
+ def epoch_local(epoch, timezone: Zone::DEFAULT)
37
+ Zone.epoch_to_local(epoch, timezone) if epoch
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,7 @@
1
+ module GoTransit
2
+ class Gtfs::StopTimeEvent < Gtfs::Resource
3
+ attr_accessor :delay, :time, :uncertainty
4
+
5
+ epoch_time :time
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module GoTransit
2
+ class Gtfs::StopTimeUpdate < Gtfs::Resource
3
+ attr_accessor :stop_id, :arrival, :departure, :schedule_relationship
4
+
5
+ hydrate_as arrival: Gtfs::StopTimeEvent, departure: Gtfs::StopTimeEvent
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module GoTransit
2
+ class Gtfs::TimeRange < Gtfs::Resource
3
+ attr_accessor :start, :end
4
+
5
+ epoch_time :start, :end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module GoTransit
2
+ class Gtfs::TranslatedString < Gtfs::Resource
3
+ attr_accessor :translations
4
+
5
+ class Translation < Gtfs::Resource
6
+ attr_accessor :text, :language
7
+ end
8
+
9
+ hydrate_as translation: Translation
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module GoTransit
2
+ class Gtfs::TripDescriptor < Gtfs::Resource
3
+ attr_accessor :trip_id, :route_id, :direction_id, :start_time, :start_date,
4
+ :schedule_relationship
5
+
6
+ def service_date
7
+ Date.strptime(start_date, "%Y%m%d") unless blank_value?(start_date)
8
+ end
9
+
10
+ def start_time_utc
11
+ to_utc_from_anchor(start_time, service_date)
12
+ end
13
+
14
+ def start_time_local
15
+ to_local_from_anchor(start_time, service_date)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ module GoTransit
2
+ class Gtfs::TripUpdate < Gtfs::Resource
3
+ attr_accessor :trip, :vehicle, :stop_time_updates, :timestamp, :delay
4
+
5
+ hydrate_as trip: Gtfs::TripDescriptor, vehicle: Gtfs::VehicleDescriptor,
6
+ stop_time_update: Gtfs::StopTimeUpdate
7
+
8
+ epoch_time :timestamp
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module GoTransit
2
+ class Gtfs::VehicleDescriptor < Gtfs::Resource
3
+ attr_accessor :id, :label, :license_plate
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ module GoTransit
2
+ class Gtfs::VehiclePosition < Gtfs::Resource
3
+ attr_accessor :trip, :vehicle, :position, :stop_id, :current_status,
4
+ :timestamp, :congestion_level, :occupancy_status
5
+
6
+ hydrate_as trip: Gtfs::TripDescriptor, vehicle: Gtfs::VehicleDescriptor, position: Gtfs::Position
7
+
8
+ epoch_time :timestamp
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ module GoTransit
2
+ module Gtfs
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module GoTransit
2
+ class UP::Gtfs::Feed < GoTransit::Gtfs::Feed
3
+ def self.endpoint_prefix
4
+ "UP/Gtfs/Feed"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ module GoTransit
2
+ module UP
3
+ module Gtfs
4
+ end
5
+ end
6
+ end
@@ -2,7 +2,13 @@ module GoTransit
2
2
  class Response
3
3
  attr_reader :metadata, :data
4
4
 
5
- delegate :code, :error_message, to: :metadata
5
+ def code
6
+ metadata.code
7
+ end
8
+
9
+ def error_message
10
+ metadata.error_message
11
+ end
6
12
 
7
13
  def initialize(payload, http_status = nil)
8
14
  @http_status = http_status
@@ -20,6 +26,7 @@ module GoTransit
20
26
  end
21
27
 
22
28
  def payload_data(payload)
29
+ return payload if payload.key?("entity")
23
30
  return payload.values.first unless payload.values.first.kind_of?(Array)
24
31
  payload
25
32
  end
@@ -1,3 +1,3 @@
1
1
  module GoTransit
2
- VERSION = "1.3.0".freeze
2
+ VERSION = "2.0.0".freeze
3
3
  end
@@ -0,0 +1,43 @@
1
+ require "date"
2
+ require "tzinfo"
3
+
4
+ module GoTransit
5
+ module Zone
6
+ DEFAULT = "America/Toronto".freeze
7
+ ONE_HOUR = 3600
8
+
9
+ module_function
10
+
11
+ def wall_clock_to_utc(text, timezone = DEFAULT)
12
+ parsed = parse_wall_clock(text)
13
+ return parsed[:utc] if parsed[:utc]
14
+ prefer_daylight_time(parsed[:wall], TZInfo::Timezone.get(timezone))
15
+ end
16
+
17
+ def wall_clock_to_local(text, timezone = DEFAULT)
18
+ utc_to_local(wall_clock_to_utc(text, timezone), timezone)
19
+ end
20
+
21
+ def epoch_to_local(epoch, timezone = DEFAULT)
22
+ utc_to_local(Time.at(epoch).utc, timezone)
23
+ end
24
+
25
+ def utc_to_local(utc, timezone = DEFAULT)
26
+ TZInfo::Timezone.get(timezone).utc_to_local(utc)
27
+ end
28
+
29
+ def parse_wall_clock(text)
30
+ found = Date._parse(text.to_s)
31
+ raise ArgumentError, "invalid date: #{text.inspect}" unless found[:year] && found[:mon] && found[:mday]
32
+ wall = Time.utc(found[:year], found[:mon], found[:mday], found[:hour].to_i, found[:min].to_i, found[:sec].to_i)
33
+ found[:offset] ? { utc: wall - found[:offset] } : { wall: wall }
34
+ end
35
+
36
+ def prefer_daylight_time(wall, zone)
37
+ zone.local_to_utc(wall, true)
38
+ rescue TZInfo::PeriodNotFound
39
+ zone.local_to_utc(wall + ONE_HOUR, true)
40
+ end
41
+ private_class_method :parse_wall_clock, :prefer_daylight_time
42
+ end
43
+ end
data/lib/go_transit.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  require "net/http"
2
2
  require "uri"
3
3
  require "json"
4
- require "active_support"
5
- require "active_support/core_ext"
6
- require "active_support/core_ext/string"
7
4
 
5
+ require "go_transit/inflector"
6
+ require "go_transit/zone"
8
7
  require "go_transit/client"
9
8
  require "go_transit/errors"
10
9
  require "go_transit/response"
@@ -59,6 +58,24 @@ require "go_transit/resources/schedule/journey/sch_journey/service/link"
59
58
  require "go_transit/resources/schedule/journey/sch_journey/service/transfer"
60
59
  require "go_transit/resources/schedule/journey/sch_journey/service/trip"
61
60
  require "go_transit/resources/schedule/journey/sch_journey/service/trip/stop"
61
+ require "go_transit/resources/gtfs"
62
+ require "go_transit/resources/gtfs/resource"
63
+ require "go_transit/resources/gtfs/trip_descriptor"
64
+ require "go_transit/resources/gtfs/vehicle_descriptor"
65
+ require "go_transit/resources/gtfs/position"
66
+ require "go_transit/resources/gtfs/stop_time_event"
67
+ require "go_transit/resources/gtfs/stop_time_update"
68
+ require "go_transit/resources/gtfs/vehicle_position"
69
+ require "go_transit/resources/gtfs/trip_update"
70
+ require "go_transit/resources/gtfs/time_range"
71
+ require "go_transit/resources/gtfs/entity_selector"
72
+ require "go_transit/resources/gtfs/translated_string"
73
+ require "go_transit/resources/gtfs/alert"
74
+ require "go_transit/resources/gtfs/feed_header"
75
+ require "go_transit/resources/gtfs/feed_entity"
76
+ require "go_transit/resources/gtfs/feed"
77
+ require "go_transit/resources/up"
78
+ require "go_transit/resources/up/gtfs/feed"
62
79
 
63
80
  module GoTransit
64
81
  @api_key = ""
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: go_transit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Mazur
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-14 00:00:00.000000000 Z
11
+ date: 2026-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tzinfo
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: activesupport
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -17,7 +31,7 @@ dependencies:
17
31
  - - ">="
18
32
  - !ruby/object:Gem::Version
19
33
  version: '0'
20
- type: :runtime
34
+ type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
@@ -146,10 +160,27 @@ files:
146
160
  - lib/go_transit/api_resource.rb
147
161
  - lib/go_transit/client.rb
148
162
  - lib/go_transit/errors.rb
163
+ - lib/go_transit/inflector.rb
149
164
  - lib/go_transit/resources/fare.rb
150
165
  - lib/go_transit/resources/fare/fare_category.rb
151
166
  - lib/go_transit/resources/fare/fare_category/ticket.rb
152
167
  - lib/go_transit/resources/fare/fare_category/ticket/fare.rb
168
+ - lib/go_transit/resources/gtfs.rb
169
+ - lib/go_transit/resources/gtfs/alert.rb
170
+ - lib/go_transit/resources/gtfs/entity_selector.rb
171
+ - lib/go_transit/resources/gtfs/feed.rb
172
+ - lib/go_transit/resources/gtfs/feed_entity.rb
173
+ - lib/go_transit/resources/gtfs/feed_header.rb
174
+ - lib/go_transit/resources/gtfs/position.rb
175
+ - lib/go_transit/resources/gtfs/resource.rb
176
+ - lib/go_transit/resources/gtfs/stop_time_event.rb
177
+ - lib/go_transit/resources/gtfs/stop_time_update.rb
178
+ - lib/go_transit/resources/gtfs/time_range.rb
179
+ - lib/go_transit/resources/gtfs/translated_string.rb
180
+ - lib/go_transit/resources/gtfs/trip_descriptor.rb
181
+ - lib/go_transit/resources/gtfs/trip_update.rb
182
+ - lib/go_transit/resources/gtfs/vehicle_descriptor.rb
183
+ - lib/go_transit/resources/gtfs/vehicle_position.rb
153
184
  - lib/go_transit/resources/metadata.rb
154
185
  - lib/go_transit/resources/schedule.rb
155
186
  - lib/go_transit/resources/schedule/all_lines.rb
@@ -196,8 +227,11 @@ files:
196
227
  - lib/go_transit/resources/stop/place.rb
197
228
  - lib/go_transit/resources/stop/place/stop.rb
198
229
  - lib/go_transit/resources/stop/station.rb
230
+ - lib/go_transit/resources/up.rb
231
+ - lib/go_transit/resources/up/gtfs/feed.rb
199
232
  - lib/go_transit/response.rb
200
233
  - lib/go_transit/version.rb
234
+ - lib/go_transit/zone.rb
201
235
  homepage: https://github.com/jmazur/go_transit_ruby
202
236
  licenses:
203
237
  - MIT