hanswurst 0.5.4 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/hanswurst.rb +12 -379
- data/lib/hanswurst/as.rb +35 -0
- data/lib/hanswurst/callbacks.rb +68 -0
- data/lib/hanswurst/class_methods.rb +55 -0
- data/lib/hanswurst/delegates.rb +35 -0
- data/lib/hanswurst/instance_methods.rb +130 -0
- data/lib/hanswurst/method_missing.rb +18 -0
- data/lib/hanswurst/shares.rb +17 -0
- data/lib/hanswurst/validator.rb +74 -0
- data/test/test_hanswurst.rb +112 -9
- metadata +31 -23
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.5
|
data/lib/hanswurst.rb
CHANGED
@@ -1,390 +1,23 @@
|
|
1
1
|
require 'couch_potato'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
valid = true if value.is_a? klass
|
12
|
-
end
|
13
|
-
valid
|
14
|
-
end
|
15
|
-
|
16
|
-
def doc_is_valid_klass?(doc, klasses)
|
17
|
-
!(klasses & doc.hanswurst_roles.values).empty?
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
def validate_each(record, attribute, values)
|
22
|
-
#p options
|
23
|
-
#p record
|
24
|
-
return if values.nil?
|
25
|
-
values = values.values if values.class == Hash
|
26
|
-
values = [values] unless values.class == Array
|
27
|
-
valid = true
|
28
|
-
max = options[:max]
|
29
|
-
if max && values.size > max
|
30
|
-
record.errors.add attribute, "must not have more than #{max} entries"
|
31
|
-
return
|
32
|
-
end
|
33
|
-
fkey = options[:fkey] || false
|
34
|
-
if fkey
|
35
|
-
values = values.collect do |id|
|
36
|
-
CouchPotato.database.load_document id
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
if klass = options[:class]
|
41
|
-
klasses = [klass].flatten
|
42
|
-
if fkey
|
43
|
-
klasses = klasses.collect{ |k| k.to_s }
|
44
|
-
values.each do |doc|
|
45
|
-
valid = false unless doc && doc.hanswurst_roles && doc_is_valid_klass?(doc, klasses)
|
46
|
-
end
|
47
|
-
record.errors.add attribute, "must be a doc id of a class #{klasses.join(' or ')}" unless valid
|
48
|
-
else
|
49
|
-
values.each do |thing|
|
50
|
-
valid = false unless is_valid_klass?(klasses, thing)
|
51
|
-
end
|
52
|
-
record.errors.add attribute, "must be an instance of #{klasses.join(' or ')}" unless valid
|
53
|
-
end
|
54
|
-
elsif role = options[:role]
|
55
|
-
roles = [role].flatten.collect{ |r| r.to_s }
|
56
|
-
if fkey
|
57
|
-
values.each do |doc|
|
58
|
-
valid = false unless doc && doc.hanswurst_roles && doc_is_valid_role?(doc, roles)
|
59
|
-
end
|
60
|
-
record.errors.add attribute, "must be a doc id of a role #{roles.join(' or ')}" unless valid
|
61
|
-
else
|
62
|
-
klasses = roles.collect do |role_alias|
|
63
|
-
klass = Hanswurst.role_class(role_alias.to_sym)
|
64
|
-
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?
|
65
|
-
klass
|
66
|
-
end
|
67
|
-
values.each do |thing|
|
68
|
-
valid = false unless is_valid_klass?(klasses, thing)
|
69
|
-
end
|
70
|
-
record.errors.add attribute, "must be an instance of #{klasses.join(' or ')}" unless valid
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
#roles = options[:in] || [options[:with]]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
3
|
+
require_relative File.join('hanswurst', 'validator')
|
4
|
+
require_relative File.join('hanswurst', 'class_methods')
|
5
|
+
require_relative File.join('hanswurst', 'method_missing')
|
6
|
+
require_relative File.join('hanswurst', 'instance_methods')
|
7
|
+
require_relative File.join('hanswurst', 'delegates')
|
8
|
+
require_relative File.join('hanswurst', 'shares')
|
9
|
+
require_relative File.join('hanswurst', 'as')
|
10
|
+
require_relative File.join('hanswurst', 'callbacks')
|
78
11
|
|
79
12
|
# Each Hanswurst may have a different combination of roles. It's a very flexible way to be a couch potato.
|
80
13
|
class Hanswurst
|
81
|
-
module Delegates
|
82
|
-
def self.included(mod)
|
83
|
-
mod.instance_eval do
|
84
|
-
def delegates(hsh)
|
85
|
-
@delegations ||= {}
|
86
|
-
hsh.each do |prop,role|
|
87
|
-
if prop.is_a? Array
|
88
|
-
prop.each do |pr|
|
89
|
-
@delegations.update pr => role
|
90
|
-
end
|
91
|
-
else
|
92
|
-
@delegations.update prop => role
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def delegations
|
98
|
-
@delegations || {}
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# shortcuts view_for_[role], list_for_[role]
|
104
|
-
def method_missing(meth, *args, &code)
|
105
|
-
meth.to_s =~ /^([^=]+)=?$/
|
106
|
-
unified_meth = $1
|
107
|
-
if role = self.class.delegations[unified_meth.to_sym]
|
108
|
-
self.send(role).send(meth, *args, &code)
|
109
|
-
else
|
110
|
-
super
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
module Shares
|
116
|
-
def self.included(mod)
|
117
|
-
mod.instance_eval do
|
118
|
-
def shares(hsh)
|
119
|
-
hsh = {hsh => hsh} if hsh.is_a? Symbol
|
120
|
-
@shared_dependancies ||= {}
|
121
|
-
@shared_dependancies.update hsh
|
122
|
-
end
|
123
|
-
|
124
|
-
def shared_dependancies
|
125
|
-
@shared_dependancies || {}
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
# error raised when a role is not valid
|
132
|
-
class RoleNotValid < Exception
|
133
|
-
def initialize(role, value)
|
134
|
-
@role = role
|
135
|
-
@value = value
|
136
|
-
end
|
137
|
-
|
138
|
-
def message()
|
139
|
-
errors = @value.errors.messages.collect do |field, err|
|
140
|
-
"#{field} #{err.join('/')}"
|
141
|
-
end.join(" # ")
|
142
|
-
"#{@role} not valid: #{errors}"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# helper for easy access to role attributes
|
147
|
-
class As
|
148
|
-
def initialize(doc, role)
|
149
|
-
@doc = doc
|
150
|
-
@role = role
|
151
|
-
end
|
152
|
-
|
153
|
-
def _role
|
154
|
-
@role
|
155
|
-
end
|
156
|
-
|
157
|
-
def _id
|
158
|
-
@doc._id
|
159
|
-
end
|
160
|
-
|
161
|
-
def _doc
|
162
|
-
@doc
|
163
|
-
end
|
164
|
-
|
165
|
-
# we suppose, we have a subrole
|
166
|
-
def method_missing(meth, *args, &code)
|
167
|
-
# a hack around http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
|
168
|
-
# since ActiveModel::Dirty does not recognize when property is a hash and hashentries do change
|
169
|
-
@doc.update_roles! if meth =~ /=$/
|
170
|
-
|
171
|
-
obj = @role.send(meth, *args)
|
172
|
-
if obj.is_a? CouchPotato::Persistence
|
173
|
-
obj = self.class.new(@doc, @role.send(meth, *args))
|
174
|
-
end
|
175
|
-
obj.instance_eval(&code) if code
|
176
|
-
obj
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# class methods for Hanswurst
|
181
|
-
module ClassMethods
|
182
|
-
|
183
|
-
# get class obj from a classname
|
184
|
-
def getClass(classname)
|
185
|
-
classname.split('::').inject Kernel do |c,name| c = c.const_get name; end
|
186
|
-
end
|
187
|
-
|
188
|
-
# hsh is role_alias => klass where role_alias should be a symbol
|
189
|
-
def register_role(hsh)
|
190
|
-
@roles ||= {}
|
191
|
-
@roles.update hsh
|
192
|
-
end
|
193
|
-
|
194
|
-
# returns the role klass for the role_alias (role_alias should be a symbol)
|
195
|
-
def role_class(role_alias)
|
196
|
-
@roles ||= {}
|
197
|
-
@roles[role_alias]
|
198
|
-
end
|
199
|
-
|
200
|
-
# creates a view to show only documents of the role +role_alias+
|
201
|
-
def role_view(role_alias, viewname, options)
|
202
|
-
# I keep this commented out to inform the reader that we don't want this in order to easily reuse general lists
|
203
|
-
#options[:list] &&= :"#{role_alias}_#{options[:list]}"
|
204
|
-
options[:conditions] &&= " && ( #{options[:conditions]} )"
|
205
|
-
options[:conditions] = "(doc.hanswurst_roles.#{role_alias} !== undefined)#{options[:conditions]}"
|
206
|
-
self.view :"#{role_alias}_#{viewname}", options
|
207
|
-
end
|
208
|
-
|
209
|
-
alias :view_for :role_view
|
210
|
-
|
211
|
-
# creates a list for documents of the role +role_alias+
|
212
|
-
def role_list(role_alias, listname, val)
|
213
|
-
self.list :"#{role_alias}_#{listname}", val.to_s
|
214
|
-
end
|
215
|
-
|
216
|
-
alias :list_for :role_list
|
217
|
-
|
218
|
-
# shortcuts view_for_[role], list_for_[role]
|
219
|
-
def method_missing(meth, *args, &code)
|
220
|
-
case meth
|
221
|
-
when /^view_for_(.+)$/
|
222
|
-
send(:view_for, $1, *args)
|
223
|
-
when /^list_for_(.+)$/
|
224
|
-
send(:list_for, $1, *args)
|
225
|
-
else
|
226
|
-
super
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
extend ClassMethods
|
232
|
-
|
233
14
|
include CouchPotato::Persistence
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
def method_missing(meth, *args, &code)
|
238
|
-
value = args.first
|
239
|
-
case meth
|
240
|
-
when /^([^=]+)\=$/ # obj.role = ... # => we set a role
|
241
|
-
role=$1
|
242
|
-
add_role(role, value.class) unless role_exists?(role)
|
243
|
-
set_role(role, value) if role_exists?(role)
|
244
|
-
return as(meth)
|
245
|
-
else
|
246
|
-
return as(meth) if role_exists?(meth.to_s)
|
247
|
-
end
|
248
|
-
super
|
249
|
-
end
|
250
|
-
end
|
15
|
+
include MethodMissing
|
16
|
+
include Callbacks
|
17
|
+
extend ClassMethods
|
251
18
|
|
252
19
|
property :hanswurst_roles
|
253
20
|
property :hanswurst_data
|
254
|
-
|
255
|
-
# check if every role is valid before saving
|
256
|
-
before_save do
|
257
|
-
self.hanswurst_data.each do |role,val|
|
258
|
-
unless val.valid?
|
259
|
-
raise RoleNotValid.new(role, val)
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
include MethodMissing
|
265
|
-
|
266
|
-
def initialize(hsh={})
|
267
|
-
unless hsh.empty?
|
268
|
-
hsh.each do |role, obj|
|
269
|
-
self.send(:"#{role}=", obj)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
# copy the doc including the roles
|
275
|
-
def copy()
|
276
|
-
attributes = self.to_hash
|
277
|
-
attributes.delete "ruby_class"
|
278
|
-
attributes.delete "_id"
|
279
|
-
attributes.delete "_rev"
|
280
|
-
attributes.delete :created_at
|
281
|
-
attributes.delete :updated_at
|
282
|
-
hanswust_data = attributes.delete :hanswurst_data
|
283
|
-
obj = self.class.new attributes
|
284
|
-
hanswust_data.each do |role,val|
|
285
|
-
obj.send(:"#{role}=", val.dup)
|
286
|
-
end
|
287
|
-
obj
|
288
|
-
end
|
289
|
-
|
290
|
-
def <<(hsh)
|
291
|
-
add_roles(hsh)
|
292
|
-
end
|
293
|
-
|
294
|
-
# a hack around http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
|
295
|
-
# since ActiveModel::Dirty does not recognize when property is a hash and hashentries do change
|
296
|
-
def update_roles!
|
297
|
-
self.hanswurst_data_will_change!
|
298
|
-
end
|
299
|
-
|
300
|
-
private
|
301
|
-
|
302
|
-
# add a role
|
303
|
-
def add_role(role, klass, &code)
|
304
|
-
add_roles(role => klass)
|
305
|
-
as(role, &code)
|
306
|
-
end
|
307
|
-
|
308
|
-
def handle_shared(role, klass)
|
309
|
-
if klass.respond_to?(:shared_dependancies)
|
310
|
-
shared = {}
|
311
|
-
klass.shared_dependancies.each do |shared_role, shared_class|
|
312
|
-
shared_class = Hanswurst.role_class(shared_class) if shared_class.is_a? Symbol
|
313
|
-
shared[shared_role] = shared_class unless role_exists? shared_role
|
314
|
-
end
|
315
|
-
add_roles shared
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
# add more hanswurst_roles at once
|
320
|
-
def add_roles(hsh)
|
321
|
-
self.hanswurst_data ||= {}
|
322
|
-
self.hanswurst_roles ||= {}
|
323
|
-
hsh.each do |role,klass|
|
324
|
-
raise "class expected: #{klass.inspect}" unless klass.is_a? Class
|
325
|
-
handle_shared(role, klass)
|
326
|
-
self.hanswurst_roles.update role.to_s => klass.name
|
327
|
-
end
|
328
|
-
update_roles!
|
329
|
-
self.hanswurst_roles
|
330
|
-
end
|
331
|
-
|
332
|
-
# does he have a role
|
333
|
-
def role_exists?(role)
|
334
|
-
self.hanswurst_roles and self.hanswurst_roles[role.to_s]
|
335
|
-
end
|
336
|
-
|
337
|
-
# does he have hanswurst_data for the role
|
338
|
-
def hanswurst_data_exists?(role)
|
339
|
-
self.hanswurst_data and self.hanswurst_data[role.to_s]
|
340
|
-
end
|
341
|
-
|
342
|
-
# set a role
|
343
|
-
def set_role(role, value)
|
344
|
-
value ? set(role, value) : delete_role(role)
|
345
|
-
end
|
346
|
-
|
347
|
-
# delete a role
|
348
|
-
def delete_role(role)
|
349
|
-
delete role # delete the hanswurst_data
|
350
|
-
self.hanswurst_roles.delete role.to_s # and the role itself
|
351
|
-
end
|
352
|
-
|
353
|
-
# set instance for a role
|
354
|
-
def set(role, val)
|
355
|
-
self.hanswurst_data ||= {}
|
356
|
-
self.hanswurst_data.update role.to_s => val
|
357
|
-
update_roles!
|
358
|
-
end
|
359
|
-
|
360
|
-
# create a new instance of a role
|
361
|
-
def create(role)
|
362
|
-
raise "unknown role #{role.inspect}" unless role_exists? role.to_s
|
363
|
-
self.hanswurst_data ||= {}
|
364
|
-
self.hanswurst_data[role.to_s] = self.class.getClass(self.hanswurst_roles[role.to_s]).new
|
365
|
-
update_roles!
|
366
|
-
end
|
367
|
-
|
368
|
-
# delete a role
|
369
|
-
def delete(role)
|
370
|
-
self.hanswurst_data ||= {}
|
371
|
-
self.hanswurst_data.delete(role.to_s)
|
372
|
-
update_roles!
|
373
|
-
#self.hanswurst_data = {} # we have to do this, otherwise it won't save?!
|
374
|
-
#self.hanswurst_data = hsh
|
375
|
-
end
|
376
|
-
|
377
|
-
def as(role, &code)
|
378
|
-
return nil unless role_exists?(role)
|
379
|
-
unless hanswurst_data[role.to_s]
|
380
|
-
create(role.to_s)
|
381
|
-
end
|
382
|
-
if role_obj = hanswurst_data[role.to_s]
|
383
|
-
obj = As.new(self, role_obj)
|
384
|
-
obj.instance_eval(&code) if code
|
385
|
-
return obj
|
386
|
-
end
|
387
|
-
nil
|
388
|
-
end
|
389
21
|
end
|
390
22
|
|
23
|
+
|
data/lib/hanswurst/as.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# Each Hanswurst may have a different combination of roles. It's a very flexible way to be a couch potato.
|
2
|
+
class Hanswurst
|
3
|
+
|
4
|
+
# helper for easy access to role attributes
|
5
|
+
class As
|
6
|
+
def initialize(doc, role)
|
7
|
+
@doc = doc
|
8
|
+
@role = role
|
9
|
+
end
|
10
|
+
|
11
|
+
def _role
|
12
|
+
@role
|
13
|
+
end
|
14
|
+
|
15
|
+
def _id
|
16
|
+
@doc._id
|
17
|
+
end
|
18
|
+
|
19
|
+
def _doc
|
20
|
+
@doc
|
21
|
+
end
|
22
|
+
|
23
|
+
# we suppose, we have a subrole
|
24
|
+
def method_missing(meth, *args, &code)
|
25
|
+
# a hack around http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
|
26
|
+
# since ActiveModel::Dirty does not recognize when property is a hash and hashentries do change
|
27
|
+
@doc.update_roles! if meth =~ /=$/
|
28
|
+
|
29
|
+
obj = @role.send(meth, *args)
|
30
|
+
obj = self.class.new(@doc, @role.send(meth, *args)) if obj.is_a? CouchPotato::Persistence
|
31
|
+
obj.instance_eval(&code) if code
|
32
|
+
obj
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Hanswurst
|
2
|
+
module Callbacks
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
# mimic the create_document method from https://github.com/langalex/couch_potato/blob/master/lib/couch_potato/database.rb
|
6
|
+
before_create do
|
7
|
+
ok = true
|
8
|
+
self.hanswurst_data.each do |role,document|
|
9
|
+
if document.is_a?(CouchPotato::Persistence)
|
10
|
+
document.errors.clear
|
11
|
+
document.created_at ||= (Time.zone || Time).now
|
12
|
+
document.updated_at = (Time.zone || Time).now
|
13
|
+
(ok = false) if false == document.run_callbacks(:validation_on_save) do
|
14
|
+
(ok = false) if false == document.run_callbacks(:validation_on_create) do
|
15
|
+
raise(CouchPotato::Database::ValidationsFailedError.new(["role: " + role].concat(document.errors.full_messages))) unless database.send(:valid_document?, document)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
(ok = false) if false == document.run_callbacks(:save) do
|
20
|
+
(ok = false) if false == document.run_callbacks(:create) do
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
ok
|
27
|
+
end
|
28
|
+
|
29
|
+
# mimic the update_document method from https://github.com/langalex/couch_potato/blob/master/lib/couch_potato/database.rb
|
30
|
+
before_update do
|
31
|
+
ok = true
|
32
|
+
self.hanswurst_data.each do |role,document|
|
33
|
+
if document.is_a?(CouchPotato::Persistence)
|
34
|
+
document.errors.clear
|
35
|
+
document.created_at ||= (Time.zone || Time).now
|
36
|
+
document.updated_at = (Time.zone || Time).now
|
37
|
+
(ok = false) if false == document.run_callbacks(:validation_on_save) do
|
38
|
+
(ok = false) if false == document.run_callbacks(:validation_on_update) do
|
39
|
+
raise(CouchPotato::Database::ValidationsFailedError.new(["role: " + role].concat(document.errors.full_messages))) unless database.send(:valid_document?, document)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
(ok = false) if false == document.run_callbacks(:save) do
|
44
|
+
(ok = false) if false == document.run_callbacks(:update) do
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
ok
|
51
|
+
end
|
52
|
+
|
53
|
+
# mimic the destroy_document method from https://github.com/langalex/couch_potato/blob/master/lib/couch_potato/database.rb
|
54
|
+
before_destroy do
|
55
|
+
ok = true
|
56
|
+
self.hanswurst_data.each do |role,document|
|
57
|
+
if document.is_a?(CouchPotato::Persistence)
|
58
|
+
(ok = false) if false == document.run_callbacks(:destroy) do
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
ok
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
# TODO allow subclasses of Hanswurst to have the role registry (or handle it via callback)
|
3
|
+
|
4
|
+
class Hanswurst
|
5
|
+
# class methods for Hanswurst
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
# get class obj from a classname
|
9
|
+
def getClass(classname)
|
10
|
+
classname.split('::').inject Kernel do |c,name| c = c.const_get name; end
|
11
|
+
end
|
12
|
+
|
13
|
+
# hsh is role_alias => klass where role_alias should be a symbol
|
14
|
+
def register_role(hsh)
|
15
|
+
@roles ||= {}
|
16
|
+
@roles.update hsh
|
17
|
+
end
|
18
|
+
|
19
|
+
# returns the role klass for the role_alias (role_alias should be a symbol)
|
20
|
+
def role_class(role_alias)
|
21
|
+
@roles ||= {}
|
22
|
+
@roles[role_alias]
|
23
|
+
end
|
24
|
+
|
25
|
+
# creates a view to show only documents of the role +role_alias+
|
26
|
+
def role_view(role_alias, viewname, options)
|
27
|
+
# I keep this commented out to inform the reader that we don't want this in order to easily reuse general lists
|
28
|
+
#options[:list] &&= :"#{role_alias}_#{options[:list]}"
|
29
|
+
options[:conditions] &&= " && ( #{options[:conditions]} )"
|
30
|
+
options[:conditions] = "(doc.hanswurst_roles.#{role_alias} !== undefined)#{options[:conditions]}"
|
31
|
+
self.view :"#{role_alias}_#{viewname}", options
|
32
|
+
end
|
33
|
+
|
34
|
+
alias :view_for :role_view
|
35
|
+
|
36
|
+
# creates a list for documents of the role +role_alias+
|
37
|
+
def role_list(role_alias, listname, val)
|
38
|
+
self.list :"#{role_alias}_#{listname}", val.to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
alias :list_for :role_list
|
42
|
+
|
43
|
+
# shortcuts view_for_[role], list_for_[role]
|
44
|
+
def method_missing(meth, *args, &code)
|
45
|
+
case meth
|
46
|
+
when /^view_for_(.+)$/
|
47
|
+
send(:view_for, $1, *args)
|
48
|
+
when /^list_for_(.+)$/
|
49
|
+
send(:list_for, $1, *args)
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class Hanswurst
|
2
|
+
module Delegates
|
3
|
+
def self.included(mod)
|
4
|
+
mod.instance_eval do
|
5
|
+
def delegates(hsh)
|
6
|
+
@delegations ||= {}
|
7
|
+
hsh.each do |prop,role|
|
8
|
+
if prop.is_a? Array
|
9
|
+
prop.each do |pr|
|
10
|
+
@delegations.update pr => role
|
11
|
+
end
|
12
|
+
else
|
13
|
+
@delegations.update prop => role
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def delegations
|
19
|
+
@delegations || {}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# shortcuts view_for_[role], list_for_[role]
|
25
|
+
def method_missing(meth, *args, &code)
|
26
|
+
meth.to_s =~ /^([^=]+)=?$/
|
27
|
+
unified_meth = $1
|
28
|
+
if role = self.class.delegations[unified_meth.to_sym]
|
29
|
+
self.send(role).send(meth, *args, &code)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
class Hanswurst
|
2
|
+
def initialize(hsh={})
|
3
|
+
unless hsh.empty?
|
4
|
+
hsh.each do |role, obj|
|
5
|
+
self.send(:"#{role}=", obj)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# copy the doc including the roles
|
11
|
+
def copy()
|
12
|
+
attributes = self.to_hash
|
13
|
+
attributes.delete "ruby_class"
|
14
|
+
attributes.delete "_id"
|
15
|
+
attributes.delete "_rev"
|
16
|
+
attributes.delete :created_at
|
17
|
+
attributes.delete :updated_at
|
18
|
+
hanswust_data = attributes.delete :hanswurst_data
|
19
|
+
obj = self.class.new attributes
|
20
|
+
hanswust_data.each do |role,val|
|
21
|
+
obj.send(:"#{role}=", val.dup)
|
22
|
+
end
|
23
|
+
obj
|
24
|
+
end
|
25
|
+
|
26
|
+
def <<(hsh)
|
27
|
+
add_roles(hsh)
|
28
|
+
end
|
29
|
+
|
30
|
+
# a hack around http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
|
31
|
+
# since ActiveModel::Dirty does not recognize when property is a hash and hashentries do change
|
32
|
+
def update_roles!
|
33
|
+
self.hanswurst_data_will_change!
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# add a role
|
40
|
+
def add_role(role, klass, &code)
|
41
|
+
add_roles(role => klass)
|
42
|
+
as(role, &code)
|
43
|
+
end
|
44
|
+
|
45
|
+
def handle_shared(role, klass)
|
46
|
+
if klass.respond_to?(:shared_dependancies)
|
47
|
+
shared = {}
|
48
|
+
klass.shared_dependancies.each do |shared_role, shared_class|
|
49
|
+
shared_class = Hanswurst.role_class(shared_class) if shared_class.is_a? Symbol
|
50
|
+
shared[shared_role] = shared_class unless role_exists? shared_role
|
51
|
+
end
|
52
|
+
add_roles shared
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# add more hanswurst_roles at once
|
57
|
+
def add_roles(hsh)
|
58
|
+
self.hanswurst_data ||= {}
|
59
|
+
self.hanswurst_roles ||= {}
|
60
|
+
hsh.each do |role,klass|
|
61
|
+
raise "class expected: #{klass.inspect}" unless klass.is_a? Class
|
62
|
+
handle_shared(role, klass)
|
63
|
+
self.hanswurst_roles.update role.to_s => klass.name
|
64
|
+
end
|
65
|
+
update_roles!
|
66
|
+
self.hanswurst_roles
|
67
|
+
end
|
68
|
+
|
69
|
+
# does he have a role
|
70
|
+
def role_exists?(role)
|
71
|
+
self.hanswurst_roles and self.hanswurst_roles[role.to_s]
|
72
|
+
end
|
73
|
+
|
74
|
+
# does he have hanswurst_data for the role
|
75
|
+
def hanswurst_data_exists?(role)
|
76
|
+
self.hanswurst_data and self.hanswurst_data[role.to_s]
|
77
|
+
end
|
78
|
+
|
79
|
+
# set a role
|
80
|
+
def set_role(role, value)
|
81
|
+
value ? set(role, value) : delete_role(role)
|
82
|
+
end
|
83
|
+
|
84
|
+
# delete a role
|
85
|
+
def delete_role(role)
|
86
|
+
return false unless delete(role) # delete the hanswurst_data
|
87
|
+
self.hanswurst_roles.delete role.to_s # and the role itself
|
88
|
+
end
|
89
|
+
|
90
|
+
# set instance for a role
|
91
|
+
def set(role, val)
|
92
|
+
self.hanswurst_data ||= {}
|
93
|
+
self.hanswurst_data.update role.to_s => val
|
94
|
+
update_roles!
|
95
|
+
end
|
96
|
+
|
97
|
+
# create a new instance of a role
|
98
|
+
def create(role)
|
99
|
+
raise "unknown role #{role.inspect}" unless role_exists? role.to_s
|
100
|
+
self.hanswurst_data ||= {}
|
101
|
+
self.hanswurst_data[role.to_s] = self.class.getClass(self.hanswurst_roles[role.to_s]).new
|
102
|
+
update_roles!
|
103
|
+
end
|
104
|
+
|
105
|
+
# delete a role
|
106
|
+
def delete(role)
|
107
|
+
self.hanswurst_data ||= {}
|
108
|
+
doc = self.hanswurst_data[role.to_s]
|
109
|
+
if doc && doc.is_a?(CouchPotato::Persistence)
|
110
|
+
return false if false == doc.run_callbacks(:destroy) do
|
111
|
+
self.hanswurst_data.delete(role.to_s)
|
112
|
+
update_roles!
|
113
|
+
end
|
114
|
+
end
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
def as(role, &code)
|
119
|
+
return nil unless role_exists?(role)
|
120
|
+
unless hanswurst_data[role.to_s]
|
121
|
+
create(role.to_s)
|
122
|
+
end
|
123
|
+
if role_obj = hanswurst_data[role.to_s]
|
124
|
+
obj = As.new(self, role_obj)
|
125
|
+
obj.instance_eval(&code) if code
|
126
|
+
return obj
|
127
|
+
end
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Hanswurst
|
2
|
+
module MethodMissing
|
3
|
+
# dispatches self.role calls and self.role= setters
|
4
|
+
def method_missing(meth, *args, &code)
|
5
|
+
value = args.first
|
6
|
+
case meth
|
7
|
+
when /^([^=]+)\=$/ # obj.role = ... # => we set a role
|
8
|
+
role=$1
|
9
|
+
add_role(role, value.class) unless role_exists?(role)
|
10
|
+
set_role(role, value) if role_exists?(role)
|
11
|
+
return as(meth)
|
12
|
+
else
|
13
|
+
return as(meth) if role_exists?(meth.to_s)
|
14
|
+
end
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Hanswurst
|
2
|
+
module Shares
|
3
|
+
def self.included(mod)
|
4
|
+
mod.instance_eval do
|
5
|
+
def shares(hsh)
|
6
|
+
hsh = {hsh => hsh} if hsh.is_a? Symbol
|
7
|
+
@shared_dependancies ||= {}
|
8
|
+
@shared_dependancies.update hsh
|
9
|
+
end
|
10
|
+
|
11
|
+
def shared_dependancies
|
12
|
+
@shared_dependancies || {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class HanswurstValidator < ActiveModel::EachValidator
|
2
|
+
def doc_is_valid_role?(doc, roles)
|
3
|
+
!(roles & doc.hanswurst_roles.keys).empty?
|
4
|
+
end
|
5
|
+
|
6
|
+
def is_valid_klass?(klasses, value)
|
7
|
+
valid = false
|
8
|
+
klasses.each do |klass|
|
9
|
+
valid = true if value.is_a? klass
|
10
|
+
end
|
11
|
+
valid
|
12
|
+
end
|
13
|
+
|
14
|
+
def doc_is_valid_klass?(doc, klasses)
|
15
|
+
!(klasses & doc.hanswurst_roles.values).empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def validate_each(record, attribute, values)
|
20
|
+
#p options
|
21
|
+
#p record
|
22
|
+
return if values.nil?
|
23
|
+
values = values.values if values.class == Hash
|
24
|
+
values = [values] unless values.class == Array
|
25
|
+
valid = true
|
26
|
+
max = options[:max]
|
27
|
+
if max && values.size > max
|
28
|
+
record.errors.add attribute, "must not have more than #{max} entries"
|
29
|
+
return
|
30
|
+
end
|
31
|
+
fkey = options[:fkey] || false
|
32
|
+
if fkey
|
33
|
+
values = values.collect do |id|
|
34
|
+
CouchPotato.database.load_document id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
if klass = options[:class]
|
39
|
+
klasses = [klass].flatten
|
40
|
+
if fkey
|
41
|
+
klasses = klasses.collect{ |k| k.to_s }
|
42
|
+
values.each do |doc|
|
43
|
+
valid = false unless doc && doc.hanswurst_roles && doc_is_valid_klass?(doc, klasses)
|
44
|
+
end
|
45
|
+
record.errors.add attribute, "must be a doc id of a class #{klasses.join(' or ')}" unless valid
|
46
|
+
else
|
47
|
+
values.each do |thing|
|
48
|
+
valid = false unless is_valid_klass?(klasses, thing)
|
49
|
+
end
|
50
|
+
record.errors.add attribute, "must be an instance of #{klasses.join(' or ')}" unless valid
|
51
|
+
end
|
52
|
+
elsif role = options[:role]
|
53
|
+
roles = [role].flatten.collect{ |r| r.to_s }
|
54
|
+
if fkey
|
55
|
+
values.each do |doc|
|
56
|
+
valid = false unless doc && doc.hanswurst_roles && doc_is_valid_role?(doc, roles)
|
57
|
+
end
|
58
|
+
record.errors.add attribute, "must be a doc id of a role #{roles.join(' or ')}" unless valid
|
59
|
+
else
|
60
|
+
klasses = roles.collect do |role_alias|
|
61
|
+
klass = Hanswurst.role_class(role_alias.to_sym)
|
62
|
+
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?
|
63
|
+
klass
|
64
|
+
end
|
65
|
+
values.each do |thing|
|
66
|
+
valid = false unless is_valid_klass?(klasses, thing)
|
67
|
+
end
|
68
|
+
record.errors.add attribute, "must be an instance of #{klasses.join(' or ')}" unless valid
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
#roles = options[:in] || [options[:with]]
|
73
|
+
end
|
74
|
+
end
|
data/test/test_hanswurst.rb
CHANGED
@@ -5,6 +5,7 @@ CouchPotato::Config.database_name = ENV['COUCH_POTATO_TEST_DB']
|
|
5
5
|
|
6
6
|
|
7
7
|
class Pers
|
8
|
+
|
8
9
|
include CouchPotato::Persistence
|
9
10
|
property :firstname
|
10
11
|
property :lastname
|
@@ -12,6 +13,57 @@ class Pers
|
|
12
13
|
def name(seperator)
|
13
14
|
"#{lastname}#{seperator}#{firstname}"
|
14
15
|
end
|
16
|
+
|
17
|
+
attr_accessor :callbacks
|
18
|
+
|
19
|
+
before_save do
|
20
|
+
@callbacks ||= []
|
21
|
+
@callbacks << :before_save
|
22
|
+
end
|
23
|
+
|
24
|
+
after_save do
|
25
|
+
@callbacks ||= []
|
26
|
+
@callbacks << :after_save
|
27
|
+
end
|
28
|
+
|
29
|
+
before_create do
|
30
|
+
@callbacks ||= []
|
31
|
+
@callbacks << :before_create
|
32
|
+
end
|
33
|
+
|
34
|
+
after_create do
|
35
|
+
@callbacks ||= []
|
36
|
+
@callbacks << :after_create
|
37
|
+
end
|
38
|
+
|
39
|
+
before_update do
|
40
|
+
@callbacks ||= []
|
41
|
+
@callbacks << :before_update
|
42
|
+
end
|
43
|
+
|
44
|
+
after_update do
|
45
|
+
@callbacks ||= []
|
46
|
+
@callbacks << :after_update
|
47
|
+
end
|
48
|
+
|
49
|
+
before_destroy do
|
50
|
+
@callbacks ||= []
|
51
|
+
@callbacks << :before_destroy
|
52
|
+
end
|
53
|
+
|
54
|
+
after_destroy do
|
55
|
+
@callbacks ||= []
|
56
|
+
@callbacks << :after_destroy
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class PreventsDeletion
|
61
|
+
include CouchPotato::Persistence
|
62
|
+
property :data
|
63
|
+
|
64
|
+
before_destroy do
|
65
|
+
false
|
66
|
+
end
|
15
67
|
end
|
16
68
|
|
17
69
|
class Prod
|
@@ -55,18 +107,11 @@ end
|
|
55
107
|
class F
|
56
108
|
include CouchPotato::Persistence
|
57
109
|
|
58
|
-
#depends_on 'd' => D
|
59
|
-
|
60
110
|
property :d
|
61
|
-
|
62
111
|
property :f
|
63
|
-
|
64
112
|
property :a # should be an instance of A
|
65
|
-
|
66
113
|
property :perss # should be an Array of instances of Pers
|
67
|
-
|
68
|
-
property :h # should be a Hash
|
69
|
-
|
114
|
+
property :h # should be a Hash
|
70
115
|
end
|
71
116
|
|
72
117
|
class G
|
@@ -142,6 +187,10 @@ class TestCouch < Test::Unit::TestCase
|
|
142
187
|
CouchPotato.database.view v
|
143
188
|
end
|
144
189
|
|
190
|
+
def destroy(doc)
|
191
|
+
CouchPotato.database.destroy_document doc
|
192
|
+
end
|
193
|
+
|
145
194
|
def update(id)
|
146
195
|
doc = load id
|
147
196
|
yield doc
|
@@ -153,6 +202,52 @@ class TestCouch < Test::Unit::TestCase
|
|
153
202
|
recreate_db()
|
154
203
|
end
|
155
204
|
|
205
|
+
should "invoke callbacks" do
|
206
|
+
o = Hanswurst.new
|
207
|
+
o.pers = Pers.new( :lastname => 'Duck' )
|
208
|
+
save o
|
209
|
+
assert_equal [:before_save, :before_create, :after_create, :after_save], o.pers.callbacks
|
210
|
+
|
211
|
+
o = load o._id
|
212
|
+
o.pers.lastname = 'Doc'
|
213
|
+
save o
|
214
|
+
assert_equal [:before_save, :before_update, :after_update, :after_save], o.pers.callbacks
|
215
|
+
|
216
|
+
id = o._id
|
217
|
+
o = load o._id
|
218
|
+
pers = o.pers
|
219
|
+
destroy o
|
220
|
+
assert_equal [:before_destroy, :after_destroy], pers.callbacks
|
221
|
+
|
222
|
+
o = load id
|
223
|
+
assert_equal nil, o
|
224
|
+
|
225
|
+
o = Hanswurst.new
|
226
|
+
o.pers = Pers.new( :lastname => 'Duck' )
|
227
|
+
save o
|
228
|
+
|
229
|
+
o = load o._id
|
230
|
+
pers = o.pers
|
231
|
+
o.pers = nil
|
232
|
+
assert_equal [:before_destroy, :after_destroy], pers.callbacks
|
233
|
+
|
234
|
+
o = Hanswurst.new
|
235
|
+
o.prevents = PreventsDeletion.new :data => 'something'
|
236
|
+
save o
|
237
|
+
o = load o._id
|
238
|
+
o.prevents = nil
|
239
|
+
assert_equal 'something', o.prevents.data
|
240
|
+
|
241
|
+
o = Hanswurst.new
|
242
|
+
o.prevents = PreventsDeletion.new :data => 'something'
|
243
|
+
save o
|
244
|
+
id = o._id
|
245
|
+
o = load o._id
|
246
|
+
destroy o
|
247
|
+
o = load id
|
248
|
+
assert_equal 'something', o.prevents.data
|
249
|
+
end
|
250
|
+
|
156
251
|
should "save stuff" do
|
157
252
|
o = Hanswurst.new
|
158
253
|
o.product = Prod.new( :article_number => 'xyz', :name => 'prod1' )
|
@@ -241,11 +336,19 @@ class TestCouch < Test::Unit::TestCase
|
|
241
336
|
assert_equal 'hiho', o.thing.a
|
242
337
|
end
|
243
338
|
|
339
|
+
should "destroy a doc" do
|
340
|
+
o = Hanswurst.new
|
341
|
+
o.pers = Pers.new
|
342
|
+
o.pers.lastname = "hiho"
|
343
|
+
save o
|
344
|
+
o = load(o._id)
|
345
|
+
destroy o
|
346
|
+
end
|
244
347
|
|
245
348
|
should "not save when validation fails" do
|
246
349
|
o = Hanswurst.new
|
247
350
|
o.product = Prod.new( :article_number => 'xyz')
|
248
|
-
assert_raises
|
351
|
+
assert_raises CouchPotato::Database::ValidationsFailedError do
|
249
352
|
save o
|
250
353
|
end
|
251
354
|
end
|
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.5.
|
4
|
+
version: 0.5.5
|
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-20 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: couch_potato
|
16
|
-
requirement: &
|
16
|
+
requirement: &15523120 !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: *15523120
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: yard
|
27
|
-
requirement: &
|
27
|
+
requirement: &15522500 !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: *15522500
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bundler
|
38
|
-
requirement: &
|
38
|
+
requirement: &15521920 !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: *15521920
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: jeweler
|
49
|
-
requirement: &
|
49
|
+
requirement: &15521320 !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: *15521320
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rcov
|
60
|
-
requirement: &
|
60
|
+
requirement: &15520780 !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: *15520780
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: mocha
|
71
|
-
requirement: &
|
71
|
+
requirement: &15520200 !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: *15520200
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: shoulda
|
82
|
-
requirement: &
|
82
|
+
requirement: &15495700 !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: *15495700
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: linecache19
|
93
|
-
requirement: &
|
93
|
+
requirement: &15495060 !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: *15495060
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: ruby-debug19
|
104
|
-
requirement: &
|
104
|
+
requirement: &15494420 !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: *15494420
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: couch_potato
|
115
|
-
requirement: &
|
115
|
+
requirement: &15493800 !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: *15493800
|
124
124
|
description: flexible enhancement of couch potato
|
125
125
|
email: ! 'Base64.decode64(''bGludXhAbWFyY3JlbmVhcm5zLmRl
|
126
126
|
|
@@ -138,6 +138,14 @@ files:
|
|
138
138
|
- Rakefile
|
139
139
|
- VERSION
|
140
140
|
- lib/hanswurst.rb
|
141
|
+
- lib/hanswurst/as.rb
|
142
|
+
- lib/hanswurst/callbacks.rb
|
143
|
+
- lib/hanswurst/class_methods.rb
|
144
|
+
- lib/hanswurst/delegates.rb
|
145
|
+
- lib/hanswurst/instance_methods.rb
|
146
|
+
- lib/hanswurst/method_missing.rb
|
147
|
+
- lib/hanswurst/shares.rb
|
148
|
+
- lib/hanswurst/validator.rb
|
141
149
|
- test/helper.rb
|
142
150
|
- test/test_hanswurst.rb
|
143
151
|
homepage: http://github.com/metakeule/hanswurst
|
@@ -155,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
163
|
version: '0'
|
156
164
|
segments:
|
157
165
|
- 0
|
158
|
-
hash: -
|
166
|
+
hash: -1349200765658973839
|
159
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
168
|
none: false
|
161
169
|
requirements:
|