passive_record 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -13
- data/lib/passive_record.rb +16 -0
- data/lib/passive_record/associations.rb +10 -0
- data/lib/passive_record/class_methods.rb +13 -10
- data/lib/passive_record/core/identifier.rb +11 -2
- data/lib/passive_record/instance_methods.rb +29 -4
- data/lib/passive_record/pretty_printing.rb +2 -24
- data/lib/passive_record/version.rb +1 -1
- data/passive_record.gemspec +5 -5
- data/spec/passive_record_spec.rb +85 -51
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab5ed84f9328d3e424d8a8d15a29c00f080b78b3
|
4
|
+
data.tar.gz: 2f35779eacb19dc155d895b4a526d988f3eafc7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf7b97feb259d40a4bf9599854c5bbb297aba5cd7c9534547e0d45ee32a4ca80df652667d026786dd12cfad84545745ebd819aa0e9364c5bb59239a44ac07b5d
|
7
|
+
data.tar.gz: 7150fe4460f64351692f83e163b785d36df33eedbcbedb7e0e3c114f43c6c7a836a4ae2f7dbe6c7d818f970d3a8cabfbaaabc957bd4704e3b7e449823c807138
|
data/README.md
CHANGED
@@ -82,19 +82,6 @@ PassiveRecord may be right for you!
|
|
82
82
|
=> [Dog (id: 1)]
|
83
83
|
````
|
84
84
|
|
85
|
-
## Requirements
|
86
|
-
|
87
|
-
## Install
|
88
|
-
|
89
|
-
$ gem install passive_record
|
90
|
-
|
91
|
-
|
92
|
-
## Synopsis
|
93
|
-
|
94
|
-
$ passive_record
|
95
|
-
|
96
85
|
## Copyright
|
97
86
|
|
98
87
|
Copyright (c) 2016 Joseph Weissman
|
99
|
-
|
100
|
-
See {file:LICENSE.txt} for details.
|
data/lib/passive_record.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
1
3
|
require 'active_support'
|
2
4
|
require 'active_support/core_ext/string/inflections'
|
3
5
|
|
@@ -36,4 +38,18 @@ module PassiveRecord
|
|
36
38
|
def self.drop_all
|
37
39
|
(model_classes + model_classes.flat_map(&:descendants)).each(&:destroy_all)
|
38
40
|
end
|
41
|
+
|
42
|
+
def self.configure
|
43
|
+
yield configuration
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.configuration
|
47
|
+
@config ||= default_configuration
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.default_configuration
|
51
|
+
OpenStruct.new(
|
52
|
+
:identify_using => Identifier
|
53
|
+
)
|
54
|
+
end
|
39
55
|
end
|
@@ -10,6 +10,16 @@ module PassiveRecord
|
|
10
10
|
@associations += [assn]
|
11
11
|
end
|
12
12
|
|
13
|
+
def associations_id_syms
|
14
|
+
@associations&.map do |assn|
|
15
|
+
if assn.is_a?(HasOneAssociation) || assn.is_a?(BelongsToAssociation)
|
16
|
+
(assn.target_name_symbol.to_s + "_id").to_sym
|
17
|
+
else # plural ids
|
18
|
+
(assn.target_name_symbol.to_s + "_ids").to_sym
|
19
|
+
end
|
20
|
+
end || []
|
21
|
+
end
|
22
|
+
|
13
23
|
def belongs_to(parent_name_sym, opts={})
|
14
24
|
target_class_name = opts.delete(:class_name) { (parent_name_sym.to_s).split('_').map(&:capitalize).join }
|
15
25
|
association = BelongsToAssociation.new(self, target_class_name, parent_name_sym)
|
@@ -30,12 +30,13 @@ module PassiveRecord
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def find_by(conditions)
|
33
|
-
if conditions.is_a?(
|
34
|
-
|
35
|
-
|
36
|
-
find_by_ids(conditions)
|
37
|
-
else
|
33
|
+
#if conditions.is_a?(Array)
|
34
|
+
# find_by_ids(conditions)
|
35
|
+
if conditions.is_a?(Hash)
|
38
36
|
where(conditions).first
|
37
|
+
else # assume we have an identifier/identifiers
|
38
|
+
find(conditions)
|
39
|
+
# find_by_id(conditions)
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
@@ -55,7 +56,7 @@ module PassiveRecord
|
|
55
56
|
instance = new
|
56
57
|
|
57
58
|
instance.singleton_class.class_eval { attr_accessor :id }
|
58
|
-
instance.send(:"id=",
|
59
|
+
instance.send(:"id=", id_factory.generate(self))
|
59
60
|
|
60
61
|
register(instance)
|
61
62
|
|
@@ -75,9 +76,8 @@ module PassiveRecord
|
|
75
76
|
end
|
76
77
|
|
77
78
|
protected
|
78
|
-
def find_by_id(
|
79
|
-
|
80
|
-
instances_by_id[key] if key
|
79
|
+
def find_by_id(id_to_find)
|
80
|
+
find_by(id: id_to_find)
|
81
81
|
end
|
82
82
|
|
83
83
|
def find_by_ids(ids)
|
@@ -93,6 +93,9 @@ module PassiveRecord
|
|
93
93
|
instances_by_id[model.id] = model
|
94
94
|
self
|
95
95
|
end
|
96
|
-
end
|
97
96
|
|
97
|
+
def id_factory
|
98
|
+
PassiveRecord.configuration.identify_using
|
99
|
+
end
|
100
|
+
end
|
98
101
|
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
module PassiveRecord
|
2
2
|
class Identifier < Struct.new(:value)
|
3
3
|
def self.generate(klass)
|
4
|
-
new(klass
|
5
|
-
|
4
|
+
new(generate_id_value_for(klass))
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.generate_id_value_for(klass)
|
8
|
+
klass.count+1
|
6
9
|
end
|
7
10
|
|
8
11
|
def ==(other_id)
|
@@ -13,4 +16,10 @@ module PassiveRecord
|
|
13
16
|
value
|
14
17
|
end
|
15
18
|
end
|
19
|
+
|
20
|
+
class SecureRandomIdentifier < Identifier
|
21
|
+
def self.generate_id_value_for(*)
|
22
|
+
SecureRandom.uuid
|
23
|
+
end
|
24
|
+
end
|
16
25
|
end
|
@@ -2,6 +2,31 @@ module PassiveRecord
|
|
2
2
|
module InstanceMethods
|
3
3
|
include PrettyPrinting
|
4
4
|
|
5
|
+
def attribute_names
|
6
|
+
attr_names = instance_variables
|
7
|
+
attr_names += self.class.associations_id_syms
|
8
|
+
attr_names += members rescue []
|
9
|
+
attr_names.reject! { |name| name.to_s.start_with?("@_") }
|
10
|
+
attr_names - blacklisted_attribute_names
|
11
|
+
end
|
12
|
+
|
13
|
+
def blacklisted_attribute_names
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
|
17
|
+
# from http://stackoverflow.com/a/8417341/90042
|
18
|
+
def to_h
|
19
|
+
Hash[
|
20
|
+
attribute_names.
|
21
|
+
map do |name| [
|
22
|
+
name.to_s.gsub("@","").to_sym, # key
|
23
|
+
(instance_variable_get(name) rescue send(name))] # val
|
24
|
+
end
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
###
|
29
|
+
|
5
30
|
def respond_to?(meth,*args,&blk)
|
6
31
|
if find_relation_by_target_name_symbol(meth)
|
7
32
|
true
|
@@ -12,7 +37,7 @@ module PassiveRecord
|
|
12
37
|
|
13
38
|
def method_missing(meth, *args, &blk)
|
14
39
|
if (matching_relation = find_relation_by_target_name_symbol(meth))
|
15
|
-
send_relation(matching_relation, meth, *args
|
40
|
+
send_relation(matching_relation, meth, *args)
|
16
41
|
else
|
17
42
|
super(meth,*args,&blk)
|
18
43
|
end
|
@@ -20,7 +45,7 @@ module PassiveRecord
|
|
20
45
|
|
21
46
|
protected
|
22
47
|
|
23
|
-
def send_relation(matching_relation, meth, *args
|
48
|
+
def send_relation(matching_relation, meth, *args)
|
24
49
|
target_name = matching_relation.association.target_name_symbol.to_s
|
25
50
|
|
26
51
|
case meth.to_s
|
@@ -40,9 +65,9 @@ module PassiveRecord
|
|
40
65
|
end
|
41
66
|
|
42
67
|
def relata
|
43
|
-
@_relata ||= self.class.associations
|
68
|
+
@_relata ||= self.class.associations&.map do |assn|
|
44
69
|
assn.to_relation(self)
|
45
|
-
end
|
70
|
+
end || []
|
46
71
|
end
|
47
72
|
|
48
73
|
private
|
@@ -1,33 +1,11 @@
|
|
1
1
|
module PassiveRecord
|
2
2
|
module PrettyPrinting
|
3
3
|
def inspect
|
4
|
-
pretty_vars =
|
4
|
+
pretty_vars = to_h.map do |k,v|
|
5
5
|
"#{k.to_s.gsub(/^\@/,'')}: #{v.inspect}"
|
6
6
|
end.join(', ')
|
7
|
-
"#{self.class.name} (#{pretty_vars})"
|
8
|
-
end
|
9
|
-
|
10
|
-
protected
|
11
|
-
|
12
|
-
def uninspectable_instance_variables
|
13
|
-
[]
|
14
|
-
end
|
15
7
|
|
16
|
-
|
17
|
-
|
18
|
-
def inspectable_instance_variables
|
19
|
-
vars = instance_variables
|
20
|
-
vars += members rescue []
|
21
|
-
vars - uninspectable_instance_variables
|
22
|
-
end
|
23
|
-
|
24
|
-
# from http://stackoverflow.com/a/8417341/90042
|
25
|
-
def instance_variables_hash
|
26
|
-
Hash[
|
27
|
-
inspectable_instance_variables.
|
28
|
-
reject { |sym| sym.to_s.start_with?("@_") }.
|
29
|
-
map { |name| [name, (instance_variable_get(name) rescue send(name))] }
|
30
|
-
]
|
8
|
+
"#{self.class.name} (#{pretty_vars})"
|
31
9
|
end
|
32
10
|
end
|
33
11
|
end
|
data/passive_record.gemspec
CHANGED
@@ -7,12 +7,12 @@ Gem::Specification.new do |gem|
|
|
7
7
|
|
8
8
|
gem.name = gemspec.fetch('name')
|
9
9
|
gem.version = gemspec.fetch('version') do
|
10
|
-
|
11
|
-
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
11
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
require 'passive_record/version'
|
14
|
+
PassiveRecord::VERSION
|
15
|
+
end
|
16
16
|
|
17
17
|
gem.summary = gemspec['summary']
|
18
18
|
gem.description = gemspec['description']
|
data/spec/passive_record_spec.rb
CHANGED
@@ -16,82 +16,95 @@ describe PassiveRecord do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
describe
|
20
|
-
|
19
|
+
describe "passive record models" do
|
20
|
+
context "with a simple model including PR" do
|
21
21
|
let!(:model) { SimpleModel.create(foo: value) }
|
22
22
|
let(:value) { 'foo_value' }
|
23
23
|
|
24
|
-
describe "
|
25
|
-
|
26
|
-
|
24
|
+
describe "instance methods" do
|
25
|
+
describe "#inspect" do
|
26
|
+
it 'should report attribute details' do
|
27
|
+
expect(model.inspect).to eq("SimpleModel (id: #{model.id.inspect}, foo: \"foo_value\")")
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should report relations' do
|
31
|
+
dog = Dog.create
|
32
|
+
expect(dog.inspect).to eq("Dog (id: #{dog.id.inspect}, created_at: #{dog.created_at}, sound: \"bark\", child_id: nil)")
|
33
|
+
end
|
27
34
|
end
|
28
|
-
end
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
36
|
+
describe "#id" do
|
37
|
+
it 'should be retrievable by id' do
|
38
|
+
expect(SimpleModel.find_by(model.id)).to eq(model)
|
39
|
+
end
|
33
40
|
end
|
34
41
|
end
|
35
42
|
|
36
|
-
|
43
|
+
describe "class methods" do
|
44
|
+
describe "#first" do
|
45
|
+
it 'should find the first model' do
|
46
|
+
expect(Model.first).to eq(Model.find(1))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
37
50
|
describe "#count" do
|
38
51
|
it 'should indicate the size of the models list' do
|
39
52
|
expect { SimpleModel.create }.to change { SimpleModel.count }.by(1)
|
40
53
|
end
|
41
54
|
end
|
42
|
-
end
|
43
55
|
|
44
|
-
|
45
|
-
|
46
|
-
|
56
|
+
describe "#create" do
|
57
|
+
it 'should assign attributes' do
|
58
|
+
expect(model.foo).to eq('foo_value')
|
59
|
+
end
|
47
60
|
end
|
48
|
-
end
|
49
61
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
it 'should remove all models' do
|
57
|
-
expect { SimpleModel.destroy_all }.to change { SimpleModel.count }.by(-SimpleModel.count)
|
58
|
-
end
|
59
|
-
end
|
62
|
+
describe "#destroy_all" do
|
63
|
+
before {
|
64
|
+
SimpleModel.create(foo: 'val1')
|
65
|
+
SimpleModel.create(foo: 'val2')
|
66
|
+
}
|
60
67
|
|
61
|
-
|
62
|
-
|
63
|
-
subject(:model) { SimpleModel.create }
|
64
|
-
it 'should lookup a record based on an identifier' do
|
65
|
-
expect(SimpleModel.find(-1)).to eq(nil)
|
66
|
-
expect(SimpleModel.find(model.id)).to eq(model)
|
68
|
+
it 'should remove all models' do
|
69
|
+
expect { SimpleModel.destroy_all }.to change { SimpleModel.count }.by(-SimpleModel.count)
|
67
70
|
end
|
71
|
+
end
|
68
72
|
|
69
|
-
|
70
|
-
|
71
|
-
|
73
|
+
context 'querying by id' do
|
74
|
+
describe "#find" do
|
75
|
+
subject(:model) { SimpleModel.create }
|
76
|
+
it 'should lookup a record based on an identifier' do
|
77
|
+
expect(SimpleModel.find(-1)).to eq(nil)
|
78
|
+
expect(SimpleModel.find(model.id)).to eq(model)
|
79
|
+
end
|
72
80
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
81
|
+
it 'should lookup records based on primary key value' do
|
82
|
+
expect(SimpleModel.find(model.id.value)).to eq(model)
|
83
|
+
end
|
78
84
|
|
79
|
-
|
80
|
-
|
81
|
-
|
85
|
+
it 'should lookup records based on ids' do
|
86
|
+
model_b = SimpleModel.create
|
87
|
+
expect(SimpleModel.find([model.id, model_b.id])).to eq([model, model_b])
|
88
|
+
end
|
82
89
|
end
|
83
90
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
expect{SimpleModel.where(id: 'new_id').create }.to change{SimpleModel.count}.by(1)
|
88
|
-
end
|
91
|
+
describe "#where" do
|
92
|
+
it 'should return a query obj' do
|
93
|
+
expect(SimpleModel.where(id: 'fake_id')).to be_a(PassiveRecord::Core::Query)
|
89
94
|
end
|
90
95
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
context "queries" do
|
97
|
+
describe "#create" do
|
98
|
+
it 'should create objects' do
|
99
|
+
expect{SimpleModel.where(id: 'new_id').create }.to change{SimpleModel.count}.by(1)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#first_or_create" do
|
104
|
+
it 'should create the object or return matching' do
|
105
|
+
expect{SimpleModel.where(id: 'another_id').first_or_create }.to change{SimpleModel.count}.by(1)
|
106
|
+
expect{SimpleModel.where(id: 'another_id').first_or_create }.not_to change{SimpleModel.count}
|
107
|
+
end
|
95
108
|
end
|
96
109
|
end
|
97
110
|
end
|
@@ -257,5 +270,26 @@ describe Model do
|
|
257
270
|
end
|
258
271
|
end
|
259
272
|
end
|
273
|
+
end
|
260
274
|
|
275
|
+
describe "configuration" do
|
276
|
+
describe 'configuring id factory' do
|
277
|
+
context 'with default config' do
|
278
|
+
it 'should generate simple identifiers' do
|
279
|
+
expect(Model.create.id).to be_a(PassiveRecord::Identifier)
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
context 'with a new id factory configured' do
|
284
|
+
before do
|
285
|
+
PassiveRecord.configure do |passive_records|
|
286
|
+
passive_records.identify_using = PassiveRecord::SecureRandomIdentifier
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'should generate uuids' do
|
291
|
+
expect(Model.create.id).to be_a(PassiveRecord::SecureRandomIdentifier)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
261
295
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Weissman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
170
|
version: '0'
|
171
171
|
requirements: []
|
172
172
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
173
|
+
rubygems_version: 2.5.1
|
174
174
|
signing_key:
|
175
175
|
specification_version: 4
|
176
176
|
summary: no-persistence relational algebra
|