enumbler 0.10.0 → 0.11.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: 717637e70fa4a5c5b5419945258e2132e2fd0c5d6c9e88f983f17cc00aaabe55
4
- data.tar.gz: b5a2a0d6c731fdf14fa260ceea6af15940ed146ee94c7adf6547f972d885dc00
3
+ metadata.gz: e565cc926b8cca7f06e64cc90503f5965003a3e5c60d1c2a5cd689ea690c8215
4
+ data.tar.gz: e2cfef7c22ed8ce2d51d706802c79ce1fc0b4abe8b3268aa634400051f9970b1
5
5
  SHA512:
6
- metadata.gz: 1e13f79de97b243c0a914fda812722ffce084e36e15c9930e5f4ec5e6dc7c345a19909351c6da6eeb8113bf97d60eafd7aee8a80cf99ae829d9f929c8ce60c67
7
- data.tar.gz: f0bfd2c79d944854af27b2b953c3fdbe7ae2e7d2e88b321d2c7332cff5fcc07f7342c2e4e6fb0be919fd9e377a7e1fce91d4c03cfb15d0de36995bb4d5527bc4
6
+ metadata.gz: 77c6de7fc4fbebc329e77ccee8ead1998a71e6539d45a218a1f018424a4a6e087869e0c04fc51d074f006fddfa32cf7e047e417e3b1c5706be822003029b432c
7
+ data.tar.gz: 8e30d49be482fc9fa3da561c134c93c8db1b8362f05c7dd83300e5e6db16b001c399382ed5c9fa3d96291ab232d4a28ac1d147bf8d7833294ece0ed98b3135e6
@@ -6,9 +6,18 @@ on:
6
6
  tags: ["*"]
7
7
  pull_request:
8
8
 
