nummy 0.1.0 → 0.3.0

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: 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