hanswurst 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.md +24 -59
  2. data/VERSION +1 -1
  3. data/lib/hanswurst.rb +168 -54
  4. data/test/test_hanswurst.rb +222 -101
  5. 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.add_role 'person', Person # first role then class
51
- hw.add_role 'product', Product
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
- person = hw.as :person
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.person___first_name # => 'Diederich'
71
- hw.person___name # => 'Diederich Hessling'
72
- hw.product___price # => 20
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
- depends_on 'address_privat', Address
97
- depends_on 'address_work', Address
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.add_role 'employee', Person
105
- hw.employee___last_name = 'Hessling'
106
- hw.employee__address_privat___city = 'Berlin'
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 'address_privat', Address
135
- shares 'address_work', Address
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.add_role 'employee', Person
143
- hw.employee___last_name = 'Hessling'
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.4.3
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 depends_on(aliasname, role)
10
- @dependancies ||= {}
11
- @dependancies[aliasname] = role
80
+ def delegates(attr_symbol, role)
81
+ @delegations ||= {}
82
+ @delegations[attr_symbol] = role
12
83
  end
13
84
 
14
- def dependancies
15
- @dependancies || {}
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(aliasname, role)
106
+ def shares(hsh)
107
+ hsh = {hsh => hsh} if hsh.is_a? Symbol
25
108
  @shared_dependancies ||= {}
26
- @shared_dependancies[aliasname] = role
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, *roles)
136
+ def initialize(doc, obj)
54
137
  @doc = doc
55
- @roles = roles
138
+ @obj = obj
56
139
  end
57
140
 
58
141
  def _id
59
142
  @doc._id
60
143
  end
61
144
 
62
- def as(*new_roles)
63
- self.class.new(@doc, *@roles.dup.concat(new_roles))
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
- if meth.to_s =~ /__/
73
- @doc.send(:"#{roles_as_string}__#{meth}", *args)
74
- else
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
- role, property, setter = $1, $2, $3
130
- return setter ? set_property(role, property, value) : read(role, property, *args)
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
- return set_role(role, value) if role_exists?(role=$1)
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
- # add a role
153
- def add_role(role, klass)
154
- add_roles(role => klass)
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
- def handle_dependancies(role, klass)
158
- if klass.respond_to?(:dependancies)
159
- deps = {}
160
- klass.dependancies.each do |dep_role, dep_class|
161
- deps["#{role}__#{dep_role}"] = dep_class
162
- end
163
- add_roles deps
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
- return self.hanswurst_data[role.to_s].send(property.to_sym, *args) if hanswurst_data_exists?(role.to_s)
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
- return As.new(self, role)
248
- end
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
- obj
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
@@ -32,10 +32,9 @@ end
32
32
 
33
33
  class D
34
34
  include CouchPotato::Persistence
35
- include Hanswurst::Depends
36
35
 
37
- depends_on 'person', Pers
38
- depends_on 'prod', Prod
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 'person', Pers
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', 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.hanswurst_data["product"].name
126
- assert_equal 'Donald', o.hanswurst_data["person"].firstname
127
- assert_equal 'Donald', o.person___firstname
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.add_role 'person', Pers
133
- o.add_role 'product', Prod
134
- o.product___article_number = "abc"
135
- o.product___name = "prod1"
136
- o.person___firstname = "Bugs"
137
- o.person___lastname = "Bunny"
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.person___firstname
143
- assert_equal 'Bunny', o.person___lastname
144
- assert_equal 'abc', o.product___article_number
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.product___article_number = "cde"
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.product___name
150
- assert_equal 'Bugs', o.person___firstname
151
- assert_equal 'cde', o.product___article_number
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
- assert_equal nil, o.product___name
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.person___firstname
159
- assert_equal nil, o.product___article_number
160
- #p [:person, o.person]
161
- assert_equal 'Bunny, Bugs', o.person___name(', ')
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.add_role 'thing', Thing::A
167
- o.thing___a = "hiho"
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.thing___a
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 "create dependancies based on definitions" do
199
- o = Hanswurst.new
200
- o.add_role 'do', D
201
- o.do___my_prop = "4AD"
202
- o.do__person___firstname = "Dagobert"
203
- o.do__person___lastname = "Duck"
204
- o.do__prod___name = "Comic Hero"
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.do___my_prop
208
- assert_equal "Dagobert", o.do__person___firstname
209
- assert_equal "Comic Hero", o.do__prod___name
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.add_role 'done', D
260
+ q << {'done' => D}
213
261
  q.done = D.new( :my_prop => '5AD')
