nobrainer-references 1.0.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/LICENSE +21 -0
- data/README.md +72 -0
- data/lib/no_brainer/document/references.rb +41 -0
- data/lib/no_brainer/references/eager_loader.rb +61 -0
- data/lib/no_brainer/references/version.rb +7 -0
- data/lib/no_brainer/types/reference.rb +117 -0
- data/lib/nobrainer-references.rb +13 -0
- data/spec/integration/eager_loader_spec.rb +37 -0
- data/spec/integration/reference_spec.rb +57 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/auto_remove_const_in_rspec.rb +12 -0
- data/spec/support/factory_bot.rb +8 -0
- data/spec/support/nobrainer.rb +15 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 65580cce199dbbd155e48df8d0a7bbd3639829306b9b5ff6928030210cd37720
|
4
|
+
data.tar.gz: f1d9e1bde0a355826be32ad48dcccce95cdc236439f71d034b15e49822a7489c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f38850e024055580bbad17616b9348e5c473ab4198b5f4e0aaacab94b2bb6a978fa74705067d81fb2546b70ebdb78c8747fea39f66376786d90a3ebff6b3bb56
|
7
|
+
data.tar.gz: 97bd8654f56171de5ad971b2fc302814efe68fcd5822f4c049b0594504f2eb362f99ed10f727abc2fef89e79ba3aa3eaa1d0cb248deac6533c0cbae2ec779731
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017-2024 Steve Sloan
|
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 all
|
13
|
+
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 THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# NoBrainer References
|
2
|
+
|
3
|
+
An alternative to ActiveRecord-style associations using idiomatic Ruby.
|
4
|
+
|
5
|
+
## Design
|
6
|
+
|
7
|
+
ActiveRecord provides _associations_ between models as a convenient interface to SQL's use of _relations_ between table rows, and NoBrainer matches this functionality. But they are fundamentally different to the way that Ruby and most programming languages store relationships between models: _references_.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add the Ruby gem to your Gemfile:
|
12
|
+
|
13
|
+
$ bundle add nobrainer-references
|
14
|
+
|
15
|
+
## Example
|
16
|
+
|
17
|
+
class Publisher
|
18
|
+
include NoBrainer::Document
|
19
|
+
field :name, type: String
|
20
|
+
end
|
21
|
+
|
22
|
+
class Person
|
23
|
+
include NoBrainer::Document
|
24
|
+
field :name, type: String
|
25
|
+
end
|
26
|
+
|
27
|
+
class Book
|
28
|
+
include NoBrainer::Document
|
29
|
+
field :title, type: String
|
30
|
+
references_many :authors, model: Person
|
31
|
+
references_one :publisher
|
32
|
+
end
|
33
|
+
|
34
|
+
douglas_adams = Person.create!(name: "Douglas Adams")
|
35
|
+
john_lloyd = Person.create!(name: "John Lloyd")
|
36
|
+
publisher = Publisher.create!(name: "Pan Books")
|
37
|
+
book = Book.create!(
|
38
|
+
title: "The Meaning of Liff",
|
39
|
+
authors: [douglas_adams, john_lloyd],
|
40
|
+
publisher: publisher
|
41
|
+
)
|
42
|
+
|
43
|
+
...
|
44
|
+
|
45
|
+
book = Book.where(title: "The Meaning of Liff").first
|
46
|
+
book.publisher.name #=> "Pan Books"
|
47
|
+
book.authors.map(&:name) #=> [ "Douglas Adams", "John Lloyd" ]
|
48
|
+
|
49
|
+
## How It Works
|
50
|
+
|
51
|
+
This gem adds a NoBrainer field type that's a `Reference` to a model of a particular type. This type acts as a lazy-loading _delegator_, which serializes the referred object by its `id` when saving the model, and then later loads that object when it's dereferenced (or is eager-loaded).
|
52
|
+
|
53
|
+
`references_one` and `references_many` are convenience methods for creating fields with the correct types and default names according to convention:
|
54
|
+
|
55
|
+
references_one :publisher
|
56
|
+
# ... same as ...
|
57
|
+
field :publisher, type: Reference.to(Publisher), store_as: 'publishder_id'
|
58
|
+
|
59
|
+
references_many :authors, model: Person
|
60
|
+
# ... same as ...
|
61
|
+
field :authors, type: Array.of(Reference.to(Person)), store_as: 'author_ids'
|
62
|
+
|
63
|
+
It also supports eager-loading of references:
|
64
|
+
|
65
|
+
book = Book.eager_load(:authors, :publisher).where(title: "The Meaning of Liff").first
|
66
|
+
book.authors(&:map) #=> [ "Douglas Adams", "John Lloyd" ]
|
67
|
+
|
68
|
+
## Future Plans
|
69
|
+
|
70
|
+
* Add a `referenced_by` convenience method for tracking which other models/fields reference this one. Provides parity with the ActiveRecord `belongs_to`/`has_many` inverse associations. This would be installed automatically by the `references_one` and `references_many` convenience methods.
|
71
|
+
|
72
|
+
* Use reference tracking to implement garbage collection.
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/dependencies/autoload'
|
4
|
+
require 'active_support/concern'
|
5
|
+
|
6
|
+
require 'no_brainer/types/reference'
|
7
|
+
require 'no_brainer/references/eager_loader'
|
8
|
+
|
9
|
+
module NoBrainer
|
10
|
+
module Document
|
11
|
+
module References
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def references_one(name, model: nil, store_as: nil, inverse: nil, **opts)
|
16
|
+
name = name.to_s
|
17
|
+
store_as ||= "#{name}_id"
|
18
|
+
model ||= name.classify.constantize
|
19
|
+
if model.is_a?(String)
|
20
|
+
name = model
|
21
|
+
model = ->{ const_get(name) }
|
22
|
+
end
|
23
|
+
|
24
|
+
field name.to_sym, type: Reference.to(model), store_as: store_as, **opts
|
25
|
+
end
|
26
|
+
|
27
|
+
def references_many(name, model: nil, store_as: nil, inverse: nil, **opts)
|
28
|
+
name = name.to_s
|
29
|
+
store_as ||= "#{name.singularize}_ids"
|
30
|
+
model ||= name.singularize.classify.constantize
|
31
|
+
if model.is_a?(String)
|
32
|
+
name = model
|
33
|
+
model = ->{ const_get(name) }
|
34
|
+
end
|
35
|
+
|
36
|
+
field name.to_sym, type: Array.of(Reference.to(model)), store_as: store_as, **opts
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'no_brainer/document/association/eager_loader'
|
4
|
+
|
5
|
+
module NoBrainer::Document::References
|
6
|
+
# adapted from NoBrainer::Document::Association::EagerLoader
|
7
|
+
def self.eager_load(docs, field_name, field=nil, criteria=nil)
|
8
|
+
return if docs.blank?
|
9
|
+
|
10
|
+
field_name = field_name.to_sym
|
11
|
+
field ||= docs.first.root_class.fields[field_name]
|
12
|
+
ref_type = field_type = field[:type]
|
13
|
+
if (field_type <= Array) && field_type.respond_to?(:object_type) && (field_type.object_type <= NoBrainer::Reference)
|
14
|
+
ref_type = field_type.object_type
|
15
|
+
end
|
16
|
+
raise TypeError, "#{ref_type} is not a NoBrainer::Reference" unless ref_type <= NoBrainer::Reference
|
17
|
+
model_type = ref_type.model_type
|
18
|
+
|
19
|
+
refs = docs.flat_map { |doc| doc.read_attribute(field_name) }
|
20
|
+
refs.compact!
|
21
|
+
refs.reject!(&:__hasobj__)
|
22
|
+
|
23
|
+
if refs.present?
|
24
|
+
target_key = model_type.table_config.primary_key.to_sym
|
25
|
+
ref_ids = refs.map(&:id).uniq
|
26
|
+
|
27
|
+
query = model_type.without_ordering
|
28
|
+
query = query.merge(criteria) if criteria
|
29
|
+
targets = query.where(target_key.in => ref_ids).group_by(&target_key)
|
30
|
+
refs.each do |ref|
|
31
|
+
if (target = targets[ref.id]&.first)
|
32
|
+
ref.__setobj__(target)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
refs.uniq!
|
36
|
+
end
|
37
|
+
|
38
|
+
docs.select { |doc| Array(doc.read_attribute(field_name)).all?(&:__hasobj__) }
|
39
|
+
end
|
40
|
+
|
41
|
+
module AssociationExt
|
42
|
+
def eager_load_association(docs, association_name, criteria=nil)
|
43
|
+
if (field = docs&.first) && (field = field.root_class.fields[association_name.to_sym]) && field_is_reference_type?(field)
|
44
|
+
NoBrainer::Document::References.eager_load(docs, association_name, field, criteria)
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def field_is_reference_type?(field)
|
53
|
+
field && (type = field[:type]) && (
|
54
|
+
(type <= NoBrainer::Reference) ||
|
55
|
+
(type <= Array && type.respond_to?(:object_type) && (type.object_type <= NoBrainer::Reference))
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
NoBrainer::Document::Association::EagerLoader.extend(self)
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'no_brainer/document'
|
4
|
+
|
5
|
+
module NoBrainer
|
6
|
+
class Reference < SimpleDelegator
|
7
|
+
mattr_accessor :autosave
|
8
|
+
self.autosave = true
|
9
|
+
|
10
|
+
def self.to(model_type = nil, &model_type_proc)
|
11
|
+
raise ArgumentError, "wrong number of arguments (given 2, expect 1)" if model_type && model_type_proc
|
12
|
+
raise ArgumentError, "wrong number of arguments (given 0, expect 1)" unless model_type || model_type_proc
|
13
|
+
if model_type.respond_to?(:call)
|
14
|
+
model_type_proc = model_type
|
15
|
+
model_type = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
if model_type.const_defined?('Reference', !:inherited)
|
19
|
+
return model_type.const_get('Reference', !:inherited)
|
20
|
+
end
|
21
|
+
|
22
|
+
ref_type = if model_type
|
23
|
+
model_type = resolve_model_type(model_type)
|
24
|
+
::Class.new(Reference) { define_singleton_method(:model_type) { model_type } }
|
25
|
+
else
|
26
|
+
# lazy-load model class
|
27
|
+
::Class.new(Reference) { define_singleton_method(:model_type) { @model_type ||= resolve_model_type(model_type_proc) } }
|
28
|
+
end
|
29
|
+
model_type.const_set('Reference', ref_type)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.resolve_model_type(type)
|
33
|
+
type = type.call if type.respond_to?(:call)
|
34
|
+
if type.const_defined?('Reference', !:inherited)
|
35
|
+
return type.const_get('Reference', !:inherited)
|
36
|
+
end
|
37
|
+
unless type < Document
|
38
|
+
raise TypeError, "Expected Document subclass, got #{type.inspect}"
|
39
|
+
end
|
40
|
+
type
|
41
|
+
end
|
42
|
+
private_class_method :resolve_model_type
|
43
|
+
|
44
|
+
def self.name
|
45
|
+
str = "Reference"
|
46
|
+
str += "(#{model_type.name})" if respond_to?(:model_type)
|
47
|
+
str
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :id
|
51
|
+
|
52
|
+
def initialize(id, object = nil)
|
53
|
+
@id = id
|
54
|
+
__setobj__(object) unless object.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
"#<*#{self.class.model_type} " + (
|
59
|
+
__hasobj__ ? __getobj__.inspectable_attributes.map { |k,v| "#{k}: #{v.inspect}" }.join(', ')
|
60
|
+
: "#{self.class.model_type.table_config.primary_key}: #{id.inspect}"
|
61
|
+
) + ">"
|
62
|
+
end
|
63
|
+
|
64
|
+
def dup
|
65
|
+
self.class.new(@id)
|
66
|
+
end
|
67
|
+
alias_method :deep_dup, :dup
|
68
|
+
|
69
|
+
def __getobj__
|
70
|
+
super do
|
71
|
+
if @missing
|
72
|
+
nil
|
73
|
+
elsif @id
|
74
|
+
model = self.class.model_type
|
75
|
+
unless (obj = model.find?(@id))
|
76
|
+
@missing = true
|
77
|
+
raise NoBrainer::Error::MissingAttribute, "#{model} :#{model.pk_name}=>#{@id.inspect} not found"
|
78
|
+
end
|
79
|
+
__setobj__(obj)
|
80
|
+
elsif block_given?
|
81
|
+
yield
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def __hasobj__
|
87
|
+
defined? @delegate_sd_obj
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.nobrainer_cast_user_to_model(value)
|
91
|
+
case value
|
92
|
+
when Reference
|
93
|
+
unless value.class.model_type == model_type
|
94
|
+
raise NoBrainer::Error::InvalidType, "Expected Reference to #{model_type}, got #{value}"
|
95
|
+
end
|
96
|
+
value
|
97
|
+
when model_type
|
98
|
+
new(value.id, value)
|
99
|
+
when nil
|
100
|
+
nil
|
101
|
+
else
|
102
|
+
raise NoBrainer::Error::InvalidType
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.nobrainer_cast_model_to_db(value)
|
107
|
+
value&.save! if value&.new_record? && self.autosave
|
108
|
+
value&.id
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.nobrainer_cast_db_to_model(value)
|
112
|
+
value && new(value)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
Document::Types::Reference = Reference
|
117
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe NoBrainer::Document::References do
|
6
|
+
before(:all) do
|
7
|
+
class Person
|
8
|
+
include NoBrainer::Document
|
9
|
+
field :name, type: String
|
10
|
+
end
|
11
|
+
|
12
|
+
class Post
|
13
|
+
include NoBrainer::Document
|
14
|
+
field :title, type: String
|
15
|
+
field :authors, type: Array.of(Reference.to(Person))
|
16
|
+
field :publisher, type: Reference.to(Person)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "eager loads single reference" do
|
21
|
+
publisher = Person.create!(name: Faker::Name.name)
|
22
|
+
post = Post.create!(title: Faker::Name.name, publisher: publisher)
|
23
|
+
|
24
|
+
post = Post.where(title: post.title).eager_load(:publisher).first
|
25
|
+
expect(Person).not_to receive(:find)
|
26
|
+
expect(post.publisher.name).to eq publisher.name
|
27
|
+
end
|
28
|
+
|
29
|
+
it "eager loads reference array" do
|
30
|
+
bob, doug = Person.create!(name: "Bob"), Person.create!(name: "Doug")
|
31
|
+
post = Post.create!(title: Faker::Name.name, authors: [bob, doug])
|
32
|
+
|
33
|
+
post = Post.where(title: post.title).eager_load(:authors).first
|
34
|
+
expect(Person).not_to receive(:find)
|
35
|
+
expect(post.authors.map(&:name)).to eq [bob, doug].map(&:name)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe NoBrainer::Reference do
|
4
|
+
before(:all) do
|
5
|
+
class Person
|
6
|
+
include NoBrainer::Document
|
7
|
+
field :name, type: String
|
8
|
+
end
|
9
|
+
|
10
|
+
class Post
|
11
|
+
include NoBrainer::Document
|
12
|
+
field :title, type: String
|
13
|
+
field :authors, type: Array.of(Reference.to(Person))
|
14
|
+
field :publisher, type: Reference.to(Person)
|
15
|
+
index :authors, multi: true
|
16
|
+
index :publisher
|
17
|
+
end
|
18
|
+
|
19
|
+
NoBrainer.sync_schema
|
20
|
+
end
|
21
|
+
|
22
|
+
it "references one" do
|
23
|
+
publisher = Person.create!(name: "Marvin")
|
24
|
+
post = Post.create!(title: "Stuff", publisher: publisher)
|
25
|
+
|
26
|
+
post.reload
|
27
|
+
expect(post.publisher.name).to eq publisher.name
|
28
|
+
expect(Post.where(publisher: publisher)).to eq [post]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "references many" do
|
32
|
+
bob, doug = Person.create!(name: "Bob"), Person.create!(name: "Doug")
|
33
|
+
bob_post = Post.create!(title: "Bob Stuff", authors: bob).reload
|
34
|
+
doug_post = Post.create!(title: "Doug Stuff", authors: doug).reload
|
35
|
+
bd_post = Post.create!(title: "Body & Doug Stuff", authors: [bob, doug]).reload
|
36
|
+
db_post = Post.create!(title: "Doug & Bob Stuff", authors: [doug, bob]).reload
|
37
|
+
|
38
|
+
expect(Post.where(:authors.any => bob)).to eq [bob_post, bd_post, db_post]
|
39
|
+
expect(Post.where(:authors.any => doug)).to eq [doug_post, bd_post, db_post]
|
40
|
+
expect(Post.where(:authors.any.in => [bob, doug])).to eq [bob_post, doug_post, bd_post, db_post]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "exception when referenced item is missing" do
|
44
|
+
publisher = Person.create!(name: "Marvin")
|
45
|
+
post = Post.create!(title: "Stuff", publisher: publisher)
|
46
|
+
|
47
|
+
expect(post.publisher).to eq publisher
|
48
|
+
publisher.delete
|
49
|
+
post.reload
|
50
|
+
expect {
|
51
|
+
post.publisher
|
52
|
+
}.to raise_error(NoBrainer::Error::MissingAttribute)
|
53
|
+
|
54
|
+
post.publisher = nil
|
55
|
+
post.save!
|
56
|
+
end
|
57
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.require(:default, :test)
|
4
|
+
|
5
|
+
SPEC_ROOT = File.expand_path File.dirname(__FILE__)
|
6
|
+
Dir["#{SPEC_ROOT}/support/**/*.rb"].each { |f| require f unless File.basename(f) =~ /^_/ }
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.order = :random
|
10
|
+
config.color = true
|
11
|
+
config.expect_with :rspec do |c|
|
12
|
+
c.syntax = :expect
|
13
|
+
end
|
14
|
+
|
15
|
+
if ENV['TRACE']
|
16
|
+
config.before do
|
17
|
+
$trace_file = File.open(ENV['TRACE'], 'w')
|
18
|
+
TracePoint.new(:call, :raise) do |tp|
|
19
|
+
$trace_file.puts "#{tp.event} #{tp.path} #{tp.method_id}:#{tp.lineno}"
|
20
|
+
end.enable
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
config.around(:example, remove_const: true) do |example|
|
3
|
+
const_before = Object.constants
|
4
|
+
|
5
|
+
example.run
|
6
|
+
|
7
|
+
const_after = Object.constants
|
8
|
+
(const_after - const_before).each do |const|
|
9
|
+
Object.send(:remove_const, const)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.configure do |config|
|
2
|
+
config.before(:suite) do
|
3
|
+
NoBrainer.sync_schema
|
4
|
+
NoBrainer.purge!
|
5
|
+
end
|
6
|
+
|
7
|
+
config.after(:suite) do
|
8
|
+
NoBrainer.drop!
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
NoBrainer.configure do |config|
|
13
|
+
config.app_name = 'nobrainer_refs'
|
14
|
+
config.environment = :test
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nobrainer-references
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steve Sloan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-12-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nobrainer
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.44'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.44'
|
27
|
+
description: ''
|
28
|
+
email: steve@finagle.org
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- LICENSE
|
34
|
+
- README.md
|
35
|
+
- lib/no_brainer/document/references.rb
|
36
|
+
- lib/no_brainer/references/eager_loader.rb
|
37
|
+
- lib/no_brainer/references/version.rb
|
38
|
+
- lib/no_brainer/types/reference.rb
|
39
|
+
- lib/nobrainer-references.rb
|
40
|
+
- spec/integration/eager_loader_spec.rb
|
41
|
+
- spec/integration/reference_spec.rb
|
42
|
+
- spec/spec_helper.rb
|
43
|
+
- spec/support/auto_remove_const_in_rspec.rb
|
44
|
+
- spec/support/factory_bot.rb
|
45
|
+
- spec/support/nobrainer.rb
|
46
|
+
homepage: https://github.com/CodeMonkeySteve/nobrainer-references
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
metadata: {}
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 2.7.0
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubygems_version: 3.5.22
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: NoBrainer support for model references
|
69
|
+
test_files:
|
70
|
+
- spec/integration/eager_loader_spec.rb
|
71
|
+
- spec/integration/reference_spec.rb
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
- spec/support/auto_remove_const_in_rspec.rb
|
74
|
+
- spec/support/factory_bot.rb
|
75
|
+
- spec/support/nobrainer.rb
|