predicate_scope 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +76 -0
- data/LICENSE.txt +21 -0
- data/README.md +93 -0
- data/Rakefile +6 -0
- data/bin/setup +8 -0
- data/lib/predicate_scope.rb +144 -0
- data/predicate_scope.gemspec +30 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4303a83687a4e642391b48835df15110a27b8332106b20c3862ae0bb3783cddf
|
4
|
+
data.tar.gz: 90f46bdeb4d84e7845cdba2b261950eb0f6ea307dc03dc6069801050e8d36b33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e866550daef989fa62270f6643d4bde7ef6c0d1a4c4bf873e5e64fa3712b8e33db1533e5cb3ff25ce0c8873d5dbcd5d5f7a2537f0904b53e9421b49b9748140
|
7
|
+
data.tar.gz: f297f94b3beb585607f0a7abb4b72561ecd8a75936d2f8ef8af06fad44b5d00c02546ce3540d096bdfff3fc2361a258ecb0786cdd91aa8d43c5917d0087e9592
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
predicate_scope (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activemodel (7.1.3.2)
|
10
|
+
activesupport (= 7.1.3.2)
|
11
|
+
activerecord (7.1.3.2)
|
12
|
+
activemodel (= 7.1.3.2)
|
13
|
+
activesupport (= 7.1.3.2)
|
14
|
+
timeout (>= 0.4.0)
|
15
|
+
activesupport (7.1.3.2)
|
16
|
+
base64
|
17
|
+
bigdecimal
|
18
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
19
|
+
connection_pool (>= 2.2.5)
|
20
|
+
drb
|
21
|
+
i18n (>= 1.6, < 2)
|
22
|
+
minitest (>= 5.1)
|
23
|
+
mutex_m
|
24
|
+
tzinfo (~> 2.0)
|
25
|
+
base64 (0.2.0)
|
26
|
+
bigdecimal (3.1.7)
|
27
|
+
concurrent-ruby (1.2.3)
|
28
|
+
connection_pool (2.4.1)
|
29
|
+
diff-lcs (1.5.1)
|
30
|
+
drb (2.2.1)
|
31
|
+
i18n (1.14.4)
|
32
|
+
concurrent-ruby (~> 1.0)
|
33
|
+
minitest (5.22.3)
|
34
|
+
mutex_m (0.2.0)
|
35
|
+
rake (13.2.1)
|
36
|
+
rspec (3.13.0)
|
37
|
+
rspec-core (~> 3.13.0)
|
38
|
+
rspec-expectations (~> 3.13.0)
|
39
|
+
rspec-mocks (~> 3.13.0)
|
40
|
+
rspec-core (3.13.0)
|
41
|
+
rspec-support (~> 3.13.0)
|
42
|
+
rspec-expectations (3.13.0)
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
+
rspec-support (~> 3.13.0)
|
45
|
+
rspec-mocks (3.13.0)
|
46
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
47
|
+
rspec-support (~> 3.13.0)
|
48
|
+
rspec-support (3.13.1)
|
49
|
+
sqlite3 (1.7.3-aarch64-linux)
|
50
|
+
sqlite3 (1.7.3-arm-linux)
|
51
|
+
sqlite3 (1.7.3-arm64-darwin)
|
52
|
+
sqlite3 (1.7.3-x86-linux)
|
53
|
+
sqlite3 (1.7.3-x86_64-darwin)
|
54
|
+
sqlite3 (1.7.3-x86_64-linux)
|
55
|
+
timeout (0.4.1)
|
56
|
+
tzinfo (2.0.6)
|
57
|
+
concurrent-ruby (~> 1.0)
|
58
|
+
|
59
|
+
PLATFORMS
|
60
|
+
aarch64-linux
|
61
|
+
arm-linux
|
62
|
+
arm64-darwin
|
63
|
+
x86-linux
|
64
|
+
x86_64-darwin
|
65
|
+
x86_64-linux
|
66
|
+
|
67
|
+
DEPENDENCIES
|
68
|
+
activerecord (~> 7.1)
|
69
|
+
bundler (~> 2.5)
|
70
|
+
predicate_scope!
|
71
|
+
rake (~> 13.2)
|
72
|
+
rspec (~> 3.13)
|
73
|
+
sqlite3 (~> 1.4)
|
74
|
+
|
75
|
+
BUNDLED WITH
|
76
|
+
2.5.10
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Chris Stadler
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# predicate_scope
|
2
|
+
|
3
|
+
Have you ever written code like this?
|
4
|
+
|
5
|
+
```rb
|
6
|
+
class User < ActiveRecord::Base
|
7
|
+
scope :active, -> { where(deleted: false, state: "confirmed") }
|
8
|
+
|
9
|
+
def active?
|
10
|
+
!deleted && state == "confirmed"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
And noticed that the definition of an "active" user is duplicated? What if the
|
16
|
+
definition changes, and you forget to update both places?
|
17
|
+
|
18
|
+
With `predicate_scope` you can write it once:
|
19
|
+
|
20
|
+
```rb
|
21
|
+
class User < ActiveRecord::Base
|
22
|
+
include PredicateScope
|
23
|
+
|
24
|
+
predicate_scope :active, -> { where(deleted: false, state: "confirmed") }
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
This defines two methods:
|
29
|
+
- A `User.active` scope, as if you had used `scope` like normal.
|
30
|
+
- A predicate instance method `User#active?`, which behaves just like the
|
31
|
+
hand-written version of `active?` in the original example:
|
32
|
+
|
33
|
+
```rb
|
34
|
+
user = User.new(deleted: false, state: "confirmed")
|
35
|
+
user.active? # true
|
36
|
+
user.state = "unconfirmed"
|
37
|
+
user.active? # false
|
38
|
+
```
|
39
|
+
|
40
|
+
The predicate method checks the conditions of the scope against the instance _in
|
41
|
+
memory_, without querying the database. Again, just like the hand-written `active?`.
|
42
|
+
|
43
|
+
## Implementation
|
44
|
+
|
45
|
+
In addition to `predicate_scope`, this gem also defines a instance method
|
46
|
+
`#satisfies_conditions_of?`. This takes an `ActiveRecord::Relation` and returns
|
47
|
+
whether the instance it is called on satisfies its conditions. The predicate
|
48
|
+
methods defined by `predicate_scope` call `satisfies_conditions_of?` with the
|
49
|
+
relation from the scope. So in the above example `user.active?` is implemented
|
50
|
+
as `user.satisfies_conditions_of?(User.active)`.
|
51
|
+
|
52
|
+
`satisfies_conditions_of? ` extracts the `Arel` abstract syntax tree (AST)
|
53
|
+
from the given `ActiveRecord::Relation` and interprets its conditions as Ruby
|
54
|
+
predicates. These predicates are evaluated against the instance.
|
55
|
+
|
56
|
+
## Limitations
|
57
|
+
|
58
|
+
Not all `Arel` operations are implemented. If you define
|
59
|
+
a `predicate_scope` that uses an unsupported operation
|
60
|
+
`PredicateScope::Errors::UnsupportedOperation` will be raised when the predicate
|
61
|
+
method is called. PRs to implement additional operations are appreciated!
|
62
|
+
|
63
|
+
## Installation
|
64
|
+
|
65
|
+
Add this line to your application's Gemfile:
|
66
|
+
|
67
|
+
```rb
|
68
|
+
gem 'predicate_scope'
|
69
|
+
```
|
70
|
+
|
71
|
+
And then execute:
|
72
|
+
|
73
|
+
$ bundle
|
74
|
+
|
75
|
+
Or install it yourself as:
|
76
|
+
|
77
|
+
$ gem install predicate_scope
|
78
|
+
|
79
|
+
In any models where you want to use `predicate_scope` add
|
80
|
+
|
81
|
+
```rb
|
82
|
+
include PredicateScope
|
83
|
+
```
|
84
|
+
|
85
|
+
## Contributing
|
86
|
+
|
87
|
+
Bug reports and pull requests are welcome on GitHub at
|
88
|
+
https://github.com/CJStadler/predicate_scope.
|
89
|
+
|
90
|
+
## License
|
91
|
+
|
92
|
+
The gem is available as open source under the terms of the
|
93
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
module PredicateScope
|
2
|
+
VERSION = "0.1.0"
|
3
|
+
|
4
|
+
module Errors
|
5
|
+
class UnsupportedOperation < StandardError
|
6
|
+
def initialize(node)
|
7
|
+
super("Operation node type #{node.class} is not yet supported.")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class UnsupportedAttribute < StandardError
|
12
|
+
def initialize(attribute)
|
13
|
+
super("Attribute type #{attribute.class} is not yet supported.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class UnsupportedInOperand < StandardError
|
18
|
+
def initialize(operand)
|
19
|
+
super("In operations with operand type #{operand.class} are not yet supported.")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class MissingAssociation < StandardError
|
24
|
+
def initialize(table)
|
25
|
+
super("Missing association for table \"#{table}\". You probably need to join it.")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class MultipleCores < StandardError
|
30
|
+
def initialize
|
31
|
+
super("More than one core is not yet supported.")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
def predicate_scope(scope_name, relation_proc, ...)
|
38
|
+
# Add the scope to the class.
|
39
|
+
scope(scope_name, relation_proc, ...)
|
40
|
+
|
41
|
+
# Define the predicate instance method.
|
42
|
+
predicate_name = :"#{scope_name}?"
|
43
|
+
define_method(predicate_name) do |*predicate_args|
|
44
|
+
relation = relation_proc.call(*predicate_args)
|
45
|
+
satisfies_conditions_of?(relation)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Evaluator
|
51
|
+
def initialize(relation, instance)
|
52
|
+
@relation = relation
|
53
|
+
@instance = instance
|
54
|
+
|
55
|
+
@instances_by_table = { instance.class.table_name => instance }
|
56
|
+
associations = relation.values[:joins].to_a.chain(relation.values[:includes].to_a)
|
57
|
+
associations.each do |association_name|
|
58
|
+
object = instance.public_send(association_name)
|
59
|
+
@instances_by_table[object.class.table_name] = object
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def eval
|
64
|
+
cores = @relation.arel.ast.cores
|
65
|
+
if cores.length > 1
|
66
|
+
raise Errors::MultipleCores.new
|
67
|
+
end
|
68
|
+
root = cores.first
|
69
|
+
eval_node(root)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def eval_node(node)
|
75
|
+
case node
|
76
|
+
in Arel::Nodes::SelectCore
|
77
|
+
node.wheres.all? { |node| eval_node(node) }
|
78
|
+
in Arel::Nodes::Not
|
79
|
+
!eval_node(node.expr)
|
80
|
+
in Arel::Nodes::And
|
81
|
+
node.children.all? { |child| eval_node(child) }
|
82
|
+
in Arel::Nodes::Or
|
83
|
+
eval_node(node.left) || eval_node(node.right)
|
84
|
+
# This is used with `or` but I don't know what it represents.
|
85
|
+
in Arel::Nodes::Grouping
|
86
|
+
eval_node(node.expr)
|
87
|
+
in Arel::Nodes::In
|
88
|
+
attribute_value = eval_attribute(node.left)
|
89
|
+
if node.right.is_a?(Enumerable)
|
90
|
+
node.right.any? { |value| value == attribute_value }
|
91
|
+
else
|
92
|
+
raise Errors::UnsupportedInOperand.new(node.right)
|
93
|
+
end
|
94
|
+
in Arel::Nodes::HomogeneousIn
|
95
|
+
attribute_value = eval_attribute(node.attribute)
|
96
|
+
node.values.any? { |value| value == attribute_value }
|
97
|
+
in Arel::Nodes::Equality
|
98
|
+
eval_comparison(node, :==)
|
99
|
+
in Arel::Nodes::NotEqual
|
100
|
+
eval_comparison(node, :!=)
|
101
|
+
in Arel::Nodes::GreaterThan
|
102
|
+
eval_comparison(node, :>)
|
103
|
+
in Arel::Nodes::LessThan
|
104
|
+
eval_comparison(node, :<)
|
105
|
+
in Arel::Nodes::GreaterThanOrEqual
|
106
|
+
eval_comparison(node, :>=)
|
107
|
+
in Arel::Nodes::LessThanOrEqual
|
108
|
+
eval_comparison(node, :<=)
|
109
|
+
else
|
110
|
+
raise Errors::UnsupportedOperation.new(node)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def eval_comparison(node, operator)
|
115
|
+
eval_attribute(node.left).public_send(operator, eval_attribute(node.right))
|
116
|
+
end
|
117
|
+
|
118
|
+
def eval_attribute(attribute)
|
119
|
+
case attribute
|
120
|
+
in Arel::Attributes::Attribute
|
121
|
+
table_name = attribute.relation.name
|
122
|
+
instance = @instances_by_table[table_name]
|
123
|
+
|
124
|
+
if instance
|
125
|
+
instance.public_send(attribute.name)
|
126
|
+
else
|
127
|
+
raise Errors::MissingAssociation.new(table_name)
|
128
|
+
end
|
129
|
+
in ActiveRecord::Relation::QueryAttribute | Arel::Nodes::Casted
|
130
|
+
attribute.value
|
131
|
+
else
|
132
|
+
raise Errors::UnsupportedAttribute.new(attribute)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.included(klass)
|
138
|
+
klass.extend(ClassMethods)
|
139
|
+
end
|
140
|
+
|
141
|
+
def satisfies_conditions_of?(relation)
|
142
|
+
Evaluator.new(relation, self).eval
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "predicate_scope"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "predicate_scope"
|
8
|
+
spec.version = PredicateScope::VERSION
|
9
|
+
spec.authors = ["Chris Stadler"]
|
10
|
+
spec.email = ["chrisstadler@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = 'Check whether an ActiveRecord instance satisfies the conditions of a relation, in memory'
|
13
|
+
spec.homepage = "https://github.com/CJStadler/predicate_scope"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.required_ruby_version = ">= 3.0"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 2.5"
|
26
|
+
spec.add_development_dependency "rake", "~> 13.2"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.13"
|
28
|
+
spec.add_development_dependency "activerecord", "~> 7.1"
|
29
|
+
spec.add_development_dependency "sqlite3", "~> 1.4" # activerecord seems to require this version.
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: predicate_scope
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Stadler
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13.2'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.13'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.13'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activerecord
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '7.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '7.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.4'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.4'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- chrisstadler@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
93
|
+
- Gemfile
|
94
|
+
- Gemfile.lock
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- bin/setup
|
99
|
+
- lib/predicate_scope.rb
|
100
|
+
- predicate_scope.gemspec
|
101
|
+
homepage: https://github.com/CJStadler/predicate_scope
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '3.0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubygems_version: 3.5.10
|
121
|
+
signing_key:
|
122
|
+
specification_version: 4
|
123
|
+
summary: Check whether an ActiveRecord instance satisfies the conditions of a relation,
|
124
|
+
in memory
|
125
|
+
test_files: []
|