mormon 1.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -13,8 +13,50 @@ Usage
13
13
  - Notes:
14
14
  - trasnports: must be one in [:cycle, :car, :train, :foot, :horse]
15
15
  - node_start and node_end must be node ids
16
-
16
+
17
+ Caching
18
+ =======
19
+
20
+ You probably wants to cache the parsed osm file:
21
+
22
+ osm_loader = Mormon::OSM::Loader.new "path/to/filename.osm", :cache => true
23
+
24
+ The previous code generate a filename.pstore file and it's stored in Dir.tmpdir, "mormon", "cache" depending of your so, if you need to change the cache dir try ie:
25
+
26
+ cache_dir = File.join File.dirname(__FILE__), "cache"
27
+ Mormon::OSM::Loader.cache_dir = cache_dir
28
+ osm_loader = Mormon::OSM::Loader.new "path/to/file.osm", :cache => true
29
+
30
+
31
+ Routing algorithm
32
+ =======
33
+
34
+ The default algorithm is A* with weights, but a Random algorithm is available, it traces a random route from start to end:
35
+
36
+ osm_loader = Mormon::OSM::Loader.new "path/to/file.osm"
37
+ osm_router = Mormon::OSM::Router.new osm_loader, :algorithm => :random
38
+ osm_router.find_route node_start, node_end, transport
39
+
40
+ Breadth in Ramdom algorithm
41
+ -----
42
+
43
+ The programming technique to find a random route is Backtracking, so in order to don't loop forever we need to narrow the search in neighbors, for that reason i use a breadth value combined with distance between start and end nodes:
44
+
45
+ max_amplitude = @breadth * distance(start, end)
46
+
47
+ The default breadth value is 2 but you could change it doing one of:
48
+
49
+ osm_router = Mormon::OSM::Router.new osm_loader, :algorithm => :random, :breadth => 1.5
50
+ or
51
+ osm_router.algorithm.breath = 2.5
52
+
17
53
  License
18
54
  =======
19
55
 
20
- - WTFYW License
56
+ Copyright (c) 2012 Hugo Gerónimo Díaz
57
+
58
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
59
+
60
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
61
+
62
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/lib/mormon.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "mormon/string_ex"
1
2
  require "mormon/version"
2
3
  require "mormon/weight"
3
4
  require "mormon/tile_name"
@@ -240,52 +240,6 @@ module Mormon
240
240
  }[tag.to_sym] || tag
241
241
  end
242
242
 
243
- # def find_node(lat, lon, route_type)
244
- # # find the nearest node that can be the start of a route
245
- # load_area(lat, lon)
246
-
247
- # max_dist = 1E+20
248
- # node_found = nil
249
- # pos_found = nil
250
-
251
- # rnodes.values.each do |node_id, pos|
252
- # dy = pos[0] - lat
253
- # dx = pos[1] - lon
254
- # dist = dx * dx + dy * dy
255
-
256
- # if dist < maxDist
257
- # max_dist = dist
258
- # node_found = node_id
259
- # pos_found = pos
260
- # end
261
-
262
- # node_found
263
- # end
264
- # end
265
-
266
- # @unused: load the specific area instead an osm file
267
- # def load_area(lat, lon)
268
- # if options[:file]
269
- # puts "The %s file was already loaded" % options[:file]
270
- # return
271
- # end
272
-
273
- # # Download data in the vicinity of a lat/long
274
- # z = Mormon::Tile::Data.download_level
275
- # (x,y) = @tilename.xy(lat, lon, z)
276
-
277
- # tile_id = '%d,%d' % [x, y]
278
-
279
- # return if @tiles[tile_id]
280
-
281
- # @tiles[tile_id] = true
282
-
283
- # filename = @tiledata.get_osm(z, x, y)
284
- # # print "Loading %d,%d at z%d from %s" % (x,y,z,filename)
285
-
286
- # parse filename
287
- # end
288
-
289
243
  end
290
244
  end
291
245
  end
@@ -1,51 +1,47 @@
1
1
  module Mormon
2
2
  module OSM
3
- class Router
4
- # attr_reader :data
3
+
4
+ module Algorithm
5
+ class Base
6
+ def initialize(router, options = {})
7
+ @router = router
8
+ @queue = []
9
+ end
5
10
 
6
- def initialize(loader)
7
- @loader = loader
8
- end
11
+ def route(node_start, node_end, transport)
12
+ raise "subclass responsability"
13
+ end
9
14
 
10
- # Calculate distance between two nodes via pitagoras c**2 = a**2 + b**2
11
- def distance(n1, n2)
12
- node1, node2 = @loader.nodes[n1.to_s], @loader.nodes[n2.to_s]
15
+ def enqueue(*args)
16
+ raise "subclass responsability"
17
+ end
13
18
 
14
- lat1, lon1 = node1[:lat], node1[:lon]
15
- lat2, lon2 = node2[:lat], node2[:lon]
16
-
17
- # TODO: projection issues
18
- dlat = lat2 - lat1
19
- dlon = lon2 - lon1
19
+ private
20
20
 
21
- Math.sqrt dlat**2 + dlon**2
22
- end
21
+ # Calculate distance between two nodes via pitagoras c**2 = a**2 + b**2
22
+ def distance(n1, n2)
23
+ node1, node2 = @router.loader.nodes[n1.to_s], @router.loader.nodes[n2.to_s]
23
24
 
24
- def find_route(node_start, node_end, transport)
25
- result, nodes = route(node_start.to_i, node_end.to_i, transport.to_sym)
26
-
27
- return [result,[]] if result != 'success'
28
-
29
- nodes.map! do |node|
30
- data = @loader.nodes[node.to_s]
31
- [data[:lat], data[:lon]]
32
- end
25
+ lat1, lon1 = node1[:lat], node1[:lon]
26
+ lat2, lon2 = node2[:lat], node2[:lon]
27
+
28
+ dlat = lat2 - lat1
29
+ dlon = lon2 - lon1
33
30
 
34
- [result, nodes]
31
+ Math.sqrt dlat**2 + dlon**2
32
+ end
35
33
  end
36
34
 
37
- private
35
+ # A* Algorithm
36
+ class Astar < Base
38
37
 
39
38
  def route(node_start, node_end, transport)
40
- return "no_such_transport" unless @loader.routing[transport]
41
- return "no_such_node" unless @loader.routing[transport][node_start.to_s]
42
-
43
- @_end = node_end
44
- @queue = []
39
+ return "no_such_transport" unless @router.loader.routing[transport]
40
+ return "no_such_node" unless @router.loader.routing[transport][node_start.to_s]
45
41
 
46
42
  # Start by queueing all outbound links from the start node
47
- @loader.routing[transport][node_start.to_s].each do |neighbor, weight|
48
- add_to_queue(node_start, neighbor, { node_end: nil, distance: 0, nodes: [node_start] }, weight)
43
+ @router.loader.routing[transport][node_start.to_s].each do |neighbor, weight|
44
+ enqueue(node_start, neighbor.to_i, node_end, { node_end: nil, distance: 0, nodes: [node_start] }, weight)
49
45
  end
50
46
 
51
47
  closed = [node_start]
@@ -63,22 +59,19 @@ module Mormon
63
59
 
64
60
  closed << x
65
61
 
66
- @loader.routing[transport][x.to_s].each do |node, weight|
67
- add_to_queue(x, node, next_item, weight) unless closed.include?(node)
68
- end if @loader.routing[transport][x.to_s]
62
+ @router.loader.routing[transport][x.to_s].each do |node, weight|
63
+ enqueue(x, node.to_i, node_end, next_item, weight) unless closed.include?(node.to_i)
64
+ end if @router.loader.routing[transport][x.to_s]
69
65
  end
