transprt 0.2.1 → 0.2.2

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.
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