discriminable 2.0.0 → 2.2.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 +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +49 -7
- data/Rakefile +5 -0
- data/TODO.md +5 -1
- data/lib/discriminable/version.rb +1 -1
- data/lib/discriminable.rb +40 -6
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63543cd5b47a63a6870368d2d16c9570e7cd0cebb53cfd296d717884c37fb4c3
|
4
|
+
data.tar.gz: b4417f8e33ff2d24a71a9ec436a26b66c38cab59395ed7fbb1182c818ff48439
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e053310353bf54fcfbef35b32b5de0015f9b28903cb6dc04631bc04cfbaeec274359c0dc34d687eca7a9813eee36590f2c745e90d3c9587e381fceb9bb38886d
|
7
|
+
data.tar.gz: dbf905a1c5a7c7c10154ad5cc9eb73b67d81cd65513e5ac7a1ab33086dbfaee92a885b511942ecc37db4b8528a75283d270ec807db9c4982defb7ba7f2c814a8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [2.2.0](https://github.com/gregorw/discriminable/compare/v2.1.1...v2.2.0) (2022-04-16)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* Alternative syntax respecting open-closed principle ([8a8f885](https://github.com/gregorw/discriminable/commit/8a8f8857dc24753dc08f21b2bfbb7b4317b7ed5c))
|
9
|
+
|
10
|
+
### [2.1.1](https://github.com/gregorw/discriminable/compare/v2.1.0...v2.1.1) (2022-04-15)
|
11
|
+
|
12
|
+
|
13
|
+
### Bug Fixes
|
14
|
+
|
15
|
+
* Subclass is not properly initialized on new objects ([c24706c](https://github.com/gregorw/discriminable/commit/c24706c9e8cd4c80ea20016e341f010a5a3c792b))
|
16
|
+
* Use correct, i.e. first value, when using multiple states for same subclass ([3a05c0d](https://github.com/gregorw/discriminable/commit/3a05c0d3a76080a39f40b1d57ce2862316693f97))
|
17
|
+
|
18
|
+
## [2.1.0](https://github.com/gregorw/discriminable/compare/v2.0.0...v2.1.0) (2022-04-01)
|
19
|
+
|
20
|
+
|
21
|
+
### Features
|
22
|
+
|
23
|
+
* discriminable booleans ([f2ce286](https://github.com/gregorw/discriminable/commit/f2ce2867db9b9f0504474d7237faa9caaab96624))
|
24
|
+
|
3
25
|
## [2.0.0](https://github.com/gregorw/discriminable/compare/v1.0.2...v2.0.0) (2022-03-31)
|
4
26
|
|
5
27
|
|
data/README.md
CHANGED
@@ -1,10 +1,20 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
|
3
3
|
# Discriminable
|
4
4
|
|
5
|
-
|
5
|
+
[](https://rubygems.org/gems/discriminable)
|
6
|
+
[](https://github.com/gregorw/discriminable/actions/workflows/main.yml)
|
7
|
+
[](https://codeclimate.com/github/gregorw/discriminable/maintainability)
|
8
|
+
[](https://codeclimate.com/github/gregorw/discriminable/test_coverage)
|
9
|
+
|
10
|
+
Single table inheritance (STI) for Ruby on Rails models (ActiveRecord) using enum, boolean, string and integer column types.
|
11
|
+
|
12
|
+
In other words, use any _existing_ model attribute for STI instead of storing class names in a `type` column.
|
13
|
+
|
14
|
+
**Related work**
|
15
|
+
|
16
|
+
The idea was originally described in [“Bye Bye STI, Hello Discriminable Model”](https://www.salsify.com/blog/engineering/bye-bye-sti-hello-discriminable-model) by Randy Burkes and this Gem has started out with [his code](https://gist.github.com/rlburkes/798e186acb2f93e787a5).
|
6
17
|
|
7
|
-
TODO: Delete this and the text above, and describe your gem
|
8
18
|
|
9
19
|
## Installation
|
10
20
|
|
@@ -18,13 +28,45 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
18
28
|
|
19
29
|
## Usage
|
20
30
|
|
21
|
-
|
31
|
+
```ruby
|
32
|
+
class Order < ActiveRecord::Base
|
33
|
+
include Discriminable
|
34
|
+
|
35
|
+
enum state: { open: 0, completed: 1 }
|
36
|
+
discriminable state: { open: "Cart" }
|
37
|
+
end
|
38
|
+
|
39
|
+
class Cart < Order
|
40
|
+
end
|
41
|
+
|
42
|
+
Cart.create
|
43
|
+
=> #<Cart id: 1, state: "open">
|
44
|
+
Order.all
|
45
|
+
=> #<ActiveRecord::Relation [#<Cart id: 1, state: "open">]>
|
46
|
+
```
|
47
|
+
|
48
|
+
### Alternative syntax
|
49
|
+
|
50
|
+
Instead of defining subclass names within the parent you may prefer to be open for extension but closed for modification (open-closed principle) using the alternative syntax.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class Order < ActiveRecord::Base
|
54
|
+
include Discriminable
|
55
|
+
|
56
|
+
enum state: { open: 0, completed: 1 }
|
57
|
+
discriminable_by :state
|
58
|
+
end
|
22
59
|
|
23
|
-
|
60
|
+
class Cart < Order
|
61
|
+
discriminable_as :open
|
62
|
+
end
|
24
63
|
|
25
|
-
|
64
|
+
Cart.create
|
65
|
+
=> #<Cart id: 1, state: "open">
|
66
|
+
Order.all
|
67
|
+
=> #<ActiveRecord::Relation [#<Cart id: 1, state: "open">]>
|
68
|
+
```
|
26
69
|
|
27
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
28
70
|
|
29
71
|
## Contributing
|
30
72
|
|
data/Rakefile
CHANGED
data/TODO.md
CHANGED
data/lib/discriminable.rb
CHANGED
@@ -25,7 +25,9 @@ module Discriminable
|
|
25
25
|
|
26
26
|
included do
|
27
27
|
class_attribute :discriminable_map, instance_writer: false
|
28
|
-
class_attribute :
|
28
|
+
class_attribute :discriminable_inverse_map, instance_writer: false
|
29
|
+
class_attribute :discriminable_values, instance_writer: false
|
30
|
+
class_attribute :discriminable_as_descendant_value, instance_writer: false
|
29
31
|
end
|
30
32
|
|
31
33
|
# Specify the column to use for discrimination.
|
@@ -33,18 +35,49 @@ module Discriminable
|
|
33
35
|
def discriminable(**options)
|
34
36
|
raise "Subclasses should not override .discriminable" unless base_class?
|
35
37
|
|
36
|
-
|
38
|
+
attribute, map = options.first
|
37
39
|
|
38
40
|
self.discriminable_map = map.with_indifferent_access
|
39
|
-
|
40
|
-
|
41
|
+
|
42
|
+
# Use first key as default discriminator
|
43
|
+
# { a: "C", b: "C" }.invert => { "C" => :b }
|
44
|
+
# { a: "C", b: "C" }.to_a.reverse.to_h.invert => { "C" => :a }
|
45
|
+
self.discriminable_inverse_map = map.to_a.reverse.to_h.invert
|
46
|
+
self.inheritance_column = attribute.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def discriminable_by(attribute)
|
50
|
+
raise "Subclasses should not override .discriminable_by" unless base_class?
|
51
|
+
|
52
|
+
self.discriminable_as_descendant_value = true
|
53
|
+
self.inheritance_column = attribute.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def discriminable_as(*values)
|
57
|
+
raise "Only subclasses should specify .discriminable_as" if base_class?
|
58
|
+
|
59
|
+
self.discriminable_values = values.map do |value|
|
60
|
+
value.instance_of?(Symbol) ? value.to_s : value
|
61
|
+
end
|
41
62
|
end
|
42
63
|
|
43
64
|
def sti_name
|
44
|
-
|
65
|
+
if discriminable_as_descendant_value
|
66
|
+
self.discriminable_inverse_map ||= Hash.new do |map, value|
|
67
|
+
map[value] = name.constantize.discriminable_values&.first
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
discriminable_inverse_map[name]
|
45
72
|
end
|
46
73
|
|
47
74
|
def sti_class_for(value)
|
75
|
+
if discriminable_as_descendant_value
|
76
|
+
self.discriminable_map ||= Hash.new do |map, v|
|
77
|
+
map[v] = descendants.detect { |d| d.discriminable_values.include? v }&.name
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
48
81
|
return self unless (type_name = discriminable_map[value])
|
49
82
|
|
50
83
|
super type_name
|
@@ -57,7 +90,8 @@ module Discriminable
|
|
57
90
|
attrs = attrs.to_h if attrs.respond_to?(:permitted?)
|
58
91
|
return unless attrs.is_a?(Hash)
|
59
92
|
|
60
|
-
value =
|
93
|
+
value = attrs.with_indifferent_access[inheritance_column]
|
94
|
+
value = base_class.type_for_attribute(inheritance_column).cast(value)
|
61
95
|
sti_class_for(value)
|
62
96
|
end
|
63
97
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: discriminable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregor Wassmann
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.26'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.17.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.17.0
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: sqlite3
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|