nextbus 0.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.
Files changed (54) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +6 -0
  3. data/Gemfile.lock +29 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +17 -0
  6. data/Rakefile +27 -0
  7. data/VERSION +1 -0
  8. data/doc/ERM.graffle +1318 -0
  9. data/doc/MBTA_XML_Feed_Trial_Docs_13Nov09-1.pdf +0 -0
  10. data/lib/attr_with_default.rb +51 -0
  11. data/lib/instantiate_with_attrs.rb +12 -0
  12. data/lib/nextbus.rb +10 -0
  13. data/lib/nextbus/agency.rb +18 -0
  14. data/lib/nextbus/client.rb +70 -0
  15. data/lib/nextbus/direction.rb +18 -0
  16. data/lib/nextbus/mash_extensions.rb +12 -0
  17. data/lib/nextbus/prediction.rb +18 -0
  18. data/lib/nextbus/report.rb +10 -0
  19. data/lib/nextbus/route.rb +18 -0
  20. data/lib/nextbus/stop.rb +18 -0
  21. data/lib/nextbus/string_extensions.rb +16 -0
  22. data/lib/nextbus/vehicle.rb +18 -0
  23. data/nextbus.gemspec +106 -0
  24. data/test/fixtures/agency_list.xml +5 -0
  25. data/test/fixtures/error.xml +6 -0
  26. data/test/fixtures/predictions.xml +12 -0
  27. data/test/fixtures/predictions_for_multi_stops.xml +21 -0
  28. data/test/fixtures/route_config.xml +755 -0
  29. data/test/fixtures/route_list.xml +5 -0
  30. data/test/fixtures/vehicle_locations.xml +11 -0
  31. data/test/helper.rb +78 -0
  32. data/test/unit/test_agency.rb +56 -0
  33. data/test/unit/test_attr_with_default.rb +158 -0
  34. data/test/unit/test_client.rb +107 -0
  35. data/test/unit/test_direction.rb +59 -0
  36. data/test/unit/test_instantiate_with_attrs.rb +31 -0
  37. data/test/unit/test_mash_extensions.rb +45 -0
  38. data/test/unit/test_nextbus.rb +9 -0
  39. data/test/unit/test_prediction.rb +47 -0
  40. data/test/unit/test_report.rb +34 -0
  41. data/test/unit/test_route.rb +51 -0
  42. data/test/unit/test_stop.rb +64 -0
  43. data/test/unit/test_string_extensions.rb +33 -0
  44. data/test/unit/test_vehicle.rb +52 -0
  45. data/vendor/cache/columnize-0.3.1.gem +0 -0
  46. data/vendor/cache/crack-0.1.6.gem +0 -0
  47. data/vendor/cache/hashie-0.1.8.gem +0 -0
  48. data/vendor/cache/httparty-0.5.2.gem +0 -0
  49. data/vendor/cache/linecache-0.43.gem +0 -0
  50. data/vendor/cache/mocha-0.9.8.gem +0 -0
  51. data/vendor/cache/rake-0.8.7.gem +0 -0
  52. data/vendor/cache/ruby-debug-0.10.3.gem +0 -0
  53. data/vendor/cache/ruby-debug-base-0.10.3.gem +0 -0
  54. metadata +121 -0
@@ -0,0 +1,51 @@
1
+ # http://snippets.dzone.com/posts/show/4382
2
+
3
+ module AttrWithDefault
4
+
5
+ module ClassMethods
6
+
7
+ def attr_accessor(*args)
8
+ attrs, attrs_with_defaults = split_for_last_hash(args)
9
+ attrs_with_defaults.each do |name, default|
10
+ attr_reader_with_default name, default
11
+ attr_writer name
12
+ end
13
+
14
+ super(*attrs)
15
+ end
16
+
17
+ def attr_reader(*args)
18
+ attrs, attrs_with_defaults = split_for_last_hash(args)
19
+ attrs_with_defaults.each do |name, default|
20
+ attr_reader_with_default name, default
21
+ end
22
+
23
+ super(*attrs)
24
+ end
25
+
26
+ private
27
+
28
+ def attr_reader_with_default(name, default)
29
+ define_method(name) do
30
+ unless instance_variable_defined?("@#{name}")
31
+ instance_variable_set "@#{name}", default
32
+ end
33
+ instance_variable_get "@#{name}"
34
+ end
35
+ end
36
+
37
+ def split_for_last_hash(args)
38
+ if args.last.is_a?(Hash)
39
+ [args[0...-1], args.last]
40
+ else
41
+ [args, {}]
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ def self.included(other_module)
48
+ other_module.extend ClassMethods
49
+ end
50
+
51
+ end
@@ -0,0 +1,12 @@
1
+ module InstantiateWithAttrs
2
+
3
+ def initialize(attrs={})
4
+ super()
5
+ attrs.each do |name, value|
6
+ setter = "#{name.to_s}=".to_sym
7
+ self.send(setter, value) if self.respond_to?(setter)
8
+ end
9
+ self
10
+ end
11
+
12
+ end
@@ -0,0 +1,10 @@
1
+ require 'httparty'
2
+ require 'hashie'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ require 'instantiate_with_attrs'
6
+ require 'attr_with_default'
7
+
8
+ dir = File.join(File.dirname(__FILE__), 'nextbus')
9
+ $LOAD_PATH.unshift(dir)
10
+ Dir[File.join(dir, "*.rb")].each {|file| require File.basename(file) }
@@ -0,0 +1,18 @@
1
+ module Nextbus
2
+ class Agency
3
+
4
+ include InstantiateWithAttrs
5
+ include AttrWithDefault
6
+
7
+ attr_accessor :tag, :title, :short_title, :region_title, :routes => [], :vehicles => []
8
+
9
+ def self.all
10
+ Nextbus.client.agencies.map{|agency| new(agency) }
11
+ end
12
+
13
+ def self.find(id)
14
+ all.detect{|agency| agency.tag == id }
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,70 @@
1
+ require 'singleton'
2
+ module Nextbus
3
+
4
+ def self.client
5
+ Nextbus::Client.instance
6
+ end
7
+
8
+ class Client
9
+
10
+ include Singleton
11
+ include HTTParty
12
+
13
+ base_uri "http://webservices.nextbus.com/service/publicXMLFeed?command="
14
+
15
+ def agencies
16
+ response = self.class.do_request("agencyList", {})
17
+ response.agency
18
+ end
19
+
20
+ def routes(agency_id)
21
+ response = self.class.do_request("routeList", {"a" => agency_id})
22
+ response.route
23
+ end
24
+
25
+ def route(agency_id, route_id)
26
+ response = self.class.do_request("routeConfig", {"a" => agency_id, "r" => route_id})
27
+ response.route
28
+ end
29
+
30
+ def predictions(agency_id, route_id, stop_id)
31
+ response = self.class.do_request("predictions", {"a" => agency_id, "r" => route_id, "s" => stop_id})
32
+ response.predictions.direction.prediction
33
+ end
34
+
35
+ def vehicles(agency_id, route_id, time=Time.now)
36
+ response = self.class.do_request("vehicleLocations", {"a" => agency_id, "r" => route_id, "t" => time.to_i.to_s})
37
+ response.vehicle
38
+ end
39
+
40
+ def directions(agency_id, route_id)
41
+ response = self.class.do_request("routeConfig", {"a" => agency_id, "r" => route_id})
42
+ response.route.direction
43
+ end
44
+
45
+ def stops(agency_id, route_id, direction_id)
46
+ response = self.class.do_request("routeConfig", {"a" => agency_id, "r" => route_id})
47
+ response.route.direction.detect{|direction| direction.tag == direction_id }.stop
48
+ end
49
+
50
+ protected
51
+
52
+ def self.do_request(resource, params)
53
+ uri = build_uri(resource, params)
54
+ response = get(uri)
55
+ mash_response_body(response)
56
+ end
57
+
58
+ def self.build_uri(resource, params)
59
+ params = params.to_a
60
+ params.map!{|pair| pair.join('=') }
61
+ params.unshift(resource)
62
+ params.join('&')
63
+ end
64
+
65
+ def self.mash_response_body(response)
66
+ Hashie::Mash.new(response["body"])
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,18 @@
1
+ module Nextbus
2
+ class Direction
3
+
4
+ include InstantiateWithAttrs
5
+ include AttrWithDefault
6
+
7
+ attr_accessor :tag, :title, :name, :route, :reports => [], :stops => []
8
+
9
+ def self.all(agency_id, route_id)
10
+ Nextbus.client.directions(agency_id, route_id).map{|direction| new(direction) }
11
+ end
12
+
13
+ def self.find(agency_id, route_id, id)
14
+ all(agency_id, route_id).detect{|direction| direction.tag == id }
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ module Hashie
2
+
3
+ class Mash < Hashie::Hash
4
+
5
+ protected
6
+
7
+ def convert_key(key) #:nodoc:
8
+ key.to_s.underscore
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ module Nextbus
2
+ class Prediction
3
+
4
+ include InstantiateWithAttrs
5
+ include AttrWithDefault
6
+
7
+ attr_accessor :time, :departure, :stop
8
+
9
+ def epoch_time=(nanosecs)
10
+ self.time = Time.at(nanosecs.to_i/1000)
11
+ end
12
+
13
+ def self.all(agency_id, route_id, stop_id)
14
+ Nextbus.client.predictions(agency_id, route_id, stop_id).map{|prediction| new(prediction) }
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ module Nextbus
2
+ class Report
3
+
4
+ include InstantiateWithAttrs
5
+ include AttrWithDefault
6
+
7
+ attr_accessor :lat, :lon, :heading, :time, :vehicle, :direction
8
+
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ module Nextbus
2
+ class Route
3
+
4
+ include InstantiateWithAttrs
5
+ include AttrWithDefault
6
+
7
+ attr_accessor :tag, :title, :agency, :directions => []
8
+
9
+ def self.all(agency_id)
10
+ Nextbus.client.routes(agency_id).map{|agency| new(agency) }
11
+ end
12
+
13
+ def self.find(agency_id, id)
14
+ new Nextbus.client.route(agency_id, id)
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Nextbus
2
+ class Stop
3
+
4
+ include InstantiateWithAttrs
5
+ include AttrWithDefault
6
+
7
+ attr_accessor :tag, :title, :lat, :lon, :id, :direction, :predictions => []
8
+
9
+ def self.all(agency_id, route_id, direction_id)
10
+ Nextbus.client.stops(agency_id, route_id, direction_id).map{|stop| new(stop) }
11
+ end
12
+
13
+ def self.find(agency_id, route_id, direction_id, id)
14
+ all(agency_id, route_id, direction_id).detect{|stop| stop.tag == id }
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ class String
2
+
3
+ def underscore
4
+ self.class.underscore(self)
5
+ end
6
+
7
+ def self.underscore(camel_cased_word)
8
+ camel_cased_word.to_s.gsub(/::/, '/').
9
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
10
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
11
+ tr(" ", "_").
12
+ tr("-", "_").
13
+ downcase
14
+ end
15
+
16
+ end
@@ -0,0 +1,18 @@
1
+ module Nextbus
2
+ class Vehicle
3
+
4
+ include InstantiateWithAttrs
5
+ include AttrWithDefault
6
+
7
+ attr_accessor :id, :agency, :route, :reports => []
8
+
9
+ def self.all(agency_id, route_id)
10
+ Nextbus.client.vehicles(agency_id, route_id).map{|vehicle| new(vehicle) }
11
+ end
12
+
13
+ def self.find(agency_id, route_id, id)
14
+ all(agency_id, route_id).detect{|vehicle| vehicle.id == id }
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,106 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{nextbus}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Greg Sterndale"]
12
+ s.date = %q{2010-02-23}
13
+ s.description = %q{NextBus API client}
14
+ s.email = %q{gsterndale@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "doc/ERM.graffle",
28
+ "doc/MBTA_XML_Feed_Trial_Docs_13Nov09-1.pdf",
29
+ "lib/attr_with_default.rb",
30
+ "lib/instantiate_with_attrs.rb",
31
+ "lib/nextbus.rb",
32
+ "lib/nextbus/agency.rb",
33
+ "lib/nextbus/client.rb",
34
+ "lib/nextbus/direction.rb",
35
+ "lib/nextbus/mash_extensions.rb",
36
+ "lib/nextbus/prediction.rb",
37
+ "lib/nextbus/report.rb",
38
+ "lib/nextbus/route.rb",
39
+ "lib/nextbus/stop.rb",
40
+ "lib/nextbus/string_extensions.rb",
41
+ "lib/nextbus/vehicle.rb",
42
+ "nextbus.gemspec",
43
+ "test/fixtures/agency_list.xml",
44
+ "test/fixtures/error.xml",
45
+ "test/fixtures/predictions.xml",
46
+ "test/fixtures/predictions_for_multi_stops.xml",
47
+ "test/fixtures/route_config.xml",
48
+ "test/fixtures/route_list.xml",
49
+ "test/fixtures/vehicle_locations.xml",
50
+ "test/helper.rb",
51
+ "test/unit/test_agency.rb",
52
+ "test/unit/test_attr_with_default.rb",
53
+ "test/unit/test_client.rb",
54
+ "test/unit/test_direction.rb",
55
+ "test/unit/test_instantiate_with_attrs.rb",
56
+ "test/unit/test_mash_extensions.rb",
57
+ "test/unit/test_nextbus.rb",
58
+ "test/unit/test_prediction.rb",
59
+ "test/unit/test_report.rb",
60
+ "test/unit/test_route.rb",
61
+ "test/unit/test_stop.rb",
62
+ "test/unit/test_string_extensions.rb",
63
+ "test/unit/test_vehicle.rb",
64
+ "vendor/cache/columnize-0.3.1.gem",
65
+ "vendor/cache/crack-0.1.6.gem",
66
+ "vendor/cache/hashie-0.1.8.gem",
67
+ "vendor/cache/httparty-0.5.2.gem",
68
+ "vendor/cache/linecache-0.43.gem",
69
+ "vendor/cache/mocha-0.9.8.gem",
70
+ "vendor/cache/rake-0.8.7.gem",
71
+ "vendor/cache/ruby-debug-0.10.3.gem",
72
+ "vendor/cache/ruby-debug-base-0.10.3.gem"
73
+ ]
74
+ s.homepage = %q{http://github.com/neweryankee/nextbus}
75
+ s.rdoc_options = ["--charset=UTF-8"]
76
+ s.require_paths = ["lib"]
77
+ s.rubygems_version = %q{1.3.5}
78
+ s.summary = %q{NextBus API client}
79
+ s.test_files = [
80
+ "test/helper.rb",
81
+ "test/unit/test_agency.rb",
82
+ "test/unit/test_attr_with_default.rb",
83
+ "test/unit/test_client.rb",
84
+ "test/unit/test_direction.rb",
85
+ "test/unit/test_instantiate_with_attrs.rb",
86
+ "test/unit/test_mash_extensions.rb",
87
+ "test/unit/test_nextbus.rb",
88
+ "test/unit/test_prediction.rb",
89
+ "test/unit/test_report.rb",
90
+ "test/unit/test_route.rb",
91
+ "test/unit/test_stop.rb",
92
+ "test/unit/test_string_extensions.rb",
93
+ "test/unit/test_vehicle.rb"
94
+ ]
95
+
96
+ if s.respond_to? :specification_version then
97
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
98
+ s.specification_version = 3
99
+
100
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
101
+ else
102
+ end
103
+ else
104
+ end
105
+ end
106
+
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <body copyright="All data copyright agencies listed below and NextBus Inc 2010.">
3
+ <agency tag="mbta" title="MBTA" regionTitle="Massachusetts"/>
4
+ <agency tag="sf-muni" title="San Francisco Muni" shortTitle="SF Muni" regionTitle="California-Northern"/>
5
+ </body>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <body copyright="All data copyright MBTA 2010.">
3
+ <Error shouldRetry="false">
4
+ Exception occurred in XMLFeed, status=[command=vehicleLocations,agency=mbta] message: For input string: ""
5
+ </Error>
6
+ </body>
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <body copyright="All data copyright MBTA 2010.">
3
+ <predictions agencyTitle="MBTA" routeTitle="39" routeTag="39" stopTitle="105 S Huntington (Stop 22365)">
4
+ <direction title="Outbound">
5
+ <prediction seconds="745" minutes="12" epochTime="1266681828070" isDeparture="false" dirTag="out" vehicle="1041" block="S393_6"/>
6
+ <prediction seconds="1299" minutes="21" epochTime="1266681828075" isDeparture="false" dirTag="out" vehicle="1022" block="S393_7"/>
7
+ <prediction seconds="1929" minutes="32" epochTime="1266683011947" isDeparture="false" dirTag="out" vehicle="1027" block="S393_1"/>
8
+ <prediction seconds="2529" minutes="42" epochTime="1266683611947" isDeparture="false" dirTag="out" vehicle="1040" block="S393_2"/>
9
+ <prediction seconds="3129" minutes="52" epochTime="1266684211947" isDeparture="false" dirTag="out" vehicle="1037" block="S393_8"/>
10
+ </direction>
11
+ </predictions>
12
+ </body>