9
+ # A new push to the same ref supersedes any in-flight run; cancel the stale
10
+ # one rather than paying for both.
11
+ concurrency:
12
+ group: ci-${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
9
15
  jobs:
10
16
  rspec:
11
17
  runs-on: ubuntu-latest
18
+ # Typical matrix job is under 2 minutes; a hung job otherwise runs to
19
+ # GitHub's 6-hour default.
20
+ timeout-minutes: 10
12
21
  strategy:
13
22
  fail-fast: false
14
23
  matrix:
@@ -51,21 +60,34 @@ jobs:
51
60
 
52
61
  name: Publish Gem
53
62
  runs-on: ubuntu-latest
63
+ timeout-minutes: 10
54
64
 
55
65
  if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
56
66
 
67
+ # Publishes via RubyGems trusted publishing (OIDC) — no API key, and
68
+ # exempt from the account's OTP requirement. The trusted publisher on
69
+ # rubygems.org is registered for this repo + this workflow filename.
70
+ # Uses configure-rubygems-credentials + a plain `gem push` rather than
71
+ # the release-gem action: that action runs `rake release`, which wants
72
+ # to git-push and create its own v-prefixed tag — this repo tags
73
+ # manually (bare version numbers) and this job runs on a detached HEAD.
74
+ permissions:
75
+ id-token: write
76
+
57
77
  steps:
58
78
  - uses: actions/checkout@v4
79
+ with:
80
+ persist-credentials: false
59
81
 
60
82
  - name: Set up Ruby
61
83
  uses: ruby/setup-ruby@v1
62
84
  with:
63
85
  ruby-version: 3.4
64
86
 
65
- - name: Publish to RubyGems
87
+ - uses: rubygems/configure-rubygems-credentials@v2.1.0
88
+
89
+ - name: Build and push gem
66
90
  run: |
67
91
  gem build *.gemspec
68
92
  gem push *.gem
69
- env:
70
- GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
71
93
 
data/AGENTS.md CHANGED
@@ -5,7 +5,8 @@
5
5
 
6
6
  ## Running Checks
7
7
  - Use Bundler for all commands (`bundle exec`).
8
- - Lint changed Ruby files with `bundle exec rspec`.
8
+ - Run tests with `bundle exec rspec`.
9
+ - Lint changed Ruby files with `bundle exec rubocop`.
9
10
 
10
11
  ## Commit Guidelines
11
12
  - Keep commit messages concise and descriptive.
data/CLAUDE.md ADDED
@@ -0,0 +1,55 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What this is
6
+
7
+ Enumbler is a Ruby gem that provides database-backed enums for ActiveRecord: real foreign-key lookup tables that behave like `enum`s. It supports ActiveRecord/ActiveSupport >= 6.0, < 9 and Ruby >= 3.1.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ bin/setup # install dependencies
13
+ bundle exec rspec # run all tests
14
+ bundle exec rspec spec/enumbler_spec.rb:42 # run a single test by file:line
15
+ bundle exec rubocop # lint (also runs as a lefthook pre-commit hook)
16
+ ```
17
+
18
+ ### Matrix testing
19
+
20
+ CI tests Ruby 3.1–3.4 against Rails 6.0–8.0 using the `Gemfile.rails*` files. To reproduce locally:
21
+
22
+ ```bash
23
+ BUNDLE_GEMFILE=Gemfile.rails7.2 bundle install
24
+ BUNDLE_GEMFILE=Gemfile.rails7.2 bundle exec rspec
25
+ ```
26
+
27
+ When changing dependencies, keep all `Gemfile.rails*` variants (and their lockfiles) in sync with the main `Gemfile`.
28
+
29
+ ### Branching & releasing
30
+
31
+ Modified git flow (see README "Development"): feature branches off `develop`; releases go to `main` via `release/x.y.z` (or `hotfix/x.y.z` off `main`), then the tag is merged back into `develop`. A release is a bare version tag on `main` (no `v` prefix, e.g. `0.10.0`) matching `lib/enumbler/version.rb`; pushing the tag makes CI run the rspec matrix and publish the gem to rubygems.org.
32
+
33
+ ## Architecture
34
+
35
+ The gem is four small files under `lib/enumbler/`, split across the two sides of the relationship:
36
+
37
+ - **`lib/enumbler.rb`** (`Enumbler` module) — included in `ApplicationRecord`; gives *consuming* models `enumbled_to :color`, a `belongs_to` replacement. It defines class scopes (`House.color(:black)`), per-enum predicates (`house.black?`, `house.not_black?`, optionally prefixed), and db-free helper attributes (`house.color_label`, `color_enum`, `color_graphql_enum`).
38
+
39
+ - **`lib/enumbler/enabler.rb`** (`Enumbler::Enabler`) — included in the *lookup* model (e.g. `Color`); provides the `enumble :black, 1, ...` DSL. Each call builds an `Enumble`, registers it in the class-level `@enumbles` collection, and metaprograms constants (`Color::BLACK`), class finders (`Color.black`, `Color.black(:label)`), and predicates — with conflict detection against ActiveRecord methods (modeled on `ActiveRecord::Enum`). Also holds all the `find_enumble(s)` / `ids_from_enumbler` lookup methods (in-memory, no db hit; bang variants raise `Enumbler::Error`) and `seed_the_enumbler(!)` for syncing the definitions into the database table.
40
+
41
+ - **`lib/enumbler/enumble.rb`** (`Enumbler::Enumble`) — plain value object for one enum row (id, enum symbol, label, extra attributes). Equality is loose: two Enumbles are `==` if id **or** enum **or** label match (this is how duplicate definitions are caught).
42
+
43
+ - **`lib/enumbler/collection.rb`** — an `Array` subclass with `method_missing` so `Color.enumbles.black` works.
44
+
45
+ - **`lib/enumbler/core_ext/symbol/case_equality_operator.rb`** — patches `Symbol#===` so `case Color.black; when :black` works. It's a global core extension; be careful changing it.
46
+
47
+ The label column defaults to `label` but can be remapped per-model with `enumbler_label_column_name :emotion`; internally `Enumble#label` always refers to the enumbler value regardless of the underlying column.
48
+
49
+ ## Tests
50
+
51
+ Specs run against an in-memory SQLite database (`spec/support/establish_sqlite_connection.rb`); each spec file defines its own schema with `ActiveRecord::Schema.define` and DatabaseCleaner wraps each example in a transaction. `spec/enumbler_spec.rb` covers nearly everything and defines the shared test models (Color, House, Feeling). Rails-version-conditional behavior may need `BUNDLE_GEMFILE` runs to verify.
52
+
53
+ ## Style
54
+
55
+ RuboCop enforces double-quoted strings, max line length 119, trailing commas in multiline literals, and `TargetRubyVersion: 3.4` — but code must still run on Ruby 3.1 (see the gemspec), so avoid 3.2+-only syntax.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.10.0)
4
+ enumbler (0.11.0)
5
5
  activerecord (>= 6.0, < 9)
6
6
  activesupport (>= 6.0, < 9)
7
7
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.10.0)
4
+ enumbler (0.11.0)
5
5
  activerecord (>= 6.0, < 9)
6
6
  activesupport (>= 6.0, < 9)
7
7
 
@@ -96,4 +96,4 @@ DEPENDENCIES
96
96
  sqlite3 (~> 1.6)
97
97
 
98
98
  BUNDLED WITH
99
- 2.4.12
99
+ 2.6.9
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.10.0)
5
- activerecord (>= 5.2.3, < 7)
6
- activesupport (>= 5.2.3, < 7)
4
+ enumbler (0.11.0)
5
+ activerecord (>= 6.0, < 9)
6
+ activesupport (>= 6.0, < 9)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
@@ -72,6 +72,7 @@ GEM
72
72
  parser (>= 2.7.1.5)
73
73
  ruby-progressbar (1.13.0)
74
74
  sqlite3 (1.7.3-arm64-darwin)
75
+ sqlite3 (1.7.3-x86_64-linux)
75
76
  tzinfo (2.0.6)
76
77
  concurrent-ruby (~> 1.0)
77
78
  unicode-display_width (1.8.0)
@@ -79,6 +80,7 @@ GEM
79
80
 
80
81
  PLATFORMS
81
82
  arm64-darwin-24
83
+ x86_64-linux
82
84
 
83
85
  DEPENDENCIES
84
86
  activemodel (= 6.1.7.10)
@@ -95,4 +97,4 @@ DEPENDENCIES
95
97
  sqlite3 (~> 1.6)
96
98
 
97
99
  BUNDLED WITH
98
- 2.4.12
100
+ 2.6.9
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.10.0)
5
- activerecord (>= 5.2.3, < 8)
6
- activesupport (>= 5.2.3, < 8)
4
+ enumbler (0.11.0)
5
+ activerecord (>= 6.0, < 9)
6
+ activesupport (>= 6.0, < 9)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
@@ -71,12 +71,14 @@ GEM
71
71
  parser (>= 2.7.1.5)
72
72
  ruby-progressbar (1.13.0)
73
73
  sqlite3 (1.7.3-arm64-darwin)
74
+ sqlite3 (1.7.3-x86_64-linux)
74
75
  tzinfo (2.0.6)
75
76
  concurrent-ruby (~> 1.0)
76
77
  unicode-display_width (1.8.0)
77
78
 
78
79
  PLATFORMS
79
80
  arm64-darwin-24
81
+ x86_64-linux
80
82
 
81
83
  DEPENDENCIES
82
84
  activemodel (= 7.0.8.7)
@@ -93,4 +95,4 @@ DEPENDENCIES
93
95
  sqlite3 (~> 1.6)
94
96
 
95
97
  BUNDLED WITH
96
- 2.4.12
98
+ 2.6.9
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.10.0)
5
- activerecord (>= 5.2.3, < 8)
6
- activesupport (>= 5.2.3, < 8)
4
+ enumbler (0.11.0)
5
+ activerecord (>= 6.0, < 9)
6
+ activesupport (>= 6.0, < 9)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
@@ -47,6 +47,7 @@ GEM
47
47
  concurrent-ruby (~> 1.0)
48
48
  logger (1.7.0)
49
49
  method_source (1.1.0)
50
+ mini_portile2 (2.8.9)
50
51
  minitest (5.25.5)
51
52
  mutex_m (0.3.0)
52
53
  parallel (1.27.0)
@@ -87,6 +88,8 @@ GEM
87
88
  parser (>= 2.7.1.5)
88
89
  ruby-progressbar (1.13.0)
89
90
  securerandom (0.4.1)
91
+ sqlite3 (1.5.4)
92
+ mini_portile2 (~> 2.8.0)
90
93
  sqlite3 (1.5.4-arm64-darwin)
91
94
  timeout (0.4.3)
92
95
  tzinfo (2.0.6)
@@ -95,6 +98,7 @@ GEM
95
98
 
96
99
  PLATFORMS
97
100
  arm64-darwin-24
101
+ x86_64-linux
98
102
 
99
103
  DEPENDENCIES
100
104
  activemodel (= 7.1.5.1)
@@ -111,4 +115,4 @@ DEPENDENCIES
111
115
  sqlite3 (~> 1.5.0)
112
116
 
113
117
  BUNDLED WITH
