enumbler 0.6.11 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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!