london-bike-hire-cli 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +1 -0
  4. data/README.md +19 -17
  5. data/lib/london_bike_hire_cli/application.rb +8 -1
  6. data/lib/london_bike_hire_cli/basic_renderer.rb +15 -22
  7. data/lib/london_bike_hire_cli/color_helper.rb +24 -0
  8. data/lib/london_bike_hire_cli/controller.rb +21 -31
  9. data/lib/london_bike_hire_cli/feed_parser.rb +9 -10
  10. data/lib/london_bike_hire_cli/queries/stations_by_name.rb +9 -0
  11. data/lib/london_bike_hire_cli/queries/stations_near.rb +5 -0
  12. data/lib/london_bike_hire_cli/query_response.rb +4 -14
  13. data/lib/london_bike_hire_cli/repository/in_memory_store_adapter.rb +69 -0
  14. data/lib/london_bike_hire_cli/repository/repo.rb +39 -0
  15. data/lib/london_bike_hire_cli/repository/spatial_search_adapter.rb +28 -0
  16. data/lib/london_bike_hire_cli/repository/station_repo.rb +35 -0
  17. data/lib/london_bike_hire_cli/repository/station_store.rb +22 -0
  18. data/lib/london_bike_hire_cli/station.rb +4 -0
  19. data/lib/london_bike_hire_cli/station_not_found_error.rb +3 -0
  20. data/lib/london_bike_hire_cli/version.rb +1 -1
  21. data/lib/london_bike_hire_cli/views/error.erb +5 -0
  22. data/lib/london_bike_hire_cli/views/stations.erb +11 -0
  23. data/lib/london_bike_hire_cli.rb +12 -7
  24. data/london-bike-hire-cli.gemspec +3 -2
  25. data/spec/controller_spec.rb +29 -61
  26. data/spec/feed_parser_spec.rb +10 -12
  27. data/spec/station_repo_spec.rb +148 -0
  28. data/spec/support/test_datasource.rb +8 -4
  29. data/test.rb +1 -0
  30. metadata +17 -13
  31. data/lib/london_bike_hire_cli/spatial_search.rb +0 -20
  32. data/lib/london_bike_hire_cli/station_adapter.rb +0 -19
  33. data/lib/london_bike_hire_cli/station_repository.rb +0 -51
  34. data/spec/spatial_search_spec.rb +0 -27
  35. data/spec/station_adapter_spec.rb +0 -29
  36. data/spec/station_respository_spec.rb +0 -117
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a31585a5f453c569a80dc06e07b7c2ff6fbda20f
4
- data.tar.gz: 94dab876d1d9638e36f5d8415246ef0b70dcad0d
3
+ metadata.gz: d671c2c0f1e169a21f29d72549a428bb33611d4c
4
+ data.tar.gz: 3f32c3f533b6a18741d28e57275a289762b3260d
5
5
  SHA512:
6
- metadata.gz: d7b7c87317e34fc58ccbb8e867ffa553662245f07e6c26f2680dfbbc0d471a7db7106d099fd9a7b1ca08206bf3d0c934195874ef7bf59fe2f89d11eae9ddf241
7
- data.tar.gz: d954e6c03befdd669094c432ef7a5c1131104f4d88b8526a329c8f6b98dd6ccae1cfcf1c556ecb4453203a77143a14206b6f3bfc0dd3b2016a0963aa676cd400
6
+ metadata.gz: 664bcbc0ebcbf7fe0ad5b3af52961f186f618928eb84dc4c9c571742052da197e92a6a8bb93addba70927a9c028ecc8b575f646351a89abe00d71643a7a40f86
7
+ data.tar.gz: 3665a466b1f0d4d2a3d08ca212ebbf401be996c3e99cf8a3f4dd5858732ed7498425cfa6d598a8349a67d379e3b16be0ca6c03279a8f2ca1f3d018b43845ef7e
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.1.1
1
+ 2.2.0
data/.travis.yml CHANGED
@@ -3,6 +3,7 @@ cache: bundler
3
3
  rvm:
4
4
  - 2.0.0
5
5
  - 2.1.0
6
+ - 2.2.0
6
7
  - ruby-head
7
8
 