70
66
 
71
67
  'gave_up'
72
68
  end
73
69
 
74
- def add_to_queue(node_start, node_end, current_queue, weight = 1)
70
+ def enqueue(node_start, node_end, node_finish, current_queue, weight = 1)
75
71
  # Add another potential route to the queue
76
72
 
77
- node_start = node_start.to_i
78
- node_end = node_end.to_i
79
-
80
73
  # if already in queue
81
- @queue.each { |other| return if other[:node_end] == node_end }
74
+ return if @queue.any? { |other| other[:node_end] == node_end }
82
75
 
83
76
  distance = distance(node_start, node_end)
84
77
 
@@ -92,15 +85,87 @@ module Mormon
92
85
 
93
86
  queue_item = {
94
87
  distance: current_distance + distance,
95
- max_distance: current_distance + distance(node_end, @_end),
88
+ max_distance: current_distance + distance(node_end, node_finish),
96
89
  nodes: nodes,
97
90
  node_end: node_end
98
91
  }
99
92
 
100
93
  # Try to insert, keeping the queue ordered by decreasing worst-case distance
101
- found = @queue.find { |other| other[:max_distance] > queue_item[:max_distance] }
102
- found ? @queue.insert(@queue.index(found), queue_item) : @queue << queue_item
94
+ ix = @queue.find_index { |other| other[:max_distance] > queue_item[:max_distance] } || -1
95
+ @queue.insert(ix, queue_item)
103
96
  end
97
+ end
98
+
99
+ class Random < Base
100
+
101
+ attr_accessor :breadth
102
+
103
+ def initialize(router, options = {})
104
+ super
105
+ @breadth = options[:breadth] || 2
106
+ end
107
+
108
+ def route(node_start, node_end, transport)
109
+ max_amplitude = @breadth * distance(node_start, node_end)
110
+ enqueue node_start, node_end, transport, [node_start], [], max_amplitude
111
+ @queue.any? ? ["success", @queue[rand(@queue.size-1)]] : ["no_route", []]
112
+ end
113
+
114
+ def enqueue(node_start, node_end, transport, current_route, visited, max_amplitude)
115
+ current_route ||= []
116
+ visited ||= []
117
+
118
+ if node_start == node_end
119
+ @queue << current_route.dup
120
+ else
121
+ visited << node_start
122
+ neighbors = @router.loader.routing[transport][node_start.to_s]
123
+
124
+ if neighbors
125
+ neighbors = neighbors.keys.map(&:to_i)
126
+ not_visited = neighbors - (neighbors & visited)
127
+
128
+ # random sort in order to not take the same order for neighbors every time.
129
+ not_visited.sort_by { rand }.each do |neighbor|
130
+ # limit the width of the route go further more than max_distance the distance between start and end
131
+ next if distance(neighbor, node_end) > max_amplitude
132
+ current_route << neighbor
133
+ enqueue neighbor, node_end, transport, current_route, visited, max_amplitude
134
+ current_route.delete neighbor
135
+ end
136
+ end
137
+
138
+ visited.delete node_start
139
+ end
140
+ end
141
+
142
+ end
143
+ end
144
+
145
+
146
+ class Router
147
+ attr_reader :loader, :queue, :algorithm
148
+
149
+ def initialize(loader, options = {})
150
+ algorithm = options.delete(:algorithm) || :astar
151
+ algorithm_class = "Mormon::OSM::Algorithm::#{algorithm.to_s.capitalize}".constantize
152
+
153
+ @loader = loader
154
+ @algorithm = algorithm_class.new self, options
155
+ end
156
+
157
+ def find_route(node_start, node_end, transport)
158
+ result, nodes = @algorithm.route(node_start.to_i, node_end.to_i, transport.to_sym)
159
+
160
+ return [result,[]] if result != 'success'
161
+
162
+ nodes.map! do |node|
163
+ data = @loader.nodes[node.to_s]
164
+ [data[:lat], data[:lon]]
165
+ end
166
+
167
+ [result, nodes]
168
+ end
104
169
 
