doublemap_api 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dde680b8393299472cc7dcb6a01ce62778cc5298
4
+ data.tar.gz: f1865c943dc16601c7d9b603ec9346b4cbd85aca
5
+ SHA512:
6
+ metadata.gz: 47372e2dece943ae5ada69ff5820e019d582a797c2694269ebdfb281abb772cb0c8bb6d2691d6e6a079f50398b80acdc2b2b4bfbc688fb3a79d1acee380fec27
7
+ data.tar.gz: 37ad58f6f57c6e8314172109998bbaeeefd98582dfd5fcc810f86c2e94c770c1e99146ea00178c4a7a0da73b48a2a989a3fc6a5d6c5e9362831926b305514f93
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 Jon Egeland
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,32 @@
1
+ require_relative 'doublemap_api/core_ext/string'
2
+
3
+ require_relative 'doublemap_api/version'
4
+ require_relative 'doublemap_api/configuration'
5
+ require_relative 'doublemap_api/connection'
6
+ require_relative 'doublemap_api/models'
7
+ require_relative 'doublemap_api/api'
8
+ require_relative 'doublemap_api/client'
9
+
10
+ module DoubleMap
11
+ class << self
12
+ # Alias for `DoubleMap::Client.new`
13
+ def new
14
+ Client.new
15
+ end
16
+
17
+ # The current client configuration
18
+ def configuration
19
+ @configuration ||= Configuration.new
20
+ end
21
+
22
+ # Allow users to set configuration options via a block. By default, the
23
+ # configuration will be validated after the block returns. This will raise
24
+ # an exception if any required configurations are not provided. This
25
+ # behavior can be skipped by passing `validate: false` as a parameter.
26
+ def configure validate: true
27
+ yield configuration
28
+ configuration.validate! if validate
29
+ configuration
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,52 @@
1
+ require 'memoist'
2
+
3
+ module DoubleMap
4
+ # A base class implementing common API operations
5
+ class API
6
+ include Connection
7
+
8
+ class << self
9
+ extend Memoist
10
+
11
+ # Include another API's functionality via a new method on this API.
12
+ # For example, `include_api :routes` would include the "Routes" API into
13
+ # the "Client" API, accessible as `Client#routes`.
14
+ def include_api name
15
+ klass = self.const_get(name.to_s.constantize)
16
+ define_method(name) do
17
+ klass.new
18
+ end
19
+ self.memoize name
20
+ end
21
+
22
+ # Require all the files given in `names` that exist in the given folder
23
+ def require_all folder, *libs
24
+ libs.each do |lib|
25
+ require_relative "#{File.join(folder, lib)}"
26
+ end
27
+ end
28
+
29
+ # Return a singleton instance of this API
30
+ def singleton
31
+ @singleton ||= self.new
32
+ end
33
+ end
34
+
35
+
36
+ # Perform a GET request over the connection to the given endpoint.
37
+ def get_request endpoint, opts={}, &block
38
+ connection.get endpoint, opts, &block
39
+ end
40
+
41
+ # Perform a POST request over the connection to the given endpoint.
42
+ def post_request endpoint, opts={}, &block
43
+ connection.post endpoint, opts, &block
44
+ end
45
+
46
+ # For APIs that extend Memoist, allow the user to call `refresh` as an
47
+ # alias for `flush_cache`.
48
+ def refresh
49
+ send(:flush_cache) if respond_to?(:flush_cache)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,17 @@
1
+ require 'memoist'
2
+
3
+ module DoubleMap
4
+ class Client < API
5
+ extend Memoist
6
+
7
+ require_all 'client',
8
+ 'routes',
9
+ 'stops',
10
+ 'vehicles'
11
+
12
+ include_api :routes
13
+ include_api :stops
14
+ include_api :vehicles
15
+ end
16
+ end
17
+
@@ -0,0 +1,19 @@
1
+ module DoubleMap
2
+ class Client::Routes < API
3
+ extend Memoist
4
+
5
+ # Return a list of all routes on the system.
6
+ def list
7
+ get_request('/map/v2/routes').map{ |route| Route.new(route) }
8
+ end
9
+ memoize :list
10
+ alias_method :all, :list
11
+
12
+ # Return the route whose id matches the given id
13
+ def get id
14
+ list.find{ |route| route.id == id }
15
+ end
16
+ memoize :get
17
+ alias_method :find, :get
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module DoubleMap
2
+ class Client::Stops < API
3
+ extend Memoist
4
+
5
+ # Return a list of all stops on the system.
6
+ def list
7
+ get_request('/map/v2/stops').map{ |stop| Stop.new(stop) }
8
+ end
9
+ memoize :list
10
+ alias_method :all, :list
11
+
12
+ # Return the route whose id matches the given id
13
+ def get id
14
+ list.find{ |stop| stop.id == id }
15
+ end
16
+ memoize :get
17
+ alias_method :find, :get
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module DoubleMap
2
+ class Client::Vehicles < API
3
+ extend Memoist
4
+
5
+ # Return a list of all vehicles currently traveling on routes.
6
+ def list
7
+ get_request('/map/v2/buses').map{ |vehicle| Vehicle.new(vehicle) }
8
+ end
9
+ memoize :list
10
+ alias_method :all, :list
11
+
12
+ # Return the vehicle whose id matches the given id
13
+ def get id
14
+ list.find{ |vehicle| vehicle.id == id }
15
+ end
16
+ memoize :get
17
+ alias_method :find, :get
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ module DoubleMap
2
+ class Configuration
3
+ # The version of the DoubleMap system
4
+ attr_accessor :version
5
+ # The base URL of the DoubleMap system
6
+ attr_accessor :base_uri
7
+ # The adapter to use for network communication
8
+ attr_accessor :adapter
9
+ # The output stream to which debug information should be written
10
+ attr_accessor :debug_output
11
+
12
+ # The defaults to use for any configuration options that are not provided
13
+ DEFAULT_CONFIGURATION = {
14
+ version: '3.2', # Taken from a comment on "http://bus.gocitybus.com/RouteMap/Index"
15
+ adapter: :httparty,
16
+ debug_output: false
17
+ }
18
+
19
+ # The options required when configuring a DoubleMap instance
20
+ REQUIRED_CONFIGURATION = [
21
+ :base_uri
22
+ ]
23
+
24
+ def initialize
25
+ # Apply the default set of configurations before anything else to ensure
26
+ # all options are initialized.
27
+ DEFAULT_CONFIGURATION.each do |name, value|
28
+ send("#{name}=", value)
29
+ end
30
+ end
31
+
32
+ # Ensure that all required configurations have been given a value. Returns
33
+ # true if all required configuration options have been set.
34
+ def validate!
35
+ REQUIRED_CONFIGURATION.each do |name|
36
+ raise "`#{name}` is a required configuration option, but was not given a value." if send("#{name}").nil?
37
+ end
38
+ true
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ module DoubleMap
2
+ module Connection
3
+ extend self
4
+
5
+ # Return the connection adapter instance
6
+ def connection
7
+ @connection ||= adapter.new(DoubleMap.configuration)
8
+ end
9
+
10
+ # Return the class of the adapter to use for the connection
11
+ def adapter
12
+ @@adapters[DoubleMap.configuration.adapter]
13
+ end
14
+
15
+ # Register a new class that can be used as a connection adapter
16
+ def register_adapter name, klass
17
+ (@@adapters ||= {})[name] = klass
18
+ end
19
+ end
20
+ end
21
+
22
+ # Include the adapters that come packaged with the gem
23
+ require_relative 'connection_adapters/httparty_adapter.rb'
@@ -0,0 +1,27 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ # A Connection adapter using HTTParty as the network transport
5
+ module DoubleMap
6
+ module Connection
7
+ class HTTPartyAdapter
8
+ include HTTParty
9
+
10
+ def initialize config
11
+ self.class.base_uri config.base_uri
12
+ # Write debug information to the configured output stream
13
+ self.class.debug_output config.debug_output
14
+ end
15
+
16
+ def get endpoint, opts={}, &block
17
+ self.class.get(endpoint, opts, &block).parsed_response
18
+ end
19
+
20
+ def post endpoint, opts={}, &block
21
+ self.class.post(endpoint, opts, &block).parsed_response
22
+ end
23
+ end
24
+
25
+ register_adapter :httparty, HTTPartyAdapter
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ class String
2
+ def underscore
3
+ self.dup.underscore!
4
+ end unless method_defined? :underscore
5
+
6
+ def underscore!
7
+ self.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
8
+ self.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
9
+ self.tr_s!('- ', '_')
10
+ self.downcase!
11
+ self
12
+ end unless method_defined? :underscore!
13
+
14
+ def titleize
15
+ self.tr_s('- ', '_').split('_').map(&:capitalize).join(' ')
16
+ end unless method_defined? :titleize
17
+
18
+ def constantize
19
+ self.tr_s('- ', '_').split('_').map(&:capitalize).join
20
+ end unless method_defined? :constantize
21
+ end
@@ -0,0 +1,88 @@
1
+ require 'set'
2
+
3
+ module DoubleMap
4
+ class Model
5
+ extend Forwardable
6
+
7
+ class << self
8
+ # Define a new attribute of the model.
9
+ # If `type` is given, a new instance of `type` will be created whenever
10
+ # this attribute is assigned a value. This allows creation of nested
11
+ # objects from a simple Hash.
12
+ # If `type` is given and `array` is true, the value given to this
13
+ # attribute will be interpreted as an array and a new instance of `type`
14
+ # will be created for each entry in the array
15
+ # It `type` is given, and the value given to this attribute is nil, no
16
+ # new instance of `type` will be created. Instead, the value will remain
17
+ # nil, as an instance of NilClass.
18
+ def attribute name, type: nil, array: false
19
+ attributes << [name, type]
20
+ attr_reader name
21
+ # Use a custom writer method to allow typed attributes to be
22
+ # instantiated properly.
23
+ define_method "#{name}=" do |value|
24
+ # Only do type conversion if the type is specified and the value is
25
+ # not nil.
26
+ if type and !value.nil?
27
+ # Lookup is done on DoubleMap to ensure that Model subclasses are
28
+ # searched first, falling back to other types (Numeric, Hash, etc.)
29
+ # if no Model subclass is found.
30
+ klass = DoubleMap.const_get(type.to_s.constantize)
31
+ value = array ? value.map{ |v| klass.new(v) } : klass.new(value)
32
+ end
33
+ instance_variable_set("@#{name}", value)
34
+ end
35
+ end
36
+
37
+ # The list of attributes defined on the model
38
+ def attributes
39
+ @attributes ||= Set.new
40
+ end
41
+
42
+ # The attribute of the model that can be used to uniquely identify an
43
+ # instance from any other. The primary attribute should also be set
44
+ # with `attribute <name>`.
45
+ attr_accessor :identifier
46
+ def primary_attribute name
47
+ @identifier = name
48
+ end
49
+
50
+ # Define one or more delegated methods on the model, passing them to the
51
+ # given attribute.
52
+ def delegate *names, to:
53
+ names.each do |name|
54
+ def_delegator to, name
55
+ end
56
+ end
57
+ end
58
+
59
+ # Initialize a model instance with any given attributes assigned
60
+ def initialize args={}
61
+ assign(args)
62
+ end
63
+
64
+ # Mass assign a group of attributes. Attribute names will be automatically
65
+ # be converted to snake_case for consistency.
66
+ def assign args={}
67
+ args.each do |_name, value|
68
+ public_send("#{_name.underscore}=", value)
69
+ end
70
+ end
71
+
72
+ # The value of the primary attribute on this model
73
+ def identifier
74
+ send(self.class.identifier)
75
+ end
76
+
77
+ # Assume that two Model objects are the same if their primary attributes
78
+ # have the same value
79
+ def == o
80
+ identifier == o.identifier
81
+ end
82
+ end
83
+ end
84
+
85
+ # Include all model subclasses
86
+ require_relative 'models/route'
87
+ require_relative 'models/stop'
88
+ require_relative 'models/vehicle'
@@ -0,0 +1,36 @@
1
+ module DoubleMap
2
+ class Route < Model
3
+ # The unique id used when referencing this route
4
+ attribute :id
5
+ # The full name of this route
6
+ attribute :name
7
+ # The name used to quickly identify this route
8
+ attribute :short_name
9
+ # A short summary of the purpose of this route
10
+ attribute :description
11
+ # The hexadecimal color to use when displaying this route
12
+ attribute :color
13
+ # The list of lat/lon points that this route passes through
14
+ attribute :path
15
+ # The time of day that this route becomes active
16
+ attribute :start_time
17
+ # The time of day that this route stops being active
18
+ attribute :end_time
19
+ # The url where schedule information for this route can be found
20
+ attribute :schedule_url
21
+ # Is the route currently an active route being serviced
22
+ attribute :active
23
+ alias_method :active?, :active
24
+ alias_method :is_active, :active
25
+ # NOTE: The purpose of this field is unknown, as it is almost always given
26
+ # a value of `null`.
27
+ # It's default value is a Hash, so the assumed purpose is extra information
28
+ # about the route that doesn't conform to the API schema.
29
+ attribute :fields
30
+ # The list of stop ids that this route passes through.
31
+ attribute :stops
32
+
33
+
34
+ primary_attribute :id
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ module DoubleMap
2
+ class Stop < Model
3
+ # The unique id used when referencing this stop
4
+ attribute :id
5
+ # The name of this stop
6
+ attribute :name
7
+ # A short summary of the purpose of this stop
8
+ attribute :description
9
+ # The latitudinal position of this stop
10
+ attribute :lat
11
+ alias_method :latitude, :lat
12
+ # The longitudinal position of this stop
13
+ attribute :lon
14
+ alias_method :longitude, :lon
15
+ # NOTE: The purpose of this field is unknown, as it is almost always given
16
+ # a value of `null`.
17
+ attribute :buddy
18
+ # NOTE: The purpose of this field is unknown, as it is almost always given
19
+ # a value of `null`.
20
+ # It's default value is a Hash, so the assumed purpose is extra information
21
+ # about the route that doesn't conform to the API schema.
22
+ attribute :fields
23
+
24
+
25
+ primary_attribute :id
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ module DoubleMap
2
+ class Vehicle < Model
3
+ # The unique id used when referencing this vehicle
4
+ attribute :id
5
+ # The name given to this vehicle
6
+ attribute :name
7
+ # The latitudinal position of this vehicle
8
+ attribute :lat
9
+ alias_method :latitude, :lat
10
+ # The longitudinal position of this vehicle
11
+ attribute :lon
12
+ alias_method :longitude, :lon
13
+ # NOTE: The purpose of this field is unknown, as it is almost always given
14
+ # a value of `null`.
15
+ attribute :heading
16
+ # The route this vehicle is currently traveling
17
+ attribute :route
18
+ # The last stop that this vehicle departed from
19
+ attribute :last_stop
20
+ # NOTE: The purpose of this field is unknown, as it is almost always given
21
+ # a value of `null`.
22
+ # It's default value is a Hash, so the assumed purpose is extra information
23
+ # about the route that doesn't conform to the API schema.
24
+ attribute :fields
25
+ # The time at which this vehicle was last updated. Stored as seconds since
26
+ # the Unix epoch.
27
+ attribute :last_update
28
+
29
+
30
+ primary_attribute :id
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module DoubleMap
2
+ VERSION = "2.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: doublemap_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jon Egeland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.13'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: memoist
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.14'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.14'
41
+ description: A Ruby client for the DoubleMap real-time transit API. The major version
42
+ of this gem will match the version of the DoubleMap API that it is built for (e.g.,
43
+ 2.0.0 -> v2).
44
+ email: jonegeland@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files:
48
+ - LICENSE
49
+ files:
50
+ - LICENSE
51
+ - lib/doublemap_api.rb
52
+ - lib/doublemap_api/api.rb
53
+ - lib/doublemap_api/client.rb
54
+ - lib/doublemap_api/client/routes.rb
55
+ - lib/doublemap_api/client/stops.rb
56
+ - lib/doublemap_api/client/vehicles.rb
57
+ - lib/doublemap_api/configuration.rb
58
+ - lib/doublemap_api/connection.rb
59
+ - lib/doublemap_api/connection_adapters/httparty_adapter.rb
60
+ - lib/doublemap_api/core_ext/string.rb
61
+ - lib/doublemap_api/models.rb
62
+ - lib/doublemap_api/models/route.rb
63
+ - lib/doublemap_api/models/stop.rb
64
+ - lib/doublemap_api/models/vehicle.rb
65
+ - lib/doublemap_api/version.rb
66
+ homepage: http://github.com/propershark/doublemap_api
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 2.2.0
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.4.8
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: A Ruby client for the DoubleMap real-time transit API.
90
+ test_files: []