114
- 2.4.12
118
+ 2.6.9
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.10.0)
5
- activerecord (>= 5.2.3, < 8)
6
- activesupport (>= 5.2.3, < 8)
4
+ enumbler (0.11.0)
5
+ activerecord (>= 6.0, < 9)
6
+ activesupport (>= 6.0, < 9)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
@@ -46,6 +46,7 @@ GEM
46
46
  concurrent-ruby (~> 1.0)
47
47
  logger (1.7.0)
48
48
  method_source (1.1.0)
49
+ mini_portile2 (2.8.9)
49
50
  minitest (5.25.5)
50
51
  parallel (1.27.0)
51
52
  parser (3.3.8.0)
@@ -85,6 +86,8 @@ GEM
85
86
  parser (>= 2.7.1.5)
86
87
  ruby-progressbar (1.13.0)
87
88
  securerandom (0.4.1)
89
+ sqlite3 (1.5.4)
90
+ mini_portile2 (~> 2.8.0)
88
91
  sqlite3 (1.5.4-arm64-darwin)
89
92
  timeout (0.4.3)
90
93
  tzinfo (2.0.6)
@@ -93,6 +96,7 @@ GEM
93
96
 
94
97
  PLATFORMS
95
98
  arm64-darwin-24
99
+ x86_64-linux
96
100
 
97
101
  DEPENDENCIES
98
102
  activemodel (<= 8)
@@ -109,4 +113,4 @@ DEPENDENCIES
109
113
  sqlite3 (~> 1.5.0)
110
114
 
111
115
  BUNDLED WITH
112
- 2.4.12
116
+ 2.6.9
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.10.0)
4
+ enumbler (0.11.0)
5
5
  activerecord (>= 6.0, < 9)
6
6
  activesupport (>= 6.0, < 9)
7
7
 
@@ -85,6 +85,7 @@ GEM
85
85
  ruby-progressbar (1.10.1)
86
86
  securerandom (0.4.1)
87
87
  sqlite3 (2.6.0-arm64-darwin)
88
+ sqlite3 (2.6.0-x86_64-linux-gnu)
88
89
  timeout (0.4.3)
89
90
  tzinfo (2.0.6)
90
91
  concurrent-ruby (~> 1.0)
@@ -93,6 +94,7 @@ GEM
93
94
 
94
95
  PLATFORMS
95
96
  arm64-darwin
97
+ x86_64-linux
96
98
 
97
99
  DEPENDENCIES
98
100
  activemodel (>= 8)
data/README.md CHANGED
@@ -162,11 +162,54 @@ when :blue, :purple
162
162
  end
