london-bike-hire-cli 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +14 -0
  6. data/Gemfile +4 -0
  7. data/Guardfile +11 -0
  8. data/LICENSE +21 -0
  9. data/README.md +144 -0
  10. data/Rakefile +19 -0
  11. data/bin/lbh +5 -0
  12. data/boris-on-a-bike_med.jpg +0 -0
  13. data/lib/london_bike_hire_cli.rb +15 -0
  14. data/lib/london_bike_hire_cli/application.rb +71 -0
  15. data/lib/london_bike_hire_cli/basic_renderer.rb +38 -0
  16. data/lib/london_bike_hire_cli/controller.rb +82 -0
  17. data/lib/london_bike_hire_cli/feed_parser.rb +76 -0
  18. data/lib/london_bike_hire_cli/geocoding_adapter.rb +27 -0
  19. data/lib/london_bike_hire_cli/query_response.rb +22 -0
  20. data/lib/london_bike_hire_cli/spatial_search.rb +20 -0
  21. data/lib/london_bike_hire_cli/station.rb +16 -0
  22. data/lib/london_bike_hire_cli/station_adapter.rb +19 -0
  23. data/lib/london_bike_hire_cli/station_repository.rb +51 -0
  24. data/lib/london_bike_hire_cli/version.rb +3 -0
  25. data/london-bike-hire-cli.gemspec +37 -0
  26. data/spec/controller_spec.rb +186 -0
  27. data/spec/feed_parser_spec.rb +42 -0
  28. data/spec/fixtures/feed_xml.yml +822 -0
  29. data/spec/fixtures/n19ae_geocode.yml +114 -0
  30. data/spec/fixtures/no_results_geocode.yml +50 -0
  31. data/spec/geocoding_adapter_spec.rb +47 -0
  32. data/spec/spatial_search_spec.rb +27 -0
  33. data/spec/spec_helper.rb +83 -0
  34. data/spec/station_adapter_spec.rb +29 -0
  35. data/spec/station_respository_spec.rb +117 -0
  36. data/spec/station_spec.rb +28 -0
  37. data/spec/support/test_datasource.rb +24 -0
  38. data/spec/support/vcr.rb +7 -0
  39. data/test.rb +6 -0
  40. metadata +307 -0
@@ -0,0 +1,114 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://maps.googleapis.com/maps/api/geocode/json?address=n19ae&language=en&sensor=false
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Content-Type:
22
+ - application/json; charset=UTF-8
23
+ Date:
24
+ - Sat, 23 Aug 2014 07:31:30 GMT
25
+ Expires:
26
+ - Sun, 24 Aug 2014 07:31:30 GMT
27
+ Cache-Control:
28
+ - public, max-age=86400
29
+ Access-Control-Allow-Origin:
30
+ - "*"
31
+ Server:
32
+ - mafe
33
+ X-Xss-Protection:
34
+ - 1; mode=block
35
+ X-Frame-Options:
36
+ - SAMEORIGIN
37
+ Alternate-Protocol:
38
+ - 80:quic
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: UTF-8
43
+ string: |
44
+ {
45
+ "results" : [
46
+ {
47
+ "address_components" : [
48
+ {
49
+ "long_name" : "N1 9AE",
50
+ "short_name" : "N1 9AE",
51
+ "types" : [ "postal_code" ]
52
+ },
53
+ {
54
+ "long_name" : "Kings Cross",
55
+ "short_name" : "Kings Cross",
56
+ "types" : [ "neighborhood", "political" ]
57
+ },
58
+ {
59
+ "long_name" : "London",
60
+ "short_name" : "London",
61
+ "types" : [ "locality", "political" ]
62
+ },
63
+ {
64
+ "long_name" : "London",
65
+ "short_name" : "London",
66
+ "types" : [ "postal_town" ]
67
+ },
68
+ {
69
+ "long_name" : "Greater London",
70
+ "short_name" : "Gt Lon",
71
+ "types" : [ "administrative_area_level_2", "political" ]
72
+ },
73
+ {
74
+ "long_name" : "United Kingdom",
75
+ "short_name" : "GB",
76
+ "types" : [ "country", "political" ]
77
+ }
78
+ ],
79
+ "formatted_address" : "Kings Cross, London N1 9AE, UK",
80
+ "geometry" : {
81
+ "bounds" : {
82
+ "northeast" : {
83
+ "lat" : 51.5310654,
84
+ "lng" : -0.1212172
85
+ },
86
+ "southwest" : {
87
+ "lat" : 51.5308025,
88
+ "lng" : -0.1218269
89
+ }
90
+ },
91
+ "location" : {
92
+ "lat" : 51.5309584,
93
+ "lng" : -0.1215387
94
+ },
95
+ "location_type" : "APPROXIMATE",
96
+ "viewport" : {
97
+ "northeast" : {
98
+ "lat" : 51.5322829302915,
99
+ "lng" : -0.120173069708498
100
+ },
101
+ "southwest" : {
102
+ "lat" : 51.5295849697085,
103
+ "lng" : -0.122871030291502
104
+ }
105
+ }
106
+ },
107
+ "types" : [ "postal_code" ]
108
+ }
109
+ ],
110
+ "status" : "OK"
111
+ }
112
+ http_version:
113
+ recorded_at: Sat, 23 Aug 2014 07:31:30 GMT
114
+ recorded_with: VCR 2.9.2
@@ -0,0 +1,50 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://maps.googleapis.com/maps/api/geocode/json?address=====&language=en&sensor=false
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Content-Type:
22
+ - application/json; charset=UTF-8
23
+ Date:
24
+ - Sat, 23 Aug 2014 10:15:38 GMT
25
+ Expires:
26
+ - Sun, 24 Aug 2014 10:15:38 GMT
27
+ Cache-Control:
28
+ - public, max-age=86400
29
+ Access-Control-Allow-Origin:
30
+ - "*"
31
+ Server:
32
+ - mafe
33
+ X-Xss-Protection:
34
+ - 1; mode=block
35
+ X-Frame-Options:
36
+ - SAMEORIGIN
37
+ Alternate-Protocol:
38
+ - 80:quic
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: UTF-8
43
+ string: |
44
+ {
45
+ "results" : [],
46
+ "status" : "ZERO_RESULTS"
47
+ }
48
+ http_version:
49
+ recorded_at: Sat, 23 Aug 2014 10:15:38 GMT
50
+ recorded_with: VCR 2.9.2
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe LondonBikeHireCli::GeocodingAdapter do
4
+ subject { described_class.new }
5
+
6
+ describe '#geocode with valid search term', vcr: { cassette_name: 'n19ae_geocode' } do
7
+ let(:search_term) { 'n19ae' }
8
+
9
+ it 'returns hash' do
10
+ expect(subject.geocode(search_term)).to be_instance_of(Hash)
11
+ end
12
+
13
+ it 'returns 2d point with lat key' do
14
+ expect(subject.geocode(search_term)).to have_key(:lat)
15
+ end
16
+
17
+ it 'returns 2d point with lat key' do
18
+ expect(subject.geocode(search_term)).to have_key(:long)
19
+ end
20
+
21
+ it 'returns 2d point with lat value' do
22
+ point = subject.geocode(search_term)
23
+ expect(point[:lat]).to eq(51.5309584)
24
+ end
25
+
26
+ it 'returns 2d point with long value' do
27
+ point = subject.geocode(search_term)
28
+ expect(point[:long]).to eq(-0.1215387)
29
+ end
30
+ end
31
+
32
+ describe '#geocode with search term returning no results', vcr: { cassette_name: 'no_results_geocode' } do
33
+ let(:search_term) { '====' }
34
+
35
+ it 'returns non nil' do
36
+ expect(subject.geocode(search_term)).not_to be_nil
37
+ end
38
+
39
+ it 'returns hash' do
40
+ expect(subject.geocode(search_term)).to be_instance_of(Hash)
41
+ end
42
+
43
+ it 'returns emtpy hash' do
44
+ expect(subject.geocode(search_term)).to be_empty
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe LondonBikeHireCli::SpatialSearch do
4
+ let(:point_1) { [51.53005939, -0.120973687, 1] }
5
+ let(:point_2) { [51.50810309, -0.12602103, 2] }
6
+ let(:datasource) { [point_1, point_2] }
7
+ subject { described_class.new(datasource) }
8
+
9
+ describe '#nearest' do
10
+ context 'with datasource' do
11
+ let(:request) { { lat: 51.5309, long: -0.1215 } }
12
+ it 'returns results ordered by distance' do
13
+ results = subject.nearest(request)
14
+
15
+ expect(results).to eq([1, 2])
16
+ end
17
+
18
+ context 'given a limit request' do
19
+ it 'returns correct number of results' do
20
+ results = subject.nearest(request, 1)
21
+
22
+ expect(results.size).to eq(1)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,83 @@
1
+ require 'codeclimate-test-reporter'
2
+ require 'coveralls'
3
+ require 'pry-byebug'
4
+ CodeClimate::TestReporter.start
5
+ Coveralls.wear!
6
+
7
+ require File.join(File.dirname(__FILE__), '..', '/lib/', 'london_bike_hire_cli')
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
9
+
10
+ # This file was generated by the `rspec --init` command. Conventionally, all
11
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
12
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
13
+ # file to always be loaded, without a need to explicitly require it in any files.
14
+ #
15
+ # Given that it is always loaded, you are encouraged to keep this file as
16
+ # light-weight as possible. Requiring heavyweight dependencies from this file
17
+ # will add to the boot time of your test suite on EVERY test run, even for an
18
+ # individual file that may not need all of that loaded. Instead, make a
19
+ # separate helper file that requires this one and then use it only in the specs
20
+ # that actually need it.
21
+ #
22
+ # The `.rspec` file also contains a few flags that are not defaults but that
23
+ # users commonly want.
24
+ #
25
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
26
+ RSpec.configure do |config|
27
+ # These two settings work together to allow you to limit a spec run
28
+ # to individual examples or groups you care about by tagging them with
29
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
30
+ # get run.
31
+ config.filter_run :focus
32
+ config.run_all_when_everything_filtered = true
33
+
34
+ # Many RSpec users commonly either run the entire suite or an individual
35
+ # file, and it's useful to allow more verbose output when running an
36
+ # individual spec file.
37
+ if config.files_to_run.one?
38
+ # Use the documentation formatter for detailed output,
39
+ # unless a formatter has already been configured
40
+ # (e.g. via a command-line flag).
41
+ config.default_formatter = 'doc'
42
+ end
43
+
44
+ # Print the 10 slowest examples and example groups at the
45
+ # end of the spec run, to help surface which specs are running
46
+ # particularly slow.
47
+ config.profile_examples = 10
48
+
49
+ # Run specs in random order to surface order dependencies. If you find an
50
+ # order dependency and want to debug it, you can fix the order by providing
51
+ # the seed, which is printed after each run.
52
+ # --seed 1234
53
+ config.order = :random
54
+
55
+ # Seed global randomization in this process using the `--seed` CLI option.
56
+ # Setting this allows you to use `--seed` to deterministically reproduce
57
+ # test failures related to randomization by passing the same `--seed` value
58
+ # as the one that triggered the failure.
59
+ Kernel.srand config.seed
60
+
61
+ # rspec-expectations config goes here. You can use an alternate
62
+ # assertion/expectation library such as wrong or the stdlib/minitest
63
+ # assertions if you prefer.
64
+ config.expect_with :rspec do |expectations|
65
+ # Enable only the newer, non-monkey-patching expect syntax.
66
+ # For more details, see:
67
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
68
+ expectations.syntax = :expect
69
+ end
70
+
71
+ # rspec-mocks config goes here. You can use an alternate test double
72
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
73
+ config.mock_with :rspec do |mocks|
74
+ # Enable only the newer, non-monkey-patching expect syntax.
75
+ # For more details, see:
76
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
77
+ mocks.syntax = :expect
78
+
79
+ # Prevents you from mocking or stubbing a method that does not exist on
80
+ # a real object. This is generally recommended.
81
+ mocks.verify_partial_doubles = true
82
+ end
83
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe LondonBikeHireCli::StationAdapter do
4
+ let(:datasource) { TestDatasource.new }
5
+ let(:test_repository) { LondonBikeHireCli::StationRepository.new(datasource) }
6
+ subject { described_class.new(test_repository.all) }
7
+
8
+ describe '#to_triples' do
9
+ context 'given datasource' do
10
+ it 'returns expected number of results' do
11
+ results = subject.to_triples
12
+
13
+ expect(results.size).to eq(2)
14
+ end
15
+
16
+ it 'produces triple of first station' do
17
+ results = subject.to_triples
18
+
19
+ expect(results.first).to eq([51.53005939, -0.120973687, 1])
20
+ end
21
+
22
+ it 'produces triple of second station' do
23
+ results = subject.to_triples
24
+
25
+ expect(results.last).to eq([51.50810309, -0.12602103, 2])
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe LondonBikeHireCli::StationRepository do
4
+ let(:datasource) { TestDatasource.new }
5
+ subject { described_class.new(datasource) }
6
+
7
+ describe '#all' do
8
+ context 'given feed_parser returns dataset' do
9
+ it 'should return expected number of results' do
10
+ results = subject.all
11
+
12
+ expect(results.size).to eq(2)
13
+ end
14
+ end
15
+ end
16
+
17
+ describe '#find_by_id' do
18
+ context 'given feed_parser returns dataset' do
19
+ it 'should return expected number of results' do
20
+ results = subject.find_by_id(1)
21
+
22
+ expect(results.size).to eq(1)
23
+ end
24
+
25
+ it 'should return expected result' do
26
+ result = subject.find_by_id(1).first
27
+
28
+ expect(result.name).to eq('test-station-1')
29
+ end
30
+
31
+ context 'given a request for an id that does not exist' do
32
+ it 'should raise error' do
33
+ expect do
34
+ subject.find_by_id(99)
35
+ end.to raise_error
36
+ end
37
+ end
38
+
39
+ context 'given a request for more than one id' do
40
+ it 'should return expected number of results' do
41
+ results = subject.find_by_id(1, 2)
42
+
43
+ expect(results.size).to eq(2)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#find_by_name' do
50
+ context 'given feed_parser returns dataset' do
51
+ it 'should return expected number of results' do
52
+ results = subject.find_by_name('test-station-1')
53
+
54
+ expect(results.size).to eq(1)
55
+ end
56
+
57
+ it 'should return expected result' do
58
+ result = subject.find_by_name('test-station-1').first
59
+
60
+ expect(result.id).to eq(1)
61
+ end
62
+
63
+ context 'given a request for an id that does not exist' do
64
+ it 'should not raise error' do
65
+ expect do
66
+ subject.find_by_name('foo')
67
+ end.not_to raise_error
68
+ end
69
+
70
+ it 'should return empty array' do
71
+ expect(subject.find_by_name('foo').size).to eq(0)
72
+ end
73
+ end
74
+ end
75
+
76
+ describe 'integration tests', vcr: { cassette_name: 'feed_xml' } do
77
+ subject { LondonBikeHireCli::StationRepository.new(LondonBikeHireCli::FeedParser.new) }
78
+
79
+ describe '#find_by_id' do
80
+ it 'should return expected number of results' do
81
+ results = subject.find_by_id(777)
82
+
83
+ expect(results.size).to eq(1)
84
+ end
85
+
86
+ it 'should return expected result' do
87
+ result = subject.find_by_id(777).first
88
+
89
+ expect(result.name).to eq('Limburg Road, Clapham Common')
90
+ end
91
+ end
92
+
93
+ describe '#find_by_name' do
94
+ it 'should return expected number of results' do
95
+ results = subject.find_by_name('kings')
96
+
97
+ expect(results.size).to eq(3)
98
+ end
99
+
100
+ it 'should return expected result' do
101
+ results = subject.find_by_name('kings')
102
+ actual_ids = results.map(&:id)
103
+
104
+ expect(actual_ids).to include(283, 439, 594)
105
+ end
106
+ end
107
+
108
+ describe '#all' do
109
+ it 'should return expected number of results' do
110
+ results = subject.all
111
+
112
+ expect(results.size).to eq(747)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end