hanswurst 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +24 -59
- data/VERSION +1 -1
- data/lib/hanswurst.rb +168 -54
- data/test/test_hanswurst.rb +222 -101
- metadata +23 -23
data/README.md
CHANGED
@@ -47,16 +47,12 @@ first you have to build your roles as normal couch potato classes
|
|
47
47
|
then you may use them as you like
|
48
48
|
|
49
49
|
hw = Hanswurst.new
|
50
|
-
hw
|
51
|
-
hw.
|
52
|
-
|
53
|
-
hw.person___first_name = 'Diederich'
|
54
|
-
hw.person___last_name = 'Hessling' # an RoleNotValid error is raised if person___last_name is missing
|
50
|
+
hw << {:person => Person} # first role then class
|
51
|
+
hw.person.first_name = 'Diederich'
|
52
|
+
hw.person.last_name = 'Hessling' # an RoleNotValid error is raised if person___last_name is missing
|
55
53
|
|
56
54
|
# you may also use some syntatic sugar with 'as', the following does the same thing as above
|
57
|
-
|
58
|
-
person.first_name = 'Diederich'
|
59
|
-
person.last_name = 'Hessling'
|
55
|
+
hw = Hanswurst.new :person => Person.new(:first_name => 'Diederich', :last_name => 'Hessling')
|
60
56
|
|
61
57
|
# this is also possible
|
62
58
|
hw.product = Product.new :price => 20, :in_stock => 1
|
@@ -67,19 +63,11 @@ later...
|
|
67
63
|
|
68
64
|
hw = CouchPotato.database.load_document id
|
69
65
|
|
70
|
-
hw.
|
71
|
-
hw.
|
72
|
-
hw.
|
73
|
-
|
74
|
-
# or with 'as'
|
75
|
-
person = hw.as :person
|
76
|
-
person.first_name # => 'Diederich'
|
77
|
-
person.last_name # => 'Hessling'
|
78
|
-
person.name # => 'Diederich Hessling'
|
66
|
+
hw.person.first_name # => 'Diederich'
|
67
|
+
hw.person.name # => 'Diederich Hessling'
|
68
|
+
hw.product.price # => 20
|
79
69
|
|
80
|
-
|
81
|
-
you may also declare that roles are depending on other roles
|
82
|
-
when you add that role, the others are also automatically added
|
70
|
+
you may also set roles as properties of other roles
|
83
71
|
|
84
72
|
class Address
|
85
73
|
include CouchPotato::Persistence
|
@@ -91,33 +79,24 @@ when you add that role, the others are also automatically added
|
|
91
79
|
|
92
80
|
class Person
|
93
81
|
include CouchPotato::Persistence
|
94
|
-
include Hanswurst::Depends
|
95
82
|
|
96
|
-
|
97
|
-
|
83
|
+
property :address_privat
|
84
|
+
property :address_work
|
85
|
+
|
86
|
+
# gets invalid if address_privat / address_work are instances of Address
|
87
|
+
validates :address_privat, :hanswurst => {:class => Address}
|
88
|
+
validates :address_work, :hanswurst => {:class => Address}
|
98
89
|
|
99
90
|
property :last_name
|
100
91
|
property :first_name
|
101
92
|
end
|
102
93
|
|
103
|
-
hw = Hanswurst.new
|
104
|
-
hw.
|
105
|
-
|
106
|
-
|
107
|
-
hw.employee__address_work___city = 'Potsdam'
|
108
|
-
|
109
|
-
# or with 'as'
|
110
|
-
emp = hw.as :employee
|
111
|
-
emp.last_name = 'Hessling'
|
112
|
-
|
113
|
-
privat = emp.as :address_privat
|
114
|
-
privat.city = 'Berlin'
|
115
|
-
|
116
|
-
work = emp.as :address_work
|
117
|
-
work.city = 'Potsdam'
|
94
|
+
hw = Hanswurst.new :employee => Person.new(:last_name => 'Hessling')
|
95
|
+
emp = hw.employee
|
96
|
+
emp.address_privat = Address.new :city => 'Berlin'
|
97
|
+
emp.address_work = Address.new :city => 'Potsdam'
|
118
98
|
|
119
|
-
|
120
|
-
or as shared dependancy without prefix
|
99
|
+
or as a shared dependancy
|
121
100
|
|
122
101
|
class Address
|
123
102
|
include CouchPotato::Persistence
|
@@ -131,30 +110,16 @@ or as shared dependancy without prefix
|
|
131
110
|
include CouchPotato::Persistence
|
132
111
|
include Hanswurst::Shares
|
133
112
|
|
134
|
-
shares
|
135
|
-
shares
|
113
|
+
shares :address_privat => Address
|
114
|
+
shares :address_work => Address
|
136
115
|
|
137
116
|
property :last_name
|
138
117
|
property :first_name
|
139
118
|
end
|
140
119
|
|
141
|
-
hw = Hanswurst.new
|
142
|
-
hw.
|
143
|
-
hw.
|
144
|
-
hw.address_privat___city = 'Berlin'
|
145
|
-
hw.address_work___city = 'Potsdam'
|
146
|
-
|
147
|
-
# or with 'as'
|
148
|
-
emp = hw.as :employee
|
149
|
-
emp.last_name = 'Hessling'
|
150
|
-
|
151
|
-
privat = hw.as :address_privat
|
152
|
-
privat.city = 'Berlin'
|
153
|
-
|
154
|
-
work = hw.as :address_work
|
155
|
-
work.city = 'Potsdam'
|
156
|
-
|
157
|
-
|
120
|
+
hw = Hanswurst.new :employee => Person.new(:last_name => 'Hessling')
|
121
|
+
hw.address_privat.city = 'Berlin'
|
122
|
+
hw.address_work.city = 'Potsdam'
|
158
123
|
|
159
124
|
All views are attached to the hanswurst design document
|
160
125
|
You may create general views:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/lib/hanswurst.rb
CHANGED
@@ -1,29 +1,112 @@
|
|
1
1
|
require 'couch_potato'
|
2
2
|
|
3
|
+
class HanswurstValidator < ActiveModel::EachValidator
|
4
|
+
def doc_is_valid_role?(doc, roles)
|
5
|
+
!(roles & doc.hanswurst_roles.keys).empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
def is_valid_klass?(klasses, value)
|
9
|
+
klasses.include? value.class
|
10
|
+
end
|
11
|
+
|
12
|
+
def doc_is_valid_klass?(doc, klasses)
|
13
|
+
!(klasses & doc.hanswurst_roles.values).empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def validate_each(record, attribute, values)
|
18
|
+
#p options
|
19
|
+
#p record
|
20
|
+
return if values.nil?
|
21
|
+
values = values.values if values.class == Hash
|
22
|
+
values = [values] unless values.class == Array
|
23
|
+
valid = true
|
24
|
+
max = options[:max]
|
25
|
+
if max && values.size > max
|
26
|
+
record.errors.add attribute, "must not have more than #{max} entries"
|
27
|
+
return
|
28
|
+
end
|
29
|
+
fkey = options[:fkey] || false
|
30
|
+
if fkey
|
31
|
+
values = values.collect do |id|
|
32
|
+
CouchPotato.database.load_document id
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
if klass = options[:class]
|
37
|
+
klasses = [klass].flatten
|
38
|
+
if fkey
|
39
|
+
klasses = klasses.collect{ |k| k.to_s }
|
40
|
+
values.each do |doc|
|
41
|
+
valid = false unless doc && doc.hanswurst_roles && doc_is_valid_klass?(doc, klasses)
|
42
|
+
end
|
43
|
+
record.errors.add attribute, "must be a doc id of a class #{klasses.join(' or ')}" unless valid
|
44
|
+
else
|
45
|
+
values.each do |thing|
|
46
|
+
valid = false unless is_valid_klass?(klasses, thing)
|
47
|
+
end
|
48
|
+
record.errors.add attribute, "must be an instance of #{klasses.join(' or ')}" unless valid
|
49
|
+
end
|
50
|
+
elsif role = options[:role]
|
51
|
+
roles = [role].flatten.collect{ |r| r.to_s }
|
52
|
+
if fkey
|
53
|
+
values.each do |doc|
|
54
|
+
valid = false unless doc && doc.hanswurst_roles && doc_is_valid_role?(doc, roles)
|
55
|
+
end
|
56
|
+
record.errors.add attribute, "must be a doc id of a role #{roles.join(' or ')}" unless valid
|
57
|
+
else
|
58
|
+
klasses = roles.collect do |role_alias|
|
59
|
+
klass = Hanswurst.role_class(role_alias.to_sym)
|
60
|
+
record.errors.add(attribute, "could not find role #{role_alias} with Hanswurst.role_class. Did you register it with Hanswurst.register_role() ?") if klass.nil?
|
61
|
+
klass
|
62
|
+
end
|
63
|
+
values.each do |thing|
|
64
|
+
valid = false unless is_valid_klass?(klasses, thing)
|
65
|
+
end
|
66
|
+
record.errors.add attribute, "must be an instance of #{klasses.join(' or ')}" unless valid
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
#roles = options[:in] || [options[:with]]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
|
3
75
|
# Each Hanswurst may have a different combination of roles. It's a very flexible way to be a couch potato.
|
4
76
|
class Hanswurst
|
5
|
-
|
6
|
-
module Depends
|
77
|
+
module Delegates
|
7
78
|
def self.included(mod)
|
8
79
|
mod.instance_eval do
|
9
|
-
def
|
10
|
-
@
|
11
|
-
@
|
80
|
+
def delegates(attr_symbol, role)
|
81
|
+
@delegations ||= {}
|
82
|
+
@delegations[attr_symbol] = role
|
12
83
|
end
|
13
84
|
|
14
|
-
def
|
15
|
-
@
|
85
|
+
def delegations
|
86
|
+
@delegations || {}
|
16
87
|
end
|
17
88
|
end
|
18
89
|
end
|
90
|
+
|
91
|
+
# shortcuts view_for_[role], list_for_[role]
|
92
|
+
def method_missing(meth, *args, &code)
|
93
|
+
meth.to_s =~ /^([^=]+)=?$/
|
94
|
+
unified_meth = $1
|
95
|
+
if role = self.class.delegations[unified_meth.to_sym]
|
96
|
+
self.send(role).send(meth, *args, &code)
|
97
|
+
else
|
98
|
+
super
|
99
|
+
end
|
100
|
+
end
|
19
101
|
end
|
20
102
|
|
21
103
|
module Shares
|
22
104
|
def self.included(mod)
|
23
105
|
mod.instance_eval do
|
24
|
-
def shares(
|
106
|
+
def shares(hsh)
|
107
|
+
hsh = {hsh => hsh} if hsh.is_a? Symbol
|
25
108
|
@shared_dependancies ||= {}
|
26
|
-
@shared_dependancies
|
109
|
+
@shared_dependancies.update hsh
|
27
110
|
end
|
28
111
|
|
29
112
|
def shared_dependancies
|
@@ -50,30 +133,27 @@ class Hanswurst
|
|
50
133
|
|
51
134
|
# helper for easy access to role attributes
|
52
135
|
class As
|
53
|
-
def initialize(doc,
|
136
|
+
def initialize(doc, obj)
|
54
137
|
@doc = doc
|
55
|
-
@
|
138
|
+
@obj = obj
|
56
139
|
end
|
57
140
|
|
58
141
|
def _id
|
59
142
|
@doc._id
|
60
143
|
end
|
61
144
|
|
62
|
-
def
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
def roles_as_string
|
67
|
-
@roles.join('__')
|
145
|
+
def _doc
|
146
|
+
@doc
|
68
147
|
end
|
69
148
|
|
70
149
|
# we suppose, we have a subrole
|
71
|
-
def method_missing(meth, *args)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
@doc.send(:"#{roles_as_string}___#{meth}", *args)
|
150
|
+
def method_missing(meth, *args, &code)
|
151
|
+
obj = @obj.send(meth, *args)
|
152
|
+
if obj.is_a? CouchPotato::Persistence
|
153
|
+
obj = self.class.new(@doc, @obj.send(meth, *args))
|
76
154
|
end
|
155
|
+
obj.instance_eval(&code) if code
|
156
|
+
obj
|
77
157
|
end
|
78
158
|
end
|
79
159
|
|
@@ -85,6 +165,18 @@ class Hanswurst
|
|
85
165
|
classname.split('::').inject Kernel do |c,name| c = c.const_get name; end
|
86
166
|
end
|
87
167
|
|
168
|
+
# hsh is role_alias => klass where role_alias should be a symbol
|
169
|
+
def register_role(hsh)
|
170
|
+
@roles ||= {}
|
171
|
+
@roles.update hsh
|
172
|
+
end
|
173
|
+
|
174
|
+
# returns the role klass for the role_alias (role_alias should be a symbol)
|
175
|
+
def role_class(role_alias)
|
176
|
+
@roles ||= {}
|
177
|
+
@roles[role_alias]
|
178
|
+
end
|
179
|
+
|
88
180
|
# creates a view to show only documents of the role +role_alias+
|
89
181
|
def role_view(role_alias, viewname, options)
|
90
182
|
# I keep this commented out to inform the reader that we don't want this in order to easily reuse general lists
|
@@ -126,10 +218,15 @@ class Hanswurst
|
|
126
218
|
value = args.first
|
127
219
|
case meth
|
128
220
|
when /^([^=]+)___([^=]+)(\=)?$/ # obj.role__prop # => we get / set a property
|
129
|
-
|
130
|
-
|
221
|
+
raise "use of ___ methods is deprecated, please use Hanswurst#as"
|
222
|
+
# role, property, setter = $1, $2, $3
|
223
|
+
# return setter ? set_property(role, property, value) : read(role, property, *args)
|
131
224
|
when /^([^=]+)\=$/ # obj.role = ... # => we set a role
|
132
|
-
|
225
|
+
role=$1
|
226
|
+
add_role(role, value.class) unless role_exists?(role)
|
227
|
+
return set_role(role, value) if role_exists?(role)
|
228
|
+
else
|
229
|
+
return as(meth) if role_exists?(meth.to_s)
|
133
230
|
end
|
134
231
|
super
|
135
232
|
end
|
@@ -149,25 +246,48 @@ class Hanswurst
|
|
149
246
|
|
150
247
|
include MethodMissing
|
151
248
|
|
152
|
-
|
153
|
-
|
154
|
-
|
249
|
+
def initialize(hsh={})
|
250
|
+
unless hsh.empty?
|
251
|
+
hsh.each do |role, obj|
|
252
|
+
self.send(:"#{role}=", obj)
|
253
|
+
end
|
254
|
+
end
|
155
255
|
end
|
156
256
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
257
|
+
# copy the doc including the roles
|
258
|
+
def copy()
|
259
|
+
attributes = self.to_hash
|
260
|
+
attributes.delete "ruby_class"
|
261
|
+
attributes.delete "_id"
|
262
|
+
attributes.delete "_rev"
|
263
|
+
attributes.delete :created_at
|
264
|
+
attributes.delete :updated_at
|
265
|
+
hanswust_data = attributes.delete :hanswurst_data
|
266
|
+
obj = self.class.new attributes
|
267
|
+
hanswust_data.each do |role,val|
|
268
|
+
#obj.set role, val
|
269
|
+
obj.send(:"#{role}=", val.dup)
|
164
270
|
end
|
271
|
+
obj
|
272
|
+
end
|
273
|
+
|
274
|
+
def <<(hsh)
|
275
|
+
add_roles(hsh)
|
276
|
+
end
|
277
|
+
|
278
|
+
private
|
279
|
+
|
280
|
+
# add a role
|
281
|
+
def add_role(role, klass, &code)
|
282
|
+
add_roles(role => klass)
|
283
|
+
as(role, &code)
|
165
284
|
end
|
166
285
|
|
167
286
|
def handle_shared(role, klass)
|
168
287
|
if klass.respond_to?(:shared_dependancies)
|
169
288
|
shared = {}
|
170
289
|
klass.shared_dependancies.each do |shared_role, shared_class|
|
290
|
+
shared_class = Hanswurst.role_class(shared_class) if shared_class.is_a? Symbol
|
171
291
|
shared[shared_role] = shared_class unless role_exists? shared_role
|
172
292
|
end
|
173
293
|
add_roles shared
|
@@ -180,9 +300,9 @@ class Hanswurst
|
|
180
300
|
self.hanswurst_roles ||= {}
|
181
301
|
hsh.each do |role,klass|
|
182
302
|
raise "class expected: #{klass.inspect}" unless klass.is_a? Class
|
183
|
-
handle_dependancies(role, klass)
|
184
303
|
handle_shared(role, klass)
|
185
304
|
self.hanswurst_roles.update role.to_s => klass.name
|
305
|
+
|
186
306
|
end
|
187
307
|
self.hanswurst_roles
|
188
308
|
end
|
@@ -239,28 +359,22 @@ class Hanswurst
|
|
239
359
|
|
240
360
|
# read a property of a role
|
241
361
|
def read(role, property, *args)
|
242
|
-
|
362
|
+
if hanswurst_data_exists?(role.to_s)
|
363
|
+
return self.hanswurst_data[role.to_s].send(property.to_sym, *args)
|
364
|
+
end
|
243
365
|
nil
|
244
366
|
end
|
245
367
|
|
246
|
-
def as(role)
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
# copy the doc including the roles
|
251
|
-
def copy()
|
252
|
-
attributes = self.to_hash
|
253
|
-
attributes.delete "ruby_class"
|
254
|
-
attributes.delete "_id"
|
255
|
-
attributes.delete "_rev"
|
256
|
-
attributes.delete :created_at
|
257
|
-
attributes.delete :updated_at
|
258
|
-
hanswust_data = attributes.delete :hanswurst_data
|
259
|
-
obj = self.class.new attributes
|
260
|
-
hanswust_data.each do |role,val|
|
261
|
-
obj.set role, val
|
368
|
+
def as(role, &code)
|
369
|
+
unless hanswurst_data[role.to_s]
|
370
|
+
create(role.to_s)
|
262
371
|
end
|
263
|
-
|
372
|
+
if role_obj = hanswurst_data[role.to_s]
|
373
|
+
obj = As.new(self, role_obj)
|
374
|
+
obj.instance_eval(&code) if code
|
375
|
+
return obj
|
376
|
+
end
|
377
|
+
nil
|
264
378
|
end
|
265
379
|
|
266
380
|
# update a property of a role
|
data/test/test_hanswurst.rb
CHANGED
@@ -32,10 +32,9 @@ end
|
|
32
32
|
|
33
33
|
class D
|
34
34
|
include CouchPotato::Persistence
|
35
|
-
include Hanswurst::Depends
|
36
35
|
|
37
|
-
|
38
|
-
|
36
|
+
property :person # looks into Hanswurst.role_class
|
37
|
+
property :prod # => Prod
|
39
38
|
property :my_prop
|
40
39
|
|
41
40
|
end
|
@@ -44,7 +43,10 @@ class E
|
|
44
43
|
include CouchPotato::Persistence
|
45
44
|
include Hanswurst::Shares
|
46
45
|
|
47
|
-
shares
|
46
|
+
shares :person => :person
|
47
|
+
shares :prod => Prod
|
48
|
+
|
49
|
+
shares :product
|
48
50
|
|
49
51
|
property :e
|
50
52
|
end
|
@@ -52,12 +54,53 @@ end
|
|
52
54
|
|
53
55
|
class F
|
54
56
|
include CouchPotato::Persistence
|
55
|
-
include Hanswurst::Depends
|
56
57
|
|
57
|
-
depends_on 'd'
|
58
|
+
#depends_on 'd' => D
|
59
|
+
|
60
|
+
property :d
|
61
|
+
|
58
62
|
property :f
|
63
|
+
|
64
|
+
property :a # should be an instance of A
|
65
|
+
|
66
|
+
property :perss # should be an Array of instances of Pers
|
67
|
+
|
68
|
+
property :h # should be a Hash
|
59
69
|
|
60
70
|
end
|
71
|
+
|
72
|
+
class G
|
73
|
+
include CouchPotato::Persistence
|
74
|
+
include Hanswurst::Delegates
|
75
|
+
|
76
|
+
#depends_on 'd' => D
|
77
|
+
property :d
|
78
|
+
delegates :my_prop, :d
|
79
|
+
|
80
|
+
property :a_instance # should be an instance of Thing::A
|
81
|
+
property :prod # should be an instance of Prod
|
82
|
+
property :pers # should be an instance of Pers
|
83
|
+
property :prod_doc_id # should be an doc id of a doc with role Prod
|
84
|
+
property :pers_doc_id # should be an doc id of a doc with role Pers
|
85
|
+
|
86
|
+
property :prod_or_pers # could have an instance of Prod or Pers
|
87
|
+
property :prod_or_pers_doc_id # could be a doc with a role of Prod or Pers
|
88
|
+
|
89
|
+
delegates :name, :prod
|
90
|
+
delegates :article_number, :prod
|
91
|
+
delegates :a, :a_instance
|
92
|
+
|
93
|
+
validates :prod, :hanswurst => {:class => Prod}
|
94
|
+
validates :pers, :hanswurst => {:role => :person} # warning this role is from Hanswurst#roles
|
95
|
+
validates :prod_or_pers, :hanswurst => {:class => [Prod, Pers]}
|
96
|
+
validates :prod_or_pers_doc_id, :hanswurst => {:role => [:person, :prod], :fkey => true, :max => 2}
|
97
|
+
|
98
|
+
validates :pers_doc_id, :hanswurst => {:role => :person, :fkey => true} # warning this role is from the added role alias
|
99
|
+
validates :prod_doc_id, :hanswurst => {:class => Prod, :fkey => true}
|
100
|
+
end
|
101
|
+
|
102
|
+
Hanswurst.register_role(:person => Pers, :product => Prod)
|
103
|
+
|
61
104
|
Hanswurst.list_for :pers, :complete_name, %q|
|
62
105
|
function(head, req) {
|
63
106
|
var row;
|
@@ -114,68 +157,72 @@ class TestCouch < Test::Unit::TestCase
|
|
114
157
|
|
115
158
|
should "save stuff" do
|
116
159
|
o = Hanswurst.new
|
117
|
-
o.add_role 'person', Pers
|
118
|
-
o.add_role 'product', Prod
|
119
160
|
o.product = Prod.new( :article_number => 'xyz', :name => 'prod1' )
|
120
161
|
o.person = Pers.new( :firstname => 'Donald', :lastname => 'Duck' )
|
121
162
|
save o
|
122
163
|
o = load(o._id)
|
123
164
|
hanswurst_roles = {'person' => 'Pers', 'product' => 'Prod'}
|
124
165
|
assert_equal hanswurst_roles, o.hanswurst_roles
|
125
|
-
assert_equal 'prod1', o.
|
126
|
-
assert_equal 'Donald', o.
|
127
|
-
assert_equal 'Donald', o.
|
166
|
+
assert_equal 'prod1', o.product.name
|
167
|
+
assert_equal 'Donald', o.person.firstname
|
168
|
+
assert_equal 'Donald', o.person.firstname
|
128
169
|
end
|
129
170
|
|
130
171
|
should "save hanswurst_roles" do
|
131
172
|
o = Hanswurst.new
|
132
|
-
o.
|
133
|
-
o.
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
173
|
+
o.person = Pers.new
|
174
|
+
o.product = Prod.new
|
175
|
+
prod = o.product
|
176
|
+
prod.article_number = "abc"
|
177
|
+
prod.name = "prod1"
|
178
|
+
|
179
|
+
pers = o.person
|
180
|
+
pers.firstname = "Bugs"
|
181
|
+
pers.lastname = "Bunny"
|
138
182
|
save o
|
139
183
|
o = load(o._id)
|
140
184
|
hanswurst_roles = {'person' => 'Pers', 'product' => 'Prod'}
|
141
185
|
assert_equal hanswurst_roles, o.hanswurst_roles
|
142
|
-
assert_equal 'Bugs', o.
|
143
|
-
assert_equal 'Bunny', o.
|
144
|
-
assert_equal 'abc', o.
|
186
|
+
assert_equal 'Bugs', o.person.firstname
|
187
|
+
assert_equal 'Bunny', o.person.lastname
|
188
|
+
assert_equal 'abc', o.product.article_number
|
145
189
|
|
146
|
-
o.
|
190
|
+
o.product.article_number = "cde"
|
191
|
+
#p o.product._doc
|
147
192
|
save o
|
148
193
|
o = load(o._id)
|
149
|
-
assert_equal 'prod1', o.
|
150
|
-
assert_equal 'Bugs', o.
|
151
|
-
assert_equal '
|
194
|
+
assert_equal 'prod1', o.product.name
|
195
|
+
assert_equal 'Bugs', o.person.firstname
|
196
|
+
assert_equal 'abc', o.product.article_number
|
152
197
|
|
153
198
|
o.product = nil
|
154
199
|
save o
|
155
200
|
o = load(o._id)
|
156
|
-
|
201
|
+
assert_raise NoMethodError do
|
202
|
+
o.product.name
|
203
|
+
end
|
157
204
|
assert !o.hanswurst_roles.has_key?("product")
|
158
|
-
assert_equal 'Bugs', o.
|
159
|
-
|
160
|
-
|
161
|
-
|
205
|
+
assert_equal 'Bugs', o.person.firstname
|
206
|
+
assert_raise NoMethodError do
|
207
|
+
o.product.article_number
|
208
|
+
end
|
209
|
+
assert_equal 'Bunny, Bugs', o.person.name(', ')
|
162
210
|
end
|
163
211
|
|
164
212
|
should "save for moduled classed" do
|
165
213
|
o = Hanswurst.new
|
166
|
-
o.
|
167
|
-
o.
|
214
|
+
o.thing = Thing::A.new
|
215
|
+
o.thing.a = "hiho"
|
168
216
|
save o
|
169
217
|
o = load(o._id)
|
170
218
|
hanswurst_roles = {'thing' => 'Thing::A'}
|
171
219
|
assert_equal hanswurst_roles, o.hanswurst_roles
|
172
|
-
assert_equal 'hiho', o.
|
220
|
+
assert_equal 'hiho', o.thing.a
|
173
221
|
end
|
174
222
|
|
175
223
|
|
176
224
|
should "not save when validation fails" do
|
177
225
|
o = Hanswurst.new
|
178
|
-
o.add_role 'product', Prod
|
179
226
|
o.product = Prod.new( :article_number => 'xyz')
|
180
227
|
assert_raises Hanswurst::RoleNotValid do
|
181
228
|
save o
|
@@ -183,118 +230,192 @@ class TestCouch < Test::Unit::TestCase
|
|
183
230
|
end
|
184
231
|
|
185
232
|
should "make a view with list" do
|
186
|
-
o = Hanswurst.new
|
187
|
-
o.add_role 'pers', Pers
|
188
|
-
o.pers = Pers.new :firstname => "Donald", :lastname => "Duck"
|
233
|
+
o = Hanswurst.new(:pers => Pers.new(:firstname => "Donald", :lastname => "Duck"))
|
189
234
|
save o
|
190
235
|
a = Hanswurst.new
|
191
|
-
a.add_role 'pers', Pers
|
192
236
|
a.pers = Pers.new :firstname => "Mickey", :lastname => "Mouse"
|
193
237
|
save a
|
194
238
|
assert_equal "Donald Duck", view(Hanswurst.pers_all_names(:startkey_docid => "Donald")).first.hanswurst_data["pers"].complete_name
|
195
239
|
assert_equal "Donald", view(Hanswurst.pers_all_names(:startkey_docid => "Donald")).first.hanswurst_data["pers"].firstname
|
196
240
|
end
|
197
241
|
|
198
|
-
should "
|
199
|
-
o = Hanswurst.new
|
200
|
-
o.
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
242
|
+
should "allow roles to have roles" do
|
243
|
+
o = Hanswurst.new(:do => D.new)
|
244
|
+
doer = o.do
|
245
|
+
doer.my_prop = "4AD"
|
246
|
+
doer.person = Pers.new
|
247
|
+
pers = doer.person
|
248
|
+
pers.firstname = "Dagobert"
|
249
|
+
pers.lastname = "Duck"
|
250
|
+
doer.prod = Prod.new
|
251
|
+
doer.prod.name = "Comic Hero"
|
252
|
+
|
205
253
|
save o
|
206
254
|
o = load(o._id)
|
207
|
-
assert_equal "4AD", o.
|
208
|
-
assert_equal "Dagobert", o.
|
209
|
-
assert_equal "Comic Hero", o.
|
255
|
+
assert_equal "4AD", o.do.my_prop
|
256
|
+
assert_equal "Dagobert", o.do.person.firstname
|
257
|
+
assert_equal "Comic Hero", o.do.prod.name
|
210
258
|
|
211
259
|
q = Hanswurst.new
|
212
|
-
q
|
260
|
+
q << {'done' => D}
|
213
261
|
q.done = D.new( :my_prop => '5AD')
|
214
|
-
q.
|
215
|
-
q.
|
216
|
-
q.
|
262
|
+
q.done.person = Pers.new
|
263
|
+
q.done.person.firstname = "Dagobert"
|
264
|
+
q.done.person.lastname = "Duck"
|
265
|
+
q.done.prod = Prod.new
|
266
|
+
q.done.prod.name = "Comic Hero"
|
217
267
|
save q
|
218
268
|
q = load(q._id)
|
219
|
-
assert_equal "5AD", q.
|
220
|
-
assert_equal "Dagobert", q.
|
221
|
-
assert_equal "Comic Hero", q.
|
269
|
+
assert_equal "5AD", q.done.my_prop
|
270
|
+
assert_equal "Dagobert", q.done.person.firstname
|
271
|
+
assert_equal "Comic Hero", q.done.prod.name
|
222
272
|
end
|
223
273
|
|
224
|
-
should "create shared dependancies based on definitions" do
|
225
|
-
o = Hanswurst.new
|
226
|
-
o.
|
227
|
-
o.
|
228
|
-
o.
|
274
|
+
should "create shared dependancies based on definitions A" do
|
275
|
+
o = Hanswurst.new(:do => E.new)
|
276
|
+
o.do.e = "4AD"
|
277
|
+
#p [:roles, o.hanswurst_roles]
|
278
|
+
o.person.lastname = "Duck"
|
279
|
+
o.prod.name = 'tester'
|
280
|
+
o.product.name = 'tester2'
|
229
281
|
save o
|
230
282
|
o = load(o._id)
|
231
|
-
assert_equal "4AD", o.
|
232
|
-
assert_equal "Duck", o.
|
283
|
+
assert_equal "4AD", o.do.e
|
284
|
+
assert_equal "Duck", o.person.lastname
|
285
|
+
assert_equal "tester", o.prod.name
|
286
|
+
assert_equal "tester2", o.product.name
|
233
287
|
end
|
234
288
|
|
235
289
|
should "create shared dependancies based on definitions" do
|
236
290
|
o = Hanswurst.new
|
237
|
-
o
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
291
|
+
o << {'fff' => F}
|
292
|
+
fff = o.fff
|
293
|
+
fff.d = D.new
|
294
|
+
d = fff.d
|
295
|
+
d.person = Pers.new
|
296
|
+
d.person.lastname = "Duck"
|
297
|
+
d.prod = Prod.new
|
298
|
+
d.prod.name = "testerer"
|
299
|
+
fff.f = "FFF"
|
300
|
+
d.my_prop = "hiho"
|
242
301
|
save o
|
243
302
|
q = load(o._id)
|
244
|
-
assert_equal "FFF", q.
|
245
|
-
assert_equal "Duck", q.
|
246
|
-
assert_equal "hiho", q.
|
247
|
-
assert_equal "testerer", q.
|
303
|
+
assert_equal "FFF", q.fff.f
|
304
|
+
assert_equal "Duck", q.fff.d.person.lastname
|
305
|
+
assert_equal "hiho", q.fff.d.my_prop
|
306
|
+
assert_equal "testerer", q.fff.d.prod.name
|
248
307
|
end
|
249
308
|
|
250
|
-
should "
|
309
|
+
should "copy docs" do
|
251
310
|
o = Hanswurst.new
|
252
|
-
o
|
253
|
-
f = o.
|
254
|
-
d =
|
255
|
-
|
311
|
+
o << { 'fff' => F }
|
312
|
+
f = o.fff
|
313
|
+
f.d = D.new
|
314
|
+
d = f.d
|
315
|
+
d.person = Pers.new
|
316
|
+
person = d.person
|
256
317
|
person.firstname = "Donald"
|
257
318
|
person.lastname = "Duck"
|
258
319
|
f.f = "FFF"
|
259
|
-
d.
|
320
|
+
d.prod = Prod.new
|
321
|
+
d.prod.name = "testerer"
|
260
322
|
d.my_prop = "hiho"
|
261
323
|
save o
|
262
324
|
q = load(o._id)
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
assert_equal "
|
325
|
+
r = q.copy
|
326
|
+
save r
|
327
|
+
s = load(r._id)
|
328
|
+
assert o._id != r._id, "id of source and copy should not be equal"
|
329
|
+
assert_equal "FFF", s.fff.f
|
330
|
+
assert_equal "Duck", s.fff.d.person.lastname
|
331
|
+
assert_equal "hiho", s.fff.d.my_prop
|
332
|
+
assert_equal "testerer", s.fff.d.prod.name
|
333
|
+
end
|
334
|
+
|
335
|
+
should "copy docs with role that has property of another role" do
|
336
|
+
o = Hanswurst.new
|
337
|
+
o << {'f' => F }
|
338
|
+
o.f.a = Thing::A.new :a => 'A'
|
339
|
+
save o
|
340
|
+
q = load(o._id)
|
341
|
+
r = q.copy
|
342
|
+
save r
|
343
|
+
s = load(r._id)
|
271
344
|
|
272
|
-
|
273
|
-
|
274
|
-
assert_equal "
|
345
|
+
assert_equal "A", q.f.a.a
|
346
|
+
assert o._id != r._id, "id of source and copy should not be equal"
|
347
|
+
assert_equal "A", s.f.a.a
|
275
348
|
end
|
276
349
|
|
277
|
-
should "copy docs" do
|
350
|
+
should "copy docs with role that has property of another role" do
|
278
351
|
o = Hanswurst.new
|
279
|
-
o
|
280
|
-
f =
|
281
|
-
|
282
|
-
person = d.as "person"
|
283
|
-
person.firstname = "Donald"
|
284
|
-
person.lastname = "Duck"
|
285
|
-
f.f = "FFF"
|
286
|
-
d.prod___name = "testerer"
|
287
|
-
d.my_prop = "hiho"
|
352
|
+
o << { 'f' => F }
|
353
|
+
o.f.h = {"test" => "hash"}
|
354
|
+
o.f.perss = [Pers.new(:firstname => 'Donald'), Pers.new(:firstname => 'Dagobert')]
|
288
355
|
save o
|
289
356
|
q = load(o._id)
|
290
357
|
r = q.copy
|
291
358
|
save r
|
292
359
|
s = load(r._id)
|
360
|
+
|
361
|
+
assert_equal "Donald", q.f.perss.first.firstname
|
362
|
+
assert_equal "Dagobert", q.f.perss.last.firstname
|
363
|
+
assert_equal({"test" => "hash"}, q.f.h)
|
293
364
|
assert o._id != r._id, "id of source and copy should not be equal"
|
294
|
-
assert_equal "
|
295
|
-
assert_equal "
|
296
|
-
assert_equal "
|
297
|
-
|
365
|
+
assert_equal "Donald", s.f.perss.first.firstname
|
366
|
+
assert_equal "Dagobert", s.f.perss.last.firstname
|
367
|
+
assert_equal({"test" => "hash"}, s.f.h)
|
368
|
+
end
|
369
|
+
|
370
|
+
should "delegate" do
|
371
|
+
o = Hanswurst.new
|
372
|
+
o << {'g' => G}
|
373
|
+
o.g.d = D.new
|
374
|
+
o.g.my_prop = 'testprop'
|
375
|
+
o.g.a_instance = Thing::A.new(:a => 'My A')
|
376
|
+
o.g.prod = Prod.new
|
377
|
+
o.g.name = "my prod name"
|
378
|
+
o.g.article_number = "my article number"
|
379
|
+
save o
|
380
|
+
q = load(o._id)
|
381
|
+
assert_equal "My A", q.g.a_instance.a
|
382
|
+
assert_equal "testprop", q.g.d.my_prop
|
383
|
+
assert_equal "My A", q.g.a
|
384
|
+
assert_equal "testprop", q.g.d.my_prop
|
385
|
+
assert_equal "testprop", q.g.my_prop
|
386
|
+
assert_equal "my prod name", q.g.name
|
387
|
+
assert_equal "my prod name", q.g.prod.name
|
388
|
+
assert_equal "my article number", q.g.article_number
|
389
|
+
end
|
390
|
+
|
391
|
+
should "make the right validations" do
|
392
|
+
pers = Hanswurst.new
|
393
|
+
pers << { 'person' => Pers }
|
394
|
+
pers.person.lastname = "Duck"
|
395
|
+
save pers
|
396
|
+
prod = Hanswurst.new :prod => Prod.new
|
397
|
+
prod.prod.name = "Car"
|
398
|
+
save prod
|
399
|
+
o = Hanswurst.new 'g' => G.new
|
400
|
+
g = o.g
|
401
|
+
g.pers = Pers.new(:lastname => "Simpson")
|
402
|
+
g.prod = { :prod => Prod.new(:name => "Automobile")}
|
403
|
+
g.prod_or_pers = [Pers.new(:lastname => "He-Man"), Prod.new(:name => "Superman")]
|
404
|
+
g.prod_or_pers_doc_id = {:pers => pers._id, :prod => prod._id}
|
405
|
+
g.pers_doc_id = pers._id
|
406
|
+
g.prod_doc_id = [prod._id]
|
407
|
+
|
408
|
+
save o
|
409
|
+
q = load(o._id)
|
410
|
+
g = q.g
|
411
|
+
assert_equal "Simpson", g.pers.lastname
|
412
|
+
assert_equal "Automobile", g.prod['prod'].name
|
413
|
+
assert_equal pers._id, g.pers_doc_id
|
414
|
+
assert_equal prod._id, g.prod_doc_id.first
|
415
|
+
assert_equal "He-Man", g.prod_or_pers.first.lastname
|
416
|
+
assert_equal "Superman", g.prod_or_pers.last.name
|
417
|
+
assert_equal pers._id, g.prod_or_pers_doc_id['pers']
|
418
|
+
assert_equal prod._id, g.prod_or_pers_doc_id['prod']
|
298
419
|
end
|
299
420
|
end
|
300
421
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanswurst
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-18 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: couch_potato
|
16
|
-
requirement: &
|
16
|
+
requirement: &24934880 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *24934880
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: yard
|
27
|
-
requirement: &
|
27
|
+
requirement: &24934100 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 0.6.0
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *24934100
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bundler
|
38
|
-
requirement: &
|
38
|
+
requirement: &24933340 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 1.0.0
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *24933340
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: jeweler
|
49
|
-
requirement: &
|
49
|
+
requirement: &24932660 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.5.2
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *24932660
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rcov
|
60
|
-
requirement: &
|
60
|
+
requirement: &24932080 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *24932080
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: mocha
|
71
|
-
requirement: &
|
71
|
+
requirement: &24931380 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *24931380
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: shoulda
|
82
|
-
requirement: &
|
82
|
+
requirement: &24905140 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *24905140
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: linecache19
|
93
|
-
requirement: &
|
93
|
+
requirement: &24904540 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *24904540
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: ruby-debug19
|
104
|
-
requirement: &
|
104
|
+
requirement: &24903960 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *24903960
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: couch_potato
|
115
|
-
requirement: &
|
115
|
+
requirement: &24903340 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,7 +120,7 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :runtime
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *24903340
|
124
124
|
description: flexible enhancement of couch potato
|
125
125
|
email: ! 'Base64.decode64(''bGludXhAbWFyY3JlbmVhcm5zLmRl
|
126
126
|
|
@@ -155,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
155
|
version: '0'
|
156
156
|
segments:
|
157
157
|
- 0
|
158
|
-
hash:
|
158
|
+
hash: 542468889761003364
|
159
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
160
|
none: false
|
161
161
|
requirements:
|