transprt 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 37769de876d6c551e33027f937f972c6a7b8c3bd
4
- data.tar.gz: 0ea98dc958a2df6b632b2af56cb24d569fa0e97e
3
+ metadata.gz: 50047652bf414068ce0972cef66b2b1606f98773
4
+ data.tar.gz: 2af08e598c7326f1aa257f1ee0b03761ec321d65
5
5
  SHA512:
6
- metadata.gz: 9e6f58ee195a1124a6ce8a8e8014ed7be496217da5beb6fc571122d610960d65d575ed92eb5472fe784c732d99f7830991ae0a2133342804bc6c5a11349e72dd
7
- data.tar.gz: 9677cca5e16aa134cd8fb547e7a992a79d628bc8c1ca68844a664d9805934bddab2d2f26502720904affa11c4abf670949ede1faa6ae29a5933172986e787918
6
+ metadata.gz: d64dd8bf69522d816c2da877982d628552254b3cabfda9fa9109be859ec768f9c9a511aca1d33892f20a9b697a745b83b62128570d3820e51f44d18afebe76ab
7
+ data.tar.gz: f977ef47116e658412936c0a0da04aa7593a3a9e67d68ab6417e75981fb008af9718e38bc2c2332ce4633f85af76cc80214db7ebfcf21e355b83f7bac469538e
@@ -0,0 +1,2 @@
1
+ ruby:
2
+ config_file: .rubocop.yml
@@ -0,0 +1,4 @@
1
+ Style/Documentation:
2
+ Include: []
3
+ Metrics/MethodLength:
4
+ Max: 20
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ sudo: true
3
+ rvm:
4
+ - 2.3.0
5
+ - 2.2.4
6
+
7
+ script: bundle exec rake test
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in bramipsum.gemspec
4
3
  gemspec
@@ -2,8 +2,8 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  transprt (0.2.1)
5
- json (>= 1.8.0)
6
- rest-client (>= 1.6.7, < 2.1.0)
5
+ json
6
+ rest-client
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
@@ -22,6 +22,7 @@ GEM
22
22
  mime-types-data (3.2016.0521)
23
23
  minitest (5.8.4)
24
24
  netrc (0.11.0)
25
+ rake (11.2.2)
25
26
  rest-client (2.0.0)
26
27
  http-cookie (>= 1.0.2, < 2.0)
27
28
  mime-types (>= 1.16, < 4.0)
@@ -39,7 +40,9 @@ PLATFORMS
39
40
  ruby
40
41
 
41
42
  DEPENDENCIES
43
+ bundler
42
44
  minitest (~> 5.8.4)
45
+ rake
43
46
  transprt!
44
47
  webmock (~> 2.1.0)
45
48
 
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  #transprt
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/transprt.png)](http://badge.fury.io/rb/transprt)
4
- [![Dependency Status](https://gemnasium.com/ghn/transprt.png)](https://gemnasium.com/ghn/transprt)
3
+ [![Gem Version](https://badge.fury.io/rb/transprt.svg)](https://badge.fury.io/rb/transprt)
4
+ [![Dependency Status](https://gemnasium.com/badges/github.com/ghn/transprt.svg)](https://gemnasium.com/github.com/ghn/transprt)
5
+ [![Build Status](https://travis-ci.org/ghn/transprt.svg?branch=master)](https://travis-ci.org/ghn/transprt)
5
6
 
6
7
  Ruby client for the Swiss public transport API at http://transport.opendata.ch
7
8
 
@@ -61,6 +62,6 @@ Running the tests
61
62
  rake test
62
63
  ```
63
64
 
64
- ##Licence
65
+ ## License
65
66
 
66
67
  MIT License (MIT)
data/Rakefile CHANGED
@@ -2,5 +2,5 @@ require 'rake/testtask'
2
2
 
3
3
  Rake::TestTask.new do |t|
4
4
  t.libs << 'test'
5
- t.pattern = "test/*_test.rb"
5
+ t.pattern = 'test/*_test.rb'
6
6
  end
@@ -1,78 +1 @@
1
- require 'rubygems'
2
- require 'rest_client'
3
- require 'json'
4
-
5
- module Transprt
6
- class Client
7
- DEFAULT_DOMAIN = 'http://transport.opendata.ch'
8
- VERSION = 'v1'
9
-
10
- def initialize(domain=DEFAULT_DOMAIN, version=VERSION)
11
- @domain = domain
12
- @version = version
13
- end
14
-
15
- #
16
- # => find locations
17
- #
18
- def locations(parameters)
19
- allowed_parameters = ['query', 'x', 'y', 'type']
20
-
21
- query = create_query(parameters, allowed_parameters)
22
- locations = perform('locations', query)
23
-
24
- locations['stations']
25
- end
26
-
27
- #
28
- # => find connections
29
- #
30
- def connections(parameters)
31
- allowed_parameters = ['from', 'to', 'via', 'date', 'time', 'isArrivalTime', 'transportations', 'limit', 'page',
32
- 'direct', 'sleeper', 'couchette', 'bike']
33
-
34
- query = create_query(parameters, allowed_parameters)
35
- locations = perform('connections', query)
36
-
37
- locations['connections']
38
- end
39
-
40
- #
41
- # => find station boards
42
- #
43
- def stationboard(parameters)
44
- allowed_parameters = ['station', 'id', 'limit', 'transportations', 'datetime']
45
-
46
- query = create_query(parameters, allowed_parameters)
47
- locations = perform('stationboard', query)
48
-
49
- locations['stationboard']
50
- end
51
-
52
- private
53
- attr_reader :domain, :version
54
-
55
- def perform(endpoint, query)
56
- url = "#{create_url(endpoint)}#{query}"
57
- response = RestClient.get(url)
58
-
59
- # Uncomment the line below to dump the response in order to generate
60
- # a file to use as response stub in tests.
61
- # File.write('/tmp/response.json', response)
62
-
63
- JSON.parse(response)
64
- end
65
-
66
- def create_url(endpoint)
67
- [domain, version, endpoint].join('/') + '?'
68
- end
69
-
70
- def create_query(parameters, allowed_parameters)
71
- parameters.map do |k,v|
72
- next unless allowed_parameters.include?(k.to_s)
73
-
74
- "#{k}=#{URI.escape(v)}"
75
- end.join('&')
76
- end
77
- end
78
- end
1
+ require 'transprt/client'
@@ -0,0 +1,87 @@
1
+ require 'rubygems'
2
+ require 'rest_client'
3
+ require 'json'
4
+
5
+ require_relative 'rate_limiting'
6
+
7
+ module Transprt
8
+ class Client
9
+ DEFAULT_DOMAIN = 'http://transport.opendata.ch'.freeze
10
+ VERSION = 'v1'.freeze
11
+
12
+ def initialize(domain = DEFAULT_DOMAIN, version = VERSION)
13
+ @domain = domain
14
+ @version = version
15
+ end
16
+
17
+ #
18
+ # => find locations
19
+ #
20
+ def locations(parameters)
21
+ allowed_parameters = %w(query x y type)
22
+
23
+ query = create_query(parameters, allowed_parameters)
24
+ locations = perform('locations', query)
25
+
26
+ locations['stations']
27
+ end
28
+
29
+ #
30
+ # => find connections
31
+ #
32
+ def connections(parameters)
33
+ allowed_parameters = %w(from to via date time isArrivalTime
34
+ transportations limit page direct sleeper
35
+ couchette bike)
36
+
37
+ query = create_query(parameters, allowed_parameters)
38
+ locations = perform('connections', query)
39
+
40
+ locations['connections']
41
+ end
42
+
43
+ #
44
+ # => find station boards
45
+ #
46
+ def stationboard(parameters)
47
+ allowed_parameters = %w(station id limit transportations datetime)
48
+
49
+ query = create_query(parameters, allowed_parameters)
50
+ locations = perform('stationboard', query)
51
+
52
+ locations['stationboard']
53
+ end
54
+
55
+ private
56
+
57
+ attr_reader :domain, :version
58
+
59
+ def perform(endpoint, query)
60
+ url = "#{create_url(endpoint)}#{query}"
61
+
62
+ response = limiter.get(url)
63
+
64
+ # Uncomment the line below to dump the response in order to generate
65
+ # a file to use as response stub in tests.
66
+ # File.write('/tmp/response.json', response)
67
+
68
+ JSON.parse(response)
69
+ end
70
+
71
+ def create_url(endpoint)
72
+ [domain, version, endpoint].join('/') + '?'
73
+ end
74
+
75
+ def create_query(parameters, allowed_parameters)
76
+ parameters.map do |k, v|
77
+ next unless allowed_parameters.include?(k.to_s)
78
+
79
+ "#{k}=#{CGI.escape(v)}"
80
+ end.join('&')
81
+ end
82
+
83
+ def limiter
84
+ @limiter ||= RateLimiting.new
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,48 @@
1
+ module Transprt
2
+ class RateLimiting
3
+ # Performs HTTP queries while respecting the rate limit.
4
+
5
+ # @param wait_for_quota [Boolean] whether to wait for quota reset
6
+ # and query again if the rate limit (300 requests/s) is exceeded.
7
+ def initialize(wait_for_quota = true)
8
+ @wait_for_quota = wait_for_quota
9
+ end
10
+
11
+ # @return The HTTP response or nil if we're hitting the rate limit and
12
+ # wait_for_quota is false (@see #initialize).
13
+ def get(url)
14
+ begin
15
+ response = perform_get(url)
16
+ rescue RestClient::TooManyRequests => e
17
+ # API uses HTTP 429 to notify us,
18
+ # @see https://github.com/OpendataCH/Transport/blob/master/lib/Transport/Application.php
19
+
20
+ return nil unless wait_for_quota
21
+
22
+ sleep_until_quota_reset(e.response)
23
+ response = perform_get(url)
24
+ end
25
+
26
+ response
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :wait_for_quota
32
+
33
+ def perform_get(url)
34
+ RestClient.get(url)
35
+ end
36
+
37
+ def sleep_until_quota_reset(response)
38
+ # NOTE We rely on the local clock being synchronized
39
+ # with the server clock.
40
+
41
+ reset_at = response.headers['X-Rate-Limit-Reset'].to_i
42
+ delta = reset_at - Time.now.to_i
43
+
44
+ return if delta < 0
45
+ sleep delta
46
+ end
47
+ end
48
+ end
@@ -2,7 +2,6 @@ require 'test_helper'
2
2
  require 'pp'
3
3
 
4
4
  class ClientTest < Minitest::Test
5
-
6
5
  def setup
7
6
  WebMock.reset!
8
7
 
@@ -18,8 +17,8 @@ class ClientTest < Minitest::Test
18
17
 
19
18
  first_location = locations.first
20
19
 
21
- assert first_location['id'] == "008501008"
22
- assert first_location['name'] == "Genève"
20
+ assert first_location['id'] == '008501008'
21
+ assert first_location['name'] == 'Genève'
23
22
  end
24
23
 
25
24
  def test_connections
@@ -38,15 +37,40 @@ class ClientTest < Minitest::Test
38
37
  end
39
38
 
40
39
  def test_escaping
41
- # This makes sure the umlaut below gets escaped, if not we'll see an URI::InvalidURIError
42
- stub_request(:get, /.*/).to_return(status: 200, body: {'connections': nil}.to_json)
40
+ stub_request(:get, /.*/).to_return(
41
+ status: 200,
42
+ body: { connections: nil }.to_json)
43
+
44
+ # The following line fails with an URI::InvalidURIError
45
+ # should the umlaut in 'Zurich' not get escaped.
46
+ @client.connections from: 'Lausanne', to: 'Zürich'
47
+ end
43
48
 
44
- connections = @client.connections from: 'Lausanne', to: 'Zürich'
49
+ def test_rate_limit
50
+ request_count = 0
51
+
52
+ stub_request(:get, /.*/).to_return do
53
+ request_count += 1
54
+
55
+ if request_count == 1 # First request fails.
56
+ # Mock "rate limit hit" response code
57
+ { status: 429,
58
+ headers: { 'X-Rate-Limit-Reset' => Time.now.to_i.to_s } }
59
+ elsif request_count == 2 # Second request succeeds.
60
+ { status: 200, body: { connections: nil }.to_json }
61
+ else
62
+ raise "Did not expect request_count to be #{request_count}"
63
+ end
64
+ end
65
+
66
+ @client.connections from: 'Lausanne', to: 'Bern'
67
+ assert request_count == 2
45
68
  end
46
69
 
47
- def stub_response(name, url=/.*/, method=:get)
48
- # Uncomment lines below should you feel the urge to test against the live API
49
- # as the stubbing isn't very thorough as of now. (e.g. URLs requested aren't checked)
70
+ def stub_response(name, url = /.*/, method = :get)
71
+ # Uncomment lines below should you feel the urge to test against the live
72
+ # API as the stubbing isn't very thorough as of now. (e.g. URLs requested
73
+ # aren't checked)
50
74
  # WebMock.allow_net_connect!
51
75
  # return
52
76
 
@@ -5,4 +5,3 @@ require 'minitest/pride'
5
5
  require 'webmock/minitest'
6
6
 
7
7
  require 'transprt'
8
-
@@ -1,24 +1,22 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
-
4
1
  Gem::Specification.new do |gem|
5
- gem.name = "transprt"
6
- gem.version = '0.2.1'
7
- gem.authors = ["ghn"]
8
- gem.email = ["ghugon@gmail.com"]
9
- gem.description = %q{Ruby client for the Swiss public transport API}
10
- gem.summary = "Swiss public transport API"
2
+ gem.name = 'transprt'
3
+ gem.version = '0.2.2'
4
+ gem.authors = ['ghn']
5
+ gem.email = ['ghugon@gmail.com']
6
+ gem.description = 'Ruby client for the Swiss public transport API'
7
+ gem.summary = 'Ruby client for the Swiss public transport API'
11
8
  gem.homepage = 'https://github.com/ghn/transprt'
12
- gem.license = "MIT"
9
+ gem.license = 'MIT'
13
10
 
14
- gem.files = `git ls-files`.split($/)
11
+ gem.files = `git ls-files`.split($RS)
15
12
  gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
13
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
- gem.require_paths = ["lib"]
14
+ gem.require_paths = ['lib']
18
15
 
19
- gem.add_dependency('rest-client', '>=1.6.7', '<2.1.0')
20
- gem.add_dependency('json', '>= 1.8.0')
16
+ gem.add_dependency('rest-client')
17
+ gem.add_dependency('json')
18
+ gem.add_development_dependency 'bundler'
19
+ gem.add_development_dependency('rake')
21
20
  gem.add_development_dependency('minitest', '~> 5.8.4')
22
21
  gem.add_development_dependency('webmock', '~> 2.1.0')
23
22
  end
24
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transprt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ghn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-15 00:00:00.000000000 Z
11
+ date: 2016-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -16,34 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.6.7
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: 2.1.0
19
+ version: '0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: 1.6.7
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: 2.1.0
26
+ version: '0'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: json
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - ">="
38
32
  - !ruby/object:Gem::Version
39
- version: 1.8.0
33
+ version: '0'
40
34
  type: :runtime
41
35
  prerelease: false
42
36
  version_requirements: !ruby/object:Gem::Requirement
43
37
  requirements:
44
38
  - - ">="
45
39
  - !ruby/object:Gem::Version
46
- version: 1.8.0
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
47
69
  - !ruby/object:Gem::Dependency
48
70
  name: minitest
49
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +102,9 @@ extensions: []
80
102
  extra_rdoc_files: []
81
103
  files:
82
104
  - ".gitignore"
105
+ - ".hound.yml"
106
+ - ".rubocop.yml"
107
+ - ".travis.yml"
83
108
  - Gemfile
84
109
  - Gemfile.lock
85
110
  - LICENSE
@@ -87,6 +112,8 @@ files:
87
112
  - Rakefile
88
113
  - example.rb
89
114
  - lib/transprt.rb
115
+ - lib/transprt/client.rb
116
+ - lib/transprt/rate_limiting.rb
90
117
  - test/client_test.rb
91
118
  - test/responses/client_test_test_connections.json
92
119
  - test/responses/client_test_test_locations.json
@@ -115,7 +142,7 @@ rubyforge_project:
115
142
  rubygems_version: 2.4.5.1
116
143
  signing_key:
117
144
  specification_version: 4
118
- summary: Swiss public transport API
145
+ summary: Ruby client for the Swiss public transport API
119
146
  test_files:
120
147
  - test/client_test.rb
121
148
  - test/responses/client_test_test_connections.json