105
170
  end
106
171
  end
@@ -0,0 +1,12 @@
1
+ class String
2
+ def constantize
3
+ names = self.split('::')
4
+ names.shift if names.empty? || names.first.empty?
5
+
6
+ constant = Object
7
+ names.each do |name|
8
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
9
+ end
10
+ constant
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
1
  module Mormon
2
- VERSION = "1.0.2"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ require 'mormon'
3
+
4
+ def spec_osm_file
5
+ File.join File.dirname(__FILE__), "spec.osm"
6
+ end
7
+
8
+ describe Mormon::OSM::Loader do
9
+ def common_specs(loader)
10
+ loader.nodes.keys.size.should eq 534
11
+ loader.ways.keys.size.should eq 135
12
+
13
+ loader.routing[:cycle].keys.size.should eq 240
14
+ loader.routing[:car].keys.size.should eq 240
15
+ loader.routing[:train].keys.size.should eq 0
16
+ loader.routing[:foot].keys.size.should eq 281
17
+ loader.routing[:horse].keys.size.should eq 216
18
+ end
19
+
20
+ describe "whitout cache" do
21
+ before :each do
22
+ @loader = Mormon::OSM::Loader.new spec_osm_file
23
+ end
24
+
25
+ it "should load the correct data" do
26
+ common_specs @loader
27
+ end
28
+
29
+ it "should has the correct nodes" do
30
+ map = { "448193026" => 1, "448193243" => 1, "448193220" => 1, "318099173" => 1 }
31
+ @loader.routing[:foot]["448193024"].should eq(map)
32
+ end
33
+ end
34
+
35
+ describe "with cache" do
36
+ it "should exists the cached version" do
37
+ @loader = Mormon::OSM::Loader.new spec_osm_file, :cache => true
38
+ File.exists?(@loader.cache_filename).should eq true
39
+ File.zero?(@loader.cache_filename).should eq false
40
+ end
41
+
42
+ it "should let change the cache dir" do
43
+ cache_dir = File.join File.dirname(__FILE__), "..", "cache"
44
+ Mormon::OSM::Loader.cache_dir = cache_dir
45
+ @loader = Mormon::OSM::Loader.new spec_osm_file, :cache => true
46
+ cache_filename = File.join Mormon::OSM::Loader.cache_dir, File.basename(spec_osm_file) + ".pstore"
47
+ @loader.cache_filename.should eq cache_filename
48
+ end
49
+
50
+ it "should have stored the same data" do
51
+ @without_cache = Mormon::OSM::Loader.new spec_osm_file
52
+ @with_cache = Mormon::OSM::Loader.new spec_osm_file, :cache => true
53
+
54
+ common_specs @without_cache
55
+ common_specs @with_cache
56
+
57
+ @without_cache.nodes.should eq @with_cache.nodes
58
+ @without_cache.ways.should eq @with_cache.ways
59
+ @without_cache.routing.should eq @with_cache.routing
60
+ @without_cache.routeable_nodes.should eq @with_cache.routeable_nodes
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -1,104 +1,10 @@
1
1
  require 'spec_helper'
2
2
  require 'mormon'
3
3
 
