Class: TrimetterArrivalQuery

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

Overview

You will need to supply three things when calling:

- A Trimet developer ID.  Get one from http://developer.trimet.org/registration/
- An array of one or more stop IDs.  These are the 4 or 5 digits numbers assigned to each stop.
- An array of one or more bus numbers.  For instance, 14 or 17 or 9.

Once these have been assigned, you can then call fetch_update. This will return an array of TrimetArrival structures. This class will automatically check for ~/.trimetid and, if it exists, use the first line as your Trimet developer ID. This is so that you don’t have to embed your ID in code (and risk accidentally checking it in to source control).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeTrimetterArrivalQuery

Returns a new instance of TrimetterArrivalQuery.



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/trimetter.rb', line 77

def initialize()
    @developer_id = ''
    @stop_list = Array.new
    @route_list = Array.new
    @debug = false;
    if File.exists?(File.expand_path("~/.trimetid"))
        f = File.new(File.expand_path("~/.trimetid"), "r")
        @developer_id = f.readline().strip()
        f.close()
    end
end

Instance Attribute Details

#debugObject

Returns the value of attribute debug.



76
77
78
# File 'lib/trimetter.rb', line 76

def debug
  @debug
end

#developer_idObject

Returns the value of attribute developer_id.



76
77
78
# File 'lib/trimetter.rb', line 76

def developer_id
  @developer_id
end

Instance Method Details

#fetch_update(result_array, error_string) ⇒ Object

After setting your query parameters, call this to retrieve live data from the server. Note that all requests are tied to your developer ID. Try to space them out and not overload their server. If you slam their server, they can block your ID.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/trimetter.rb', line 108

def fetch_update(result_array, error_string)
    result_array.clear()
    error_string.gsub!(/.*/, '')
    error_string << 'No developer ID given' if @developer_id.empty?
    error_string << 'No stop list given' if @stop_list.empty?
    error_string << 'No route list given' if @route_list.empty?
    return false unless error_string.empty?
    
    # Build request
    url = "http://developer.trimet.org/ws/V1/arrivals?appID=#{@developer_id}&locIDs="
    url << @stop_list.join(',')
    
    # Send request
    print "Sending request to #{url}\n" if @debug
    response = Net::HTTP.get(URI(url))
    print "Received #{response.length()} bytes\n" if @debug
    if response.empty?
        error_string << "Empty document returned"
        return false
    end
    print "\n\n#{response}\n\n\n" if @debug
    
    # Parse resulting XML
    begin
        document = REXML::Document.new(response)
    rescue
        error_string << "Error parsing XML"
        return false
    end
    
    # Server returned valid XML, but it contained an error node
    document.each_element("//errorMessage") { |el|
        error_string << el.get_text() if !el.get_text().empty?
    }
    return false unless error_string.empty?
    
    # Look for arrivals
    now = Time.new
    document.each_element("//arrival") { |el|
        arrival = TrimetterArrival.new
        arrival.route = el.attributes["route"].to_s.strip
        arrival.location = el.attributes["locid"].to_s.strip
        if el.attributes.has_key?("estimated")
            arrival.arrival_time = Time.at(el.attributes["estimated"].to_s.strip.to_i / 1000)
            arrival.status = :estimated
        elsif el.attributes.has_key?("scheduled")
            arrival.arrival_time = Time.at(el.attributes["scheduled"].to_s.strip.to_i / 1000)
            arrival.status = :scheduled
        end
        arrival.arriving_in_minutes = ((arrival.arrival_time - now) / 60).to_i
        if (arrival.arriving_in_minutes < 0 || arrival.arriving_in_minutes > 120)
            arrival.status = :error
        end
        if el.attributes["status"].to_s == "delayed"
            arrival.status = :delayed
        elsif el.attributes["status"].to_s == "canceled"
            arrival.status = :canceled
        end
        arrival.sign_full = el.attributes["fullSign"].to_s.strip
        arrival.sign_short = el.attributes["shortSign"].to_s.strip
        print "#{arrival.inspect}\n" if @debug
        result_array << arrival
    }
    error_string << 'No records found' if result_array.empty?
    return error_string.empty?
end

#route_list=(new_list) ⇒ Object

Add elements, removing duplicates



99
100
101
# File 'lib/trimetter.rb', line 99

def route_list=(new_list)
    @route_list = new_list.flatten().uniq
end

#stop_list=(new_list) ⇒ Object

Add elements, forcing numbers, removing duplicates



90
91
92
93
94
95
96
# File 'lib/trimetter.rb', line 90

def stop_list=(new_list)
    @stop_list.clear()
    new_list.flatten().each() { |i|
        @stop_list << i.to_i
    }
    @stop_list.uniq!
end