8
9
  matrix:
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![Build Status](https://travis-ci.org/rob-murray/london-bike-hire-cli.svg?branch=master)](https://travis-ci.org/rob-murray/london-bike-hire-cli)
6
6
  [![Code Climate](https://codeclimate.com/github/rob-murray/london-bike-hire-cli.png)](https://codeclimate.com/github/rob-murray/london-bike-hire-cli)
7
- [![Coverage Status](https://coveralls.io/repos/rob-murray/london-bike-hire-cli/badge.png)](https://coveralls.io/r/rob-murray/london-bike-hire-cli)
7
+ [![Coverage Status](https://coveralls.io/repos/rob-murray/london-bike-hire-cli/badge.svg?branch=master)](https://coveralls.io/r/rob-murray/london-bike-hire-cli?branch=master)
8
8
  [![Dependency Status](https://gemnasium.com/rob-murray/ferver.svg)](https://gemnasium.com/rob-murray/london-bike-hire-cli)
9
9
  [![Gem Version](https://badge.fury.io/rb/london-bike-hire-cli.svg)](http://badge.fury.io/rb/london-bike-hire-cli)
10
10
  [![Haz Commitz Status](http://haz-commitz.herokuapp.com/repos/rob-murray/london-bike-hire-cli.svg)](http://haz-commitz.herokuapp.com/repos/rob-murray/london-bike-hire-cli)
@@ -12,17 +12,19 @@
12
12
 
13
13
  ### Description
14
14
 
15
- This gem provides a command line interface to find information about London's Bike Hire stations, it allows you to find stations by name or their ID and retrieve information about the status of a station.
15
+ This gem provides a command line interface to find information about London's Bike Hire stations, it allows you to find stations by name or their ID or a location and retrieve information about the status of a station.
16
+
17
+ I got fed up digging through [the official map](https://web.barclayscyclehire.tfl.gov.uk/maps) to see which bike stations were free - everyone knows the command line is way more efficient.
16
18
 
17
19
  ![Boris](boris-on-a-bike_med.jpg?raw=true "Boris Johnson on a bike")
18
20
 
19
21
  Here's the spec for **London Bike Hire CLI**:
20
22
 
21
- * Find all stations
22
- * Find nearest station
23
- * Find by ID
24
- * Find by by name
25
- * Display status of stations
23
+ * [Find all stations](#list-all-bike-stations)
24
+ * [Find by ID](#find-a-bike-station-by-id)
25
+ * [Find nearest station](#find-the-nearest-bike-station)
26
+ * [Find by name](#find-all-bike-stations-by-name)
27
+ * [Display status of stations](#results)
26
28
 
27
29
 
28
30
  ### Getting started
@@ -38,7 +40,7 @@ $ gem install london-bike-hire-cli
38
40
 
39
41
  You can run **london-bike-hire-cli** from the command line with just the `lbh` command.
40
42
 
41
- ##### Command line help
43
+ #### Command line help
42
44
 
43
45
  For a list of arguments just use the `-h` switch.
44
46
 
@@ -46,7 +48,7 @@ For a list of arguments just use the `-h` switch.
46
48
  $ lbh -h
47
49
  ````
48
50
 
49
- ##### List all bike stations
51
+ #### List all bike stations
50
52
 
51
53
  List all however-many-hundred bike stations there are. With pagination.
52
54
 
@@ -54,7 +56,7 @@ List all however-many-hundred bike stations there are. With pagination.
54
56
  $ lbh all
55
57
  ````
56
58
 
57
- ##### Find the nearest bike station
59
+ #### Find the nearest bike station
58
60
 
59
61
  Find a the nearest bike station to the specified type below. This will return five stations.
60
62
 
@@ -76,7 +78,7 @@ $ lbh near --id 123
76
78
 
77
79
  **Note:** Don't forget to wrap search term in quotes if it contains spaces.
78
80
 
79
- ##### Show status of a bike station by id
81
+ #### Find a bike station by id
80
82
 
81
83
  Find a Bike station by it's Tfl station ID. This will return one station.
82
84
 
@@ -85,7 +87,7 @@ $ lbh find --id {id}
85
87
  $ lbh find --id 439
86
88
  ````
87
89
 
88
- ##### Find all bike stations by name
90
+ #### Find all bike stations by name
89
91
 
90
92
  Search all bike stations' name attribute for the search value. This will return zero or more results.
91
93
 
@@ -94,22 +96,22 @@ $ lbh where --{attribute} {search_value}
94
96
  $ lbh where --name kings
95
97
  ````
96
98
 
97
- ##### Results
99
+ #### Results
98
100
 
99
101
  ```bash
100
102
  $ lbh find --id 439
101
103
  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
102
- Feed updated: 2014-08-12 08:45:01
103
- >>> Dock
104
+ ----- Bike station
104
105
  Id: 439
105
106
  Name: Killick Street, Kings Cross
106
107
  Lat: 51.5338
107
108
  Long: -0.118677
108
109
  Temporary: false
109
- Bikes: 4
110
- Docks_free: 18
110
+ Bikes: 13
111
+ Docks_free: 9
111
112
  Docks_total: 22
112
113
  Link to map: https://www.google.co.uk/maps/preview/@51.5338,-0.118677,17z
114
+ Updated at: 2015-03-31 20:46:01
113
115
  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
114
116
  ```
115
117
 
@@ -65,7 +65,14 @@ module LondonBikeHireCli
65
65
  end
66
66
 
67
67
  def station_repository
68
- @station_repository ||= StationRepository.new(FeedParser.new)
68
+ register_adapter!
69
+ Repository::StationRepo.new
70
+ end
71
+
72
+ def register_adapter!
73
+ Repository::Repo.register(
74
+ Repository::StationStore.new(FeedParser.new.fetch)
75
+ )
69
76
  end
70
77
  end
71
78
  end
@@ -1,38 +1,31 @@
1
+ require 'erb'
2
+ require_relative 'color_helper'
3
+
1
4
  module LondonBikeHireCli
2
5
  class BasicRenderer
6
+ include ColorHelper
7
+
3
8
  def initialize(output = STDOUT)
4
9
  @output = output
5
10
  end
6
11
 
7
- def render(context)
8
- output.print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
9
- output.print "Feed updated: #{context.time_of_feed}\n"
12
+ attr_reader :context
10
13
 
11
- context.each do |station|
12
- render_station(station)
13
- end
14
-
15
- output.print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
16
- end
17
-
18
- def render_error(context)
19
- output.print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
20
- output.print "Ooops, something went wrong with the query.\n"
21
- output.print "The query #{context[:query].inspect}\n"
22
- output.print "resulted in error: #{context[:error]}\n"
23
- output.print "Try again?\n"
14
+ def render(template_name, context)
15
+ @context = context
16
+ output.print render_template(find_template(template_name))
24
17
  end
25
18
 
26
19
  private
27
20
 
28
21
  attr_reader :output
29
22
 
30
- def render_station(station)
31
- output.print ">>> Dock\n"
32
- station.each_pair.each do |attr_name, attr_value|
33
- output.print "#{attr_name.capitalize}: #{attr_value}\n"
34
- end
35
- output.print "Link to map: #{station.map_link}\n"
23
+ def render_template(template)
24
+ ERB.new(template).result(binding).gsub(/^\s+/, '')
25
+ end
26
+
27
+ def find_template(template_name)
28
+ File.read("lib/london_bike_hire_cli/views/#{template_name}.erb")
36
29
  end
37
30
  end
38
31
  end
@@ -0,0 +1,24 @@
1
+ module LondonBikeHireCli
2
+ module ColorHelper
3
+ def colorize(text, color_name = :default)
4
+ colour_code = color_code(color_name)
5
+ "\e[#{colour_code}m#{text}\e[0m"
6
+ end
7
+
8
+ private
9
+
10
+ def color_code(name)
11
+ COLOR_MAP[name]
12
+ end
13
+
14
+ COLOR_MAP = {
15
+ default: 39,
16
+ red: 31,
17
+ green: 32,
18
+ yellow: 33,
19
+ blue: 34,
20
+ pink: 35,
21
+ cyan: 36
22
+ }.freeze
23
+ end
24
+ end
@@ -1,6 +1,6 @@
1
1
  module LondonBikeHireCli
2
2
  class Controller
3
- attr_accessor :geocoder, :spatial_service
3
+ attr_accessor :geocoder
4
4
 
5
5
  def initialize(repository: nil, renderer: default_renderer)
6
6
  @repository = repository
@@ -10,58 +10,55 @@ module LondonBikeHireCli
10
10
 
11
11
  def all
12
12
  results = repository.all
13
- renderer.render(results)
13
+ renderer.render(:stations, results)
14
14
  end
15
15
 
16
16
  def find_by_id(id)
17
- results = repository.find_by_id(id.to_i)
18
- renderer.render(results)
17
+ results = repository.find(id.to_i)
18
+ renderer.render(:stations, Array(results))
19
19
 
20
- rescue StationRepository::StationNotFound => e
21
- renderer.render_error(query: "find_by_id: #{id}", error: e)
20
+ rescue StationNotFoundError => e
21
+ renderer.render(:error, query: "find_by_id: #{id}", error: e)
22
22
  end
23
23
 
24
24
  def where(params: {})
25
- results = repository.find_by_name(params[:name])
26
- renderer.render(results)
25
+ by_name_query = Queries::StationsByName.new(params[:name])
26
+ results = repository.query(by_name_query)
27
+ renderer.render(:stations, results)
27
28
 
28
- rescue StationRepository::StationNotFound => e
29
- renderer.render_error(query: "where: #{params}", error: e)
29
+ rescue StationNotFoundError => e
30
+ renderer.render(:error, query: "where: #{params}", error: e)
30
31
  end
31
32
 
32
33
  def nearest(params: {})
33
34
  unless params[:search_term].nil? ^ params[:id].nil?
34
35
  error = 'Please use either `search_term` or `id` not both.'
35
- renderer.render_error(query: "nearest: #{params}", error: error)
36
+ renderer.render(:error, query: "nearest: #{params}", error: error)
36
37
  return
37
38
  end
38
39
 
39
40
  if search_term = params[:search_term]
40
41
  geocoded_point = geocoder.geocode(search_term)
41
- end
42
-
43
- if search_term = params[:id]
42
+ elsif search_term = params[:id]
44
43
  begin
45
- stations = repository.find_by_id(search_term.to_i)
46
- rescue StationRepository::StationNotFound => e
47
- renderer.render_error(query: "where: #{params}", error: e)
44
+ station = repository.find(search_term.to_i)
45
+ rescue StationNotFoundError => e
46
+ renderer.render(:error, query: "where: #{params}", error: e)
48
47
  return
49
48
  end
50
49
 
51
- geocoded_point = stations.first.position
50
+ geocoded_point = station.position
52
51
  end
53
52
 
54
53
  unless geocoded_point
55
54
  error = 'Unable to Geocode location.'
56
- renderer.render_error(query: "nearest: #{params}", error: error)
55
+ renderer.render(:error, query: "nearest: #{params}", error: error)
57
56
  return
58
57
  end
59
58
 
60
- init_spatial_service(repository.all)
61
- nearest_ids = spatial_service.nearest(geocoded_point)
62
-
63
- results = repository.find_by_id(*nearest_ids)
64
- renderer.render(results)
59
+ near_query = Queries::StationsNear.new(geocoded_point[:lat], geocoded_point[:long], DEFAULT_SEARCH_LIMIT)
60
+ results = repository.query(near_query)
61
+ renderer.render(:stations, results)
65
62
  end
66
63
 
67
64
  private
@@ -71,12 +68,5 @@ module LondonBikeHireCli
71
68
  def default_renderer
72
69
  BasicRenderer.new
73
70
  end
74
-
75
- def init_spatial_service(all_stations)
76
- @spatial_service ||= begin
77
- datasource = StationAdapter.new(all_stations).to_triples
78
- SpatialSearch.new(datasource)
79
- end
80
- end
81
71
  end
82
72
  end
@@ -14,23 +14,21 @@ module LondonBikeHireCli
14
14
 
15
15
  private
16
16
 
17
- attr_writer :stations
17
+ attr_reader :feed_time
18
18
 
19
19
  def parse_xml(xml_doc)
20
- stations = {}
20
+ stations = []
21
+ parse_feed_time(xml_doc)
21
22
 
22
23
  xml_doc.root.elements.each do |node|
23
- station = parse_station(node)
24
- station_id = station[:id].to_i
25
- stations[station_id] = Station.new(station) unless station_id == 0
24
+ stations << parse_station(node)
26
25
  end
27
- stations[:last_update] = parse_feed_time(xml_doc)
28
26
 
29
- stations
27
+ QueryResponse.new(last_update: feed_time, results: stations)
30
28
  end
31
29
 
32
30
  def parse_feed_time(xml_doc)
33
- Time.at xml_doc.root['lastUpdate'].to_i / 1000
31
+ @feed_time ||= Time.at xml_doc.root['lastUpdate'].to_i / 1000
34
32
  end
35
33
 
36
34
  # <stations lastUpdate="1407153481506" version="2.0">
@@ -64,13 +62,14 @@ module LondonBikeHireCli
64
62
  station[:lat] = node.text.to_f if node.node_name.eql? 'lat'
65
63
  station[:long] = node.text.to_f if node.node_name.eql? 'long'
66
64
  station[:temporary] = parse_bool(node.text) if node.node_name.eql? 'temporary'
65
+ station[:updated_at] = feed_time
67
66
  end
68
67
 
69
- station
68
+ Station.new(station)
70
69
  end
71
70
 
72
71
  def parse_bool(value)
73
- value == 'true'
72
+ !!(value == 'true')
74
73
  end
75
74
  end
76
75
  end
@@ -0,0 +1,9 @@
1
+ module LondonBikeHireCli
2
+ module Queries
3
+ StationsByName = Struct.new(:search_term) do
4
+ def normalized_query
5
+ search_term.downcase
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module LondonBikeHireCli
2
+ module Queries
3
+ StationsNear = Struct.new(:lat, :long, :limit)
4
+ end
5
+ end
@@ -1,22 +1,12 @@
1
- require 'forwardable'
1
+ require 'delegate'
2
2
 
3
3
  module LondonBikeHireCli
4
- class QueryResponse
5
- extend Forwardable
6
-
7
- def_delegators :results, :[], :each, :map, :first, :size
4
+ class QueryResponse < SimpleDelegator
5
+ attr_reader :last_update
8
6
 
9
7
  def initialize(last_update: Time.now, results: [])
8
+ super(results)
10
9
  @last_update = last_update
11
- @results = results
12
- end
13
-
14
- def time_of_feed
15
- last_update.strftime('%Y-%m-%d %H:%M:%S')
16
10
  end
17
-
18
- private
19
-
20
- attr_reader :results, :last_update
21
11
  end
22
12
  end
@@ -0,0 +1,69 @@
1
+ module LondonBikeHireCli
2
+ module Repository
3
+ # Adapter that stores records in memory.
4
+ # Supports multiple record types
5
+ #
6
+ class InMemoryStoreAdapter
7
+ def initialize(items = [])
8
+ @counter = 0
9
+ @map = {}
10
+ add_items(items)
11
+ end
12
+
13
+ def create(record)
14
+ @counter = @counter + 1
15
+ record.id ||= @counter
16
+ map_for(record)[record.id] = record
17
+ end
18
+
19
+ def update(record)
20
+ map_for(record)[record.id] = record
21
+ end
22
+
23
+ def delete(record)
24
+ map_for(record).delete record.id
25
+ end
26
+
27
+ def find(klass, id)
28
+ map_for_class(klass).fetch id
29
+ end
30
+
31
+ def find_by_ids(klass, *ids)
32
+ map_for_class(klass).values_at(*ids)
33
+ end
34
+
35
+ def all(klass)
36
+ map_for_class(klass).values
37
+ end
38
+
39
+ def query(klass, selector)
40
+ # TODO fix introspection
41
+ send "query_#{underscore(selector.class.name)}", klass, selector
42
+ end
43
+
44
+ private
45
+
46
+ def add_items(items)
47
+ items.each { |item| create(item) }
48
+ end
49
+
50
+ def map_for_class(klass)
51
+ @map[klass.to_s.to_sym] ||= {}
52
+ end
53
+
54
+ def map_for(record)
55
+ map_for_class(record.class)
56
+ end
57
+
58
+ # TODO fix
59
+ def underscore(camel_cased_word)
60
+ demod_word = camel_cased_word.to_s.split('::').last
61
+ demod_word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
62
+ demod_word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
63
+ demod_word.tr!('-', '_')
64
+ demod_word.downcase!
65
+ demod_word
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,39 @@
1
+ module LondonBikeHireCli
2
+ module Repository
3
+ # Generic Repository delegating to adapter
4
+ #
5
+ module Repo
6
+ class << self
7
+ attr_reader :adapter
8
+
9
+ def register(adapter)
10
+ @adapter = adapter
11
+ end
12
+
13
+ def find(klass, id)
14
+ adapter.find klass, id
15
+ end
16
+
17
+ def all(klass)
18
+ adapter.all klass
19
+ end
20
+
21
+ def create(model)
22
+ adapter.create(model)
23
+ end
24
+
25
+ def update(model)
26
+ adapter.update(model)
27
+ end
28
+
29
+ def delete(model)
30
+ adapter.delete model
31
+ end
32
+
33
+ def query(klass, selector)
34
+ adapter.query(klass, selector)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ require "kdtree"
2
+
3
+ module LondonBikeHireCli
4
+ module Repository
5
+ class SpatialSearchAdapter
6
+ def initialize(stations = [])
7
+ init_spatial_store(stations)
8
+ end
9
+
10
+ # Public: Return the IDs of the nearest n stations
11
+ # lat, long - latitude, longitude of point to search
12
+ # limit - The maximum number of results
13
+ #
14
+ def nearest(lat, long, limit)
15
+ spatial_store.nearestk(lat, long, limit)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :spatial_store
21
+
22
+ def init_spatial_store(stations)
23
+ stations_triples = stations.map { |station| [station.lat, station.long, station.id] }
24
+ @spatial_store = Kdtree.new(stations_triples)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ module LondonBikeHireCli
2
+ module Repository
3
+ # Specialisation for Bike Stations; delegates all to Repository
4
+ #
5
+ class StationRepo
6
+ def save(record)
7
+ Repo.save(record)
8
+ end
9
+
10
+ def all
11
+ Repo.all object_class
12
+ end
13
+
14
+ def find(id)
15
+ Repo.find object_class, id
16
+ end
17
+
18
+ def delete(record)
19
+ Repo.delete record
20
+ end
21
+
22
+ def query(selector)
23
+ Repo.query object_class, selector
24
+ end
25
+
26
+ private
27
+
28
+ def object_class
29
+ # TODO fix reflection
30
+ # @object_class ||= self.to_s.match(/^(.+)Repo/)[1].constantize
31
+ Station
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ module LondonBikeHireCli
2
+ module Repository
3
+ # Specialisation for Bike Stations; implements specific queries
4
+ #
5
+ class StationStore < InMemoryStoreAdapter
6
+ def query_stations_by_name(klass, query)
7
+ all(klass).select { |station| station.name.downcase.include?(query.normalized_query) }
8
+ end
9
+
10
+ def query_stations_near(klass, query)
11
+ matched_ids = spatial_search_adapter(klass).nearest(query.lat, query.long, query.limit)
12
+ find_by_ids(klass, *matched_ids)
13
+ end
14
+
15
+ private
16
+
17
+ def spatial_search_adapter(klass)
18
+ @spatial_search_adapter ||= SpatialSearchAdapter.new all(klass)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -12,5 +12,9 @@ module LondonBikeHireCli
12
12
  long: long
13
13
  }
14
14
  end
15
+
16
+ def display_updated_at
17
+ updated_at.strftime('%Y-%m-%d %H:%M:%S')
18
+ end
15
19
  end
16
20
  end
@@ -0,0 +1,3 @@
1
+ module LondonBikeHireCli
2
+ class StationNotFoundError < StandardError; end
3
+ end
@@ -1,3 +1,3 @@
1
1
  module LondonBikeHireCli
2
- VERSION = '1.3.0'
2
+ VERSION = '1.3.1'
3
3
  end
@@ -0,0 +1,5 @@
1
+ <%= colorize('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', :yellow) %>
2
+ Ooops, something went wrong with the query.
3
+ The query <%= colorize(context[:query].inspect, :red) %>
4
+ resulted in error: <%= colorize(context[:error], :red) %>
5
+ <% colorize('Try again?', :cyan) %>
@@ -0,0 +1,11 @@
1
+ <%= colorize('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', :yellow) %>
2
+ <% context.each do |station| %>
3
+ ----- <%= colorize('Bike station', :green) %>
4
+ <% station.each_pair.each do |attr_name, attr_value| %>
5
+ <% next if attr_name == :updated_at %>
6
+ <%= attr_name.capitalize %>: <%= colorize(attr_value, :cyan) %>
7
+ <% end %>
8
+ Link to map: <%= colorize(station.map_link, :pink) %>
9
+ Updated at: <%= colorize(station.display_updated_at, :red) %>
10
+ <% end %>
11
+ <%= colorize('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', :yellow) %>