4
- describe Mormon::Weight do
5
- it "get (transport, way type) must to return a value" do
6
- Mormon::Weight.get(:car, :primary).should eq(2)
7
- end
8
- end
9
-
10
- describe Mormon::Tile::Data do
11
- before :each do
12
- @tiledata = Mormon::Tile::Data.new :reset_cache => true
13
- end
14
-
15
- it "download a tile should not work at the moment" do
16
- @tiledata.get_osm(15, 16218, 10741).should match(/Tile not found/)
17
- end
18
- end
19
-
20
- describe Mormon::Tile::Name do
21
- before :each do
22
- @tilename = Mormon::Tile::Name.new
23
- end
24
-
25
- it "should return the correct xy coordinates" do
26
- @tilename.xy(51.50610, -0.119888, 16).should eq([32746, 21792])
27
- end
28
-
29
- it "should return the correct edges" do
30
- x, y = @tilename.xy(51.50610, -0.119888, 16)
31
- @tilename.edges(x, y, 16).should eq([51.505323411493336, -0.120849609375, 51.50874245880333, -0.1153564453125])
32
- end
33
-
34
- it "should return the correct url for the tile" do
35
- @tilename.url(51.50610, -0.119888, 16, :tah).should eq("http://a.tile.openstreetmap.org/16/51/0.png")
36
- end
37
- end
38
-
39
4
  def spec_osm_file
40
5
  File.join File.dirname(__FILE__), "spec.osm"
41
6
  end
42
7
 
43
- describe Mormon::OSM::Loader do
44
- def common_specs(loader)
45
- loader.nodes.keys.size.should eq 534
46
- loader.ways.keys.size.should eq 135
47
-
48
- loader.routing[:cycle].keys.size.should eq 240
49
- loader.routing[:car].keys.size.should eq 240
50
- loader.routing[:train].keys.size.should eq 0
51
- loader.routing[:foot].keys.size.should eq 281
52
- loader.routing[:horse].keys.size.should eq 216
53
- end
54
-
55
- describe "whitout cache" do
56
- before :each do
57
- @loader = Mormon::OSM::Loader.new spec_osm_file
58
- end
59
-
60
- it "should load the correct data" do
61
- common_specs @loader
62
- end
63
-
64
- it "should has the correct nodes" do
65
- map = { "448193026" => 1, "448193243" => 1, "448193220" => 1, "318099173" => 1 }
66
- @loader.routing[:foot]["448193024"].should eq(map)
67
- end
68
- end
69
-
70
- describe "with cache" do
71
- it "should exists the cached version" do
72
- @loader = Mormon::OSM::Loader.new spec_osm_file, :cache => true
73
- File.exists?(@loader.cache_filename).should eq true
74
- File.zero?(@loader.cache_filename).should eq false
75
- end
76
-
77
- it "should let change the cache dir" do
78
- cache_dir = File.join File.dirname(__FILE__), "..", "cache"
79
- Mormon::OSM::Loader.cache_dir = cache_dir
80
- @loader = Mormon::OSM::Loader.new spec_osm_file, :cache => true
81
- cache_filename = File.join Mormon::OSM::Loader.cache_dir, File.basename(spec_osm_file) + ".pstore"
82
- @loader.cache_filename.should eq cache_filename
83
- end
84
-
85
- it "should have stored the same data" do
86
- @without_cache = Mormon::OSM::Loader.new spec_osm_file
87
- @with_cache = Mormon::OSM::Loader.new spec_osm_file, :cache => true
88
-
89
- common_specs @without_cache
90
- common_specs @with_cache
91
-
92
- @without_cache.nodes.should eq @with_cache.nodes
93
- @without_cache.ways.should eq @with_cache.ways
94
- @without_cache.routing.should eq @with_cache.routing
95
- @without_cache.routeable_nodes.should eq @with_cache.routeable_nodes
96
- end
97
-
98
- end
99
-
100
- end
101
-
102
8
  describe Mormon::OSM::Router do
103
9
  it "should find the route if the params are strings" do
104
10
  @loader = Mormon::OSM::Loader.new spec_osm_file
@@ -134,6 +40,32 @@ describe Mormon::OSM::Router do
134
40
  ]
135
41
  end
136
42
 