214
- q.done__person___firstname = "Dagobert"
215
- q.done__person___lastname = "Duck"
216
- q.done__prod___name = "Comic Hero"
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.done___my_prop
220
- assert_equal "Dagobert", q.done__person___firstname
221
- assert_equal "Comic Hero", q.done__prod___name
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.add_role 'do', E
227
- o.do___e = "4AD"
228
- o.person___lastname = "Duck"
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.do___e
232
- assert_equal "Duck", o.person___lastname
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.add_role 'fff', F
238
- o.fff__d__person___lastname = "Duck"
239
- o.fff__d__prod___name = "testerer"
240
- o.fff___f = "FFF"
241
- o.fff__d___my_prop = "hiho"
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.fff___f
245
- assert_equal "Duck", q.fff__d__person___lastname
246
- assert_equal "hiho", q.fff__d___my_prop
247
- assert_equal "testerer", q.fff__d__prod___name
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 "allow easy access to role specific methods via 'as'" do
309
+ should "copy docs" do
251
310
  o = Hanswurst.new
252
- o.add_role 'fff', F
253
- f = o.as 'fff'
254
- d = f.as "d"
255
- person = d.as "person"
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.prod___name = "testerer"
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
- assert_equal "FFF", q.fff___f
264
- assert_equal "Duck", q.fff__d__person___lastname
265
- assert_equal "hiho", q.fff__d___my_prop
266
- assert_equal "testerer", q.fff__d__prod___name
267
-
268
- qf = q.as :fff
269
-
270
- assert_equal "FFF", qf.f
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
- qpers = qf.as(:d).as :person
273
- assert_equal "Duck", qpers.lastname
274
- assert_equal "Duck, Donald", qpers.name(', ')
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.add_role 'fff', F
280
- f = o.as 'fff'
281
- d = f.as "d"
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 "FFF", s.fff___f
295
- assert_equal "Duck", s.fff__d__person___lastname
296
- assert_equal "hiho", s.fff__d___my_prop
297
- assert_equal "testerer", s.fff__d__prod___name
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.3
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-17 00:00:00.000000000Z
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: &14466440 !ruby/object:Gem::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: *14466440
24
+ version_requirements: *24934880
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: yard
27
- requirement: &14465840 !ruby/object:Gem::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: *14465840
35
+ version_requirements: *24934100
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
- requirement: &14465220 !ruby/object:Gem::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: *14465220
46
+ version_requirements: *24933340
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: jeweler
49
- requirement: &14464520 !ruby/object:Gem::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: *14464520
57
+ version_requirements: *24932660
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rcov
60
- requirement: &14463900 !ruby/object:Gem::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: *14463900
68
+ version_requirements: *24932080
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: mocha
71
- requirement: &14463220 !ruby/object:Gem::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: *14463220
79
+ version_requirements: *24931380
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: shoulda
82
- requirement: &14462520 !ruby/object:Gem::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: *14462520
90
+ version_requirements: *24905140
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: linecache19
93
- requirement: &14461820 !ruby/object:Gem::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: *14461820
101
+ version_requirements: *24904540
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: ruby-debug19
104
- requirement: &14461100 !ruby/object:Gem::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: *14461100
112
+ version_requirements: *24903960
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: couch_potato
115
- requirement: &14429280 !ruby/object:Gem::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: *14429280
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: 1650791006262531453
158
+ hash: 542468889761003364
159
159
  required_rubygems_version: !ruby/object:Gem::Requirement
160
160
  none: false
161
161
  requirements: