rp_clustering-rgeo-activerecord 0.0.2 → 0.0.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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MmJmOWM2NjZhMmMzODM1M2EyZDhkNjUyMzJjOGU1M2NlZTQ5N2IzOQ==
4
+ MzliYTdiMDQyNjMxZmQ3NGM4NGQyNTZmMjgwYmY4NDUyMTk0NGFiYQ==
5
5
  data.tar.gz: !binary |-
6
- NjZlZjdkMWNhNGYwOTdiMDU4YTdlNTIzODA2OGFmMDNhYjUyOTdkYg==
6
+ YTRmZWE4M2Q5NDhkZDE0NWYwOTEyYzRkYzk5MDU3ZmVmZDVlMDk2Mg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- Y2I1NTBjYzEyMTZmN2FjYTlmMDhjZDFlNGMxYjM0NWQxOTQ0ODUxMTYxMjBl
10
- YmI4MTgyNzAzYzhiMTYzZDFlYzAwZTgxNWQ2ZTJkN2RkNjg2NmYzN2M2ZWJh
11
- ODIyYTE0OTM0NzFlMzJkNTZhM2MxODc0ODZiOTNkNWFlYTNiYWU=
9
+ ODEwOGZjNWVmZDg3ODFkNTU5YjZlODQ0OGM5NjlkZTU2NTNkZWU5Mjg3NGIy
10
+ YzcxOWY5OGJjMzg4ZjJmODhhZWNkNDM2MjIzMGU0NTk4ZmM1NDE0MDdjNWYz
11
+ NTAwMjllZTRjMTY1MzRjNjI3NWUyZDQ3ODUxNjFiMGU5MjBhYTk=
12
12
  data.tar.gz: !binary |-
13
- NWFlODJlYWQ1Mzg2MjRmNTVlYzM0NTk0YmI3ZTQwMmY3MTlhNjE4NGVlNzQx
14
- YTZmZGJkMWFkOGVkM2Y5M2I4YzVlZDhhNDhiMjdhOGM4ZTEwNDdmNzUzYzEx
15
- ZDI2NDgyNTFjZmNjZTc5MjMyNDFlNTI2NjIxZjAxZDBjOWY4YzE=
13
+ NzQ1OTU4MWE4MDM3OWJkNTJkYWI0ZWQ2ZTkxN2Q1NTBhNjU1NWJmYTFiNWRm
14
+ NWRlMjUyN2I1NjExZjJiOWVhZTY1MjllZmQ0ZmViN2E4MmZhMjViOWQzMzFh
15
+ ODAzMzZlNjA3OGQ0ZWQ1YzczOTg1OTMwZjFkZjU2ZmM3MTNhYzM=
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # RPClustering::RGeo::ActiveRecord
2
2
 
3
+ [![Code Climate](https://codeclimate.com/github/robertpyke/rp_clustering-rgeo-activerecord.png)](https://codeclimate.com/github/robertpyke/rp_clustering-rgeo-activerecord)
4
+
3
5
  A RGeo PostGIS extension to provide Active Record (Model) clustering functionality.
4
6
 
5
7
  The intention is that this Gem will eventually provide abstracted methods for
@@ -8,7 +10,7 @@ both "on the fly" clustering, as well as cached clustering (including associated
8
10
  This Gem is currently in early development, so expect changes. On this note, if you'd like a specific clustering
9
11
  algorithm or feature added, please ask.
10
12
 
11
- If you find a problem with this Gem, please don't hesitate to raise an [issue](https://github.com/robertpyke/rp_clustering-rgeo-activerecord/issues).
13
+ If you find a problem with this Gem, please don't hesitate to [raise an issue](https://github.com/robertpyke/rp_clustering-rgeo-activerecord/issues).
12
14
 
13
15
  ## Installation
14
16
 
@@ -32,6 +34,98 @@ Or install it yourself as:
32
34
 
33
35
  ## Usage
34
36
 
37
+ ### Added in Version 0.0.3
38
+
39
+ This version allows for the "on the fly" use of a ST_SnapToGrid clustering function.
40
+ The function is added to ActiveRecord::Base (Models). The function is:
41
+
42
+ ```ruby
43
+
44
+ # Cluster using the PostGIS function ST_SnapToGrid
45
+ # -------------------------------------------------
46
+ #
47
+ # attr_to_cluster is the name of attribute to be clustered (a symbol).
48
+ # The attribute should be geometry attribute.
49
+ #
50
+ # Use the options Hash to define what cluster properties you would
51
+ # like returned.
52
+ #
53
+ # Options:
54
+ #
55
+ # [:grid_size] if set, will be used to create the cluster. The clustering
56
+ # works rougly like this; all geometries within 'grid_size'
57
+ # will be pulled together to form a single cluster. For a detailed
58
+ # explanation, please see the PostGIS docs for ST_SnapToGrid.
59
+ #
60
+ # If no +:grid_size+ is given, clusters will consist of all 'equal'
61
+ # geometries. E.g. all points at the same
62
+ # position (x,y) will be pulled together to form a single cluster.
63
+ # This is actually just a Group By of your +attr_to_cluster+.
64
+ #
65
+ # [:cluster_geometry_count] if set to true, the query will select, for
66
+ # each cluster, the number of geometries in the cluster.
67
+ #
68
+ # [:cluster_geometry_count_as] the name to select the
69
+ # cluster_geometry_count as, defaults to "cluster_geometry_count".
70
+ #
71
+ # [:cluster_centroid] if set to true, the query will select, for
72
+ # each cluster, the cluster centroid. The cluster_centroid returned
73
+ # will be a WKT string.
74
+ #
75
+ # [:cluster_centroid_as] the name to select the
76
+ # cluster_centroid as, defaults to "cluster_centroid".
77
+ #
78
+ # [:cluster_minimum_bounding_circle] if set to true, the query will select,
79
+ # for each cluster, the minimum bouding circle. The cluster_minimum_bounding_circle
80
+ # will be a WKT string.
81
+ #
82
+ # [:cluster_minimum_bounding_circle_as] the name to select the
83
+ # cluster_minimum_bounding_circle as, defaults to "cluster_minimum_bounding_circle"
84
+ #
85
+ # Note: Using the options hash, you must 'select' at least one attribute,
86
+ # else this method will rase an ArgumentError.
87
+
88
+ cluster_by_st_snap_to_grid(attr_to_cluster, options={})
89
+
90
+ ```
91
+
92
+ e.g.
93
+
94
+ ```ruby
95
+
96
+
97
+ @layer = Layer.find(params[:id])
98
+
99
+ cluster_result = @layer.cluster_by_st_snap_to_grid(
100
+ :geometry, # the column to cluster
101
+ grid_size: 0.01,
102
+ cluster_geometry_count: true,
103
+ cluster_centroid: true
104
+ )
105
+
106
+ features = []
107
+ cluster_result.each do |cluster|
108
+ geom_feature = Layer.rgeo_factory_for_column(:geometry).parse_wkt(cluster.cluster_centroid)
109
+ feature = RGeo::GeoJSON::Feature.new(geom_feature, nil, { cluster_size: cluster.cluster_geometry_count.to_i })
110
+
111
+ features << feature
112
+ end
113
+
114
+ feature_collection = RGeo::GeoJSON::FeatureCollection.new(features)
115
+ RGeo::GeoJSON.encode(feature_collection)
116
+
117
+ # BOOM! You just made some GeoJSON which is ready to be displayed on a map.
118
+ # You've also embedded the cluster_size in the GeoJSON, so you can do some
119
+ # fancy client side interaction based on cluster size. For example, you could
120
+ # make outliers (small clusters) bright red, or you could vary the size of the
121
+ # cluster centroid based on the size of cluster.
122
+ #
123
+ # Ideally, you could vary your +grid_size+ based on the user's view port.
124
+ # For example, you could set it to fixed values based on the user's zoom level.
125
+ # You could dynamically generate it based on some fraction of the user's view port bbox.
126
+
127
+ ```
128
+
35
129
  ### Added in Version 0.0.1
36
130
 
37
131
  This version allows for hand-coded low-level clustering via the Arel interface.
@@ -40,37 +134,37 @@ e.g.
40
134
 
41
135
  ```ruby
42
136
 
43
- # Get the Arel handle for the model
137
+ # Get the Arel handle for the model
44
138
 
45
- arel_table = MyModel.arel_table
139
+ arel_table = MyModel.arel_table
46
140
 
47
- # Our cluster grid size.
48
- # Smaller grid_size means more clusters.
49
- # Larger grid_size means less clusters (cluster covers a larger area).
50
- # See http://www.postgis.org/docs/ST_SnapToGrid.html for more info.
141
+ # Our cluster grid size.
142
+ # Smaller grid_size means more clusters.
143
+ # Larger grid_size means less clusters (cluster covers a larger area).
144
+ # See http://www.postgis.org/docs/ST_SnapToGrid.html for more info.
51
145
 
52
- grid_size = 0.1
146
+ grid_size = 0.1
53
147
 
54
- # Cluster against our model's :latlon attribute with a grid size of '0.1'.
55
- # Return the centroid of each cluster as "cluster_centroid".
148
+ # Cluster against our model's :latlon attribute with a grid size of '0.1'.
149
+ # Return the centroid of each cluster as "cluster_centroid".
56
150
 
57
- query = MyModel.select(
58
- arel_table.st_astext(
59
- arel_table.st_centroid(arel_table.st_collect(arel_table[:latlon]))
60
- ).as("cluster_centroid")
61
- ).group(arel_table[:latlon].st_snaptogrid(grid_size))
151
+ query = MyModel.select(
152
+ arel_table.st_astext(
153
+ arel_table.st_centroid(arel_table.st_collect(arel_table[:latlon]))
154
+ ).as("cluster_centroid")
155
+ ).group(arel_table[:latlon].st_snaptogrid(grid_size))
62
156
 
63
- # Iterate over our clusters
64
- query.all.each do |cluster|
157
+ # Iterate over our clusters
158
+ query.all.each do |cluster|
65
159
 
66
- # print the cluster_centroid (a point) as WKT
67
- puts cluster["cluster_centroid"]
160
+ # print the cluster_centroid (a point) as WKT
161
+ puts cluster["cluster_centroid"]
68
162
 
69
- # convert the WKT into a RGeo Geometry (a point)
70
- geographic_factory.parse_wkt(cluster["cluster_centroid")
163
+ # convert the WKT into a RGeo Geometry (a point)
164
+ geographic_factory.parse_wkt(cluster["cluster_centroid")
71
165
 
72
- # ...
73
- end
166
+ # ...
167
+ end
74
168
 
75
169
  ```
76
170
 
@@ -1,4 +1,5 @@
1
1
  require "rp_clustering-rgeo-activerecord/version"
2
+ require "rp_clustering-rgeo-activerecord/active_record_base_spatial_expressions"
2
3
  require "rp_clustering-rgeo-activerecord/arel_attribute_spatial_expressions"
3
4
  require "rp_clustering-rgeo-activerecord/arel_table_spatial_expressions"
4
5
 
@@ -8,12 +9,22 @@ module RPClustering
8
9
 
9
10
  module ActiveRecord
10
11
 
12
+ # Spatial Expressions to be attached directly to ActiveRecord::Base
13
+
14
+ module BaseSpatialExpressions
15
+ end
16
+
17
+ # Attach our Spatial Expression methods onto the ActiveRecord::Base class (as class methods).
18
+ class ::ActiveRecord::Base
19
+ include ::RPClustering::RGeo::ActiveRecord::BaseSpatialExpressions
20
+ end
21
+
11
22
  # Spatial Expressions to be attached directly to Arel Attributes (DB columns)
12
23
 
13
24
  module ArelAttributeSpatialExpressions
14
25
  end
15
26
 
16
- # Attach our Spatial Expression methods onto the Arel::Attribute class.
27
+ # Attach our Spatial Expression methods onto the Arel::Attribute class (as instance methods).
17
28
  #
18
29
  # i.e. As stated in the RGeo::ActiveRecord docs.. Allow chaining of spatial expressions from attributes
19
30
 
@@ -26,7 +37,7 @@ module RPClustering
26
37
  module ArelTableSpatialExpressions
27
38
  end
28
39
 
29
- # Attach our Spatial Expression methods onto the Arel::Table class.
40
+ # Attach our Spatial Expression methods onto the Arel::Table class (as instance methods).
30
41
 
31
42
  ::Arel::Table.class_eval do
32
43
  include ::RPClustering::RGeo::ActiveRecord::ArelTableSpatialExpressions
@@ -0,0 +1,154 @@
1
+ # Author: Robert Pyke
2
+
3
+ module RPClustering
4
+
5
+ module RGeo
6
+
7
+ module ActiveRecord
8
+
9
+ module BaseSpatialExpressions
10
+
11
+ # Use ActiveSupport::Concern to seperate our
12
+ # class and instance methods for inclusion into ActiveRecord::Base
13
+ extend ActiveSupport::Concern
14
+
15
+ module ClassMethods
16
+
17
+ # Cluster using the PostGIS function ST_SnapToGrid
18
+ # -------------------------------------------------
19
+ #
20
+ # attr_to_cluster is the name of attribute to be clustered (a symbol).
21
+ # The attribute should be geometry attribute.
22
+ #
23
+ # Use the options Hash to define what cluster properties you would
24
+ # like returned.
25
+ #
26
+ # Options:
27
+ #
28
+ # [:grid_size] if set, will be used to create the cluster. The clustering
29
+ # works rougly like this; all geometries within 'grid_size'
30
+ # will be pulled together to form a single cluster. For a detailed
31
+ # explanation, please see the PostGIS docs for ST_SnapToGrid.
32
+ #
33
+ # If no +:grid_size+ is given, clusters will consist of all 'equal'
34
+ # geometries. E.g. all points at the same
35
+ # position (x,y) will be pulled together to form a single cluster.
36
+ # This is actually just a Group By of your +attr_to_cluster+.
37
+ #
38
+ # [:cluster_geometry_count] if set to true, the query will select, for
39
+ # each cluster, the number of geometries in the cluster.
40
+ #
41
+ # [:cluster_geometry_count_as] the name to select the
42
+ # cluster_geometry_count as, defaults to "cluster_geometry_count".
43
+ #
44
+ # [:cluster_centroid] if set to true, the query will select, for
45
+ # each cluster, the cluster centroid. The cluster_centroid returned
46
+ # will be a WKT string.
47
+ #
48
+ # [:cluster_centroid_as] the name to select the
49
+ # cluster_centroid as, defaults to "cluster_centroid".
50
+ #
51
+ # [:cluster_minimum_bounding_circle] if set to true, the query will select,
52
+ # for each cluster, the minimum bouding circle. The cluster_minimum_bounding_circle
53
+ # will be a WKT string.
54
+ #
55
+ # [:cluster_minimum_bounding_circle_as] the name to select the
56
+ # cluster_minimum_bounding_circle as, defaults to "cluster_minimum_bounding_circle"
57
+ #
58
+ # Note: Using the options hash, you must 'select' at least one attribute,
59
+ # else this method will raise an ArgumentError.
60
+ #
61
+
62
+ def cluster_by_st_snap_to_grid(attr_to_cluster, options={})
63
+ raise ArgumentError, "Invalid cluster_by_st_snap_to_grid options provided" unless _are_cluster_options_valid?(options)
64
+
65
+ grid_size = options[:grid_size]
66
+
67
+ arel_table = self.arel_table
68
+ arel_attr = arel_table[attr_to_cluster]
69
+
70
+ q = self
71
+
72
+ # Get the cluster geometry count (if asked to)
73
+ if options[:cluster_geometry_count]
74
+ cluster_geometry_count_as = options[:cluster_geometry_count_as] || "cluster_geometry_count"
75
+ q = q._select_cluster_geometry_count(attr_to_cluster, cluster_geometry_count_as)
76
+ end
77
+
78
+ if options[:cluster_centroid]
79
+ cluster_centroid_as = options[:cluster_centroid_as] || "cluster_centroid"
80
+ q = q._select_cluster_centroid_as_wkt(attr_to_cluster, cluster_centroid_as)
81
+ end
82
+
83
+ if options[:cluster_minimum_bounding_circle]
84
+ cluster_minimum_bounding_circle_as = options[:cluster_minimum_bounding_circle_as] || "cluster_minimum_bounding_circle"
85
+ q = q._select_cluster_minimum_bounding_circle_as_wkt(attr_to_cluster, cluster_minimum_bounding_circle_as)
86
+ end
87
+
88
+ if grid_size
89
+ q = q.group(arel_attr.st_snaptogrid(grid_size))
90
+ else
91
+ q = q.group(arel_attr)
92
+ end
93
+
94
+ q
95
+ end
96
+
97
+ # Ensure the user is selecting something, and that
98
+ # the grid size is either nil, or is a valid integer
99
+
100
+ def _are_cluster_options_valid?(options)
101
+ selecting_something = (
102
+ options[:cluster_geometry_count] or
103
+ options[:cluster_centroid] or
104
+ options[:cluster_minimum_bounding_circle]
105
+ )
106
+
107
+ grid_size_valid = (
108
+ options[:grid_size].nil? or
109
+ ( options[:grid_size].is_a? Numeric and options[:grid_size] >= 0 )
110
+ )
111
+
112
+ valid = selecting_something and grid_size_valid
113
+ end
114
+
115
+ # Select the cluster geometry count
116
+
117
+ def _select_cluster_geometry_count(attr_to_cluster, as)
118
+ arel_table = self.arel_table
119
+ arel_attr = arel_table[attr_to_cluster]
120
+
121
+ select(arel_attr.count().as(as))
122
+ end
123
+
124
+ # Select the cluster centroid as WKT.
125
+
126
+ def _select_cluster_centroid_as_wkt(attr_to_cluster, as)
127
+ arel_table = self.arel_table
128
+ arel_attr = arel_table[attr_to_cluster]
129
+
130
+ select(
131
+ arel_table.st_astext(
132
+ arel_attr.st_collect
133
+ ).as(as)
134
+ )
135
+ end
136
+
137
+ # Select the cluster minimum bounding circle as WKT.
138
+
139
+ def _select_cluster_minimum_bounding_circle_as_wkt(attr_to_cluster, as)
140
+ arel_table = self.arel_table
141
+ arel_attr = arel_table[attr_to_cluster]
142
+
143
+ select(
144
+ arel_table.st_astext(
145
+ arel_table.st_minimumboundingcircle(arel_attr.st_collect)
146
+ ).as(as)
147
+ )
148
+ end
149
+
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -67,17 +67,16 @@ module RPClustering
67
67
 
68
68
  def st_minimumboundingcircle(num_segs=nil)
69
69
  args = [self]
70
+ spatial_flags = [true, true]
71
+
70
72
  if num_segs
71
73
  args << num_segs.to_s
72
-
73
- ::RGeo::ActiveRecord::SpatialNamedFunction.new(
74
- 'ST_MinimumBoundingCircle', args, [true, true, false]
75
- )
76
- else
77
- ::RGeo::ActiveRecord::SpatialNamedFunction.new(
78
- 'ST_MinimumBoundingCircle', args, [true, true]
79
- )
74
+ spatial_flags << false
80
75
  end
76
+
77
+ ::RGeo::ActiveRecord::SpatialNamedFunction.new(
78
+ 'ST_MinimumBoundingCircle', args, spatial_flags
79
+ )
81
80
  end
82
81
 
83
82
  end
@@ -83,17 +83,16 @@ module RPClustering
83
83
 
84
84
  def st_minimumboundingcircle(g, num_segs=nil)
85
85
  args = [g]
86
+ spatial_flags = [true, true]
87
+
86
88
  if num_segs
87
89
  args << num_segs.to_s
88
-
89
- ::RGeo::ActiveRecord::SpatialNamedFunction.new(
90
- 'ST_MinimumBoundingCircle', args, [true, true, false]
91
- )
92
- else
93
- ::RGeo::ActiveRecord::SpatialNamedFunction.new(
94
- 'ST_MinimumBoundingCircle', args, [true, true]
95
- )
90
+ spatial_flags << false
96
91
  end
92
+
93
+ ::RGeo::ActiveRecord::SpatialNamedFunction.new(
94
+ 'ST_MinimumBoundingCircle', args, spatial_flags
95
+ )
97
96
  end
98
97
 
99
98
  end
@@ -1,7 +1,7 @@
1
1
  module RPClustering
2
2
  module RGeo
3
3
  module ActiveRecord
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,110 @@
1
+ require 'test/unit'
2
+ require 'rgeo/active_record/adapter_test_helper'
3
+ require 'rp_clustering-rgeo-activerecord'
4
+ require 'squeel'
5
+
6
+ module RPClustering
7
+ module RGeo
8
+ module ActiveRecord
9
+ module Tests
10
+ class MyUnitTest < Test::Unit::TestCase # :nodoc:
11
+
12
+ # Use the RGEO active record adapter test helper
13
+
14
+ DATABASE_CONFIG_PATH = ::File.dirname(__FILE__)+'/database.yml'
15
+ OVERRIDE_DATABASE_CONFIG_PATH = ::File.dirname(__FILE__)+'/database_local.yml'
16
+ include ::RGeo::ActiveRecord::AdapterTestHelper
17
+
18
+
19
+ define_test_methods do
20
+
21
+ def populate_ar_class(content_)
22
+ klass_ = create_ar_class
23
+ case content_
24
+ when :latlon_point
25
+ klass_.connection.create_table(:spatial_test) do |t_|
26
+ t_.column 'latlon', :point, :srid => 4326
27
+ end
28
+ end
29
+ klass_
30
+ end
31
+
32
+ def test_cluster_by_st_snap_to_grid_exists
33
+ arel_klass = populate_ar_class(:latlon_point)
34
+ assert(
35
+ arel_klass.methods.include?(:cluster_by_st_snap_to_grid),
36
+ "ActiveRecord::Base should now have a cluster_by_st_snap_to_grid function. " +
37
+ "Found:\n#{arel_klass.methods.sort}"
38
+ )
39
+ end
40
+
41
+ def test_cluster_by_st_snap_to_grid_should_exception_with_invalid_options
42
+ arel_klass = populate_ar_class(:latlon_point)
43
+
44
+ assert_raise(ArgumentError) do
45
+ res = arel_klass.cluster_by_st_snap_to_grid(:latlon, grid_size: 10)
46
+ end
47
+
48
+ assert_raise(ArgumentError) do
49
+ res = arel_klass.cluster_by_st_snap_to_grid(:latlon, grid_size: -12, cluster_geometry_count: true)
50
+ end
51
+
52
+ assert_raise(ArgumentError) do
53
+ res = arel_klass.cluster_by_st_snap_to_grid(:latlon, grid_size: "2", cluster_geometry_count: true)
54
+ end
55
+
56
+ assert_nothing_thrown do
57
+ res = arel_klass.cluster_by_st_snap_to_grid(:latlon, grid_size: 2, cluster_geometry_count: true)
58
+ end
59
+
60
+ assert_nothing_thrown do
61
+ res = arel_klass.cluster_by_st_snap_to_grid(:latlon, grid_size: 2, cluster_centroid: true)
62
+ end
63
+
64
+ assert_nothing_thrown do
65
+ res = arel_klass.cluster_by_st_snap_to_grid(:latlon, grid_size: 2, cluster_minimum_bounding_circle: true)
66
+ end
67
+
68
+ end
69
+
70
+ def test_clustering_with_a_sufficiently_large_grid_size_reduces_count
71
+ arel_klass = populate_ar_class(:latlon_point)
72
+
73
+ points_generated = 0
74
+ (-5..5).each do |lng|
75
+ (-5..5).each do |lat|
76
+ obj = arel_klass.new
77
+ obj.latlon = @geographic_factory.point(lng, lat)
78
+ obj.save!
79
+ points_generated+=1
80
+ end
81
+ end
82
+
83
+ res = arel_klass.cluster_by_st_snap_to_grid(:latlon, grid_size: 5, cluster_geometry_count: true)
84
+ clusters = res.all
85
+ total_clusters = clusters.count()
86
+
87
+ points_found_in_clusters = 0
88
+
89
+ res.all.each do |cluster|
90
+ points_found_in_clusters += cluster["cluster_geometry_count"].to_i
91
+ end
92
+
93
+ assert_equal(points_generated, points_found_in_clusters,
94
+ "The sum of the size of our clusters should equal the number of points in the table"
95
+ )
96
+
97
+ # We should have less clusters than we have points
98
+ assert(total_clusters < points_generated, "we should have less clusters than we have points")
99
+
100
+ # We should have more than 1 cluster with this size grid
101
+ assert(total_clusters > 1, "we should have more than 1 cluster with this grid size")
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
data/test/test_unit.rb CHANGED
@@ -141,6 +141,7 @@ module RPClustering
141
141
  end
142
142
 
143
143
  end
144
+
144
145
  end
145
146
  end
146
147
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rp_clustering-rgeo-activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Pyke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-02-28 00:00:00.000000000 Z
11
+ date: 2013-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -178,11 +178,13 @@ files:
178
178
  - README.md
179
179
  - Rakefile
180
180
  - lib/rp_clustering-rgeo-activerecord.rb
181
+ - lib/rp_clustering-rgeo-activerecord/active_record_base_spatial_expressions.rb
181
182
  - lib/rp_clustering-rgeo-activerecord/arel_attribute_spatial_expressions.rb
182
183
  - lib/rp_clustering-rgeo-activerecord/arel_table_spatial_expressions.rb
183
184
  - lib/rp_clustering-rgeo-activerecord/version.rb
184
185
  - rp_clustering-rgeo-activerecord.gemspec
185
186
  - test/database.yml
187
+ - test/test_clustering.rb
186
188
  - test/test_unit.rb
187
189
  homepage: https://github.com/robertpyke/rp_clustering-rgeo-activerecord
188
190
  licenses:
@@ -210,4 +212,6 @@ specification_version: 4
210
212
  summary: RGeo PostGIS extension to provide clustering functionality
211
213
  test_files:
212
214
  - test/database.yml
215
+ - test/test_clustering.rb
213
216
  - test/test_unit.rb
217
+ has_rdoc: