active_map 0.12.2 → 0.13.0

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: d9f43399567d037a7bd1d30e0616d74764a5a8bf94fced533bed02faaf9eff81
4
- data.tar.gz: 448d1f7ae3251522374a7042915c57659ac964d01b842da66c54104cfa3c139e
3
+ metadata.gz: 9de22853c093f901edd0cdce8369b569ef2c84997e846a05fe33b51a4dbed1b3
4
+ data.tar.gz: e1d5d728d054a275a65e195a487fa89b937dbe88d544606884c7db30bfec1076
5
5
  SHA512:
6
- metadata.gz: 05ee1b5ca47f0907faf32031797909dacd2dfc807edabfbf638b76014e11d05e97504bb7105befe5b94c1c928f69a1ddd546d77d9a948ed841fccfc572dd902e
7
- data.tar.gz: 69728ced9ebba43c4fb50533797b2362bf7ecc633292984bc288449dbd9c5ab2595a4311124bf2c6ed45596b00c0ee3ab8f025f8bccb49bed82b2a5cd4ce8d22
6
+ metadata.gz: 58df67bdcf82aa7fef438e3ef10a190b38156ddd664605dbf45eab2cee23cd6f4a5b379242387723431220a1b9320ca1b6cad7740d25220615f4e54083b216fb
7
+ data.tar.gz: 85054688467ed05e7e2a1b4c2a8c4baad09136a37b0b2583edd939ead8583a34148e24d66e93849c41c663c2ef8c3af78ad562b4ea37f945fbd7f408e3ba955f
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # ActiveMap
2
2
 
3
+ [![Gem Version](https://img.shields.io/gem/v/active_map)](https://rubygems.org/gems/active_map)
3
4
  [![CI](https://github.com/itisbryan/active_map/actions/workflows/ci.yml/badge.svg)](https://github.com/itisbryan/active_map/actions/workflows/ci.yml)
4
5
 
5
6
  Declarative maps for Rails + PostgreSQL/PostGIS. A Ruby DSL turns your models
@@ -21,18 +22,23 @@ gem "active_map"
21
22
 
22
23
  ```bash
23
24
  bundle install
24
- bin/rails g active_map:install # mounts the engine at /maps, creates initializer + sample map
25
+ bin/rails g active_map:install # mounts /maps, initializer + sample map, PostGIS migration, Stimulus wiring
26
+ bin/rails db:migrate # enables the postgis extension
25
27
  ```
26
28
 
27
- Enable PostGIS and add geometry columns:
29
+ Make a model mappable — the generator adds the geometry column (with a GiST
30
+ index) and `acts_as_mappable` in one step:
28
31
 
29
- ```ruby
30
- enable_extension "postgis"
31
-
32
- add_column :warehouses, :coordinates, "geometry(Point,4326)"
33
- add_index :warehouses, :coordinates, using: :gist
32
+ ```bash
33
+ bin/rails g active_map:mappable Warehouse coordinates:point
34
+ bin/rails g active_map:mappable DeliveryZone area:polygon
35
+ bin/rails g active_map:mappable Route path:line
36
+ bin/rails db:migrate
34
37
  ```
35
38
 
39
+ Both generators are idempotent — safe to re-run. Prefer to wire it by hand?
40
+ See the Model DSL below.
41
+
36
42
  ## Model DSL
37
43
 
38
44
  ```ruby
@@ -1,3 +1,3 @@
1
1
  module ActiveMap
2
- VERSION = "0.12.2"
2
+ VERSION = "0.13.0"
3
3
  end
@@ -1,7 +1,13 @@
1
+ require "rails/generators"
2
+ require "rails/generators/migration"
3
+ require "rails/generators/active_record"
4
+
1
5
  module ActiveMap
2
6
  module Generators
3
7
  # Idempotent: safe to re-run; every step checks for prior installation.
4
8
  class InstallGenerator < Rails::Generators::Base
9
+ include Rails::Generators::Migration
10
+
5
11
  source_root File.expand_path("templates", __dir__)
6
12
 
7
13
  MOUNT = 'mount ActiveMap::Engine, at: "/maps"'.freeze
@@ -12,12 +18,24 @@ module ActiveMap
12
18
  application.register("active-map", ActiveMapController)
13
19
  JS
14
20
 
21
+ def self.next_migration_number(dir)
22
+ ActiveRecord::Generators::Base.next_migration_number(dir)
23
+ end
24
+
15
25
  def mount_engine
16
26
  return say_status :skip, "route (already mounted)", :yellow if routes_file.include?("ActiveMap::Engine")
17
27
 
18
28
  route MOUNT
19
29
  end
20
30
 
31
+ def create_postgis_migration
32
+ if postgis_migration_exists?
33
+ say_status :skip, "PostGIS migration (already present)", :yellow
34
+ else
35
+ migration_template "enable_postgis.rb.tt", "db/migrate/enable_postgis.rb"
36
+ end
37
+ end
38
+
21
39
  def create_initializer
22
40
  template "initializer.rb", "config/initializers/active_map.rb", skip: true
23
41
  end
@@ -48,17 +66,26 @@ module ActiveMap
48
66
  def next_steps
49
67
  say <<~MSG, :green
50
68
  ActiveMap installed. Next steps:
51
- 1. Enable PostGIS: bin/rails g migration EnablePostgis -> enable_extension "postgis"
52
- 2. Add a geometry column: add_column :things, :coordinates, "geometry(Point,4326)"
53
- and index it: add_index :things, :coordinates, using: :gist
54
- 3. Declare `acts_as_mappable geometry: :coordinates` in the model.
55
- 4. Define layers in app/maps/sample_map.rb, then render with <%= active_map :sample %>.
69
+ 1. Run migrations: bin/rails db:migrate (enables PostGIS)
70
+ 2. Make a model mappable, e.g.:
71
+ bin/rails g active_map:mappable Warehouse coordinates:point
72
+ 3. Define layers in app/maps/sample_map.rb, then render with <%= active_map :sample %>.
56
73
  Docs: README.md and llms.txt in the gem root (`bundle show active_map`).
57
74
  MSG
58
75
  end
59
76
 
60
77
  private
61
78
 
79
+ def migration_version
80
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
81
+ end
82
+
83
+ def postgis_migration_exists?
84
+ Dir.glob(destination.join("db/migrate/*.rb")).any? do |f|
85
+ File.read(f).include?('enable_extension "postgis"')
86
+ end
87
+ end
88
+
62
89
  def destination
63
90
  Pathname(destination_root)
64
91
  end
@@ -0,0 +1,5 @@
1
+ class EnablePostgis < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ enable_extension "postgis" unless extension_enabled?("postgis")
4
+ end
5
+ end
@@ -0,0 +1,90 @@
1
+ require "rails/generators"
2
+ require "rails/generators/migration"
3
+ require "rails/generators/active_record"
4
+
5
+ module ActiveMap
6
+ module Generators
7
+ # Scaffolds a mappable model in one step:
8
+ #
9
+ # rails g active_map:mappable Warehouse coordinates:point
10
+ # rails g active_map:mappable DeliveryZone area:polygon
11
+ #
12
+ # Adds a geometry column migration (with a GiST index) and injects
13
+ # `acts_as_mappable` into the model (creating it if absent). Idempotent.
14
+ class MappableGenerator < Rails::Generators::NamedBase
15
+ include Rails::Generators::Migration
16
+
17
+ source_root File.expand_path("templates", __dir__)
18
+
19
+ GEOMETRY_TYPES = {"point" => "Point", "polygon" => "Polygon", "line" => "LineString"}.freeze
20
+
21
+ argument :geometry, type: :string, default: "coordinates:point",
22
+ banner: "column:point|polygon|line",
23
+ desc: "geometry column and shape, e.g. coordinates:point"
24
+
25
+ def self.next_migration_number(dir)
26
+ ActiveRecord::Generators::Base.next_migration_number(dir)
27
+ end
28
+
29
+ def validate!
30
+ return if GEOMETRY_TYPES.key?(shape)
31
+
32
+ raise Thor::Error, "unknown geometry type #{shape.inspect} (one of: #{GEOMETRY_TYPES.keys.join(", ")})"
33
+ end
34
+
35
+ def create_geometry_migration
36
+ if column_migration_exists?
37
+ say_status :skip, "column migration (already present)", :yellow
38
+ else
39
+ migration_template "add_geometry_column.rb.tt",
40
+ "db/migrate/add_#{column}_to_#{table_name}.rb"
41
+ end
42
+ end
43
+
44
+ def add_acts_as_mappable
45
+ path = File.join(destination_root, "app/models", "#{file_path}.rb")
46
+ declaration = " acts_as_mappable geometry: :#{column}, type: :#{shape}\n"
47
+
48
+ if File.exist?(path)
49
+ if File.read(path).include?("acts_as_mappable")
50
+ say_status :skip, "acts_as_mappable (already declared)", :yellow
51
+ else
52
+ inject_into_class path, class_name, declaration
53
+ end
54
+ else
55
+ template "model.rb.tt", "app/models/#{file_path}.rb"
56
+ end
57
+ end
58
+
59
+ def done
60
+ say_status :info,
61
+ "Run bin/rails db:migrate, then add a layer: " \
62
+ "layer :#{table_name}, #{class_name}.all", :green
63
+ end
64
+
65
+ private
66
+
67
+ def column
68
+ @column ||= geometry.split(":").first
69
+ end
70
+
71
+ def shape
72
+ @shape ||= geometry.split(":")[1] || "point"
73
+ end
74
+
75
+ def geometry_type
76
+ GEOMETRY_TYPES.fetch(shape)
77
+ end
78
+
79
+ def migration_version
80
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
81
+ end
82
+
83
+ def column_migration_exists?
84
+ Dir.glob(File.join(destination_root, "db/migrate/*.rb")).any? do |f|
85
+ File.read(f).match?(/add_column\s+:#{table_name},\s*:#{column}\b/)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,6 @@
1
+ class Add<%= column.camelize %>To<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ add_column :<%= table_name %>, :<%= column %>, "geometry(<%= geometry_type %>,4326)"
4
+ add_index :<%= table_name %>, :<%= column %>, using: :gist
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ class <%= class_name %> < ApplicationRecord
2
+ acts_as_mappable geometry: :<%= column %>, type: :<%= shape %>
3
+ end
data/llms.txt CHANGED
@@ -5,10 +5,9 @@
5
5
  ## Install (exact steps)
6
6
 
7
7
  1. Gemfile: `gem "active_map"`; run `bundle install`.
8
- 2. `bin/rails g active_map:install` — idempotent; mounts engine at `/maps`, writes `config/initializers/active_map.rb` and `app/maps/sample_map.rb`, pins/registers the Stimulus controller when `config/importmap.rb` / `app/javascript/controllers/index.js` exist.
9
- 3. Migration: `enable_extension "postgis"`; geometry columns are plain SQL types:
10
- `add_column :warehouses, :coordinates, "geometry(Point,4326)"` + `add_index :warehouses, :coordinates, using: :gist`.
11
- Column types: `geometry(Point,4326)`, `geometry(Polygon,4326)`, `geometry(LineString,4326)`.
8
+ 2. `bin/rails g active_map:install` — idempotent; mounts engine at `/maps`, writes `config/initializers/active_map.rb` and `app/maps/sample_map.rb`, generates a PostGIS-enable migration, and pins/registers the Stimulus controller when `config/importmap.rb` / `app/javascript/controllers/index.js` exist. Then `bin/rails db:migrate`.
9
+ 3. Make a model mappable: `bin/rails g active_map:mappable Warehouse coordinates:point` (shape = point|polygon|line) — adds the geometry column migration (with GiST index) and injects `acts_as_mappable`; creates the model if absent; idempotent. Then `bin/rails db:migrate`.
10
+ Manual equivalent: `add_column :warehouses, :coordinates, "geometry(Point,4326)"` + `add_index :warehouses, :coordinates, using: :gist`. Column types: `geometry(Point,4326)`, `geometry(Polygon,4326)`, `geometry(LineString,4326)`.
12
11
  4. Assign geometry with EWKT strings: `Warehouse.create!(coordinates: "SRID=4326;POINT(<lng> <lat>)")` — LNG FIRST in WKT.
13
12
 
14
13
  ## Model DSL
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_map
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.2
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan
@@ -65,8 +65,12 @@ files:
65
65
  - lib/active_map/version.rb
66
66
  - lib/active_map/wkb.rb
67
67
  - lib/generators/active_map/install/install_generator.rb
68
+ - lib/generators/active_map/install/templates/enable_postgis.rb.tt
68
69
  - lib/generators/active_map/install/templates/initializer.rb
69
70
  - lib/generators/active_map/install/templates/sample_map.rb
71
+ - lib/generators/active_map/mappable/mappable_generator.rb
72
+ - lib/generators/active_map/mappable/templates/add_geometry_column.rb.tt
73
+ - lib/generators/active_map/mappable/templates/model.rb.tt
70
74
  - llms.txt
71
75
  - vendor/active_map/MarkerCluster.Default.css
72
76
  - vendor/active_map/MarkerCluster.css