citibike 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ spec/cassettes
12
+ test/tmp
13
+ test/version_tmp
14
+ tmp
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --order random
2
+ --fail-fast
3
+ -p
4
+ -c
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in citibike.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,59 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ citibike (0.0.1)
5
+ faraday
6
+ faraday_middleware
7
+ yajl-ruby
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ colorize (0.5.8)
13
+ coveralls (0.6.7)
14
+ colorize
15
+ multi_json (~> 1.3)
16
+ rest-client
17
+ simplecov (>= 0.7)
18
+ thor
19
+ diff-lcs (1.2.4)
20
+ faraday (0.8.7)
21
+ multipart-post (~> 1.1)
22
+ faraday_middleware (0.9.0)
23
+ faraday (>= 0.7.4, < 0.9)
24
+ metaclass (0.0.1)
25
+ mime-types (1.23)
26
+ mocha (0.13.1)
27
+ metaclass (~> 0.0.1)
28
+ multi_json (1.7.7)
29
+ multipart-post (1.2.0)
30
+ rake (10.1.0)
31
+ rest-client (1.6.7)
32
+ mime-types (>= 1.16)
33
+ rspec (2.14.1)
34
+ rspec-core (~> 2.14.0)
35
+ rspec-expectations (~> 2.14.0)
36
+ rspec-mocks (~> 2.14.0)
37
+ rspec-core (2.14.3)
38
+ rspec-expectations (2.14.0)
39
+ diff-lcs (>= 1.1.3, < 2.0)
40
+ rspec-mocks (2.14.1)
41
+ simplecov (0.7.1)
42
+ multi_json (~> 1.0)
43
+ simplecov-html (~> 0.7.1)
44
+ simplecov-html (0.7.1)
45
+ thor (0.18.1)
46
+ vcr (2.3.0)
47
+ yajl-ruby (1.1.0)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ bundler (~> 1.3)
54
+ citibike!
55
+ coveralls
56
+ mocha
57
+ rake
58
+ rspec
59
+ vcr
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Ethan Langevin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ethan Langevin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # Citibike - Wrapper for the unofficial Citibike NYC API
2
+ [![Build Status](https://secure.travis-ci.org/ejlangev/citibike.png)](http://travis-ci.org/ejlangev/citibike) [![Code Climate](https://codeclimate.com/github/ejlangev/citibike.png)](https://codeclimate.com/github/ejlangev/citibike) [![Coverage Status](https://coveralls.io/repos/ejlangev/citibike/badge.png?branch=master)](https://coveralls.io/r/ejlangev/citibike)
3
+
4
+ A simple gem for interacting with the city bike api. Gives you back
5
+ objects by default with consistently named methods for accessing data.
6
+ Also allows easy geographical searching for nearby stations via
7
+ latitude and longitude and as the crow flies distance.
8
+
9
+ I based it partially on another gem [citibikenyc](https://github.com/edgar/citibikenyc) but wanted to design mine a bit differently/play around with the API from scratch.
10
+
11
+ All contributions are welcome.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'citibike'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install citibike
26
+
27
+ ## Usage
28
+
29
+ ### Defaults
30
+ ```ruby
31
+ # Here's an example for stations, it also provides data about
32
+ # branches and helmets with more or less equivalent methods
33
+ helmets = Citibike.helmets
34
+ branches = Citibike.branches
35
+
36
+ # Returns a Citibike::Responses::Station object
37
+ stations = Citibike.stations
38
+
39
+ # This object contains the attributes of the response
40
+ stations.success? # True if the response was successful
41
+ stations.last_update # The time this data was last updated
42
+
43
+ # The response object includes Enumerable and proxies
44
+ # unknown methods to an underlying array
45
+ stations.each do |s|
46
+ puts s.class # Citibike::Station
47
+ puts s.latitude # Float
48
+ puts s.longitude # Float
49
+ puts s.available_bikes # Integer
50
+ puts s.available_docks # Integer
51
+ puts s.id # Integer id
52
+ end
53
+
54
+ # It's also simple to find stations within a given distance
55
+ # (in miles) of a LAT/LONG pair (in degrees)
56
+ # nearby will be an array of Citibike::Station objects
57
+ nearby = stations.all_within(LAT, LONG, DISTANCE)
58
+
59
+ # You can do the same thing given an instance of Citibike::Station
60
+ # Note that the results do NOT include station itself
61
+ nearby = stations.all_near(station, DISTANCE)
62
+
63
+ # It's also convenient to look up results by id within the
64
+ # list of stations
65
+ station = stations.find_by_id(ID)
66
+
67
+ # It also supports a variadic version
68
+ stats = stations.find_by_ids(ID1, ID2,...)
69
+
70
+ # Sometimes it might be convenient to a list of stations
71
+ # but still retain the methods of the Citibike::Responses::Station
72
+ # object.
73
+ filtered_stations = stations.clone_with(stations.select(&:active?))
74
+ ```
75
+
76
+ ### Configuration
77
+ If you want to change the default configuration for web requests it
78
+ is simple to do so given that it is using Faraday under the hood.
79
+ Simply create an instance of Citibike::Client and pass a hash of
80
+ your settings overrides.
81
+
82
+ ```ruby
83
+ client = Citibike::Client.new # initializes a default client
84
+
85
+ client.stations # returns Citibike::Responses::Station
86
+ client.helmets # returns Citibike::Responses::Helmet
87
+ client.branches # returns Citibike::Responses::Branch
88
+
89
+ # The simplest option is to unwrap the responses in which case they
90
+ # come back as a simple hash not a custom object
91
+ client = Citibike::Client.new(unwrapped: true)
92
+ client.stations # Instance of Hash
93
+
94
+ # Other configuration options and their default values
95
+ {
96
+ adapter: Faraday.default_adapter,
97
+ headers: {
98
+ 'Accept' => 'application/json; charset=utf-8',
99
+ 'UserAgent' => 'Citibike Gem'
100
+ },
101
+ proxy: nil,
102
+ ssl: {
103
+ verify: false
104
+ },
105
+ debug: false, # Turns on connection logging(currently unused)
106
+ test: false, # True if in a test
107
+ stubs: nil, # Stubs for the test connection
108
+ raw: false, # Don't process the response in any way
109
+ format_path: true, # Append the format to the request path if it lacks one
110
+ format: :json, # Default format
111
+ url: 'http://appservices.citibikenyc.com/'
112
+ }
113
+ ```
114
+
115
+ ## Contributing
116
+
117
+ 1. Fork it
118
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
119
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
120
+ 4. Push to the branch (`git push origin my-new-feature`)
121
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/citibike.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'citibike/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "citibike"
8
+ spec.version = Citibike::VERSION
9
+ spec.authors = ["Ethan Langevin"]
10
+ spec.email = ["ejl6266@gmail.com"]
11
+ spec.description = %q{Client for the unofficial Citibike API in NYC}
12
+ spec.summary = %q{Provides an interface for interacting with Citibike NYC data}
13
+ spec.homepage = "http://github.com/ejlangev/citibike"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "coveralls"
25
+ spec.add_development_dependency "vcr"
26
+ spec.add_development_dependency "mocha"
27
+
28
+ spec.add_runtime_dependency "faraday"
29
+ spec.add_runtime_dependency "faraday_middleware"
30
+ spec.add_runtime_dependency "yajl-ruby"
31
+ end
data/lib/citibike.rb ADDED
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'citibike/version'
4
+ require 'citibike/connection'
5
+ require 'citibike/api'
6
+ require 'citibike/client'
7
+
8
+ # Namespace for methods of accessing real time
9
+ # Citibike data for NYC
10
+ module Citibike
11
+
12
+ def self.method_missing(sym, *args, &block)
13
+ if Citibike::Client.respond_to?(sym)
14
+ return Citibike::Client.send(sym, *args, &block)
15
+ end
16
+
17
+ super
18
+ end
19
+
20
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: UTF-8
2
+
3
+ module Citibike
4
+
5
+ # Base class for shared behavior between
6
+ # all types of objects from this api
7
+ class Api
8
+
9
+ Dir[File.expand_path('../apis/*.rb', __FILE__)].each { |f| require f }
10
+
11
+ # Radius of the earth in miles
12
+ EARTH_RADIUS = 3963.1676
13
+
14
+ attr_reader :internal_object
15
+
16
+ def initialize(data)
17
+ @internal_object = data
18
+ end
19
+
20
+ #
21
+ # Shortcut to access latitude
22
+ #
23
+ # @return [Float] [Object's latitude position]
24
+ def lat
25
+ self['latitude']
26
+ end
27
+
28
+ #
29
+ # Shortcut to access longitude
30
+ #
31
+ # @return [Float] [Object's longitude position]
32
+ def long
33
+ self['longitude']
34
+ end
35
+
36
+ #
37
+ # Returns the distance this object is from the given
38
+ # latitude and longitude. Distance is as the crow flies.
39
+ #
40
+ # @param lat [Float] [A latitude position]
41
+ # @param long [Float] [A longitude position]
42
+ #
43
+ # @return [Float] [Distance from the input postion in miles]
44
+ def distance_from(lat, long)
45
+ dLat = self.degrees_to_radians(lat - self.latitude)
46
+ dLon = self.degrees_to_radians(long - self.longitude)
47
+
48
+ lat1 = self.degrees_to_radians(lat)
49
+ lat2 = self.degrees_to_radians(self.latitude)
50
+
51
+ a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
52
+ Math.sin(dLon / 2) * Math.sin(dLon / 2) *
53
+ Math.cos(lat1) * Math.cos(lat2)
54
+
55
+ c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
56
+
57
+ EARTH_RADIUS * c
58
+ end
59
+
60
+ # Allow access to the hash through the object
61
+ def [](key)
62
+ self.internal_object[key.to_s]
63
+ end
64
+
65
+ # Allow hash keys to be used as methods
66
+ def method_missing(sym, *args, &block)
67
+ if self.internal_object.key?(sym.to_s)
68
+ return self.internal_object[sym.to_s]
69
+ end
70
+
71
+ super
72
+ end
73
+
74
+ protected
75
+
76
+ def degrees_to_radians(deg)
77
+ deg * Math::PI / 180
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,11 @@
1
+ module Citibike
2
+
3
+ class Branch < Api
4
+
5
+ def self.path
6
+ return 'v1/branch/list'
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ module Citibike
2
+
3
+ class Helmet < Api
4
+
5
+ def self.path
6
+ return 'v1/helmet/list'
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: UTF-8
2
+
3
+ module Citibike
4
+ # Represents a Station in the Citibike system and
5
+ # holds the data provided from the API itself along with
6
+ # some convenience methods accessing it
7
+ class Station < Api
8
+
9
+ def self.path
10
+ 'data2/stations.php'
11
+ end
12
+ #
13
+ # Returns if this station is active
14
+ #
15
+ # @return [Bool] [Stations is active or not]
16
+ def active?
17
+ self.internal_object['status'] == 'Active'
18
+ end
19
+
20
+ #
21
+ # Returns the number of available bikes at this station
22
+ #
23
+ # @return [Integer] [Number of available bikes]
24
+ def available_bikes
25
+ self['availableBikes']
26
+ end
27
+
28
+ #
29
+ # Returns the number of available docks at this station
30
+ #
31
+ # @return [Integer] [Number of available docks]
32
+ def available_docks
33
+ self['availableDocks']
34
+ end
35
+
36
+ #
37
+ # Returns the address of the station
38
+ #
39
+ # @return [String] [Address of the station]
40
+ def station_address
41
+ self['stationAddress']
42
+ end
43
+
44
+ #
45
+ # Nearby station array of hashes of the form
46
+ # [
47
+ # {
48
+ # :id => Integer,
49
+ # :distance => Float
50
+ # },
51
+ # ...
52
+ # ]
53
+ #
54
+ # @return [Array] [Array of hashes of nearby stations]
55
+ def nearby_stations
56
+ self['nearbyStations']
57
+ end
58
+
59
+ #
60
+ # Returns the ids of nearby stations for
61
+ # easy lookup in a Citibike::Responses::Station object
62
+ #
63
+ # @return [Array] [Array of integer ids]
64
+ def nearby_station_ids
65
+ @nearby_station_ids ||= self.nearby_stations.map { |s| s['id'] }
66
+ end
67
+
68
+ #
69
+ # Returns the distance to a nearby station (in miles?)
70
+ # @param id [Integer] [Id of a nearby station]
71
+ #
72
+ # @return [Float] [Distance to nearby station in miles]
73
+ def distance_to_nearby(id)
74
+ unless self.nearby_station_ids.include?(id.to_i)
75
+ raise "Station #{id} is not a nearby station"
76
+ end
77
+
78
+ sta = self.nearby_stations.find { |s| s['id'].to_i == id.to_i }
79
+ sta['distance']
80
+ end
81
+ end
82
+
83
+ end