nummy 0.1.0 → 0.3.0

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: d9edb3b21dc12078ceec611949ebf6deb80ed4a69309aaba8a2b01c233025e66
4
- data.tar.gz: e066bb5910d68efdca902e242a1cd9269aecc48b9a77bbf9c246516dc995eb8d
3
+ metadata.gz: 83fe6928d06ebd4ba649eaa37ad3278366e2322a99fe56a7efdfed228b971841
4
+ data.tar.gz: 7116e7d5febca95ae52544bcbc42a4fd99e895ca8e60ef9cd7e3444e6dae8719
5
5
  SHA512:
6
- metadata.gz: 401f6427a1c27596f411cf11c6686a9164aabe06980c6db046887848424f01245921d45f15d01b4938d26a5ccb274e08003b51810073e1ec3cd7e71c0e2f284d
7
- data.tar.gz: 5e3c46a452c2967bc52c1ddf0df5993545af18801a3bbbaead6663fa91e0aa9d61fa87919b7c4c334791a0c7162867d023e4e346200c9d407029fb4e1497da53
6
+ metadata.gz: 4d4bb886ad7d5187aca88391c1e9366a82b4bdb08e435cb5567951a5e2a5e5d230ef5f06cdae0bd5b104c8a62d00e41c437969cf9b9b4a4cf7d5eb41e73dd4ac
7
+ data.tar.gz: dc40fbde79187708d1006bd80475b114f98f8de238faaae8bd4a9b620f5557df06c3d960123e237267041370f59baee13d42e1f4389e97e3394e68fe6e383cfc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,85 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2024-01-04
4
+
5
+ - **Adds additional flexibility to `Nummy::Enum.to_attribute` (#2)
6
+
7
+ This release teaches a few new tricks to `Nummy::Enum.to_attribute`:
8
+
9
+ - it allows passing a block to fully customize how keys are transformed
10
+
11
+ - it looks for `String#underscore` rather than calling into `ActiveSupport::Inflector.underscore` directly, which means that users can bring their own monkey patch if they want to.
12
+
13
+ - it falls back to `Symbol#downcase` if `String#underscore` is not available. If the constants are defined using `SCREAMING_SNAKE_CASE`, this will generally have the same result as calling `String#underscore`, but without requiring ActiveSupport.
14
+
15
+ ```ruby
16
+ class ShippingStatus < Nummy::Enum
17
+ IN_TRANSIT = auto
18
+ OUT_FOR_DELIVERY = auto
19
+ DELIVERED = auto
20
+ end
21
+ ```
22
+
23
+ ```ruby
24
+ # Without ActiveSupport
25
+
26
+ ShippingStatus.to_attribute
27
+ # v0.2.0 (❌)
28
+ # => nummy/lib/nummy/enum.rb:379:in `block in to_attribute': uninitialized constant ActiveSupport (NameError)
29
+ #
30
+ # ::ActiveSupport::Inflector.underscore(key).to_sym
31
+ # ^^^^^^^^^^^^^^^
32
+
33
+ # v0.3.0 (✅)
34
+ # => {:in_transit=>0, :out_for_delivery=>1, :delivered=>2}
35
+ ```
36
+
37
+ ```ruby
38
+ # With ActiveSupport
39
+ require "active_support/core_ext/string/inflections"
40
+
41
+ ShippingStatus.to_attribute
42
+ # => {:in_transit=>0, :out_for_delivery=>1, :delivered=>2}
43
+
44
+ ShippingStatus.to_attribute { |key| key.to_s.underscore.camelize.to_sym }
45
+ # => {:InTransit=>0, :OutForDelivery=>1, :Delivered=>2}
46
+ ```
47
+
48
+ - **Adds JSON serialization support (#3)**
49
+
50
+ This release adds two methods to `Nummy::Enum`: `.as_json` and `.to_json`. These methods allow you to serialize an enum to JSON.
51
+
52
+ ```ruby
53
+ class Status < Nummy::Enum
54
+ ACTIVE = auto
55
+ ARCHIVED = auto
56
+ end
57
+
58
+ Status.as_json
59
+ # => {"ACTIVE" => 0, "ARCHIVED" => 1}
60
+
61
+ Status.to_json
62
+ # => "{\"ACTIVE\":0,\"ARCHIVED\":1}
63
+ ```
64
+
65
+ ## [0.2.0] - 2024-01-04
66
+
67
+ - Add `Nummy::Enum.to_attribute` (#1), which converts the enum to a hash that can be passed as the values of an `ActiveRecord::Enum`:
68
+
69
+ ```ruby
70
+ class Conversation < ActiveRecord::Base
71
+ class Status < Nummy::Enum
72
+ ACTIVE = auto
73
+ ARCHIVED = auto
74
+ end
75
+
76
+ enum :status, Status.to_attribute
77
+ end
78
+ ```
79
+
80
+ > [!IMPORTANT]
81
+ > The conversion requires that `ActiveRecord::Inflector` is defined, but `nummy` does not depend on `ActiveRecord` directly. If you are using `nummy` in a non-Rails environment, you will need to require `ActiveRecord::Inflector` yourself.
82
+
3
83
  ## [0.1.0] - 2024-01-04
4
84
 
5
85
  - Initial release
data/README.md CHANGED
@@ -14,13 +14,13 @@ constants in a module, and iterating over the members of data classes.
14
14
  Install the gem and add to the application's Gemfile by executing:
15
15
 
16
16
  ```console
17
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
17
+ bundle add nummy
18
18
  ```
19
19
 
20
20
  If bundler is not being used to manage dependencies, install the gem by executing:
21
21
 
22
22
  ```console
23
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
23
+ gem install nummy
24
24
  ```
25
25
 
26
26
  ## Usage
@@ -146,6 +146,58 @@ end
146
146
  > [!TIP]
147
147
  > `Nummy::Enum` extends `Enumerable` and iterates over the _values_ of the enum, so you have access to things like `.include?(value)`, `.any?`, and `.find`.
148
148
 
149
+ #### Rails / ActiveRecord integration
150
+
151
+ To use nummy enums as ActiveRecord enums, you can use the `.to_attribute` method, which converts the keys to `snake_case` by default:
152
+
153
+ ```ruby
154
+ class Conversation < ActiveRecord::Base
155
+ class Status < Nummy::Enum
156
+ ACTIVE = auto
157
+ ARCHIVED = auto
158
+ end
159
+
160
+ enum :status, Status.to_attribute
161
+ end
162
+ ```
163
+
164
+ > [!NOTE]
165
+ > `to_attribute` will transform keys using `String#underscore` if it is defined, otherwise it will use `Symbol#downcase`.
166
+
167
+ > [!TIP]
168
+ > You can also do custom transformations by passing a block to `to_attribute`. See the documentation for more details.
169
+
170
+ Using `to_attribute` allows you to use all of the Rails magic for enums, like scopes and boolean helpers, while also being able to refer to values in a safer way than hash lookups.
171
+
172
+ That is, these two are the same:
173
+
174
+ ```ruby
175
+ Conversation.statuses[:active] # => 0
176
+ Conversation::Status::ACTIVE # => 0
177
+ ```
178
+
179
+ But these are not:
180
+
181
+ ```ruby
182
+ Conversation.statuses[:acitve]
183
+ # => nil
184
+
185
+ Conversation::Status::ACITVE # => nil
186
+ # =>
187
+ # uninitialized constant Conversation::Status::ACITVE (NameError)
188
+ # Did you mean? Conversation::Status::ACTIVE
189
+ ```
190
+
191
+ You can get similar behavior using `#fetch`:
192
+
193
+ ```ruby
194
+ Conversation.statuses.fetch(:acitve)
195
+ # => key not found: :acitve (KeyError)
196
+ # Did you mean? :active
197
+ ```
198
+
199
+ But that still misses out on some of the DX benefits of using constants, like improved support for things like autocompletion, documentation, and navigation ("Go To Definition") in editors.
200
+
149
201
  ### `Nummy::MemberEnumerable`
150
202
 
151
203
  `Nummy::MemberEnumerable` is a module that includes `Enumerable` and makes it possible to iterate over any class or module that responds to `members`.
data/lib/nummy/enum.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json"
4
+
3
5
  require "nummy/auto_sequenceable"
4
6
  require "nummy/ordered_const_enumerable"
5
7
  require "nummy/errors"
@@ -354,6 +356,79 @@ module Nummy
354
356
  # Alias to support splatting enums into keyword args.
355
357
  alias to_hash to_h
356
358
 
359
+ # Converts +self+ to a +Hash+ that can be converted to JSON.
360
+ #
361
+ # @return [Hash{String => Object}]
362
+ #
363
+ # @see .to_json
364
+ def as_json
365
+ to_h.transform_keys!(&:to_s)
366
+ end
367
+
368
+ # Converts +self+ to a +Hash+ and serializes it to a JSON string.
369
+ #
370
+ # Supports same options as +JSON#generate+.
371
+ #
372
+ # @return [String]
373
+ #
374
+ # @see .as_json
375
+ def to_json(*)
376
+ as_json.to_json(*)
377
+ end
378
+
379
+ # Converts the enum to a +Hash+ with snake_case keys.
380
+ #
381
+ # This is intended to be used with +ActiveRecord::Enum+, but can be used
382
+ # with any library that supports defining enums using a +Hash+ and expects
383
+ # to have lowercase keys.
384
+ #
385
+ # @overload to_attribute
386
+ # If +String#underscore+ is defined, converts the keys to snake_case
387
+ # by calling +underscore+ on the stringified key.
388
+ #
389
+ # Otherwise, converts each key using +Symbol#downcase+.
390
+ #
391
+ # @return [Hash{Symbol => Object}]
392
+ #
393
+ # @example Using with +ActiveRecord::Enum+.
394
+ # class Conversation < ActiveRecord::Base
395
+ # class Status < Nummy::Enum
396
+ # ACTIVE = auto
397
+ # ARCHIVED = auto
398
+ # end
399
+ #
400
+ # enum :status, Status.to_attribute
401
+ # end
402
+ #
403
+ # @overload to_attribute(&)
404
+ # Transforms the keys by calling the given block on each key.
405
+ #
406
+ # @yieldparam key [Symbol]
407
+ # @return [Hash{Symbol => Object}]
408
+ #
409
+ # @example Using custom key transformer.
410
+ # class ShippingStatus < Nummy::Enum
411
+ # IN_TRANSIT = auto
412
+ # OUT_FOR_DELIVERY = auto
413
+ # DELIVERED = auto
414
+ # end
415
+ #
416
+ # ShippingStatus.to_attribute { |key| key.to_s.underscore.camelize.to_sym }
417
+ # # => {:InTransit=>0, :OutForDelivery=>1, :Delivered=>2}
418
+ def to_attribute(&)
419
+ return to_h.transform_keys!(&) if block_given?
420
+
421
+ # Ignore coverage because it's executed in a forked process, which
422
+ # messes with the coverage collection.
423
+ # :nocov:
424
+ if String.method_defined?(:underscore)
425
+ return to_attribute { |key| key.to_s.underscore.to_sym }
426
+ end
427
+ # :nocov:
428
+
429
+ to_attribute(&:downcase)
430
+ end
431
+
357
432
  # Returns a string representation of +self+.
358
433
  #
359
434
  # The string will contain the name-value pairs of the constants in +self+.
data/lib/nummy/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Nummy
4
4
  # The current version of the gem.
5
- VERSION = "0.1.0"
5
+ VERSION = "0.3.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nummy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Chauvette