enumbler 0.6.12 → 0.8.2

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: d88e3b0c2b84e7fc868c0c249f07024410c345c302fb73ce9d258b69c4521d9f
4
- data.tar.gz: 88221bf5dd81bd739e76ee6fafc6d1c7ea88776d5fb2cf63951a685d5ab484fc
3
+ metadata.gz: c19dd611e21b3b0353a89e15197ff4b72fac3ebd779a7d6fcf7b89b1c25d4850
4
+ data.tar.gz: 9f6659abc858f493b8c4575bfa58ee55c517874f56179d40d4b2003d3008690c
5
5
  SHA512:
6
- metadata.gz: fbb8eda79025a550a86ec856eafacd22f120ac980730036e8127f813e915a9239ff6a3277f9f3cd50b60e8013714f162dfe91b455e72a80c15fb58fc7acda405
7
- data.tar.gz: c2c4268c754c0fc957cbe3c6d669e82317c766500ef225c471ddd4e549ba4b6293ffd39ffad0ec42367e6959fd58ef3a3d7f15bf68747809fed9423cb92c5656
6
+ metadata.gz: 8826e464b99c946ea5d2bdc383f0ac92698f6a21737369c65cd6fbb15445fcab75183c57581b0737f6af103e985007070c7189a5eb1da6f4a8e542c4709f0643
7
+ data.tar.gz: 69cfd3a985fb7563c95e96243335aa90e5d945ef8cec911ecf0f2c482806a91080c2224b23ec08780536a0f7dfcaa768787387f40884402192ab44b4ac50b15c
@@ -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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumbler (0.6.12)
4
+ enumbler (0.8.2)
5
5
  activerecord (>= 5.2.3, < 6.1)
6
6
  activesupport (>= 5.2.3, < 6.1)
7
7
 
@@ -19,8 +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)
23
- byebug (11.1.3)
22
+ ast (2.4.1)
23
+ coderay (1.1.2)
24
24
  concurrent-ruby (1.1.6)
25
25
  database_cleaner (1.8.5)
26
26
  database_cleaner-active_record (1.8.0)
@@ -32,13 +32,17 @@ GEM
32
32
  ruby-progressbar (~> 1.4)
33
33
  i18n (1.8.2)
34
34
  concurrent-ruby (~> 1.0)
35
- jaro_winkler (1.5.4)
35
+ method_source (1.0.0)
36
36
  minitest (5.14.1)
37
37
  parallel (1.19.1)
38
- parser (2.7.1.3)
39
- 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)
40
43
  rainbow (3.0.0)
41
44
  rake (12.3.3)
45
+ regexp_parser (1.7.1)
42
46
  rexml (3.2.4)
43
47
  rspec (3.9.0)
44
48
  rspec-core (~> 3.9.0)
@@ -53,14 +57,17 @@ GEM
53
57
  diff-lcs (>= 1.2.0, < 2.0)
54
58
  rspec-support (~> 3.9.0)
55
59
  rspec-support (3.9.3)
56
- rubocop (0.81.0)
57
- jaro_winkler (~> 1.5.1)
60
+ rubocop (0.91.0)
58
61
  parallel (~> 1.10)
59
- parser (>= 2.7.0.1)
62
+ parser (>= 2.7.1.1)
60
63
  rainbow (>= 2.2.2, < 4.0)
64
+ regexp_parser (>= 1.7)
61
65
  rexml
66
+ rubocop-ast (>= 0.4.0, < 1.0)
62
67
  ruby-progressbar (~> 1.7)
63
68
  unicode-display_width (>= 1.4.0, < 2.0)
69
+ rubocop-ast (0.4.0)
70
+ parser (>= 2.7.1.4)
64
71
  ruby-progressbar (1.10.1)
65
72
  sqlite3 (1.4.2)
66
73
  thread_safe (0.3.6)
@@ -73,13 +80,13 @@ PLATFORMS
73
80
  ruby
74
81
 
75
82
  DEPENDENCIES
76
- byebug
77
83
  database_cleaner-active_record (~> 1.8.0)
78
84
  enumbler!
79
85
  fuubar (~> 2.5)
86
+ pry
80
87
  rake (~> 12.0)
81
88
  rspec (~> 3.9.0)
82
- rubocop (~> 0.81.0)
89
+ rubocop (~> 0.91.0)
83
90
  sqlite3 (~> 1.4.0)
84
91
 
85
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).
@@ -32,11 +32,11 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency 'activerecord', ['>= 5.2.3', '< 6.1']
33
33
  spec.add_dependency 'activesupport', ['>= 5.2.3', '< 6.1']
34
34
 
35
- spec.add_development_dependency 'byebug'
36
35
  spec.add_development_dependency 'database_cleaner-active_record', '~> 1.8.0'
37
36
  spec.add_development_dependency 'fuubar', '~> 2.5'
37
+ spec.add_development_dependency 'pry'
38
38
  spec.add_development_dependency 'rake', '~> 12.0'
39
39
  spec.add_development_dependency 'rspec', '~> 3.9.0'
40
- spec.add_development_dependency 'rubocop', '~> 0.81.0'
40
+ spec.add_development_dependency 'rubocop', '~> 0.91.0'
41
41
  spec.add_development_dependency 'sqlite3', '~> 1.4.0'
42
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
@@ -182,6 +227,8 @@ module Enumbler
182
227
  enumble =
183
228
  if arg.is_a?(Symbol)
184
229
  @enumbled_model.enumbles.find { |e| e.enum == arg }
230
+ elsif arg.is_a?(Enumbler::Enumble)
231
+ @enumbled_model.enumbles.find { |e| e.enum == arg.enum }
185
232
  elsif arg.is_a?(String)
186
233
  @enumbled_model.enumbles.find do |e|
