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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55e4caeaa0c8dc41e011352ed5931651f3f74d203f54a2a747034c384d065aea
4
- data.tar.gz: 6e772d0c3b1c8c1403298ac244a3aad601d8150497a2a76ca924f2bfecc4a661
3
+ metadata.gz: 012b0ded68a635ef8ac4cb765eec4a648f16a4365abaa1d6def1897d389bcba8
4
+ data.tar.gz: a74d123fa2635a2118e1300cbf75a56d3255756e9bf9384049bb27f74187eb7a
5
5
  SHA512:
6
- metadata.gz: b2312aec90691d56a46e99a89706eca87f82a7b4fd4e9a319e30486daad09554a41d1d40b8daf855fb099d23a4e371a276b94b53d225d782bdd6b1a912845bff
7
- data.tar.gz: 85508fb5286ab683ca10b9ffde36133d52780d5d66cbff40f59ce6b86ef191a7c63f18b6a398a8981f21614e77804c744af7e7efc7853437329d2759ed712011
6
+ metadata.gz: e623093fbb3dbc1645c9d3f713c32100fa561b8ade1a62c03d4da9ae7b6c6a964b45ddcacd4bc158f8c41cc8bdf1150a02c340ce84c9b6e94ec831f798a00a76
7
+ data.tar.gz: '09ef23ba8854c6ff1f01fbffd7e9227e183148acf6a03ce14bd02f0244d9c38f2ef2b9d1e7494320b5b6c8be08849689d1875eff1d68d81545e358299e8ebeb8'
@@ -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
@@ -9,5 +9,6 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ .byebug_history
12
13
 
13
14
  tags*
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.6.11)
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.0)
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
- jaro_winkler (1.5.4)
35
+ method_source (1.0.0)
35
36
  minitest (5.14.1)
36
37
  parallel (1.19.1)
37
- parser (2.7.1.3)
38
- ast (~> 2.4.0)
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.81.0)
56
- jaro_winkler (~> 1.5.1)
60
+ rubocop (0.91.0)
57
61
  parallel (~> 1.10)
58
- parser (>= 2.7.0.1)
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.81.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
- * We need to add in support for additional attributes/columns in the enumbled table. For example, following the `Color` concept, we may want to have a column which is `hex` and stores the colors `hex` value (e.g., `FFFFFF`). This should be supported.
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).
@@ -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.81.0'
40
+ spec.add_development_dependency 'rubocop', '~> 0.91.0'
40
41
  spec.add_development_dependency 'sqlite3', '~> 1.4.0'
41
42
  end
@@ -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("any_#{enumble.enum}?") do
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)
@@ -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
- @additional_attributes.merge({
23
- id: id,
24
- label_column_name => label,
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumbler
4
- VERSION = '0.6.11'
4
+ VERSION = '0.8.1'
5
5
  end
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.6.11
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-09-14 00:00:00.000000000 Z
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.81.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.81.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.2
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!