literal_enums-rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 01da8c12a247c4aea59cfc6595f4f5f9b5c8dd69ebdab550ba86ac7f0c5508c7
4
+ data.tar.gz: 4d813f97175ce52f2fe87b2accaa6e0897fc7c78c4d1e9e0b8e8e4c774e9a6ae
5
+ SHA512:
6
+ metadata.gz: 15677e95690ef2605599bb96102a0223e0b2db9c9a78b93f4b627221ff359b15decdcbd5e4360ec0d2d21b9ad3d8179613c3a33b7aeb014f64ef64331d1f10f8
7
+ data.tar.gz: 1ee2822126919e1c1b02205378bb860116d92613eeaac2d6528aca97e0ee30ce8b98ea018b034c3f44bed8989a3fc51fb83cf5938e1dd7f4ceedc9d0d6f224fe
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Joel Drapper
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # literal_enums-rails
2
+
3
+ Provides additional support for Rails with LiteralEnums.
4
+
5
+ ## Usage
6
+ Please see `literal_enums` for further documentaiton.
7
+
8
+ ### ActiveJob
9
+
10
+ Literal Enums are automatically serialised and deserialised for ActiveJob. You don't need to do anythign special to enable this. Just treat enums are normal arguments.
11
+
12
+ ### ActiveModel
13
+
14
+ You can add Enum attributes to any `ActiveModel` class as an `attribute`.
15
+
16
+ ```ruby
17
+ class Article < ApplicationRecord
18
+ class State < Enum
19
+ Published()
20
+ Unpublished()
21
+ end
22
+
23
+ attribute :state, Enum[State]
24
+ end
25
+ ```
26
+
27
+ Note: you need to specify exactly which Enum class the attribute is expected to be. This is so it can deserialise and cast a value to the correct member.
28
+
29
+ If you're storing the values in a database, make sure the tyep of the value matches the type of the database field. If the members don't specify values, their names will be used instead.
30
+
31
+ These are not the same as Rails enums as they don't add mysterious scopes and predicates to the model itself.
32
+
33
+ Instead of asking the Article if it is published, you'd need to inspect the Article's state attribute directly.
34
+
35
+ You can do this with a comparator e.g. `==` or with a polymorphic predicate.
36
+
37
+ ```ruby
38
+ # The Rails way
39
+ Article.published?
40
+
41
+ # The Literal Enums way
42
+ Article.state.published?
43
+ ```
44
+
45
+ Scoping the predicate to the state attribute itself reduces the risk of collision. It also means the enum makes no assumptions about the business logic of your model. It may not be the case that whole article is published because the state is published.
46
+
47
+ You can use Enums like any other value when writing database queries in ActiveRecord. For example, you might define a scope like this:
48
+
49
+ ```ruby
50
+ scope :published -> { where(state: State::Published, publish_at: ..Time.current) }
51
+ ```
52
+
53
+ You can also define associations from an enum to relevant records.
54
+
55
+ ```ruby
56
+ class Article < ApplicationRecord
57
+ class State < Enum
58
+ Published()
59
+ Unpublished()
60
+
61
+ has_many :articles
62
+ end
63
+
64
+ attribute :state, Enum[State]
65
+ end
66
+
67
+ Article::State::Published.articles # returns a relation to articles with the Published state.
68
+ ```
69
+
70
+ `has_many` optionally accepts a `class_name` for the model to query, as well as the name of the enum attribute.
71
+
72
+ ```ruby
73
+ has_many :publication_events, class_name: "ArticlePublicationEvent", as: :publication_status
74
+
75
+ # Translates to this
76
+ def self.publication_events
77
+ ArticlePublicationEvent.where(publication_status: self)
78
+ end
79
+ ```
80
+
81
+ ## Installation
82
+ Add this line to your application's Gemfile:
83
+
84
+ ```ruby
85
+ gem "literal_enums-rails"
86
+ ```
87
+
88
+ And then execute:
89
+ ```bash
90
+ $ bundle
91
+ ```
92
+
93
+ Or install it yourself as:
94
+ ```bash
95
+ $ gem install literal_enums-rails
96
+ ```
97
+
98
+ ## Contributing
99
+ Contribution directions go here.
100
+
101
+ ## License
102
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ class Enum
2
+ extend LiteralEnums::Rails::Associations
3
+
4
+ def self.[](enum)
5
+ LiteralEnums::Rails::EnumType.new(enum)
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ module LiteralEnums
2
+ module Rails
3
+ module Associations
4
+ private
5
+
6
+ def has_many(name, class_name: nil, as: nil)
7
+ class_name ||= name.to_s.classify
8
+ full_class_name = class_name.constantize.name
9
+ foreign_key = as || relative_foreign_key(self.name, relative_to: full_class_name)
10
+
11
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
12
+ def #{name}
13
+ #{class_name}.where(#{foreign_key}: self)
14
+ end
15
+ RUBY
16
+ end
17
+
18
+ def relative_foreign_key(name, relative_to:)
19
+ path = name.split("::")
20
+ other_path = relative_to.split("::")
21
+
22
+ path
23
+ .zip(other_path)
24
+ .drop_while { |a, b| a == b }
25
+ .transpose
26
+ .first
27
+ &.join("_")
28
+ &.underscore()
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ module LiteralEnums
2
+ module Rails
3
+ class EnumSerializer < ::ActiveJob::Serializers::ObjectSerializer
4
+ def serialize?(object)
5
+ object.is_a? Enum
6
+ end
7
+
8
+ def serialize(enum)
9
+ super(
10
+ {
11
+ "class" => enum.class.name,
12
+ "value" => enum.value
13
+ }
14
+ )
15
+ end
16
+
17
+ def deserialize(hash)
18
+ hash["class"].constantize.cast(hash["value"])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module LiteralEnums
2
+ module Rails
3
+ class EnumType < ActiveModel::Type::String
4
+ def initialize(enum)
5
+ @enum = enum
6
+ end
7
+
8
+ def type
9
+ :enum
10
+ end
11
+
12
+ def cast_value(value)
13
+ return value if value.is_a?(@enum)
14
+ @enum.cast(value)
15
+ end
16
+
17
+ def serialize(value)
18
+ value.value
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ module LiteralEnums
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ initializer "literal_enums.configure_active_job_serializers" do
5
+ ::Rails.application.config.active_job.custom_serializers << EnumSerializer
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module LiteralEnums
2
+ module Rails
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ require "literal_enums/rails/version"
2
+ require "literal_enums/rails/enum_type"
3
+ require "literal_enums/rails/enum_serializer"
4
+ require "literal_enums/rails/associations"
5
+ require "literal_enums/rails/railtie"
6
+ require "literal_enums/enum"
7
+
8
+ module LiteralEnums
9
+ module Rails
10
+ # Your code goes here...
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :literal_enums_rails do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: literal_enums-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Joel Drapper
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-03-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: literal_enums
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mocha
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.13.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.13.0
55
+ description: Rails support for Literal Enums.
56
+ email:
57
+ - joel@drapper.me
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/literal_enums/enum.rb
66
+ - lib/literal_enums/rails.rb
67
+ - lib/literal_enums/rails/associations.rb
68
+ - lib/literal_enums/rails/enum_serializer.rb
69
+ - lib/literal_enums/rails/enum_type.rb
70
+ - lib/literal_enums/rails/railtie.rb
71
+ - lib/literal_enums/rails/version.rb
72
+ - lib/tasks/literal_enums/rails_tasks.rake
73
+ homepage: https://github.com/joeldrapper/literal_enums-rails
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ homepage_uri: https://github.com/joeldrapper/literal_enums-rails
78
+ source_code_uri: https://github.com/joeldrapper/literal_enums-rails
79
+ changelog_uri: https://github.com/joeldrapper/literal_enums-rails
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 3.3.7
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Literal Enums in Rails.
99
+ test_files: []