187
234
  if case_sensitive
@@ -330,11 +377,21 @@ module Enumbler
330
377
  method_name = "#{enumble.enum}?"
331
378
  not_method_name = "not_#{enumble.enum}?"
332
379
  alias_method_name = "is_#{enumble.enum}"
380
+ any_method_name = "any_#{enumble.enum}?"
381
+
382
+ [method_name, not_method_name, alias_method_name].each do |mname|
383
+ detect_enumbler_conflict(enumble.enum, mname)
384
+ end
385
+
386
+ [enumble.enum, any_method_name].each do |mname|
387
+ detect_enumbler_conflict(enumble.enum, mname, klass_method: true)
388
+ end
333
389
 
334
390
  const_set(enumble.enum.to_s.upcase, enumble.id)
335
391
  define_method(method_name) { id == enumble.id }
336
392
  define_method(not_method_name) { id != enumble.id }
337
393
  alias_method alias_method_name, method_name
394
+
338
395
  define_singleton_method(enumble.enum) do |attr = nil|
339
396
  return find(enumble.id) if attr.nil?
340
397
 
@@ -343,13 +400,42 @@ module Enumbler
343
400
  raise Enumbler::Error, "The attribute #{attr} is not supported on this Enumble."
344
401
  end
345
402
 
346
- define_singleton_method("any_#{enumble.enum}?") do
403
+ define_singleton_method(any_method_name) do
347
404
  where(id: enumble.id).exists?
348
405
  rescue NoMethodError
349
406
  raise Enumbler::Error, "The attribute #{attr} is not supported on this Enumble."
350
407
  end
351
408
  end
352
409
 
410
+ # This idea sourced lovingly from ActiveRecord::Enum
411
+ ENUMBLER_CONFLICT_MESSAGE = <<~TEXT.squish
412
+ You tried to define the enumble :%<enum>s on the model %<klass>s, but
413
+ this will generate a %<type>s method `%<method>s`, which is already defined
414
+ by %<source>s.
415
+ TEXT
416
+
417
+ def detect_enumbler_conflict(enumble_name, method_name, klass_method: false)
418
+ if klass_method && dangerous_class_method?(method_name)
419
+ raise_conflict_error(enumble_name, method_name, type: 'class')
420
+ elsif klass_method && method_defined_within?(method_name, ActiveRecord::Relation)
421
+ raise_conflict_error(enumble_name, method_name, type: 'class', source: ActiveRecord::Relation.name)
422
+ elsif !klass_method && dangerous_attribute_method?(method_name)
423
+ raise_conflict_error(enumble_name, method_name)
424
+ end
425
+ end
426
+
427
+ def raise_conflict_error(enumble_name, method_name, type: 'instance', source: 'ActiveRecord')
428
+ raise Error,
429
+ format(
430
+ ENUMBLER_CONFLICT_MESSAGE,
431
+ enum: enumble_name,
432
+ klass: name,
433
+ type: type,
434
+ method: method_name,
435
+ source: source
436
+ )
437
+ end
438
+
353
439
  # I accidentally forgot to provide an id one time and it was confusing as
354
440
  # the last argument became the hash of options. This should help.
355
441
  def validate_id_is_numeric(enum, id)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumbler
4
- VERSION = '0.6.12'
4
+ VERSION = '0.8.2'
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.12
4
+ version: 0.8.2
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-28 00:00:00.000000000 Z
11
+ date: 2020-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -51,47 +51,47 @@ dependencies:
51
51
  - !ruby/object:Gem::Version
52
52
  version: '6.1'
53
53
  - !ruby/object:Gem::Dependency
54
- name: byebug
54
+ name: database_cleaner-active_record
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
- - - ">="
57
+ - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '0'
59
+ version: 1.8.0
60
60
  type: :development
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - ">="
64
+ - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '0'
66
+ version: 1.8.0
67
67
  - !ruby/object:Gem::Dependency
68
- name: database_cleaner-active_record
68
+ name: fuubar
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: 1.8.0
73
+ version: '2.5'
74
74
  type: :development
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - "~>"
79
79
  - !ruby/object:Gem::Version
80
- version: 1.8.0
80
+ version: '2.5'
81
81
  - !ruby/object:Gem::Dependency
82
- name: fuubar
82
+ name: pry
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
- - - "~>"
85
+ - - ">="
86
86
  - !ruby/object:Gem::Version
87
- version: '2.5'
87
+ version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
90
  version_requirements: !ruby/object:Gem::Requirement
91
91
  requirements:
92
- - - "~>"
92
+ - - ">="
93
93
  - !ruby/object:Gem::Version
94
- version: '2.5'
94
+ version: '0'
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: rake
97
97
  requirement: !ruby/object:Gem::Requirement
@@ -126,14 +126,14 @@ dependencies:
126
126
  requirements:
127
127
  - - "~>"
128
128
  - !ruby/object:Gem::Version
129
- version: 0.81.0
129
+ version: 0.91.0
130
130
  type: :development
131
131
  prerelease: false
132
132
  version_requirements: !ruby/object:Gem::Requirement
133
133
  requirements:
134
134
  - - "~>"
135
135
  - !ruby/object:Gem::Version
136
- version: 0.81.0
136
+ version: 0.91.0
137
137
  - !ruby/object:Gem::Dependency
138
138
  name: sqlite3
139
139
  requirement: !ruby/object:Gem::Requirement
@@ -198,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
198
  - !ruby/object:Gem::Version
199
199
  version: '0'
200
200
  requirements: []
201
- rubygems_version: 3.1.2
201
+ rubygems_version: 3.1.4
202
202
  signing_key:
203
203
  specification_version: 4
204
204
  summary: Enums are terrific, but lack integrity. Let's add some!