enumbler 0.6.11 → 0.8.1
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 +4 -4
- data/.github/workflows/ruby.yml +3 -0
- data/.gitignore +1 -0
- data/Gemfile.lock +18 -9
- data/README.md +24 -5
- data/enumbler.gemspec +2 -1
- data/lib/enumbler/enabler.rb +85 -1
- data/lib/enumbler/enumble.rb +11 -5
- data/lib/enumbler/version.rb +1 -1
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 012b0ded68a635ef8ac4cb765eec4a648f16a4365abaa1d6def1897d389bcba8
|
4
|
+
data.tar.gz: a74d123fa2635a2118e1300cbf75a56d3255756e9bf9384049bb27f74187eb7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e623093fbb3dbc1645c9d3f713c32100fa561b8ade1a62c03d4da9ae7b6c6a964b45ddcacd4bc158f8c41cc8bdf1150a02c340ce84c9b6e94ec831f798a00a76
|
7
|
+
data.tar.gz: '09ef23ba8854c6ff1f01fbffd7e9227e183148acf6a03ce14bd02f0244d9c38f2ef2b9d1e7494320b5b6c8be08849689d1875eff1d68d81545e358299e8ebeb8'
|
data/.github/workflows/ruby.yml
CHANGED
@@ -3,6 +3,8 @@ name: CI Matrix Testing
|
|
3
3
|
on:
|
4
4
|
push:
|
5
5
|
branches: [ master ]
|
6
|
+
tags:
|
7
|
+
- "*"
|
6
8
|
pull_request:
|
7
9
|
branches: [ master ]
|
8
10
|
|
@@ -51,6 +53,7 @@ jobs:
|
|
51
53
|
ruby-version: 2.7.x
|
52
54
|
|
53
55
|
- name: Publish to RubyGems
|
56
|
+
if: contains(github.ref, 'refs/tags/')
|
54
57
|
run: |
|
55
58
|
mkdir -p $HOME/.gem
|
56
59
|
touch $HOME/.gem/credentials
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
enumbler (0.
|
4
|
+
enumbler (0.8.1)
|
5
5
|
activerecord (>= 5.2.3, < 6.1)
|
6
6
|
activesupport (>= 5.2.3, < 6.1)
|
7
7
|
|
@@ -19,7 +19,8 @@ GEM
|
|
19
19
|
minitest (~> 5.1)
|
20
20
|
tzinfo (~> 1.1)
|
21
21
|
zeitwerk (~> 2.2, >= 2.2.2)
|
22
|
-
ast (2.4.
|
22
|
+
ast (2.4.1)
|
23
|
+
coderay (1.1.2)
|
23
24
|
concurrent-ruby (1.1.6)
|
24
25
|
database_cleaner (1.8.5)
|
25
26
|
database_cleaner-active_record (1.8.0)
|
@@ -31,13 +32,17 @@ GEM
|
|
31
32
|
ruby-progressbar (~> 1.4)
|
32
33
|
i18n (1.8.2)
|
33
34
|
concurrent-ruby (~> 1.0)
|
34
|
-
|
35
|
+
method_source (1.0.0)
|
35
36
|
minitest (5.14.1)
|
36
37
|
parallel (1.19.1)
|
37
|
-
parser (2.7.1.
|
38
|
-
ast (~> 2.4.
|
38
|
+
parser (2.7.1.4)
|
39
|
+
ast (~> 2.4.1)
|
40
|
+
pry (0.13.1)
|
41
|
+
coderay (~> 1.1)
|
42
|
+
method_source (~> 1.0)
|
39
43
|
rainbow (3.0.0)
|
40
44
|
rake (12.3.3)
|
45
|
+
regexp_parser (1.7.1)
|
41
46
|
rexml (3.2.4)
|
42
47
|
rspec (3.9.0)
|
43
48
|
rspec-core (~> 3.9.0)
|
@@ -52,14 +57,17 @@ GEM
|
|
52
57
|
diff-lcs (>= 1.2.0, < 2.0)
|
53
58
|
rspec-support (~> 3.9.0)
|
54
59
|
rspec-support (3.9.3)
|
55
|
-
rubocop (0.
|
56
|
-
jaro_winkler (~> 1.5.1)
|
60
|
+
rubocop (0.91.0)
|
57
61
|
parallel (~> 1.10)
|
58
|
-
parser (>= 2.7.
|
62
|
+
parser (>= 2.7.1.1)
|
59
63
|
rainbow (>= 2.2.2, < 4.0)
|
64
|
+
regexp_parser (>= 1.7)
|
60
65
|
rexml
|
66
|
+
rubocop-ast (>= 0.4.0, < 1.0)
|
61
67
|
ruby-progressbar (~> 1.7)
|
62
68
|
unicode-display_width (>= 1.4.0, < 2.0)
|
69
|
+
rubocop-ast (0.4.0)
|
70
|
+
parser (>= 2.7.1.4)
|
63
71
|
ruby-progressbar (1.10.1)
|
64
72
|
sqlite3 (1.4.2)
|
65
73
|
thread_safe (0.3.6)
|
@@ -75,9 +83,10 @@ DEPENDENCIES
|
|
75
83
|
database_cleaner-active_record (~> 1.8.0)
|
76
84
|
enumbler!
|
77
85
|
fuubar (~> 2.5)
|
86
|
+
pry
|
78
87
|
rake (~> 12.0)
|
79
88
|
rspec (~> 3.9.0)
|
80
|
-
rubocop (~> 0.
|
89
|
+
rubocop (~> 0.91.0)
|
81
90
|
sqlite3 (~> 1.4.0)
|
82
91
|
|
83
92
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -91,6 +91,17 @@ Color.ids_from_enumbler(:black, 'does-no-exist') # => [1, nil]
|
|
91
91
|
Color.ids_from_enumbler!(:black, 'does-no-exist') # => raises Enumbler::Error
|
92
92
|
Color.id_from_enumbler!(:does_not_exist) # => raises Enumbler::Error
|
93
93
|
|
94
|
+
# Get a model instance (like `.find_by` in Rails)
|
95
|
+
Color.find_by_enumble(1)
|
96
|
+
Color.find_by_enumble(:black)
|
97
|
+
Color.find_by_enumble("black")
|
98
|
+
Color.find_by_enumble("BLACK")
|
99
|
+
Color.find_by_enumble(Color.black) # => self
|
100
|
+
Color.find_by_enumble("whoops") # => nil
|
101
|
+
|
102
|
+
# Raise ActiveRecord::RecordNotFound error with bang
|
103
|
+
Color.find_by_enumble!("whoops") # => nil
|
104
|
+
|
94
105
|
# Get enumble object by id
|
95
106
|
house = House.create!(color: Color.black)
|
96
107
|
|
@@ -108,12 +119,14 @@ House.color(Color.black, :white) # => ActiveRecord::Relation<house, house2>
|
|
108
119
|
|
109
120
|
### Use a column other than `label`
|
110
121
|
|
111
|
-
By default, the Enumbler expects a table in the database with a column `label`. However, you can change this to another underlying column name. Note that the enumbler still treats it as a `label` column; however it will be saved to the correct place in the database.
|
122
|
+
By default, the Enumbler expects a table in the database with a column `label`. However, you can change this to another underlying column name. Note that the enumbler still treats it as a `label` column; however it will be saved to the correct place in the database. Your model now can have its own `label` separate from whatever attribute/column was
|
123
|
+
specified for Enumbler usage.
|
112
124
|
|
113
125
|
```ruby
|
114
126
|
ActiveRecord::Schema.define do
|
115
127
|
create_table :feelings, force: true do |t|
|
116
128
|
t.string :emotion, null: false, index: { unique: true }
|
129
|
+
t.string :label
|
117
130
|
end
|
118
131
|
end
|
119
132
|
|
@@ -125,8 +138,15 @@ class Feeling < ApplicationRecord
|
|
125
138
|
|
126
139
|
enumble :sad, 1
|
127
140
|
enumble :happy, 2
|
128
|
-
enumble :verklempt, 3, label: 'overcome with emotion'
|
141
|
+
enumble :verklempt, 3, label: "Verklempt!", emotion: 'overcome with emotion'
|
129
142
|
end
|
143
|
+
|
144
|
+
# Now the `Feeling` model can use `label` if it wants to
|
145
|
+
# and not conflict with Enumbler usage (:emotion in this case)
|
146
|
+
# .enumble.label & .emotion is used internally by Enumbler
|
147
|
+
Feeling.verklempt.label # => 'Verklempt!'
|
148
|
+
Feeling.verklempt.enumble.label # => 'overcome with emotion'
|
149
|
+
Feeling.verklempt.emotion # => 'overcome with emotion'
|
130
150
|
```
|
131
151
|
|
132
152
|
## Core ext
|
@@ -140,6 +160,7 @@ when :black
|
|
140
160
|
when :blue, :purple
|
141
161
|
'very surprised'
|
142
162
|
end
|
163
|
+
```
|
143
164
|
|
144
165
|
## Development
|
145
166
|
|
@@ -149,14 +170,12 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
149
170
|
|
150
171
|
## Roadmap
|
151
172
|
|
152
|
-
*
|
153
|
-
* 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.
|
173
|
+
* 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.color(:blue)`. But right now am in a rush and not sure how to go about doing that properly.
|
154
174
|
|
155
175
|
## Contributing
|
156
176
|
|
157
177
|
Bug reports and pull requests are welcome on GitHub at https://github.com/linguabee/enumbler.
|
158
178
|
|
159
|
-
|
160
179
|
## License
|
161
180
|
|
162
181
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/enumbler.gemspec
CHANGED
@@ -34,8 +34,9 @@ Gem::Specification.new do |spec|
|
|
34
34
|
|
35
35
|
spec.add_development_dependency 'database_cleaner-active_record', '~> 1.8.0'
|
36
36
|
spec.add_development_dependency 'fuubar', '~> 2.5'
|
37
|
+
spec.add_development_dependency 'pry'
|
37
38
|
spec.add_development_dependency 'rake', '~> 12.0'
|
38
39
|
spec.add_development_dependency 'rspec', '~> 3.9.0'
|
39
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
40
|
+
spec.add_development_dependency 'rubocop', '~> 0.91.0'
|
40
41
|
spec.add_development_dependency 'sqlite3', '~> 1.4.0'
|
41
42
|
end
|
data/lib/enumbler/enabler.rb
CHANGED
@@ -126,6 +126,51 @@ module Enumbler
|
|
126
126
|
@enumbler_label_column_name = label_column_name
|
127
127
|
end
|
128
128
|
|
129
|
+
# Like `ActiveRecord#find_by`, will try and return an instance of this
|
130
|
+
# model that matches any of our enumble attributes (instance, id, string,
|
131
|
+
# or symbol).
|
132
|
+
#
|
133
|
+
# Color.find_by_enumble(1)
|
134
|
+
# Color.find_by_enumble(:black)
|
135
|
+
# Color.find_by_enumble("black")
|
136
|
+
# Color.find_by_enumble("BLACK")
|
137
|
+
# Color.find_by_enumble(Color.black) # => self
|
138
|
+
# Color.find_by_enumble("whoops") # => nil
|
139
|
+
#
|
140
|
+
# @param arg [Class, String, Integer, Symbol] search argument
|
141
|
+
# @param case_sensitive [Boolean] string search to be case sensitive (default: false)
|
142
|
+
# @param raise_error [Boolean] whether to raise RecordNotFound error (default: false)
|
143
|
+
# @return [self]
|
144
|
+
def find_by_enumble(arg, case_sensitive: false, raise_error: false)
|
145
|
+
return arg if arg.instance_of?(@enumbled_model)
|
146
|
+
|
147
|
+
id = id_from_enumbler(arg, case_sensitive: case_sensitive, raise_error: raise_error)
|
148
|
+
|
149
|
+
find_by = raise_error ? :find_by! : :find_by
|
150
|
+
@enumbled_model.public_send(find_by, id: id)
|
151
|
+
rescue Enumbler::Error
|
152
|
+
raise ActiveRecord::RecordNotFound.new("Couldn't find #{@enumbled_model}", @enumbled_model)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Like `ActiveRecord#find`, will try and return an instance of this model
|
156
|
+
# that matches any of our enumble attributes (instance, id, string, or
|
157
|
+
# symbol) raises a `RecordNotFound` error if none found.
|
158
|
+
#
|
159
|
+
# Color.find_by_enumble!(1)
|
160
|
+
# Color.find_by_enumble!(:black)
|
161
|
+
# Color.find_by_enumble!("black")
|
162
|
+
# Color.find_by_enumble!("BLACK")
|
163
|
+
# Color.find_by_enumble!(Color.black) # => returns self
|
164
|
+
# Color.find_by_enumble!("whoops") # => raise ActiveRecord::RecordNotFound
|
165
|
+
#
|
166
|
+
# @param arg [Class, String, Integer, Symbol] search argument
|
167
|
+
# @param case_sensitive [Boolean] string search to be case sensitive (default: false)
|
168
|
+
# @param raise_error [Boolean] whether to raise RecordNotFound error (default: false)
|
169
|
+
# @return [self]
|
170
|
+
def find_by_enumble!(arg, case_sensitive: false)
|
171
|
+
find_by_enumble(arg, case_sensitive: case_sensitive, raise_error: true)
|
172
|
+
end
|
173
|
+
|
129
174
|
# See {.find_enumbles}. Simply returns the first object. Use when you
|
130
175
|
# want one argument to be found and not returned in an array.
|
131
176
|
# @raise [Error] when there is no [Enumbler::Enumble] to be found and
|
@@ -330,11 +375,21 @@ module Enumbler
|
|
330
375
|
method_name = "#{enumble.enum}?"
|
331
376
|
not_method_name = "not_#{enumble.enum}?"
|
332
377
|
alias_method_name = "is_#{enumble.enum}"
|
378
|
+
any_method_name = "any_#{enumble.enum}?"
|
379
|
+
|
380
|
+
[method_name, not_method_name, alias_method_name].each do |mname|
|
381
|
+
detect_enumbler_conflict(enumble.enum, mname)
|
382
|
+
end
|
383
|
+
|
384
|
+
[enumble.enum, any_method_name].each do |mname|
|
385
|
+
detect_enumbler_conflict(enumble.enum, mname, klass_method: true)
|
386
|
+
end
|
333
387
|
|
334
388
|
const_set(enumble.enum.to_s.upcase, enumble.id)
|
335
389
|
define_method(method_name) { id == enumble.id }
|
336
390
|
define_method(not_method_name) { id != enumble.id }
|
337
391
|
alias_method alias_method_name, method_name
|
392
|
+
|
338
393
|
define_singleton_method(enumble.enum) do |attr = nil|
|
339
394
|
return find(enumble.id) if attr.nil?
|
340
395
|
|
@@ -343,13 +398,42 @@ module Enumbler
|
|
343
398
|
raise Enumbler::Error, "The attribute #{attr} is not supported on this Enumble."
|
344
399
|
end
|
345
400
|
|
346
|
-
define_singleton_method(
|
401
|
+
define_singleton_method(any_method_name) do
|
347
402
|
where(id: enumble.id).exists?
|
348
403
|
rescue NoMethodError
|
349
404
|
raise Enumbler::Error, "The attribute #{attr} is not supported on this Enumble."
|
350
405
|
end
|
351
406
|
end
|
352
407
|
|
408
|
+
# This idea sourced lovingly from ActiveRecord::Enum
|
409
|
+
ENUMBLER_CONFLICT_MESSAGE = <<~TEXT.squish
|
410
|
+
You tried to define the enumble :%<enum>s on the model %<klass>s, but
|
411
|
+
this will generate a %<type>s method `%<method>s`, which is already defined
|
412
|
+
by %<source>s.
|
413
|
+
TEXT
|
414
|
+
|
415
|
+
def detect_enumbler_conflict(enumble_name, method_name, klass_method: false)
|
416
|
+
if klass_method && dangerous_class_method?(method_name)
|
417
|
+
raise_conflict_error(enumble_name, method_name, type: 'class')
|
418
|
+
elsif klass_method && method_defined_within?(method_name, ActiveRecord::Relation)
|
419
|
+
raise_conflict_error(enumble_name, method_name, type: 'class', source: ActiveRecord::Relation.name)
|
420
|
+
elsif !klass_method && dangerous_attribute_method?(method_name)
|
421
|
+
raise_conflict_error(enumble_name, method_name)
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
def raise_conflict_error(enumble_name, method_name, type: 'instance', source: 'ActiveRecord')
|
426
|
+
raise Error,
|
427
|
+
format(
|
428
|
+
ENUMBLER_CONFLICT_MESSAGE,
|
429
|
+
enum: enumble_name,
|
430
|
+
klass: name,
|
431
|
+
type: type,
|
432
|
+
method: method_name,
|
433
|
+
source: source
|
434
|
+
)
|
435
|
+
end
|
436
|
+
|
353
437
|
# I accidentally forgot to provide an id one time and it was confusing as
|
354
438
|
# the last argument became the hash of options. This should help.
|
355
439
|
def validate_id_is_numeric(enum, id)
|
data/lib/enumbler/enumble.rb
CHANGED
@@ -8,9 +8,10 @@ module Enumbler
|
|
8
8
|
def initialize(enum, id, label: nil, label_column_name: :label, **attributes)
|
9
9
|
@id = id
|
10
10
|
@enum = enum
|
11
|
-
@label = label || enum.to_s.dasherize
|
12
11
|
@label_column_name = label_column_name
|
12
|
+
@label = (label_col_specified? ? attributes[label_column_name] : label) || enum.to_s.dasherize
|
13
13
|
@additional_attributes = attributes || {}
|
14
|
+
@additional_attributes.merge!({ label: label }) if label_col_specified?
|
14
15
|
end
|
15
16
|
|
16
17
|
def ==(other)
|
@@ -19,10 +20,9 @@ module Enumbler
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def attributes
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
})
|
23
|
+
hash = { id: id, label_column_name => label }
|
24
|
+
hash.merge!({ label: @additional_attributes[:label] }) if label_col_specified?
|
25
|
+
@additional_attributes.merge(hash)
|
26
26
|
end
|
27
27
|
|
28
28
|
# Used to return itself from a class method.
|
@@ -50,5 +50,11 @@ module Enumbler
|
|
50
50
|
def to_s
|
51
51
|
enum
|
52
52
|
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def label_col_specified?
|
57
|
+
label_column_name != :label
|
58
|
+
end
|
53
59
|
end
|
54
60
|
end
|
data/lib/enumbler/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: enumbler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damon Timm
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -78,6 +78,20 @@ dependencies:
|
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '2.5'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: pry
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
81
95
|
- !ruby/object:Gem::Dependency
|
82
96
|
name: rake
|
83
97
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,14 +126,14 @@ dependencies:
|
|
112
126
|
requirements:
|
113
127
|
- - "~>"
|
114
128
|
- !ruby/object:Gem::Version
|
115
|
-
version: 0.
|
129
|
+
version: 0.91.0
|
116
130
|
type: :development
|
117
131
|
prerelease: false
|
118
132
|
version_requirements: !ruby/object:Gem::Requirement
|
119
133
|
requirements:
|
120
134
|
- - "~>"
|
121
135
|
- !ruby/object:Gem::Version
|
122
|
-
version: 0.
|
136
|
+
version: 0.91.0
|
123
137
|
- !ruby/object:Gem::Dependency
|
124
138
|
name: sqlite3
|
125
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
198
|
- !ruby/object:Gem::Version
|
185
199
|
version: '0'
|
186
200
|
requirements: []
|
187
|
-
rubygems_version: 3.1.
|
201
|
+
rubygems_version: 3.1.4
|
188
202
|
signing_key:
|
189
203
|
specification_version: 4
|
190
204
|
summary: Enums are terrific, but lack integrity. Let's add some!
|