passive_record 0.1.0 → 0.1.1
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/README.md +7 -3
- data/lib/passive_record.rb +12 -6
- data/lib/passive_record/hooks.rb +37 -0
- data/lib/passive_record/version.rb +1 -1
- data/spec/passive_record_spec.rb +81 -61
- data/spec/spec_helper.rb +8 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e925955215f05a8a105989c34bbd462e730676b9
|
4
|
+
data.tar.gz: cdc707806939051ec202a2962bef24f88ef4921b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1da3e90a67086a5b536549d46663c6afeb50791f334ddaee2edaf4a4670980fa25ffe10dd49183d4d037dcb261cf0872fa157651c7e2a77c99e15830625d14c3
|
7
|
+
data.tar.gz: 0559e101eff6e7e1dde11ae84bcdedc4f75096889670ce2d1e388afab1a5c63405f8a5b9c685f3e71c28de957b33662b94464c8b9b29a9a171dded3a0208bbe3
|
data/README.md
CHANGED
@@ -15,7 +15,8 @@ We implement a simplified subset of AR's interface in pure Ruby.
|
|
15
15
|
## Why?
|
16
16
|
|
17
17
|
Do you need to track objects by ID and look them up again,
|
18
|
-
or look them up based on attributes,
|
18
|
+
or look them up based on attributes,
|
19
|
+
or even utilize some relational semantics,
|
19
20
|
but have no real need for persistence?
|
20
21
|
|
21
22
|
PassiveRecord may be right for you.
|
@@ -23,10 +24,12 @@ PassiveRecord may be right for you.
|
|
23
24
|
|
24
25
|
## Features
|
25
26
|
|
26
|
-
- Just 'include PassiveRecord' to activate a PORO in the system
|
27
27
|
- New objects are tracked and assigned IDs
|
28
|
-
-
|
28
|
+
- Build relationships with belongs_to, has_one and has_many
|
29
|
+
- Query on attributes and associations
|
30
|
+
- Supports many-to-many and self-referential relationships
|
29
31
|
- No database required!
|
32
|
+
- Just `include PassiveRecord` to activate a PORO in the system
|
30
33
|
|
31
34
|
## Examples
|
32
35
|
|
@@ -70,6 +73,7 @@ PassiveRecord may be right for you.
|
|
70
73
|
|
71
74
|
$ gem install passive_record
|
72
75
|
|
76
|
+
|
73
77
|
## Synopsis
|
74
78
|
|
75
79
|
$ passive_record
|
data/lib/passive_record.rb
CHANGED
@@ -6,6 +6,7 @@ require 'passive_record/core/identifier'
|
|
6
6
|
require 'passive_record/core/query'
|
7
7
|
|
8
8
|
require 'passive_record/associations'
|
9
|
+
require 'passive_record/hooks'
|
9
10
|
|
10
11
|
module PassiveRecord
|
11
12
|
def self.included(base)
|
@@ -52,6 +53,7 @@ module PassiveRecord
|
|
52
53
|
module ClassMethods
|
53
54
|
include PassiveRecord::Core
|
54
55
|
include PassiveRecord::Associations
|
56
|
+
include PassiveRecord::Hooks
|
55
57
|
|
56
58
|
include Enumerable
|
57
59
|
extend Forwardable
|
@@ -76,17 +78,21 @@ module PassiveRecord
|
|
76
78
|
end
|
77
79
|
|
78
80
|
def create(attrs={})
|
79
|
-
|
81
|
+
instance = new
|
80
82
|
|
81
|
-
|
82
|
-
|
83
|
-
register(
|
83
|
+
instance.singleton_class.class_eval { attr_accessor :id }
|
84
|
+
instance.send(:"id=", Identifier.generate)
|
85
|
+
register(instance)
|
84
86
|
|
85
87
|
attrs.each do |(k,v)|
|
86
|
-
|
88
|
+
instance.send("#{k}=", v)
|
87
89
|
end
|
88
90
|
|
89
|
-
|
91
|
+
after_create_hooks.each do |hook|
|
92
|
+
hook.run(instance)
|
93
|
+
end
|
94
|
+
|
95
|
+
instance
|
90
96
|
end
|
91
97
|
|
92
98
|
protected
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module PassiveRecord
|
2
|
+
module Hooks
|
3
|
+
class Hook
|
4
|
+
def initialize(*meth_syms,&blk)
|
5
|
+
@methods_to_call = meth_syms
|
6
|
+
@block_to_invoke = blk
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(instance)
|
10
|
+
@methods_to_call.each do |meth|
|
11
|
+
instance.send(meth)
|
12
|
+
end
|
13
|
+
|
14
|
+
unless @block_to_invoke.nil?
|
15
|
+
instance.instance_eval(&@block_to_invoke)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def hooks
|
21
|
+
@hooks ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def after_hooks
|
25
|
+
hooks[:after] ||= {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def after_create_hooks
|
29
|
+
after_hooks[:create] ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
def after_create(*meth_syms, &blk)
|
33
|
+
hook = Hook.new(*meth_syms,&blk)
|
34
|
+
after_create_hooks.push(hook)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/passive_record_spec.rb
CHANGED
@@ -11,95 +11,115 @@ describe Model do
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
context 'should be enumerable over models' do
|
15
|
+
describe "#count" do
|
16
|
+
it 'should indicate the size of the models list' do
|
17
|
+
expect { SimpleModel.create }.to change { SimpleModel.count }.by(1)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
context 'querying by attributes' do
|
23
|
+
describe "#find_by" do
|
24
|
+
it 'should be retrievable by query' do
|
25
|
+
expect(SimpleModel.find_by(foo: 'foo_value')).to eq(model)
|
26
|
+
end
|
23
27
|
end
|
24
28
|
end
|
25
|
-
end
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
let(:another_child) { Child.create }
|
30
|
+
xcontext 'querying by associations'
|
31
|
+
end
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
context 'hooks' do
|
34
|
+
context 'after create hooks' do
|
35
|
+
it 'should use a symbol to invoke a method' do
|
36
|
+
expect(Child.create.name).to eq("Alice")
|
37
|
+
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
another_dog = another_child.create_dog
|
40
|
-
expect(another_dog.child).to eq(another_child)
|
39
|
+
it 'should use a block' do
|
40
|
+
expect(Parent.create.created_at).to be_a(Time)
|
41
|
+
end
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
context '
|
45
|
-
|
45
|
+
context 'associations' do
|
46
|
+
context 'one-to-one relationships' do
|
47
|
+
let(:child) { Child.create }
|
48
|
+
let(:another_child) { Child.create }
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
+
it 'should create children' do
|
51
|
+
expect { child.create_dog }.to change { Dog.count }.by(1)
|
52
|
+
expect(child.dog).to eq(Dog.first)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should have inverse relationships' do
|
56
|
+
dog = child.create_dog
|
57
|
+
expect(dog.child).to eq(child)
|
58
|
+
another_dog = another_child.create_dog
|
59
|
+
expect(another_dog.child).to eq(another_child)
|
60
|
+
end
|
50
61
|
end
|
51
62
|
|
52
|
-
|
53
|
-
|
54
|
-
|
63
|
+
context 'one-to-many relationships' do
|
64
|
+
let(:parent) { Parent.create }
|
65
|
+
|
66
|
+
it 'should create children' do
|
67
|
+
expect { parent.create_child }.to change{ Child.count }.by(1)
|
68
|
+
expect(parent.children).to all(be_a(Child))
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should create inverse relationships' do
|
72
|
+
child = parent.create_child
|
73
|
+
expect(child.parent).to eq(parent)
|
55
74
|
|
56
|
-
|
57
|
-
|
75
|
+
another_child = parent.create_child
|
76
|
+
expect(another_child.parent).to eq(parent)
|
58
77
|
|
59
|
-
|
60
|
-
|
78
|
+
expect(child.id).not_to eq(another_child.id)
|
79
|
+
expect(parent.children).to eq([child, another_child])
|
80
|
+
end
|
61
81
|
end
|
62
|
-
end
|
63
82
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
83
|
+
context 'one-to-many through relationships' do
|
84
|
+
let(:parent) { Parent.create }
|
85
|
+
let(:child) { parent.create_child }
|
86
|
+
subject(:dogs) { parent.dogs }
|
68
87
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
88
|
+
it 'should collect children of children' do
|
89
|
+
child.create_dog
|
90
|
+
expect(dogs).to all(be_a(Dog))
|
91
|
+
expect(dogs.first).to eq(child.dog)
|
92
|
+
end
|
73
93
|
end
|
74
|
-
end
|
75
94
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
95
|
+
context 'many-to-many' do
|
96
|
+
let(:patient) { Patient.create }
|
97
|
+
let(:doctor) { Doctor.create }
|
98
|
+
let!(:appointment) { Appointment.create(patient: patient, doctor: doctor) }
|
80
99
|
|
81
|
-
|
82
|
-
|
83
|
-
|
100
|
+
it 'should manage many-to-many relations' do
|
101
|
+
expect(appointment.doctor).to eq(doctor)
|
102
|
+
expect(appointment.patient).to eq(patient)
|
84
103
|
|
85
|
-
|
86
|
-
|
104
|
+
expect(patient.doctors).to eq([doctor])
|
105
|
+
expect(doctor.patients).to eq([patient])
|
106
|
+
end
|
87
107
|
end
|
88
|
-
end
|
89
108
|
|
90
|
-
|
91
|
-
|
92
|
-
|
109
|
+
context 'self-referential many-to-many' do
|
110
|
+
let!(:user_a) { User.create }
|
111
|
+
let!(:user_b) { User.create }
|
93
112
|
|
94
|
-
|
95
|
-
|
113
|
+
it 'should permit relations' do
|
114
|
+
expect(user_a.friends).to be_empty
|
96
115
|
|
97
|
-
|
98
|
-
|
99
|
-
|
116
|
+
# need to create bidirectional friendship
|
117
|
+
Friendship.create(user: user_a, friend: user_b)
|
118
|
+
Friendship.create(user: user_b, friend: user_a)
|
100
119
|
|
101
|
-
|
102
|
-
|
120
|
+
expect(user_a.friends).to eq([user_b])
|
121
|
+
expect(user_b.friends).to eq([user_a])
|
122
|
+
end
|
103
123
|
end
|
104
124
|
end
|
105
125
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -17,11 +17,19 @@ end
|
|
17
17
|
class Child < Model
|
18
18
|
has_one :dog
|
19
19
|
belongs_to :parent
|
20
|
+
|
21
|
+
after_create :give_name
|
22
|
+
|
23
|
+
attr_reader :name
|
24
|
+
def give_name; @name = "Alice" end
|
20
25
|
end
|
21
26
|
|
22
27
|
class Parent < Model
|
23
28
|
has_many :children
|
24
29
|
has_many :dogs, :through => :children
|
30
|
+
|
31
|
+
attr_reader :created_at
|
32
|
+
after_create { @created_at = Time.now }
|
25
33
|
end
|
26
34
|
|
27
35
|
###
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passive_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Weissman
|
@@ -141,6 +141,7 @@ files:
|
|
141
141
|
- lib/passive_record/associations/has_one.rb
|
142
142
|
- lib/passive_record/core/identifier.rb
|
143
143
|
- lib/passive_record/core/query.rb
|
144
|
+
- lib/passive_record/hooks.rb
|
144
145
|
- lib/passive_record/hstruct.rb
|
145
146
|
- lib/passive_record/version.rb
|
146
147
|
- passive_record.gemspec
|
@@ -171,4 +172,3 @@ signing_key:
|
|
171
172
|
specification_version: 4
|
172
173
|
summary: no-persistence relational algebra
|
173
174
|
test_files: []
|
174
|
-
has_rdoc:
|