gtfs_stops_clustering 0.1.2 → 0.1.3

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
  SHA256:
3
- metadata.gz: 32c396f8f9377660da84a4b29d78657e23efcfefe01e6d05368894dd1ffbf07d
4
- data.tar.gz: 42f3961fb4a896fb3f25c3f113672a0ac8894d74458270bfce2fef82f5e50e11
3
+ metadata.gz: d10d21f2d65afcf335560f35f8a34e4c8e46b3e6eeb6b7c74d9edf73e3336227
4
+ data.tar.gz: 67f4f260b43a6ac2f8af21b8c1a5471ee241b3c86f6a8532c55e0554268cdaa0
5
5
  SHA512:
6
- metadata.gz: 197ec5fb775f93c61c1207392bb2b0a136c09b61572327d2855b9f0c73bf1dc94f552b6665d842a757c20e06248692001ff013c23407e3bc94ed7a024ca5dbd0
7
- data.tar.gz: 88c0c3d4106abf305d0ac7a4196a6612f40745bf2632ffadab32673d3fb60f04800a2d4de44027fa9fb4a3c8c03db206881dccc91505fb15e48253e56e85952c
6
+ metadata.gz: e5ef45bb1402420422984e19918edfe60c5cc73fac8d503be3f605bd83c4b97460a688e79bba16e901cb42ecf358571cc1380467920e2c9b051be08b0fcff5fb
7
+ data.tar.gz: '0349797d0744abe6432ab20f262ac766118b2a3153b1e5dbb2796d2c3eb359fccc109bdadc17affbe43b9824457701daa5d3a1c434fe43ab40c3c1534dbce382'
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/data_import.rb
2
4
 
3
- require 'csv'
4
- require 'gtfs'
5
+ require "csv"
6
+ require "gtfs"
5
7
 
8
+ # DataImport module
6
9
  module DataImport
7
- VERSION='0.0.1'
8
10
  attr_accessor :data_import
9
11
 
12
+ # DataImport class
10
13
  class DataImport
11
14
  attr_accessor :stops, :stops_config_file, :stops_names, :stops_corner_cases, :stops_data, :stops_redis_geodata
12
15
 
@@ -22,13 +25,13 @@ module DataImport
22
25
  end
23
26
 
24
27
  def import_stops_corner_cases
25
- if File.exist?(@stops_config_file)
26
- CSV.foreach(@stops_config_file, headers: true) do |row|
27
- stop_name = row['stop_name']
28
- cluster_name = row['cluster_name']
28
+ return unless File.exist?(@stops_config_file)
29
+
30
+ CSV.foreach(@stops_config_file, headers: true) do |row|
31
+ stop_name = row["stop_name"]
32
+ cluster_name = row["cluster_name"]
29
33
 
30
- stops_corner_cases << { stop_name: stop_name, cluster_name: cluster_name }
31
- end
34
+ stops_corner_cases << { stop_name: stop_name, cluster_name: cluster_name }
32
35
  end
33
36
  end
34
37
 
@@ -38,13 +41,20 @@ module DataImport
38
41
  longitude = row.lon
39
42
  stop_name = row.name
40
43
 
41
- stop_name = @stops_corner_cases.find { |entry| entry[:stop_name] == stop_name }[:cluster_name] if stops_corner_cases.find { |entry| entry[:stop_name] == stop_name }
44
+ stop_name = stop_name_from_corner_cases(stop_name)
42
45
 
43
46
  @stops_names << stop_name
44
47
  @stops_data << [latitude, longitude]
45
48
  @stops_redis_geodata << [longitude, latitude, "#{longitude},#{latitude}"]
46
49
  end
47
50
  end
51
+
52
+ def stop_name_from_corner_cases(stop_name)
53
+ csv_entry = @stops_corner_cases.find do |entry|
54
+ entry[:stop_name] == stop_name
55
+ end
56
+ csv_entry.nil? ? stop_name : csv_entry[:cluster_name]
57
+ end
48
58
  end
49
59
 
50
60
  def import_stops_data(*args)
@@ -56,5 +66,3 @@ module DataImport
56
66
  }
57
67
  end
58
68
  end
59
-
60
- include DataImport
@@ -1,33 +1,47 @@
1
- ## https://github.com/shiguodong/dbscan (fork)
1
+ # frozen_string_literal: true
2
2
 
3
- require 'distance_measures'
4
- require 'text'
5
- require 'geocoder'
6
- require_relative 'redis_geodata'
3
+ # lib/gtfs_stops_clustering/dbscan.rb
7
4
 
5
+ require "distance_measures"
6
+ require "text"
7
+ require "geocoder"
8
+ require_relative "redis_geodata"
9
+
10
+ # Array class
8
11
  class Array
9
- def haversine_distance2(n)
10
- Geocoder::Calculations.distance_between(self, n)
12
+ def haversine_distance2(other)
13
+ Geocoder::Calculations.distance_between(self, other)
11
14
  end
12
15
  end
13
16
 
17
+ # DBSCAN module
14
18
  module DBSCAN
19
+ # Clusterer class
15
20
  class Clusterer
21
+ include RedisGeodata
16
22
  attr_accessor :points, :options, :clusters
17
23
 
18
24
  def initialize(points, stops_redis_geodata, options = {})
19
25
  options[:distance] = :euclidean_distance unless options[:distance]
20
26
  options[:labels] = [] unless options[:labels]
21
27
 
22
- c = 0
23
28
  redis_geodata_import(stops_redis_geodata, options[:epsilon])
24
- @points = points.map { |e| po = Point.new(e, options[:labels][c]); c +=1; po }
25
29
  @options = options
26
- @clusters = {-1 => []}
30
+ init_points(points)
31
+ @clusters = { -1 => [] }
27
32
 
28
33
  clusterize!
29
34
  end
30
35
 
36
+ def init_points(points)
37
+ c = 0
38
+ @points = points.map do |e|
39
+ po = Point.new(e, @options[:labels][c])
40
+ c += 1
41
+ po
42
+ end
43
+ end
44
+
31
45
  def clusterize!
32
46
  current_cluster = -1
33
47
  @points.each do |point|
@@ -49,10 +63,10 @@ module DBSCAN
49
63
  # Get Cluster Position
50
64
  cluster_pos = find_cluster_position(clusters[current_cluster])
51
65
 
52
- clusters[current_cluster].each { |e|
66
+ clusters[current_cluster].each do |e|
53
67
  e.cluster_name = cluster_name
54
68
  e.cluster_pos = cluster_pos
55
- }
69
+ end
56
70
  else
57
71
  clusters[-1].push(point)
58
72
  end
@@ -91,9 +105,11 @@ module DBSCAN
91
105
  neighbors = []
92
106
  geosearch_results = geosearch(point.items[1], point.items[0])
93
107
  geosearch_results.each do |neighbor_pos|
94
- coordinates = neighbor_pos.split(',')
95
- neighbor = @points.find { |point| point.items[0] == coordinates[1] &&
96
- point.items[1] == coordinates[0] }
108
+ coordinates = neighbor_pos.split(",")
109
+ neighbor = @points.find do |elem|
110
+ elem.items[0] == coordinates[1] &&
111
+ elem.items[1] == coordinates[0]
112
+ end
97
113
  next unless neighbor
98
114
 
99
115
  string_distance = Text::Levenshtein.distance(point.label.downcase, neighbor.label.downcase)
@@ -112,9 +128,7 @@ module DBSCAN
112
128
 
113
129
  if new_points.size >= options[:min_points]
114
130
  new_points.each do |p|
115
- unless neighbors.include?(p)
116
- neighbors.push(p)
117
- end
131
+ neighbors.push(p) unless neighbors.include?(p)
118
132
  end
119
133
  end
120
134
  end
@@ -127,32 +141,31 @@ module DBSCAN
127
141
 
128
142
  cluster_points
129
143
  end
130
- end
131
144
 
132
- def find_cluster_name(labels)
133
- words = labels.map { |label| label.strip.split }
134
- common_title = ''
145
+ def find_cluster_name(labels)
146
+ words = labels.map { |label| label.strip.split }
147
+ common_title = ""
135
148
 
136
- # Loop through each word index starting from the first
137
- (0...words.first.length).each do |i|
138
- words_at_index = words.map { |word_list| word_list[i] }
149
+ # Loop through each word index starting from the first
150
+ (0...words.first.length).each do |i|
151
+ words_at_index = words.map { |word_list| word_list[i] }
139
152
 
140
- break unless words_at_index.uniq.length == 1
153
+ break unless words_at_index.uniq.length == 1
141
154
 
142
- common_title += " #{words_at_index.first.capitalize}"
143
- end
144
-
145
- common_title.strip! ? common_title : labels.first
146
- end
155
+ common_title += " #{words_at_index.first.capitalize}"
156
+ end
147
157
 
148
- def find_cluster_position(cluster)
149
- total_lat = cluster.map { |e| e.items[0].to_f }.sum
150
- total_lon = cluster.map { |e| e.items[1].to_f }.sum
151
- avg_lat = total_lat / cluster.size
152
- avg_lon = total_lon / cluster.size
153
- [avg_lat, avg_lon]
158
+ common_title.strip ? common_title : labels.first
159
+ end
160
+ def find_cluster_position(cluster)
161
+ total_lat = cluster.map { |e| e.items[0].to_f }.sum
162
+ total_lon = cluster.map { |e| e.items[1].to_f }.sum
163
+ avg_lat = total_lat / cluster.size
164
+ avg_lon = total_lon / cluster.size
165
+ [avg_lat, avg_lon]
166
+ end
154
167
  end
155
-
168
+ # Point class
156
169
  class Point
157
170
  attr_accessor :items, :cluster, :visited, :label, :cluster_name, :cluster_pos
158
171
 
@@ -176,5 +189,3 @@ module DBSCAN
176
189
  clusterer.labeled_results
177
190
  end
178
191
  end
179
-
180
- include DBSCAN
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # lib/input_consistency_checks.rb
4
+
5
+ # InputConsistencyChecks module
6
+ module InputConsistencyChecks
7
+ # InputConsistencyChecks class
8
+ class InputConsistencyChecks
9
+ attr_accessor :gtfs_paths, :epsilon, :min_points, :names_similarity, :stops_config_path
10
+
11
+ def initialize(gtfs_paths, epsilon, min_points, names_similarity, stops_config_path)
12
+ @gtfs_paths = gtfs_paths
13
+ @stops_config_path = stops_config_path
14
+ @epsilon = epsilon
15
+ @min_points = min_points
16
+ @names_similarity = names_similarity
17
+ input_consistency_checks
18
+ end
19
+
20
+ def input_consistency_checks
21
+ gtfs_paths_check
22
+ epsilon_check
23
+ min_points_check
24
+ names_similarity_check
25
+ end
26
+
27
+ def gtfs_paths_check
28
+ raise ArgumentError, "gtfs_paths cannot be nil" if @gtfs_paths.nil?
29
+ raise ArgumentError, "gtfs_paths must be an Array" unless @gtfs_paths.is_a?(Array)
30
+ raise ArgumentError, "gtfs_paths must not be empty" if @gtfs_paths.empty?
31
+ end
32
+
33
+ def epsilon_check
34
+ raise ArgumentError, "epsilon must be a Float" unless @epsilon.is_a?(Float)
35
+ raise ArgumentError, "epsilon must be greater than 0" if @epsilon.negative?
36
+ end
37
+
38
+ def min_points_check
39
+ raise ArgumentError, "min_points must be an Integer" unless @min_points.is_a?(Integer)
40
+ raise ArgumentError, "min_points must be greater than 0" if @min_points.negative?
41
+ end
42
+
43
+ def names_similarity_check
44
+ raise ArgumentError, "names_similarity must be a Float" unless @names_similarity.is_a?(Float)
45
+ raise ArgumentError, "names_similarity must be between 0 and 1" if @names_similarity.negative? || @names_similarity > 1
46
+ end
47
+ end
48
+
49
+ def input_consistency_checks(gtfs_paths, epsilon, min_points, names_similarity, stop_config_path)
50
+ @input_consistency_checks = InputConsistencyChecks.new(gtfs_paths, epsilon, min_points, names_similarity, stop_config_path)
51
+ end
52
+ end
@@ -1,17 +1,21 @@
1
- # lib/redis_geodata.rb
2
- require 'redis'
1
+ # frozen_string_literal: true
3
2
 
3
+ # lib/gtfs_stops_clustering/redis_geodata.rb
4
+
5
+ require "redis"
6
+
7
+ # RedisGeodata module
4
8
  module RedisGeodata
5
- VERSION='0.0.1'
6
9
  attr_accessor :redis
7
10
 
11
+ # RedisGeodata class
8
12
  class RedisGeodata
9
13
  attr_accessor :stops, :key, :redis, :epsilon
10
14
 
11
15
  def initialize(stops, epsilon)
12
- @redis = Redis.new(url: 'redis://127.0.0.1:6379')
16
+ @redis = Redis.new(url: "redis://127.0.0.1:6379")
13
17
  @stops = stops
14
- @key = 'stops'
18
+ @key = "stops"
15
19
  @epsilon = epsilon
16
20
  geoadd
17
21
  end
@@ -22,8 +26,8 @@ module RedisGeodata
22
26
  end
23
27
 
24
28
  def geosearch(longitude, latitude)
25
- list = @redis.georadius(@key, longitude, latitude, @epsilon, 'km')
26
- list.reject! { |point| point == longitude.to_s + "," + latitude.to_s }
29
+ list = @redis.georadius(@key, longitude, latitude, @epsilon, "km")
30
+ list.reject! { |point| point == "#{longitude},#{latitude}" }
27
31
  list
28
32
  end
29
33
  end
@@ -36,5 +40,3 @@ module RedisGeodata
36
40
  @redis.geosearch(*args)
37
41
  end
38
42
  end
39
-
40
- include RedisGeodata
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GtfsStopsClustering
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
@@ -1,31 +1,37 @@
1
- #!/usr/bin/env ruby
1
+ # frozen_string_literal: true
2
+
2
3
  # lib/gtfs_stops_clustering.rb
3
- require 'rubygems'
4
- require 'bundler/setup'
4
+
5
+ require "rubygems"
6
+ require "bundler/setup"
5
7
  require_relative "gtfs_stops_clustering/version"
6
- require 'gtfs'
7
- require 'csv'
8
- require_relative './gtfs_stops_clustering/data_import'
9
- require_relative './gtfs_stops_clustering/dbscan'
8
+ require "gtfs"
9
+ require "csv"
10
+ require_relative "./gtfs_stops_clustering/data_import"
11
+ require_relative "./gtfs_stops_clustering/dbscan"
12
+ require_relative "./gtfs_stops_clustering/input_consistency_checks"
10
13
 
14
+ # GtfsStopClustering module
11
15
  module GtfsStopsClustering
12
- VERSION = GtfsStopsClustering::VERSION
13
16
  attr_accessor :gtfs_stops_clustering
14
17
 
18
+ # GtfsStopsClustering class
15
19
  class GtfsStopsClustering
16
- attr_accessor :clusters, :gtfs_urls, :gtfs_stops, :stops_config_path, :epsilon, :min_points, :names_similarity
20
+ include InputConsistencyChecks
21
+ include DataImport
22
+ include DBSCAN
23
+ attr_accessor :clusters, :gtfs_paths, :gtfs_stops, :stops_config_path, :epsilon, :min_points, :names_similarity
17
24
 
18
- def initialize(gtfs_urls, epsilon, min_points, names_similarity, stops_config_path)
25
+ def initialize(gtfs_paths, epsilon, min_points, names_similarity, stops_config_path)
26
+ @gtfs_paths = gtfs_paths
27
+ @stops_config_path = stops_config_path
28
+ @epsilon = epsilon
29
+ @min_points = min_points
30
+ @names_similarity = names_similarity
31
+ input_consistency_checks(@gtfs_paths, @epsilon, @min_points, @names_similarity, @stops_config_path)
19
32
  @clusters = []
20
- unless gtfs_urls.empty?
21
- @gtfs_paths = gtfs_urls
22
- @stops_config_path = stops_config_path
23
- @epsilon = epsilon
24
- @min_points = min_points
25
- @names_similarity = names_similarity
26
- @gtfs_stops = create_stops_merged
27
- clusterize_stops_csv(@gtfs_stops)
28
- end
33
+ @gtfs_stops = create_stops_merged
34
+ clusterize_stops
29
35
  end
30
36
 
31
37
  def create_stops_merged
@@ -37,11 +43,20 @@ module GtfsStopsClustering
37
43
  gtfs_stops.flatten
38
44
  end
39
45
 
40
- def clusterize_stops_csv(stops_merged)
41
- data = import_stops_data(stops_merged, @stops_config_path)
42
- @clusters = DBSCAN( data[:stops_data], data[:stops_redis_geodata], :epsilon => @epsilon, :min_points => @min_points, :similarity => @names_similarity, :distance => :haversine_distance2, :labels => data[:stops_names] )
46
+ def clusterize_stops
47
+ data = import_stops_data(@gtfs_stops, @stops_config_path)
48
+ @clusters = DBSCAN(data[:stops_data],
49
+ data[:stops_redis_geodata],
50
+ epsilon: @epsilon,
51
+ min_points: @min_points,
52
+ similarity: @names_similarity,
53
+ distance: :haversine_distance2,
54
+ labels: data[:stops_names])
55
+ map_clustered_stops
56
+ end
43
57
 
44
- @clusters.each do |cluster_id, cluster|
58
+ def map_clustered_stops
59
+ @clusters.each_value do |cluster|
45
60
  cluster.each do |stop|
46
61
  gtfs_stop = @gtfs_stops.find { |e| e.lat == stop[:stop_lat] && e.lon == stop[:stop_lon] }
47
62
  stop[:stop_id] = gtfs_stop.id
@@ -49,24 +64,11 @@ module GtfsStopsClustering
49
64
  stop[:parent_station] = gtfs_stop.parent_station
50
65
  end
51
66
  end
52
-
53
- output_path = 'stop_clusters.txt'
54
- File.open(output_path, 'w') do |file|
55
- @clusters.each do |cluster_id, cluster |
56
- file.puts "Cluster #{cluster_id}"
57
- cluster.each do |point|
58
- file.puts point.inspect
59
- end
60
- file.puts
61
- end
62
- end
63
67
  end
64
68
  end
65
69
 
66
- def build(gtfs_urls, epsilon, min_points, names_similarity = 1, stop_config_path = '')
67
- @gtfs_stops_clustering = GtfsStopsClustering.new(gtfs_urls, epsilon, min_points, names_similarity, stop_config_path)
70
+ def build_clusters(gtfs_paths, epsilon, min_points, names_similarity = 1, stop_config_path = "")
71
+ @gtfs_stops_clustering = GtfsStopsClustering.new(gtfs_paths, epsilon, min_points, names_similarity, stop_config_path)
68
72
  @gtfs_stops_clustering.clusters
69
73
  end
70
74
  end
71
-
72
- include GtfsStopsClustering
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gtfs_stops_clustering
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
- - Visco01
7
+ - Pietro Visconti
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 2023-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: gtfs
14
+ name: csv
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.4.1
19
+ version: '3.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.2.8
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
- version: 0.4.1
29
+ version: '3.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.2.8
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: distance_measures
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,85 +45,107 @@ dependencies:
39
45
  - !ruby/object:Gem::Version
40
46
  version: 0.0.6
41
47
  - !ruby/object:Gem::Dependency
42
- name: text
48
+ name: geocoder
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
51
  - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: '1.3'
53
+ version: '1.8'
48
54
  - - ">="
49
55
  - !ruby/object:Gem::Version
50
- version: 1.3.1
56
+ version: 1.8.2
51
57
  type: :runtime
52
58
  prerelease: false
53
59
  version_requirements: !ruby/object:Gem::Requirement
54
60
  requirements:
55
61
  - - "~>"
56
62
  - !ruby/object:Gem::Version
57
- version: '1.3'
63
+ version: '1.8'
58
64
  - - ">="
59
65
  - !ruby/object:Gem::Version
60
- version: 1.3.1
66
+ version: 1.8.2
61
67
  - !ruby/object:Gem::Dependency
62
- name: geocoder
68
+ name: gtfs
63
69
  requirement: !ruby/object:Gem::Requirement
64
70
  requirements:
65
71
  - - "~>"
66
72
  - !ruby/object:Gem::Version
67
- version: '1.8'
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- version: 1.8.2
73
+ version: 0.4.1
71
74
  type: :runtime
72
75
  prerelease: false
73
76
  version_requirements: !ruby/object:Gem::Requirement
74
77
  requirements:
75
78
  - - "~>"
76
79
  - !ruby/object:Gem::Version
77
- version: '1.8'
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- version: 1.8.2
80
+ version: 0.4.1
81
81
  - !ruby/object:Gem::Dependency
82
- name: csv
82
+ name: redis
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '3.2'
87
+ version: '5.0'
88
88
  - - ">="
89
89
  - !ruby/object:Gem::Version
90
- version: 3.2.8
90
+ version: 5.0.8
91
91
  type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - "~>"
96
96
  - !ruby/object:Gem::Version
97
- version: '3.2'
97
+ version: '5.0'
98
98
  - - ">="
99
99
  - !ruby/object:Gem::Version
100
- version: 3.2.8
100
+ version: 5.0.8
101
101
  - !ruby/object:Gem::Dependency
102
- name: redis
102
+ name: text
103
103
  requirement: !ruby/object:Gem::Requirement
104
104
  requirements:
105
105
  - - "~>"
106
106
  - !ruby/object:Gem::Version
107
- version: '5.0'
107
+ version: '1.3'
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 5.0.8
110
+ version: 1.3.1
111
111
  type: :runtime
112
112
  prerelease: false
113
113
  version_requirements: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '5.0'
117
+ version: '1.3'
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: 5.0.8
120
+ version: 1.3.1
121
+ - !ruby/object:Gem::Dependency
122
+ name: minitest
123
+ requirement: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '5.20'
128
+ type: :development
129
+ prerelease: false
130
+ version_requirements: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '5.20'
135
+ - !ruby/object:Gem::Dependency
136
+ name: pry
137
+ requirement: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - "~>"
140
+ - !ruby/object:Gem::Version
141
+ version: 0.14.2
142
+ type: :development
143
+ prerelease: false
144
+ version_requirements: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - "~>"
147
+ - !ruby/object:Gem::Version
148
+ version: 0.14.2
121
149
  description: A gem to read GTFS stops data and create clusters based on coordinates
122
150
  and stop names' similarities.
123
151
  email:
@@ -129,6 +157,7 @@ files:
129
157
  - lib/gtfs_stops_clustering.rb
130
158
  - lib/gtfs_stops_clustering/data_import.rb
131
159
  - lib/gtfs_stops_clustering/dbscan.rb
160
+ - lib/gtfs_stops_clustering/input_consistency_checks.rb
132
161
  - lib/gtfs_stops_clustering/redis_geodata.rb
133
162
  - lib/gtfs_stops_clustering/version.rb
134
163
  homepage: https://github.com/Visco01/gtfs_stops_clustering