passive_record 0.1.6 → 0.1.7

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