hanswurst 0.5.4 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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:
|