passive_record 0.1.6 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1f29ddf4304ae896f01ee7455929a409966799df
4
- data.tar.gz: cfa9db856459164c5864e4df1f2679cf2764a20f
3
+ metadata.gz: bd4210b6d42edbbc3b345887b2a15918d452fdd2
4
+ data.tar.gz: c5c73ddb836c84ceaaf9290e829f7b7d31ae6e20
5
5
  SHA512:
6
- metadata.gz: 0cb01f630b4bf056a4747a0f181afa3bd86859b663c831ef4f845d099d83078cc9fc20eef247ac3a08619fed9bc381996554409c113591cda491c9328817abbe
7
- data.tar.gz: ae8db06335510ad6bb9213e4ce7c6024e85a02a979f0d4d718b1bea05de713a398488b74bd9d3dfdbe678857ad873c34d0c4b38397793c8347a9b98965300ff7
6
+ metadata.gz: c56f0f03af33458ed3a8d0e0d8b8d4795187df9197a71c95625a688f47636b1898c4ce03450142bc4baaedf615c70b34ca075e018e038cdb2731a05e94254f07
7
+ data.tar.gz: 18e488e25f0ad1a0ca791920160bd0fc7f4c3fb49987f1801fa5f1485aa93dd8463ca5cf8be723ae966a5b43544c69c15aa7ea640335aba4342f4dc6780c1f07
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![Code Climate GPA](https://codeclimate.com/github/deepcerulean/passive_record/badges/gpa.svg)](https://codeclimate.com/github/deepcerulean/passive_record)
8
8
  [![Codeship Status for deepcerulean/passive_record](https://www.codeship.io/projects/66bb2d90-ba61-0133-af95-025ac38368ea/status)](https://codeship.com/projects/128700)
9
9
  [![Test Coverage](https://codeclimate.com/github/deepcerulean/passive_record/badges/coverage.svg)](https://codeclimate.com/github/deepcerulean/passive_record/coverage)
10
-
10
+ [![Gem Version](https://badge.fury.io/rb/passive_record.svg)](https://badge.fury.io/rb/passive_record)
11
11
 
12
12
  ## Description
13
13
 
@@ -27,7 +27,6 @@ PassiveRecord may be right for you!
27
27
 
28
28
  ## Features
29
29
 
30
- - New objects are tracked and assigned IDs
31
30
  - Build relationships with belongs_to, has_one and has_many
32
31
  - Query on attributes and associations
33
32
  - Supports many-to-many and self-referential relationships
@@ -0,0 +1,98 @@
1
+ module PassiveRecord
2
+ module ClassMethods
3
+ include PassiveRecord::Core
4
+ include PassiveRecord::Associations
5
+ include PassiveRecord::Hooks
6
+
7
+ include Enumerable
8
+ extend Forwardable
9
+
10
+ # from http://stackoverflow.com/a/2393750/90042
11
+ def descendants
12
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
13
+ end
14
+
15
+ def all
16
+ instances_by_id.values
17
+ end
18
+ def_delegators :all, :each
19
+
20
+ def last
21
+ all.last
22
+ end
23
+
24
+ def find(id_or_ids)
25
+ if id_or_ids.is_a?(Array)
26
+ find_by_ids(id_or_ids)
27
+ else
28
+ find_by_id(id_or_ids)
29
+ end
30
+ end
31
+
32
+ def find_by(conditions)
33
+ if conditions.is_a?(Identifier)
34
+ find_by_id(conditions)
35
+ elsif conditions.is_a?(Array) && conditions.all? { |c| c.is_a?(Identifier) }
36
+ find_by_ids(conditions)
37
+ else
38
+ where(conditions).first
39
+ end
40
+ end
41
+
42
+ def find_all_by(conditions)
43
+ if conditions.is_a?(Array) && conditions.all? { |c| c.is_a?(Identifier) }
44
+ find_by_ids(conditions)
45
+ else
46
+ where(conditions).all
47
+ end
48
+ end
49
+
50
+ def where(conditions)
51
+ Query.new(self, conditions)
52
+ end
53
+
54
+ def create(attrs={})
55
+ instance = new
56
+
57
+ instance.singleton_class.class_eval { attr_accessor :id }
58
+ instance.send(:"id=", Identifier.generate(self))
59
+
60
+ register(instance)
61
+
62
+ attrs.each do |(k,v)|
63
+ instance.send("#{k}=", v)
64
+ end
65
+
66
+ after_create_hooks.each do |hook|
67
+ hook.run(instance)
68
+ end
69
+
70
+ instance
71
+ end
72
+
73
+ def destroy_all
74
+ @instances = {}
75
+ end
76
+
77
+ protected
78
+ def find_by_id(_id)
79
+ key = instances_by_id.keys.detect { |id,_| id == _id }
80
+ instances_by_id[key] if key
81
+ end
82
+
83
+ def find_by_ids(ids)
84
+ instances_by_id.select { |id,_| ids.include?(id) }.values
85
+ end
86
+
87
+ private
88
+ def instances_by_id
89
+ @instances ||= {}
90
+ end
91
+
92
+ def register(model)
93
+ instances_by_id[model.id] = model
94
+ self
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,70 @@
1
+ module PassiveRecord
2
+ module InstanceMethods
3
+ include PrettyPrinting
4
+
5
+ def respond_to?(meth,*args,&blk)
6
+ if find_relation_by_target_name_symbol(meth)
7
+ true
8
+ else
9
+ super(meth,*args,&blk)
10
+ end
11
+ end
12
+
13
+ def method_missing(meth, *args, &blk)
14
+ if (matching_relation = find_relation_by_target_name_symbol(meth))
15
+ send_relation(matching_relation, meth, *args, &blk)
16
+ else
17
+ super(meth,*args,&blk)
18
+ end
19
+ end
20
+
21
+ protected
22
+
23
+ def send_relation(matching_relation, meth, *args, &blk)
24
+ target_name = matching_relation.association.target_name_symbol.to_s
25
+
26
+ case meth.to_s
27
+ when target_name
28
+ matching_relation.lookup
29
+ when "#{target_name}="
30
+ matching_relation.parent_model_id = args.first.id
31
+ when "create_#{target_name}", "create_#{target_name.singularize}"
32
+ matching_relation.create(*args)
33
+ when "#{target_name}_id"
34
+ matching_relation.parent_model_id
35
+ when "#{target_name}_id="
36
+ matching_relation.parent_model_id = args.first
37
+ when "#{target_name}_ids", "#{target_name.singularize}_ids"
38
+ matching_relation.parent_model.send(target_name).map(&:id)
39
+ end
40
+ end
41
+
42
+ def relata
43
+ @_relata ||= self.class.associations.map do |assn|
44
+ assn.to_relation(self)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def find_relation_by_target_name_symbol(meth)
51
+ relata.detect do |relation| # matching relation...
52
+ possible_target_names(relation).include?(meth.to_s)
53
+ end
54
+ end
55
+
56
+ def possible_target_names(relation)
57
+ target_name = relation.association.target_name_symbol.to_s
58
+ [
59
+ target_name,
60
+ "#{target_name}=",
61
+ "#{target_name}_id",
62
+ "#{target_name}_ids",
63
+ "#{target_name.singularize}_ids",
64
+ "#{target_name}_id=",
65
+ "create_#{target_name}",
66
+ "create_#{target_name.singularize}"
67
+ ]
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ module PassiveRecord
2
+ module PrettyPrinting
3
+ def inspect
4
+ pretty_vars = instance_variables_hash.map do |k,v|
5
+ "#{k.to_s.gsub(/^\@/,'')}: #{v.inspect}"
6
+ end.join(', ')
7
+ "#{self.class.name} (#{pretty_vars})"
8
+ end
9
+
10
+ protected
11
+
12
+ def uninspectable_instance_variables
13
+ []
14
+ end
15
+
16
+ private
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
+ ]
31
+ end
32
+ end
33
+ end
@@ -1,4 +1,4 @@
1
1
  module PassiveRecord
2
2
  # passive_record version
3
- VERSION = "0.1.6"
3
+ VERSION = "0.1.7"
4
4
  end
@@ -10,6 +10,11 @@ require 'passive_record/class_inheritable_attrs'
10
10
  require 'passive_record/associations'
11
11
  require 'passive_record/hooks'
12
12
 
13
+ require 'passive_record/pretty_printing'
14
+
15
+ require 'passive_record/instance_methods'
16
+ require 'passive_record/class_methods'
17
+
13
18
  module PassiveRecord
14
19
  def self.included(base)
15
20
  base.send :include, InstanceMethods
@@ -31,165 +36,4 @@ module PassiveRecord
31
36
  def self.drop_all
32
37
  (model_classes + model_classes.flat_map(&:descendants)).each(&:destroy_all)
33
38
  end
34
-
35
- module InstanceMethods
36
- def inspect
37
- pretty_vars = instance_variables_hash.map do |k,v|
38
- "#{k.to_s.gsub(/^\@/,'')}: #{v.inspect}"
39
- end.join(', ')
40
- "#{self.class.name} (#{pretty_vars})"
41
- end
42
-
43
- # from http://stackoverflow.com/a/8417341/90042
44
- def instance_variables_hash
45
- Hash[
46
- instance_variables.
47
- reject { |sym| sym.to_s.start_with?("@_") }.
48
- map { |name| [name, instance_variable_get(name)] }
49
- ]
50
- end
51
-
52
- def relata
53
- @_relata ||= self.class.associations.map do |assn|
54
- assn.to_relation(self)
55
- end
56
- end
57
-
58
-
59
- def find_relation_by_target_name_symbol(meth)
60
- relata.detect do |relation| # matching relation...
61
- meth == relation.association.target_name_symbol ||
62
- meth.to_s == relation.association.target_name_symbol.to_s + "=" ||
63
- meth.to_s == relation.association.target_name_symbol.to_s + "_id" ||
64
- meth.to_s == relation.association.target_name_symbol.to_s + "_id=" ||
65
- meth.to_s == "create_" + relation.association.target_name_symbol.to_s ||
66
- meth.to_s == "create_" + (relation.association.target_name_symbol.to_s).singularize
67
- end
68
- end
69
-
70
- def respond_to?(meth,*args,&blk)
71
- if find_relation_by_target_name_symbol(meth)
72
- true
73
- else
74
- super(meth,*args,&blk)
75
- end
76
- end
77
-
78
- def method_missing(meth, *args, &blk)
79
- matching_relation = find_relation_by_target_name_symbol(meth)
80
-
81
- if matching_relation
82
- if meth.to_s == matching_relation.association.target_name_symbol.to_s + "_id"
83
- matching_relation.parent_model_id
84
- elsif meth.to_s.end_with?("_id=")
85
- matching_relation.parent_model_id = args.first
86
- elsif meth.to_s.end_with?("=")
87
- matching_relation.parent_model_id = args.first.id
88
- elsif meth.to_s.start_with?("create_")
89
- matching_relation.create(*args)
90
- else
91
- # lookup the matching associated entities
92
- matching_relation.lookup
93
- end
94
- else
95
- super(meth,*args,&blk)
96
- end
97
- end
98
- end
99
-
100
- module ClassMethods
101
- include PassiveRecord::Core
102
- include PassiveRecord::Associations
103
- include PassiveRecord::Hooks
104
-
105
- include Enumerable
106
- extend Forwardable
107
-
108
- # from http://stackoverflow.com/a/2393750/90042
109
- def descendants
110
- ObjectSpace.each_object(Class).select { |klass| klass < self }
111
- end
112
-
113
- def all
114
- instances_by_id.values
115
- end
116
- def_delegators :all, :each
117
-
118
- def last
119
- all.last
120
- end
121
-
122
- def find(id_or_ids)
123
- if id_or_ids.is_a?(Array)
124
- find_by_ids(id_or_ids)
125
- else
126
- find_by_id(id_or_ids)
127
- end
128
- end
129
-
130
- def find_by(conditions)
131
- if conditions.is_a?(Identifier)
132
- find_by_id(conditions)
133
- elsif conditions.is_a?(Array) && conditions.all? { |c| c.is_a?(Identifier) }
134
- find_by_ids(conditions)
135
- else
136
- where(conditions).first
137
- end
138
- end
139
-
140
- def find_all_by(conditions)
141
- if conditions.is_a?(Array) && conditions.all? { |c| c.is_a?(Identifier) }
142
- find_by_ids(conditions)
143
- else
144
- where(conditions).all
145
- end
146
- end
147
-
148
- def where(conditions)
149
- Query.new(self, conditions)
150
- end
151
-
152
- def create(attrs={})
153
- instance = new
154
-
155
- instance.singleton_class.class_eval { attr_accessor :id }
156
- instance.send(:"id=", Identifier.generate(self))
157
-
158
- register(instance)
159
-
160
- attrs.each do |(k,v)|
161
- instance.send("#{k}=", v)
162
- end
163
-
164
- after_create_hooks.each do |hook|
165
- hook.run(instance)
166
- end
167
-
168
- instance
169
- end
170
-
171
- def destroy_all
172
- @instances = {}
173
- end
174
-
175
- protected
176
- def find_by_id(_id)
177
- key = instances_by_id.keys.detect { |id,_| id == _id }
178
- instances_by_id[key] if key
179
- end
180
-
181
- def find_by_ids(ids)
182
- instances_by_id.select { |id,_| ids.include?(id) }.values
183
- end
184
-
185
- private
186
- def instances_by_id
187
- @instances ||= {}
188
- end
189
-
190
- def register(model)
191
- instances_by_id[model.id] = model
192
- self
193
- end
194
- end
195
39
  end
@@ -21,6 +21,12 @@ describe Model do
21
21
  let!(:model) { SimpleModel.create(foo: value) }
22
22
  let(:value) { 'foo_value' }
23
23
 
24
+ describe "#inspect" do
25
+ it 'should report attribute details' do
26
+ expect(model.inspect).to eq("SimpleModel (id: 1, foo: \"foo_value\")")
27
+ end
28
+ end
29
+
24
30
  describe "#id" do
25
31
  it 'should be retrievable by id' do
26
32
  expect(SimpleModel.find_by(model.id)).to eq(model)
@@ -69,6 +75,27 @@ describe Model do
69
75
  expect(SimpleModel.find([model.id, model_b.id])).to eq([model, model_b])
70
76
  end
71
77
  end
78
+
79
+ describe "#where" do
80
+ it 'should return a query obj' do
81
+ expect(SimpleModel.where(id: 'fake_id')).to be_a(PassiveRecord::Core::Query)
82
+ end
83
+
84
+ context "queries" do
85
+ describe "#create" do
86
+ it 'should create objects' do
87
+ expect{SimpleModel.where(id: 'new_id').create }.to change{SimpleModel.count}.by(1)
88
+ end
89
+ end
90
+
91
+ describe "#first_or_create" do
92
+ it 'should create the object or return matching' do
93
+ expect{SimpleModel.where(id: 'another_id').first_or_create }.to change{SimpleModel.count}.by(1)
94
+ expect{SimpleModel.where(id: 'another_id').first_or_create }.not_to change{SimpleModel.count}
95
+ end
96
+ end
97
+ end
98
+ end
72
99
  end
73
100
 
74
101
  context 'querying by attributes' do
@@ -157,6 +184,7 @@ describe Model do
157
184
 
158
185
  expect(child.id).not_to eq(another_child.id)
159
186
  expect(parent.children).to eq([child, another_child])
187
+ expect(parent.children_ids).to eq([child.id, another_child.id])
160
188
  end
161
189
  end
162
190
 
@@ -169,6 +197,7 @@ describe Model do
169
197
  expect(parent.dogs).to all(be_a(Dog))
170
198
  expect(parent.dogs.count).to eq(1)
171
199
  expect(parent.dogs.first).to eq(child.dogs.first)
200
+ expect(parent.dog_ids).to eq([child.dogs.first.id])
172
201
  end
173
202
 
174
203
  it 'should do the nested query example from the readme' do
@@ -228,4 +257,5 @@ describe Model do
228
257
  end
229
258
  end
230
259
  end
260
+
231
261
  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.6
4
+ version: 0.1.7
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-21 00:00:00.000000000 Z
11
+ date: 2016-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -140,9 +140,12 @@ files:
140
140
  - lib/passive_record/associations/has_many_through.rb
141
141
  - lib/passive_record/associations/has_one.rb
142
142
  - lib/passive_record/class_inheritable_attrs.rb
143
+ - lib/passive_record/class_methods.rb
143
144
  - lib/passive_record/core/identifier.rb
144
145
  - lib/passive_record/core/query.rb
145
146
  - lib/passive_record/hooks.rb
147
+ - lib/passive_record/instance_methods.rb
148
+ - lib/passive_record/pretty_printing.rb
146
149
  - lib/passive_record/version.rb
147
150
  - passive_record.gemspec
148
151
  - spec/passive_record_spec.rb