hanswurst 0.4.3 → 0.5.0
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.
- 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:
|