43
+ it "should support random algorithm" do
44
+ @loader = Mormon::OSM::Loader.new spec_osm_file
45
+ @router = Mormon::OSM::Router.new @loader, :algorithm => :random
46
+
47
+ response, route = @router.find_route 448193311, 448193334, :car
48
+ response.should eq "success"
49
+ route.size.should be > 1
50
+ end
51
+
52
+ it "should support change the breadth of random algorithm" do
53
+ @loader = Mormon::OSM::Loader.new spec_osm_file
54
+ @router = Mormon::OSM::Router.new @loader, :algorithm => :random
55
+
56
+ @router.algorithm.breadth = 1
57
+ response, route = @router.find_route 448193311, 448193334, :car
58
+ response.should eq "success"
59
+ route.size.should be > 1
60
+
61
+ @router.algorithm.breadth = 3
62
+ response1, route1 = @router.find_route 448193311, 448193334, :car
63
+ response1.should eq "success"
64
+ route1.size.should be > 1
65
+
66
+ route.should_not eq route1
67
+ end
68
+
137
69
  describe "with tandil.osm map" do
138
70
 
139
71
  before :each do
data/spec/tile_spec.rb ADDED
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'mormon'
3
+
4
+ describe Mormon::Tile::Data do
5
+ before :each do
6
+ @tiledata = Mormon::Tile::Data.new :reset_cache => true
7
+ end
8
+
9
+ xit "download a tile doesn't work at this moment because there is some wrong with the tiles url" do
10
+ @tiledata.get_osm(15, 16218, 10741).should match(/Tile not found/)
11
+ end
12
+ end
13
+
14
+ describe Mormon::Tile::Name do
15
+ before :each do
16
+ @tilename = Mormon::Tile::Name.new
17
+ end
18
+
19
+ it "should return the correct xy coordinates" do
20
+ @tilename.xy(51.50610, -0.119888, 16).should eq([32746, 21792])
21
+ end
22
+
23
+ it "should return the correct edges" do
24
+ x, y = @tilename.xy(51.50610, -0.119888, 16)
25
+ @tilename.edges(x, y, 16).should eq([51.505323411493336, -0.120849609375, 51.50874245880333, -0.1153564453125])
26
+ end
27
+
28
+ it "should return the correct url for the tile" do
29
+ @tilename.url(51.50610, -0.119888, 16, :tah).should eq("http://a.tile.openstreetmap.org/16/51/0.png")
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'mormon'
3
+
4
+ describe Mormon::Weight do
5
+ it "get (transport, way type) must to return a value" do
6
+ Mormon::Weight.get(:car, :primary).should eq(2)
7
+ end
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mormon
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 2.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-05 00:00:00.000000000 Z
12
+ date: 2012-11-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -75,15 +75,19 @@ files:
75
75
  - lib/mormon.rb
76
76
  - lib/mormon/osm_loader.rb
77
77
  - lib/mormon/osm_router.rb
78
+ - lib/mormon/string_ex.rb
78
79
  - lib/mormon/tile_data.rb
79
80
  - lib/mormon/tile_name.rb
80
81
  - lib/mormon/version.rb
81
82
  - lib/mormon/weight.rb
82
83
  - mormon.gemspec
83
- - spec/mormon_spec.rb
84
+ - spec/loader_spec.rb
85
+ - spec/router_spec.rb
84
86
  - spec/spec.osm
85
87
  - spec/spec_helper.rb
86
88
  - spec/tandil.osm
89
+ - spec/tile_spec.rb
90
+ - spec/weight_spec.rb
87
91
  homepage: https://github.com/geronimod/mormon
88
92
  licenses: []
89
93
  post_install_message:
@@ -110,7 +114,10 @@ specification_version: 3
110
114
  summary: ! 'OSM Routing with some extra features: reset tiles cache and random routes.
111
115
  It''s based on Pyroute library.'
112
116
  test_files:
113
- - spec/mormon_spec.rb
117
+ - spec/loader_spec.rb
118
+ - spec/router_spec.rb
114
119
  - spec/spec.osm
115
120
  - spec/spec_helper.rb
116
121
  - spec/tandil.osm
122
+ - spec/tile_spec.rb
123
+ - spec/weight_spec.rb