nobrainer-references 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|