163
163
  ```
164
164
 
165
+ ## Suppressing database warnings
166
+
167
+ When an `enumble` defines extra attributes, the Enumbler verifies them against the model's table at class-load time. If the table cannot be inspected — for example, while your test databases are dropped mid-way through a `rake parallel:setup` — it prints an `[Enumbler Warning]` for every affected model rather than raising. If those warnings are just noise in your workflow, you can suppress them:
168
+
169
+ ```ruby
170
+ Enumbler.suppress_database_warnings = true
171
+ ```
172
+
173
+ Or set the environment variable `ENUMBLER_SUPPRESS_DATABASE_WARNINGS` to any non-empty value — handy for wrapping database reset commands:
174
+
175
+ ```bash
176
+ ENUMBLER_SUPPRESS_DATABASE_WARNINGS=1 bundle exec rake parallel:setup
177
+ ```
178
+
179
+ The Ruby-level setting, when assigned, takes precedence over the environment variable.
180
+
165
181
  ## Development
166
182
 
167
183
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
168
184
 
169
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
185
+ To install this gem onto your local machine, run `bundle exec rake install`.
186
+
187
+ ### Branching (modified git flow)
188
+
189
+ Day-to-day work follows git flow: feature/bug/chore branches come off `develop` and are merged back into `develop` via PR. Releases move `develop` into `main` through a `release/x.y.z` branch (or a `hotfix/x.y.z` branch off `main` for urgent fixes), and after tagging, the tag is merged back into `develop` so both branches share the release commit.
190
+
191
+ ### Releasing a New Version
192
+
193
+ A release is triggered by pushing a **version tag** to GitHub: the `CI Matrix Testing` workflow runs the rspec matrix and, if green, the `Publish Gem` job builds the gem and pushes it to [rubygems.org](https://rubygems.org).
194
+
195
+ Two things to know before tagging:
196
+
197
+ 1. The published version comes from `lib/enumbler/version.rb`, **not** the tag name — make sure they match (the tag is bare, no `v` prefix: `0.10.0`).
198
+ 2. RubyGems rejects duplicate versions, so every release needs a version bump.
199
+
200
+ Steps:
201
+
202
+ 1. Bump `Enumbler::VERSION` in `lib/enumbler/version.rb` (and run `bundle install` so the lockfiles pick it up) on a `release/x.y.z` branch off `develop` (or `hotfix/x.y.z` off `main`).
203
+ 2. Merge the branch into `main`, then tag the release commit:
204
+
205
+ ```bash
206
+ git checkout main && git pull
207
+ git tag -a 0.10.0 -m "Release 0.10.0"
208
+ git push origin main 0.10.0
209
+ ```
210
+
211
+ 3. Watch the `CI Matrix Testing` workflow on the tag: when the publish job is green, confirm the new version on [rubygems.org](https://rubygems.org/gems/enumbler).
212
+ 4. Merge the tag back into `develop`: `git checkout develop && git merge 0.10.0 && git push`.
170
213
 
171
214
  ### Matrix testing
172
215
 
@@ -462,12 +462,16 @@ module Enumbler
462
462
  raise Enumbler::Error,
463
463
  "The model #{self} does not support the attribute(s): #{unsupported_attrs.keys.map(&:to_s).to_sentence}"
464
464
  rescue ActiveRecord::PendingMigrationError
465
+ return if Enumbler.suppress_database_warnings?
466
+
465
467
  warn "[Enumbler Warning] => The model #{self} does not currently support the attribute(s): " \
466
468
  "#{unsupported_attrs.keys.map(&:to_s).to_sentence}. " \
467
469
  "You have a pending migration which hopefully would remedy this! " \
468
470
  "If not, you need to add a migration for this attibrute or " \
469
471
  "remove it from the Enumbler."
470
472
  rescue ActiveRecord::StatementInvalid
473
+ return if Enumbler.suppress_database_warnings?
474
+
471
475
  warn "[Enumbler Warning] => Unable to find a table for #{self}." \
472
476
  "This is to be expected if there is a pending migration; " \
473
477
  "however, if there is not then something is amiss."
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumbler
4
- VERSION = "0.10.0"
4
+ VERSION = "0.11.0"
5
5
  end
data/lib/enumbler.rb CHANGED
@@ -17,6 +17,26 @@ module Enumbler
17
17
  # An error raised by the Enumbler.
18
18
  class Error < StandardError; end
19
19
 
20
+ class << self
21
+ attr_writer :suppress_database_warnings
22
+
23
+ # Suppress the boot-time `[Enumbler Warning]` messages emitted when a
24
+ # model's table or attributes cannot be verified (e.g., while the database
25
+ # is dropped during a test database reset). Enable by setting
26
+ # `Enumbler.suppress_database_warnings = true` or by setting the
27
+ # environment variable `ENUMBLER_SUPPRESS_DATABASE_WARNINGS` to any
28
+ # non-empty value. The Ruby-level setting, when assigned, wins over the
29
+ # environment variable.
30
+ # @return [Boolean]
31
+ def suppress_database_warnings?
32
+ if @suppress_database_warnings.nil?
33
+ ENV["ENUMBLER_SUPPRESS_DATABASE_WARNINGS"].present?
34
+ else
35
+ @suppress_database_warnings
36
+ end
37
+ end
38
+ end
39
+
20
40
  # Include these ClassMethods in your base ApplicationRecord model to bestow
21
41
  # any of your models with the ability to be connected to an Enumbled relation
22
42
  # in the same way you would use `belongs_to` now you use `enumbled_to`.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumbler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damon Timm
@@ -63,6 +63,7 @@ files:
63
63
  - ".ruby-version"
64
64
  - ".solargraph.yml"
65
65
  - AGENTS.md
66
+ - CLAUDE.md
66
67
  - Gemfile
67
68
  - Gemfile.lock
68
69
  - Gemfile.rails6.0
@@ -114,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
115
  - !ruby/object:Gem::Version
115
116
  version: '0'
116
117
  requirements: []
117
- rubygems_version: 3.6.7
118
+ rubygems_version: 3.6.9
118
119
  specification_version: 4
119
120
  summary: Enums are terrific, but lack integrity. Let's add some!
120
121
  test_files: []