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.
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: