rufus-doric 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +9 -1
- data/TODO.txt +1 -1
- data/lib/rufus/doric/model.rb +117 -16
- data/lib/rufus/doric/models.rb +4 -0
- data/lib/rufus/doric/version.rb +1 -1
- data/rufus-doric.gemspec +5 -3
- data/test/ut_1_model.rb +23 -0
- data/test/ut_6_model_associations.rb +21 -10
- data/test/ut_7_looser_associations.rb +104 -0
- data/test/ut_8_belongings.rb +92 -0
- metadata +5 -3
data/CHANGELOG.txt
CHANGED
@@ -2,7 +2,15 @@
|
|
2
2
|
= rufus-doric CHANGELOG.txt
|
3
3
|
|
4
4
|
|
5
|
-
== rufus-doric - 0.1.
|
5
|
+
== rufus-doric - 0.1.2 released 2010/03/23
|
6
|
+
|
7
|
+
- person.belongings() returns all the object whose person_id is person._id
|
8
|
+
- multi-class associations : owner.vehicles.collect &class #=> [ Car, Boat ]
|
9
|
+
- introduced the Rufus::Doric.types hash ({ 'car' => MyDomain::Car })
|
10
|
+
- added property as an alias to h_accessor
|
11
|
+
|
12
|
+
|
13
|
+
== rufus-doric - 0.1.1 released 2010/03/22
|
6
14
|
|
7
15
|
- associations are in (_id[s]) for Model
|
8
16
|
- equality and hash for Model
|
data/TODO.txt
CHANGED
data/lib/rufus/doric/model.rb
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
# Made in Japan.
|
23
23
|
#++
|
24
24
|
|
25
|
-
|
25
|
+
require 'cgi'
|
26
26
|
|
27
27
|
|
28
28
|
module Rufus
|
@@ -41,6 +41,39 @@ module Doric
|
|
41
41
|
}
|
42
42
|
}
|
43
43
|
|
44
|
+
# Returns a hash of all the types (models) seen/registered.
|
45
|
+
#
|
46
|
+
# For example, after this class definition :
|
47
|
+
#
|
48
|
+
# class Concept < Rufus::Doric::Model
|
49
|
+
# db :doric
|
50
|
+
# doric_type :concepts
|
51
|
+
# _id_field :name
|
52
|
+
# property :name
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# this
|
56
|
+
#
|
57
|
+
# p Rufus::Doric.types
|
58
|
+
#
|
59
|
+
# will yield
|
60
|
+
#
|
61
|
+
# {"concepts"=>Concept}
|
62
|
+
#
|
63
|
+
def self.types
|
64
|
+
|
65
|
+
(@types ||= {})
|
66
|
+
end
|
67
|
+
|
68
|
+
# Given a document (a Hash instance), will look at its 'doric_type' and
|
69
|
+
# return an instance of a Rufus::Doric::Model or nil if there is
|
70
|
+
# no model defined for that doric_type
|
71
|
+
#
|
72
|
+
def self.instantiate (doc)
|
73
|
+
|
74
|
+
(types[doc['doric_type']].new(doc) rescue nil)
|
75
|
+
end
|
76
|
+
|
44
77
|
#
|
45
78
|
# Classes extending that class have 1 Couch document per instance
|
46
79
|
#
|
@@ -54,7 +87,11 @@ module Doric
|
|
54
87
|
|
55
88
|
def self.doric_type (rt=nil)
|
56
89
|
|
57
|
-
|
90
|
+
if rt
|
91
|
+
@doric_type = rt.to_s
|
92
|
+
Rufus::Doric.types[@doric_type] = self
|
93
|
+
end
|
94
|
+
|
58
95
|
@doric_type
|
59
96
|
end
|
60
97
|
|
@@ -179,6 +216,62 @@ module Doric
|
|
179
216
|
delete
|
180
217
|
end
|
181
218
|
|
219
|
+
# Returns all the other objects in the same db that have a {something}_id
|
220
|
+
# pointing to this object.
|
221
|
+
#
|
222
|
+
# For example, given
|
223
|
+
#
|
224
|
+
# Person.new(
|
225
|
+
# :name => 'friedrisch', :vehicle_id => 'GE1212'
|
226
|
+
# ).save!
|
227
|
+
#
|
228
|
+
# Book.new(
|
229
|
+
# :description => 'romance of the three kingdoms',
|
230
|
+
# :person_id => 'friedrisch'
|
231
|
+
# ).save!
|
232
|
+
# Computer.new(
|
233
|
+
# :description => 'black macbook',
|
234
|
+
# :person_id => 'friedrisch'
|
235
|
+
# ).save!
|
236
|
+
#
|
237
|
+
# then
|
238
|
+
#
|
239
|
+
# f = Person.find('friedrisch')
|
240
|
+
# p f.belongings.map { |b| b.class.name }.sort)
|
241
|
+
#
|
242
|
+
# will print
|
243
|
+
#
|
244
|
+
# ["Book", "Computer"]
|
245
|
+
#
|
246
|
+
def belongings
|
247
|
+
|
248
|
+
dd = db.get('_design/doric') || DORIC_DESIGN_DOC
|
249
|
+
|
250
|
+
s = self.class.doric_type.singularize
|
251
|
+
|
252
|
+
view = "by_#{s}_id"
|
253
|
+
|
254
|
+
unless dd['views'][view]
|
255
|
+
|
256
|
+
dd['views'][view] = {
|
257
|
+
'map' => %{
|
258
|
+
function (doc) {
|
259
|
+
if (doc.doric_type && doc.#{s}_id) emit(doc.#{s}_id, null);
|
260
|
+
}
|
261
|
+
}
|
262
|
+
}
|
263
|
+
db.put(dd)
|
264
|
+
end
|
265
|
+
|
266
|
+
i = CGI.escape(Rufus::Json.encode(_id))
|
267
|
+
|
268
|
+
result = db.get("_design/doric/_view/#{view}?key=#{i}&include_docs=true")
|
269
|
+
|
270
|
+
result['rows'].collect { |r| Rufus::Doric.instantiate(r['doc']) }
|
271
|
+
end
|
272
|
+
|
273
|
+
# All the association magic occur here, except for #belongings
|
274
|
+
#
|
182
275
|
def method_missing (m, *args)
|
183
276
|
|
184
277
|
mm = m.to_s
|
@@ -188,10 +281,30 @@ module Doric
|
|
188
281
|
klass = sm.camelize
|
189
282
|
klass = (self.class.const_get(klass) rescue nil)
|
190
283
|
|
191
|
-
return super unless klass
|
284
|
+
#return super unless klass
|
192
285
|
|
193
286
|
id_method = multiple ? "#{sm}_ids" : "#{mm}_id"
|
194
287
|
|
288
|
+
unless klass
|
289
|
+
|
290
|
+
return super unless self.respond_to?(id_method)
|
291
|
+
|
292
|
+
i = self.send(id_method)
|
293
|
+
|
294
|
+
if multiple
|
295
|
+
|
296
|
+
return [] unless i
|
297
|
+
|
298
|
+
return i.collect { |ii|
|
299
|
+
Rufus::Doric.instantiate(db.get(ii))
|
300
|
+
}.select { |e|
|
301
|
+
e != nil
|
302
|
+
}
|
303
|
+
end
|
304
|
+
|
305
|
+
return Rufus::Doric.instantiate(db.get(i))
|
306
|
+
end
|
307
|
+
|
195
308
|
if multiple
|
196
309
|
|
197
310
|
if self.respond_to?(id_method)
|
@@ -210,6 +323,7 @@ module Doric
|
|
210
323
|
else
|
211
324
|
|
212
325
|
return super unless self.respond_to?(id_method)
|
326
|
+
|
213
327
|
klass.find(self.send(id_method))
|
214
328
|
end
|
215
329
|
end
|
@@ -265,19 +379,6 @@ module Doric
|
|
265
379
|
|
266
380
|
# by_{key} views
|
267
381
|
|
268
|
-
x = {
|
269
|
-
'_id' => '_design/doric',
|
270
|
-
'views' => {
|
271
|
-
'by_doric_type' => {
|
272
|
-
'map' => %{
|
273
|
-
function(doc) {
|
274
|
-
if (doc.doric_type) emit(doc.doric_type, null);
|
275
|
-
}
|
276
|
-
}
|
277
|
-
}
|
278
|
-
}
|
279
|
-
}
|
280
|
-
|
281
382
|
ddoc = db.get(design_path) || {
|
282
383
|
'_id' => design_path,
|
283
384
|
'views' => {}
|
data/lib/rufus/doric/models.rb
CHANGED
@@ -38,6 +38,7 @@ module Doric
|
|
38
38
|
|
39
39
|
#
|
40
40
|
# The including classes get two new class methods : h_reader and h_accessor
|
41
|
+
# plus property as an alias to h_accessor
|
41
42
|
#
|
42
43
|
module WithH
|
43
44
|
|
@@ -64,6 +65,9 @@ module Doric
|
|
64
65
|
end
|
65
66
|
end
|
66
67
|
end
|
68
|
+
def target.property (*names)
|
69
|
+
h_accessor(*names)
|
70
|
+
end
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
data/lib/rufus/doric/version.rb
CHANGED
data/rufus-doric.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rufus-doric}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["John Mettraux"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-23}
|
13
13
|
s.description = %q{
|
14
14
|
something at the intersection of Rails3, CouchDB and rufus-jig
|
15
15
|
}
|
@@ -51,7 +51,9 @@ something at the intersection of Rails3, CouchDB and rufus-jig
|
|
51
51
|
"test/ut_3_model_lint.rb",
|
52
52
|
"test/ut_4_one_doc_model.rb",
|
53
53
|
"test/ut_5_value.rb",
|
54
|
-
"test/ut_6_model_associations.rb"
|
54
|
+
"test/ut_6_model_associations.rb",
|
55
|
+
"test/ut_7_looser_associations.rb",
|
56
|
+
"test/ut_8_belongings.rb"
|
55
57
|
]
|
56
58
|
s.homepage = %q{http://github.com/jmettraux/rufus-doric/}
|
57
59
|
s.rdoc_options = ["--charset=UTF-8"]
|
data/test/ut_1_model.rb
CHANGED
@@ -32,6 +32,14 @@ class Item < Rufus::Doric::Model
|
|
32
32
|
validates :supplier, :presence => true
|
33
33
|
end
|
34
34
|
|
35
|
+
class Concept < Rufus::Doric::Model
|
36
|
+
|
37
|
+
db :doric
|
38
|
+
doric_type :concepts
|
39
|
+
_id_field :name
|
40
|
+
property :name
|
41
|
+
end
|
42
|
+
|
35
43
|
|
36
44
|
class UtModelTest < Test::Unit::TestCase
|
37
45
|
|
@@ -48,6 +56,12 @@ class UtModelTest < Test::Unit::TestCase
|
|
48
56
|
#def teardown
|
49
57
|
#end
|
50
58
|
|
59
|
+
def test_types
|
60
|
+
|
61
|
+
assert_equal Hash, Rufus::Doric.types.class
|
62
|
+
assert_equal Concept, Rufus::Doric.types['concepts']
|
63
|
+
end
|
64
|
+
|
51
65
|
def test_save
|
52
66
|
|
53
67
|
Thing.new(
|
@@ -151,5 +165,14 @@ class UtModelTest < Test::Unit::TestCase
|
|
151
165
|
assert_not_equal a, c
|
152
166
|
assert_not_equal a.hash, c.hash
|
153
167
|
end
|
168
|
+
|
169
|
+
def test_property
|
170
|
+
|
171
|
+
Concept.new('name' => 'art').save!
|
172
|
+
|
173
|
+
c = Concept.find('art')
|
174
|
+
|
175
|
+
assert_equal 'art', c.name
|
176
|
+
end
|
154
177
|
end
|
155
178
|
|
@@ -56,7 +56,7 @@ class Order < Rufus::Doric::Model
|
|
56
56
|
end
|
57
57
|
|
58
58
|
|
59
|
-
class
|
59
|
+
class UtModelAssociationsTest < Test::Unit::TestCase
|
60
60
|
|
61
61
|
def setup
|
62
62
|
|
@@ -83,6 +83,9 @@ class UtModelTest < Test::Unit::TestCase
|
|
83
83
|
Interest.new(:name => 'litterature').save!
|
84
84
|
Interest.new(:name => 'music').save!
|
85
85
|
Interest.new(:name => 'dance').save!
|
86
|
+
|
87
|
+
@fred = Customer.find('fred')
|
88
|
+
@famke = Customer.find('famke')
|
86
89
|
end
|
87
90
|
|
88
91
|
#def teardown
|
@@ -91,9 +94,8 @@ class UtModelTest < Test::Unit::TestCase
|
|
91
94
|
def test_customer
|
92
95
|
|
93
96
|
o = Order.find('a')
|
94
|
-
c = Customer.find('fred')
|
95
97
|
|
96
|
-
assert_equal
|
98
|
+
assert_equal @fred, o.customer
|
97
99
|
end
|
98
100
|
|
99
101
|
def test_missing_customer
|
@@ -105,9 +107,7 @@ class UtModelTest < Test::Unit::TestCase
|
|
105
107
|
|
106
108
|
def test_orders
|
107
109
|
|
108
|
-
|
109
|
-
|
110
|
-
os = c.orders
|
110
|
+
os = @fred.orders
|
111
111
|
|
112
112
|
assert_equal 2, os.size
|
113
113
|
assert_equal [ Order ], os.collect { |o| o.class }.sort.uniq
|
@@ -115,11 +115,22 @@ class UtModelTest < Test::Unit::TestCase
|
|
115
115
|
|
116
116
|
def test_interests
|
117
117
|
|
118
|
-
|
119
|
-
famke
|
118
|
+
assert_equal [], @fred.interests
|
119
|
+
assert_equal %w[ dance music ], @famke.interests.collect { |i| i.name }.sort
|
120
|
+
end
|
120
121
|
|
121
|
-
|
122
|
-
|
122
|
+
def test_no_link
|
123
|
+
|
124
|
+
assert_raise NoMethodError do
|
125
|
+
@fred.car
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_no_links
|
130
|
+
|
131
|
+
assert_raise NoMethodError do
|
132
|
+
@fred.vehicles
|
133
|
+
end
|
123
134
|
end
|
124
135
|
end
|
125
136
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# testing rufus-doric
|
4
|
+
#
|
5
|
+
# Tue Mar 23 11:07:23 JST 2010
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), 'base')
|
9
|
+
|
10
|
+
require 'rufus/doric'
|
11
|
+
|
12
|
+
|
13
|
+
class Owner < Rufus::Doric::Model
|
14
|
+
|
15
|
+
db :doric
|
16
|
+
doric_type :owners
|
17
|
+
|
18
|
+
_id_field :name
|
19
|
+
|
20
|
+
property :name
|
21
|
+
property :vehicle_id
|
22
|
+
end
|
23
|
+
|
24
|
+
class Car < Rufus::Doric::Model
|
25
|
+
|
26
|
+
db :doric
|
27
|
+
doric_type :cars
|
28
|
+
|
29
|
+
_id_field :plate
|
30
|
+
|
31
|
+
property :plate
|
32
|
+
end
|
33
|
+
|
34
|
+
class Boat < Rufus::Doric::Model
|
35
|
+
|
36
|
+
db :doric
|
37
|
+
doric_type :boats
|
38
|
+
|
39
|
+
_id_field :immatriculation
|
40
|
+
|
41
|
+
property :immatriculation
|
42
|
+
end
|
43
|
+
|
44
|
+
class SuperOwner < Rufus::Doric::Model
|
45
|
+
|
46
|
+
db :doric
|
47
|
+
doric_type :super_owners
|
48
|
+
|
49
|
+
_id_field :name
|
50
|
+
|
51
|
+
property :name
|
52
|
+
property :vehicle_ids
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class UtLooserAssocationsTest < Test::Unit::TestCase
|
57
|
+
|
58
|
+
def setup
|
59
|
+
|
60
|
+
Rufus::Doric.db('doric').delete('.')
|
61
|
+
Rufus::Doric.db('doric').put('.')
|
62
|
+
|
63
|
+
Rufus::Doric.db('doric').http.cache.clear
|
64
|
+
# CouchDB feeds the same etags for views, even after a db has
|
65
|
+
# been deleted and put back, so have to do that 'forgetting'
|
66
|
+
|
67
|
+
Owner.new(
|
68
|
+
:name => 'fred', :vehicle_id => 'GE1212'
|
69
|
+
).save!
|
70
|
+
Owner.new(
|
71
|
+
:name => 'famke', :vehicle_id => 'GE1313'
|
72
|
+
).save!
|
73
|
+
Owner.new(
|
74
|
+
:name => 'fellini', :vehicle_id => 'TO45R4'
|
75
|
+
).save!
|
76
|
+
|
77
|
+
Car.new(:plate => 'GE1212').save!
|
78
|
+
Boat.new(:immatriculation => 'GE1313').save!
|
79
|
+
|
80
|
+
SuperOwner.new(
|
81
|
+
:name => 'aristotle', :vehicle_ids => %w[ GE1212 GE1313 NADA ]).save!
|
82
|
+
|
83
|
+
@fred = Owner.find('fred')
|
84
|
+
@famke = Owner.find('famke')
|
85
|
+
@fellini = Owner.find('fellini')
|
86
|
+
@aristotle = SuperOwner.find('aristotle')
|
87
|
+
end
|
88
|
+
|
89
|
+
#def teardown
|
90
|
+
#end
|
91
|
+
|
92
|
+
def test_vehicles
|
93
|
+
|
94
|
+
assert_equal Car, @fred.vehicle.class
|
95
|
+
assert_equal Boat, @famke.vehicle.class
|
96
|
+
assert_nil @fellini.vehicle
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_super_owner
|
100
|
+
|
101
|
+
assert_equal [ Car, Boat ], @aristotle.vehicles.collect { |v| v.class }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# testing rufus-doric
|
4
|
+
#
|
5
|
+
# Tue Mar 23 13:23:31 JST 2010
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), 'base')
|
9
|
+
|
10
|
+
require 'rufus/doric'
|
11
|
+
|
12
|
+
|
13
|
+
class Person < Rufus::Doric::Model
|
14
|
+
|
15
|
+
db :doric
|
16
|
+
doric_type :persons
|
17
|
+
|
18
|
+
_id_field :name
|
19
|
+
|
20
|
+
property :name
|
21
|
+
end
|
22
|
+
|
23
|
+
class Book < Rufus::Doric::Model
|
24
|
+
|
25
|
+
db :doric
|
26
|
+
doric_type :books
|
27
|
+
|
28
|
+
_id_field :description
|
29
|
+
|
30
|
+
property :description
|
31
|
+
property :person_id
|
32
|
+
end
|
33
|
+
|
34
|
+
class Computer < Rufus::Doric::Model
|
35
|
+
|
36
|
+
db :doric
|
37
|
+
doric_type :computers
|
38
|
+
|
39
|
+
_id_field :description
|
40
|
+
|
41
|
+
property :description
|
42
|
+
property :person_id
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
class UtBelongingsTest < Test::Unit::TestCase
|
47
|
+
|
48
|
+
def setup
|
49
|
+
|
50
|
+
Rufus::Doric.db('doric').delete('.')
|
51
|
+
Rufus::Doric.db('doric').put('.')
|
52
|
+
|
53
|
+
Rufus::Doric.db('doric').http.cache.clear
|
54
|
+
# CouchDB feeds the same etags for views, even after a db has
|
55
|
+
# been deleted and put back, so have to do that 'forgetting'
|
56
|
+
|
57
|
+
Person.new(
|
58
|
+
:name => 'friedrisch', :vehicle_id => 'GE1212'
|
59
|
+
).save!
|
60
|
+
|
61
|
+
Book.new(
|
62
|
+
:description => 'romance of the three kingdoms',
|
63
|
+
:person_id => 'friedrisch'
|
64
|
+
).save!
|
65
|
+
Computer.new(
|
66
|
+
:description => 'black macbook',
|
67
|
+
:person_id => 'friedrisch'
|
68
|
+
).save!
|
69
|
+
Computer.new(
|
70
|
+
:description => 'old thinkpad',
|
71
|
+
:person_id => 'vlad'
|
72
|
+
).save!
|
73
|
+
|
74
|
+
@friedrisch = Person.find('friedrisch')
|
75
|
+
end
|
76
|
+
|
77
|
+
#def teardown
|
78
|
+
#end
|
79
|
+
|
80
|
+
def test_belongings
|
81
|
+
|
82
|
+
assert_equal(
|
83
|
+
%w[ Book Computer ],
|
84
|
+
@friedrisch.belongings.map { |b| b.class.name }.sort)
|
85
|
+
|
86
|
+
assert_equal(
|
87
|
+
%w[ Book Computer ],
|
88
|
+
@friedrisch.belongings.map { |b| b.class.name }.sort)
|
89
|
+
# second run shouldn't insert new design_doc
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- John Mettraux
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-23 00:00:00 +09:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -139,6 +139,8 @@ files:
|
|
139
139
|
- test/ut_4_one_doc_model.rb
|
140
140
|
- test/ut_5_value.rb
|
141
141
|
- test/ut_6_model_associations.rb
|
142
|
+
- test/ut_7_looser_associations.rb
|
143
|
+
- test/ut_8_belongings.rb
|
142
144
|
has_rdoc: true
|
143
145
|
homepage: http://github.com/jmettraux/rufus-doric/
|
144
146
|
licenses: []
|