enumbler 0.1.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 +7 -0
- data/.github/workflows/ruby.yml +61 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +57 -0
- data/.solargraph.yml +15 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +42 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/pre_commit_rubocop.rb +24 -0
- data/bin/setup +13 -0
- data/enumbler.gemspec +41 -0
- data/lib/enumbler/enumble.rb +32 -0
- data/lib/enumbler/version.rb +5 -0
- data/lib/enumbler.rb +195 -0
- metadata +176 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ac96c64c119c34aa4efbc77eaa1caa227d213e1efd631fac9089dbcb70f3f04b
|
4
|
+
data.tar.gz: 5e2d1125473c01f1e05728cf0f26f7dea219a7755da4db844535164156a6b104
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 40297daeee09865736136e47095f68e7540e91bed081da0613e2e33558c127c7fe4521c8233e6d1d426cc7c37bb3e147d1216ed9f0684a039a89ab59199c3256
|
7
|
+
data.tar.gz: cff2b4a1a1d94cd67dba49f141a0ed3b8820ffed03de69edebee6a59a47a0a84b4e3a581d418bf174ebb523353e9ffc03e27de3ebaa61e408c10d1ed9a17c580
|
@@ -0,0 +1,61 @@
|
|
1
|
+
name: CI Matrix Testing
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
rspec:
|
11
|
+
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
ruby_version: [2.5, 2.6]
|
17
|
+
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v2
|
20
|
+
|
21
|
+
- name: Set up Ruby
|
22
|
+
uses: actions/setup-ruby@v1
|
23
|
+
with:
|
24
|
+
ruby-version: ${{ matrix.ruby_version }}
|
25
|
+
|
26
|
+
- name: Install sqlite3
|
27
|
+
run: |
|
28
|
+
sudo apt-get install libsqlite3-dev
|
29
|
+
|
30
|
+
- name: Install dependencies
|
31
|
+
run: |
|
32
|
+
gem install bundler -v 2.1.4 --no-document
|
33
|
+
bundle install --jobs 4 --retry 3
|
34
|
+
|
35
|
+
- name: Build and test with Rake
|
36
|
+
run: |
|
37
|
+
bundle exec rspec
|
38
|
+
|
39
|
+
build:
|
40
|
+
name: Publish Gem
|
41
|
+
runs-on: ubuntu-latest
|
42
|
+
|
43
|
+
steps:
|
44
|
+
- uses: actions/checkout@v2
|
45
|
+
|
46
|
+
- name: Set up Ruby
|
47
|
+
uses: actions/setup-ruby@v1
|
48
|
+
with:
|
49
|
+
version: 2.7.x
|
50
|
+
|
51
|
+
- name: Publish to RubyGems
|
52
|
+
run: |
|
53
|
+
mkdir -p $HOME/.gem
|
54
|
+
touch $HOME/.gem/credentials
|
55
|
+
chmod 0600 $HOME/.gem/credentials
|
56
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
57
|
+
gem build *.gemspec
|
58
|
+
gem push *.gem
|
59
|
+
env:
|
60
|
+
GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}
|
61
|
+
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.6
|
3
|
+
Exclude:
|
4
|
+
- 'bin/pre_commit_rubocop.rb'
|
5
|
+
|
6
|
+
Layout/ArgumentAlignment:
|
7
|
+
Enabled: true
|
8
|
+
EnforcedStyle: with_fixed_indentation
|
9
|
+
|
10
|
+
Layout/FirstHashElementIndentation:
|
11
|
+
Enabled: true
|
12
|
+
EnforcedStyle: consistent
|
13
|
+
|
14
|
+
Layout/LineLength:
|
15
|
+
AllowURI: true
|
16
|
+
Max: 119
|
17
|
+
|
18
|
+
Lint/RaiseException:
|
19
|
+
Enabled: true
|
20
|
+
|
21
|
+
Lint/StructNewOverride:
|
22
|
+
Enabled: true
|
23
|
+
|
24
|
+
Style/HashEachMethods:
|
25
|
+
Enabled: true
|
26
|
+
|
27
|
+
Style/HashTransformKeys:
|
28
|
+
Enabled: true
|
29
|
+
|
30
|
+
Style/HashTransformValues:
|
31
|
+
Enabled: true
|
32
|
+
|
33
|
+
Style/TrailingCommaInHashLiteral:
|
34
|
+
Enabled: true
|
35
|
+
EnforcedStyleForMultiline: consistent_comma
|
36
|
+
|
37
|
+
Style/TrailingCommaInArrayLiteral:
|
38
|
+
Enabled: true
|
39
|
+
EnforcedStyleForMultiline: consistent_comma
|
40
|
+
|
41
|
+
Metrics/BlockLength:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Metrics/AbcSize:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
Metrics/CyclomaticComplexity:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Metrics/MethodLength:
|
51
|
+
Max: 30
|
52
|
+
|
53
|
+
Metrics/ModuleLength:
|
54
|
+
Max: 300
|
55
|
+
|
56
|
+
Metrics/ClassLength:
|
57
|
+
Max: 300
|
data/.solargraph.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
enumbler (0.1.0)
|
5
|
+
activerecord (>= 6.0)
|
6
|
+
activesupport (>= 6.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (6.0.2.2)
|
12
|
+
activesupport (= 6.0.2.2)
|
13
|
+
activerecord (6.0.2.2)
|
14
|
+
activemodel (= 6.0.2.2)
|
15
|
+
activesupport (= 6.0.2.2)
|
16
|
+
activesupport (6.0.2.2)
|
17
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
18
|
+
i18n (>= 0.7, < 2)
|
19
|
+
minitest (~> 5.1)
|
20
|
+
tzinfo (~> 1.1)
|
21
|
+
zeitwerk (~> 2.2)
|
22
|
+
ast (2.4.0)
|
23
|
+
concurrent-ruby (1.1.6)
|
24
|
+
database_cleaner (1.8.4)
|
25
|
+
database_cleaner-active_record (1.8.0)
|
26
|
+
activerecord
|
27
|
+
database_cleaner (~> 1.8.0)
|
28
|
+
diff-lcs (1.3)
|
29
|
+
fuubar (2.5.0)
|
30
|
+
rspec-core (~> 3.0)
|
31
|
+
ruby-progressbar (~> 1.4)
|
32
|
+
i18n (1.8.2)
|
33
|
+
concurrent-ruby (~> 1.0)
|
34
|
+
jaro_winkler (1.5.4)
|
35
|
+
minitest (5.14.0)
|
36
|
+
parallel (1.19.1)
|
37
|
+
parser (2.7.1.0)
|
38
|
+
ast (~> 2.4.0)
|
39
|
+
rainbow (3.0.0)
|
40
|
+
rake (12.3.3)
|
41
|
+
rexml (3.2.4)
|
42
|
+
rspec (3.9.0)
|
43
|
+
rspec-core (~> 3.9.0)
|
44
|
+
rspec-expectations (~> 3.9.0)
|
45
|
+
rspec-mocks (~> 3.9.0)
|
46
|
+
rspec-core (3.9.1)
|
47
|
+
rspec-support (~> 3.9.1)
|
48
|
+
rspec-expectations (3.9.1)
|
49
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
50
|
+
rspec-support (~> 3.9.0)
|
51
|
+
rspec-mocks (3.9.1)
|
52
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
+
rspec-support (~> 3.9.0)
|
54
|
+
rspec-support (3.9.2)
|
55
|
+
rubocop (0.81.0)
|
56
|
+
jaro_winkler (~> 1.5.1)
|
57
|
+
parallel (~> 1.10)
|
58
|
+
parser (>= 2.7.0.1)
|
59
|
+
rainbow (>= 2.2.2, < 4.0)
|
60
|
+
rexml
|
61
|
+
ruby-progressbar (~> 1.7)
|
62
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
63
|
+
ruby-progressbar (1.10.1)
|
64
|
+
sqlite3 (1.4.2)
|
65
|
+
thread_safe (0.3.6)
|
66
|
+
tzinfo (1.2.7)
|
67
|
+
thread_safe (~> 0.1)
|
68
|
+
unicode-display_width (1.7.0)
|
69
|
+
zeitwerk (2.3.0)
|
70
|
+
|
71
|
+
PLATFORMS
|
72
|
+
ruby
|
73
|
+
|
74
|
+
DEPENDENCIES
|
75
|
+
database_cleaner-active_record (~> 1.8.0)
|
76
|
+
enumbler!
|
77
|
+
fuubar (~> 2.5)
|
78
|
+
rake (~> 12.0)
|
79
|
+
rspec (~> 3.9.0)
|
80
|
+
rubocop (~> 0.81.0)
|
81
|
+
sqlite3 (~> 1.4.0)
|
82
|
+
|
83
|
+
BUNDLED WITH
|
84
|
+
2.1.4
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Damon Timm, Linguabee LLC
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Enumbler
|
2
|
+
|
3
|
+
`Enums` are terrific, but they lack integrity. Enumbler!
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'enumbler'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install enumbler
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Development
|
26
|
+
|
27
|
+
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.
|
28
|
+
|
29
|
+
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).
|
30
|
+
|
31
|
+
## Roadmap
|
32
|
+
|
33
|
+
Ideally, we could make this work more like a traditional `enum`; for example, overriding the `.where` method by allowing something like: `House.where(color: :blue)` instead of `House.where_color(:blue)`. But right now am in a rush and not sure how to go about doing that properly.
|
34
|
+
|
35
|
+
## Contributing
|
36
|
+
|
37
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/linguabee/enumbler.
|
38
|
+
|
39
|
+
|
40
|
+
## License
|
41
|
+
|
42
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'enumbler'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Put this file into your path and use `<file> install` to add a new hook
|
3
|
+
# or use it as a binary to check changed files
|
4
|
+
|
5
|
+
require 'shellwords'
|
6
|
+
|
7
|
+
if ARGV == ["install"]
|
8
|
+
exec "ln", "-sf", File.expand_path(File.basename(__FILE__), __dir__), ".git/hooks/pre-commit"
|
9
|
+
else
|
10
|
+
raise unless ARGV == []
|
11
|
+
end
|
12
|
+
|
13
|
+
changed = `git status --porcelain`.
|
14
|
+
split("\n").
|
15
|
+
map { |l| l.split(" ", 2) }.
|
16
|
+
select { |status, _| ["A", "AM", "M"].include?(status) }.
|
17
|
+
map { |_, file| file.delete('"') }
|
18
|
+
|
19
|
+
exit if changed.empty?
|
20
|
+
|
21
|
+
parallel = ((File.read(".rubocop.yml").include?("UseCache: false") rescue false) ? "" : " --parallel")
|
22
|
+
result = `bundle exec rubocop #{parallel} --color --force-exclusion #{changed.shelljoin}`
|
23
|
+
puts result unless $?.success?
|
24
|
+
exit $?.exitstatus
|
data/bin/setup
ADDED
data/enumbler.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/enumbler/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'enumbler'
|
7
|
+
spec.version = Enumbler::VERSION
|
8
|
+
spec.authors = ['Damon Timm']
|
9
|
+
spec.email = ['damon@linguabee.com']
|
10
|
+
|
11
|
+
spec.summary = "Enums are terrific, but lack integrity. Let's add some!"
|
12
|
+
spec.description = 'A more complete description is forthcoming.'
|
13
|
+
spec.homepage = 'https://github.com/linguabee/enumbler'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
16
|
+
|
17
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
18
|
+
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
20
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
21
|
+
spec.metadata['changelog_uri'] = spec.homepage
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
27
|
+
end
|
28
|
+
spec.bindir = 'exe'
|
29
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ['lib']
|
31
|
+
|
32
|
+
spec.add_dependency 'activerecord', '>= 6.0'
|
33
|
+
spec.add_dependency 'activesupport', '>= 6.0'
|
34
|
+
|
35
|
+
spec.add_development_dependency 'database_cleaner-active_record', '~> 1.8.0'
|
36
|
+
spec.add_development_dependency 'fuubar', '~> 2.5'
|
37
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
38
|
+
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
39
|
+
spec.add_development_dependency 'rubocop', '~> 0.81.0'
|
40
|
+
spec.add_development_dependency 'sqlite3', '~> 1.4.0'
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Enumbler
|
4
|
+
# Class that holds each row of Enumble data.
|
5
|
+
class Enumble
|
6
|
+
attr_reader :id, :enum, :label, :options
|
7
|
+
|
8
|
+
def initialize(enum, id, label: nil, **options)
|
9
|
+
@id = id
|
10
|
+
@enum = enum
|
11
|
+
@label = label || enum.to_s.dasherize
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
other.class == self.class &&
|
17
|
+
(other.id == id || other.enum == enum || other.label == label)
|
18
|
+
end
|
19
|
+
|
20
|
+
def attributes
|
21
|
+
{
|
22
|
+
id: id,
|
23
|
+
label: label,
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def eql?(other)
|
28
|
+
other.class == self.class &&
|
29
|
+
(other.id == id || other.enum == enum || other.label == label)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/enumbler.rb
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'enumbler/enumble'
|
4
|
+
require 'enumbler/version'
|
5
|
+
|
6
|
+
require 'active_support/concern'
|
7
|
+
require 'active_support/inflector'
|
8
|
+
|
9
|
+
# The Enumbler add integrity to our enum implementation!
|
10
|
+
module Enumbler
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
# The Enumble definition that this record defined.
|
16
|
+
# @return [Enumbler::Enumble]
|
17
|
+
def enumble
|
18
|
+
@enumble = self.class.enumbles.find { |enumble| enumble.id == id }
|
19
|
+
|
20
|
+
raise Error, 'An enumble is not defined for this record!' if @enumble.nil?
|
21
|
+
|
22
|
+
@enumble
|
23
|
+
end
|
24
|
+
|
25
|
+
# These are the ClassMethods that are added to an ApplicationRecord model when
|
26
|
+
# `include Enumbler` is added to the class.
|
27
|
+
module ClassMethods
|
28
|
+
attr_reader :enumbles
|
29
|
+
|
30
|
+
# Defines an Enumble for this model. An enum with integrity.
|
31
|
+
#
|
32
|
+
# # in your migration
|
33
|
+
# create_table :colors, force: true do |t|
|
34
|
+
# t.string :label, null: false
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# class Color < ApplicationRecord
|
38
|
+
# include Enumbler
|
39
|
+
#
|
40
|
+
# enumble :black, 1
|
41
|
+
# enumble :white, 2
|
42
|
+
# enumble :dark_brown, 3, # label: 'dark-brown'
|
43
|
+
# enumble :black_hole, 3, label: 'Oh my! It is a black hole!'
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# # Dynamically adds the following methods:
|
47
|
+
# Color::BLACK #=> 1
|
48
|
+
# Color.black #=> MyRecord.find(1)
|
49
|
+
# color.black? #=> true || false
|
50
|
+
# color.is_black #=> true || false
|
51
|
+
#
|
52
|
+
# @param enum [Symbol] the enum representation
|
53
|
+
# @param id [Integer] the primary key value
|
54
|
+
# @param label [String] optional: label for humans
|
55
|
+
# @param **options [Hash] optional: additional attributes and values that
|
56
|
+
# will be saved to the database for this enumble record
|
57
|
+
def enumble(enum, id, label: nil, **options)
|
58
|
+
@enumbles ||= []
|
59
|
+
@enumbled_model = self
|
60
|
+
|
61
|
+
enumble = Enumble.new(enum, id, label: label, **options)
|
62
|
+
|
63
|
+
if @enumbles.include?(enumble)
|
64
|
+
raise Error, "You cannot add the same Enumble twice! Attempted to add: #{enum}, #{id}."
|
65
|
+
end
|
66
|
+
|
67
|
+
define_dynamic_methods_and_constants_for_enumbled_model(enum, id)
|
68
|
+
|
69
|
+
@enumbles << enumble
|
70
|
+
end
|
71
|
+
|
72
|
+
# Defines the relationship between a model and the Enumbled class. Use this
|
73
|
+
# in lieu of `belongs_to` to establish that relationship. It requires a
|
74
|
+
# model that has defined one or more `Enumbles`.
|
75
|
+
#
|
76
|
+
# # in your migration
|
77
|
+
# create_table :houses, force: true do |t|
|
78
|
+
# t.references :color, foreign_key: true, null: false
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# class House < ApplicationRecord
|
82
|
+
# include Enumbler
|
83
|
+
# enumbled_to :color
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# @param name [Symbol] symbol representation of the class this belongs_to
|
87
|
+
# @param *args [Array] additional arguments passed to `belongs_to`
|
88
|
+
def enumbled_to(name, scope = nil, prefix: nil, **options)
|
89
|
+
class_name = name.to_s.classify
|
90
|
+
@enumbled_model = class_name.constantize
|
91
|
+
|
92
|
+
unless @enumbled_model.respond_to?(:enumbles)
|
93
|
+
raise Error, "The class #{class_name} does not have any enumbles defined."\
|
94
|
+
" You can add them via `#{class_name}.enumble :blue, 1`."
|
95
|
+
end
|
96
|
+
|
97
|
+
belongs_to(name, scope, **options)
|
98
|
+
|
99
|
+
define_dynamic_methods_for_enumbled_to_models(prefix: prefix)
|
100
|
+
rescue NameError
|
101
|
+
raise Error, "The class #{class_name} cannot be found. Uninitialized constant."
|
102
|
+
end
|
103
|
+
|
104
|
+
# Return the record id(s) based on different argument types. Can accept an
|
105
|
+
# Integer, a Symbol, or an instance of Enumbled model. This lookup is a
|
106
|
+
# databse-free lookup.
|
107
|
+
#
|
108
|
+
# Color.ids_from_enumablable(1, 2) # => [1, 2]
|
109
|
+
# Color.ids_from_enumablable(:black, :white) # => [1, 2]
|
110
|
+
# Color.ids_from_enumablable(Color.black, Color.white) # => [1, 2]
|
111
|
+
#
|
112
|
+
# @raise [Error] when there is no enumble to be found
|
113
|
+
# @param *args [Integer, Symbol, Class]
|
114
|
+
# @return [Array<Integer>]
|
115
|
+
def ids_from_enumablable(*args)
|
116
|
+
args.flatten.compact.uniq.map do |arg|
|
117
|
+
err = "Unable to find a #{@enumbled_model}#enumble with #{arg}"
|
118
|
+
|
119
|
+
begin
|
120
|
+
arg = Integer(arg) # raises Type error if not a real integer
|
121
|
+
enumble = @enumbled_model.enumbles.find { |e| e.id == arg }
|
122
|
+
rescue TypeError
|
123
|
+
enumble = if arg.is_a?(Symbol)
|
124
|
+
@enumbled_model.enumbles.find { |e| e.enum == arg }
|
125
|
+
elsif arg.instance_of?(@enumbled_model)
|
126
|
+
arg.enumble
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
enumble&.id || raise(Error, err)
|
131
|
+
rescue Error
|
132
|
+
raise Error, err
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Seeds the database with the Enumble data.
|
137
|
+
# @param delete_missing_records [Boolean] remove any records that are no
|
138
|
+
# longer defined (default: false)
|
139
|
+
def seed_the_enumbler(delete_missing_records: false)
|
140
|
+
max_database_id = all.order('id desc').take&.id || 0
|
141
|
+
max_enumble_id = enumbles.map(&:id).max
|
142
|
+
|
143
|
+
max_id = max_enumble_id > max_database_id ? max_enumble_id : max_database_id
|
144
|
+
|
145
|
+
discarded_ids = []
|
146
|
+
|
147
|
+
(1..max_id).each do |id|
|
148
|
+
enumble = @enumbles.find { |e| e.id == id }
|
149
|
+
|
150
|
+
if enumble.nil?
|
151
|
+
discarded_ids << id
|
152
|
+
next
|
153
|
+
end
|
154
|
+
|
155
|
+
record = find_or_initialize_by(id: id)
|
156
|
+
record.attributes = enumble.attributes
|
157
|
+
record.save!
|
158
|
+
end
|
159
|
+
|
160
|
+
where(id: discarded_ids).delete_all if delete_missing_records
|
161
|
+
end
|
162
|
+
|
163
|
+
# Seeds the database with the Enumble data, removing any records that are no
|
164
|
+
# longer defined.
|
165
|
+
def seed_the_enumbler!
|
166
|
+
seed_the_enumbler(delete_missing_records: true)
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def define_dynamic_methods_and_constants_for_enumbled_model(enum, id)
|
172
|
+
method_name = "#{enum}?"
|
173
|
+
alias_method_name = "is_#{enum}"
|
174
|
+
|
175
|
+
const_set(enum.to_s.upcase, id)
|
176
|
+
define_method(method_name) { self.id == id }
|
177
|
+
alias_method alias_method_name, method_name
|
178
|
+
define_singleton_method(enum) { find(id) }
|
179
|
+
end
|
180
|
+
|
181
|
+
def define_dynamic_methods_for_enumbled_to_models(prefix: nil)
|
182
|
+
model_name = @enumbled_model.to_s.underscore
|
183
|
+
|
184
|
+
method = if prefix.blank?
|
185
|
+
model_name
|
186
|
+
else
|
187
|
+
"#{prefix}_#{model_name}"
|
188
|
+
end
|
189
|
+
|
190
|
+
define_singleton_method(method) do |*args|
|
191
|
+
where("#{model_name}_id": ids_from_enumablable(args))
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: enumbler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Damon Timm
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-04-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '6.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '6.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: database_cleaner-active_record
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.8.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.8.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: fuubar
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.5'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '12.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '12.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 3.9.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 3.9.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.81.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.81.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.4.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.4.0
|
125
|
+
description: A more complete description is forthcoming.
|
126
|
+
email:
|
127
|
+
- damon@linguabee.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".github/workflows/ruby.yml"
|
133
|
+
- ".gitignore"
|
134
|
+
- ".rspec"
|
135
|
+
- ".rubocop.yml"
|
136
|
+
- ".solargraph.yml"
|
137
|
+
- Gemfile
|
138
|
+
- Gemfile.lock
|
139
|
+
- LICENSE.txt
|
140
|
+
- README.md
|
141
|
+
- Rakefile
|
142
|
+
- bin/console
|
143
|
+
- bin/pre_commit_rubocop.rb
|
144
|
+
- bin/setup
|
145
|
+
- enumbler.gemspec
|
146
|
+
- lib/enumbler.rb
|
147
|
+
- lib/enumbler/enumble.rb
|
148
|
+
- lib/enumbler/version.rb
|
149
|
+
homepage: https://github.com/linguabee/enumbler
|
150
|
+
licenses:
|
151
|
+
- MIT
|
152
|
+
metadata:
|
153
|
+
allowed_push_host: https://rubygems.org
|
154
|
+
homepage_uri: https://github.com/linguabee/enumbler
|
155
|
+
source_code_uri: https://github.com/linguabee/enumbler
|
156
|
+
changelog_uri: https://github.com/linguabee/enumbler
|
157
|
+
post_install_message:
|
158
|
+
rdoc_options: []
|
159
|
+
require_paths:
|
160
|
+
- lib
|
161
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 2.3.0
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
requirements: []
|
172
|
+
rubygems_version: 3.1.2
|
173
|
+
signing_key:
|
174
|
+
specification_version: 4
|
175
|
+
summary: Enums are terrific, but lack integrity. Let's add some!
|
176
|
+
test_files: []
|