traits 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/traits-0.8.0.rb +664 -0
- data/lib/traits.rb +664 -0
- metadata +40 -0
data/lib/traits-0.8.0.rb
ADDED
@@ -0,0 +1,664 @@
|
|
1
|
+
$__TRAIT_DEBUG__ = ENV['__TRAIT_DEBUG__'] || ENV['TRAIT_DEBUG'] || ENV['DEBUG']
|
2
|
+
$__TRAIT_VERSION__ = "0.8.0"
|
3
|
+
|
4
|
+
class Object
|
5
|
+
#--{{{
|
6
|
+
def singleton_method_added(*a, &b)
|
7
|
+
#--{{{
|
8
|
+
obj = self
|
9
|
+
obj.__trait_singleton_class.__trait_module_eval{ @__trait_singleton_super = obj }
|
10
|
+
#--}}}
|
11
|
+
end
|
12
|
+
def __trait_singleton_class
|
13
|
+
#--{{{
|
14
|
+
@__trait_singleton_class ||= class << self;self;end
|
15
|
+
#--}}}
|
16
|
+
end
|
17
|
+
def __trait_singleton?
|
18
|
+
#--{{{
|
19
|
+
@__is_trait_singleton ||=
|
20
|
+
((Class === self) and (@__is_trait_singleton ||= (not self.ancestors.include?(self))))
|
21
|
+
#--}}}
|
22
|
+
end
|
23
|
+
def __trait_search_path
|
24
|
+
#--{{{
|
25
|
+
#((Class === self and not __trait_singleton?) ? ancestors : [self])
|
26
|
+
(__trait_singleton? or not respond_to? 'ancestors') ? [self] : ancestors
|
27
|
+
#--}}}
|
28
|
+
end
|
29
|
+
def __trait_getopt opts, key, default = nil
|
30
|
+
#--{{{
|
31
|
+
return opts.delete(key) if opts.has_key? key
|
32
|
+
|
33
|
+
key = "#{ key }"
|
34
|
+
return opts.delete(key) if opts.has_key? key
|
35
|
+
|
36
|
+
key = key.intern
|
37
|
+
return opts.delete(key) if opts.has_key? key
|
38
|
+
|
39
|
+
key = "#{ key }s"
|
40
|
+
return opts.delete(key) if opts.has_key? key
|
41
|
+
|
42
|
+
key = key.intern
|
43
|
+
return opts.delete(key) if opts.has_key? key
|
44
|
+
|
45
|
+
key = "#{ key }es"
|
46
|
+
return opts.delete(key) if opts.has_key? key
|
47
|
+
|
48
|
+
key = key.intern
|
49
|
+
return opts.delete(key) if opts.has_key? key
|
50
|
+
|
51
|
+
return default
|
52
|
+
#--}}}
|
53
|
+
end
|
54
|
+
def __trait_arg_filter(*args, &block)
|
55
|
+
#--{{{
|
56
|
+
pre = nil
|
57
|
+
post = nil
|
58
|
+
validate = nil
|
59
|
+
cast = nil
|
60
|
+
munge = nil
|
61
|
+
type = nil
|
62
|
+
ducktype = nil
|
63
|
+
default = nil
|
64
|
+
names_and_defaults = nil
|
65
|
+
|
66
|
+
if block and not block.respond_to? :__trait_default
|
67
|
+
block.__trait_singleton_class.class_eval{ attr '__trait_default' }
|
68
|
+
end
|
69
|
+
|
70
|
+
list, hashes = [ args ].flatten.partition{|arg| not Hash === arg}
|
71
|
+
opts = hashes.inject({}){|accum,h| accum.update h}
|
72
|
+
|
73
|
+
pre = __trait_getopt opts, 'pre'
|
74
|
+
post = __trait_getopt opts, 'post'
|
75
|
+
validate = __trait_getopt opts, 'validate'
|
76
|
+
cast = __trait_getopt opts, 'cast'
|
77
|
+
munge = __trait_getopt opts, 'munge'
|
78
|
+
type = __trait_getopt(opts, 'type', __trait_getopt(opts, 'case'))
|
79
|
+
ducktype = __trait_getopt opts, 'ducktype'
|
80
|
+
default = __trait_getopt opts, 'default'
|
81
|
+
|
82
|
+
names_and_defaults = opts
|
83
|
+
|
84
|
+
raise ArgumentError,
|
85
|
+
"cannot specify both 'default' keyword and 'default' block" if
|
86
|
+
block and default
|
87
|
+
|
88
|
+
default ||= block
|
89
|
+
|
90
|
+
list.each{|name| names_and_defaults[name] = default}
|
91
|
+
|
92
|
+
names = list + (names_and_defaults.keys - list)
|
93
|
+
|
94
|
+
hooks = {
|
95
|
+
'pre' => pre,
|
96
|
+
'cast' => cast,
|
97
|
+
'munge' => munge,
|
98
|
+
'type' => type,
|
99
|
+
'ducktype' => ducktype,
|
100
|
+
'validate' => validate,
|
101
|
+
'post' => post,
|
102
|
+
}
|
103
|
+
|
104
|
+
names_and_hooks = names.inject({}){|h, name| h.update name => hooks}
|
105
|
+
|
106
|
+
{
|
107
|
+
'names' => names,
|
108
|
+
'names_and_defaults' => names_and_defaults,
|
109
|
+
'names_and_hooks' => names_and_hooks,
|
110
|
+
'hooks' => hooks,
|
111
|
+
#'pre' => pre, 'post' => post, 'validate' => validate, 'munge' => munge, 'cast' => cast,
|
112
|
+
'default' => default,
|
113
|
+
}.update hooks
|
114
|
+
#--}}}
|
115
|
+
end
|
116
|
+
def __trait_instance_method_list
|
117
|
+
#--{{{
|
118
|
+
@__trait_instance_method_list ||= {'writers' => [], 'readers' => [], }
|
119
|
+
#--}}}
|
120
|
+
end
|
121
|
+
def __trait_singleton_method_list
|
122
|
+
#--{{{
|
123
|
+
@__trait_singleton_method_list ||= {'writers' => [], 'readers' => [], }
|
124
|
+
#--}}}
|
125
|
+
end
|
126
|
+
def __trait_instance_method_defaults
|
127
|
+
#--{{{
|
128
|
+
@__trait_instance_method_defaults ||= {}
|
129
|
+
#--}}}
|
130
|
+
end
|
131
|
+
def __trait_singleton_method_defaults
|
132
|
+
#--{{{
|
133
|
+
@__trait_singleton_method_defaults ||= {}
|
134
|
+
#--}}}
|
135
|
+
end
|
136
|
+
def __trait_instance_method_hooks
|
137
|
+
#--{{{
|
138
|
+
@__trait_instance_method_hooks ||=
|
139
|
+
#Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil, 'munge' => nil, 'cast' => nil} }
|
140
|
+
Hash::new{ |h,name| h[name] = {} }
|
141
|
+
#--}}}
|
142
|
+
end
|
143
|
+
def __trait_singleton_method_hooks
|
144
|
+
#--{{{
|
145
|
+
@__trait_singleton_method_hooks ||=
|
146
|
+
#Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil, 'munge' => nil, 'cast' => nil} }
|
147
|
+
Hash::new{ |h,name| h[name] = {} }
|
148
|
+
#--}}}
|
149
|
+
end
|
150
|
+
def __trait_evaluate(*a, &b)
|
151
|
+
#--{{{
|
152
|
+
m = "__trait_evaluate__#{ Thread::current.object_id.abs }__#{ rand 42 }__#{ rand 666 }__"
|
153
|
+
__trait_singleton_class.module_eval{ define_method m, &b }
|
154
|
+
begin
|
155
|
+
send m, *a
|
156
|
+
ensure
|
157
|
+
__trait_singleton_class.module_eval{ remove_method m }
|
158
|
+
end
|
159
|
+
#--}}}
|
160
|
+
end
|
161
|
+
|
162
|
+
def __trait_define_singleton_reader_traits(*args, &block)
|
163
|
+
#--{{{
|
164
|
+
argf = __trait_arg_filter args, &block
|
165
|
+
defaults = __trait_singleton_method_defaults
|
166
|
+
list = __trait_singleton_method_list
|
167
|
+
mhooks = __trait_singleton_method_hooks
|
168
|
+
argf['names_and_defaults'].each do |name, default|
|
169
|
+
__trait_singleton_class.__trait_define_reader_trait name, default, defaults, list
|
170
|
+
end
|
171
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
172
|
+
__trait_search_path.map{|ta| ta.__trait_singleton_method_list['readers']}.flatten
|
173
|
+
#--}}}
|
174
|
+
end
|
175
|
+
def __trait_define_singleton_writer_traits(*args, &block)
|
176
|
+
#--{{{
|
177
|
+
argf = __trait_arg_filter args, &block
|
178
|
+
defaults = __trait_singleton_method_defaults
|
179
|
+
list = __trait_singleton_method_list
|
180
|
+
mhooks = __trait_singleton_method_hooks
|
181
|
+
argf['names_and_defaults'].each do |name, default|
|
182
|
+
__trait_singleton_class.__trait_define_writer_trait name, default, defaults, list
|
183
|
+
end
|
184
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
185
|
+
__trait_search_path.map{|ta| ta.__trait_singleton_method_list['writers']}.flatten
|
186
|
+
#--}}}
|
187
|
+
end
|
188
|
+
def __trait_define_singleton_traits(*args, &block)
|
189
|
+
#--{{{
|
190
|
+
writers = __trait_define_singleton_writer_traits(*args, &block)
|
191
|
+
readers = __trait_define_singleton_reader_traits(*args, &block)
|
192
|
+
wr = writers.inject({}){|h,k| h.update k.delete('=') => k}
|
193
|
+
readers.map{|r| [r, wr[r]]}
|
194
|
+
#--}}}
|
195
|
+
end
|
196
|
+
%w(
|
197
|
+
instance_reader_traits
|
198
|
+
instance_reader_trait
|
199
|
+
reader_traits
|
200
|
+
reader_trait
|
201
|
+
r_traits
|
202
|
+
r_trait
|
203
|
+
has_readers
|
204
|
+
has_reader
|
205
|
+
has_r
|
206
|
+
|
207
|
+
instance_writer_traits
|
208
|
+
instance_writer_trait
|
209
|
+
writer_traits
|
210
|
+
writer_trait
|
211
|
+
w_traits
|
212
|
+
w_trait
|
213
|
+
has_writers
|
214
|
+
has_writer
|
215
|
+
has_w
|
216
|
+
|
217
|
+
instance_traits
|
218
|
+
instance_trait
|
219
|
+
traits
|
220
|
+
trait
|
221
|
+
has
|
222
|
+
).each do |meth|
|
223
|
+
eval <<-def
|
224
|
+
def #{ meth }(*a, &b)
|
225
|
+
__trait_singleton_class.send('#{ meth }', *a, &b)
|
226
|
+
end
|
227
|
+
def
|
228
|
+
end
|
229
|
+
#--}}}
|
230
|
+
end
|
231
|
+
class Class
|
232
|
+
#--{{{
|
233
|
+
def __trait_singleton_super
|
234
|
+
#--{{{
|
235
|
+
class_eval{ def __________trait_singleton_super_init;end } unless defined? @__trait_singleton_super
|
236
|
+
@__trait_singleton_super
|
237
|
+
#--}}}
|
238
|
+
end
|
239
|
+
#--}}}
|
240
|
+
end
|
241
|
+
class Module
|
242
|
+
#--{{{
|
243
|
+
|
244
|
+
def __trait_module_eval(*a, &b)
|
245
|
+
#--{{{
|
246
|
+
begin
|
247
|
+
module_eval(*a, &b)
|
248
|
+
rescue Exception => e
|
249
|
+
STDERR.puts([a, b].inspect) if $__TRAIT_DEBUG__
|
250
|
+
raise
|
251
|
+
end
|
252
|
+
#--}}}
|
253
|
+
end
|
254
|
+
|
255
|
+
def __trait_define_instance_reader_traits(*args, &block)
|
256
|
+
#--{{{
|
257
|
+
if __trait_singleton?
|
258
|
+
return(__trait_singleton_super.__trait_define_singleton_reader_traits(*args, &block))
|
259
|
+
end
|
260
|
+
argf = __trait_arg_filter args, &block
|
261
|
+
defaults = __trait_instance_method_defaults
|
262
|
+
list = __trait_instance_method_list
|
263
|
+
mhooks = __trait_instance_method_hooks
|
264
|
+
argf['names_and_defaults'].each do |name, default|
|
265
|
+
__trait_define_reader_trait name, default, defaults, list
|
266
|
+
end
|
267
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
268
|
+
__trait_search_path.map{|ta| ta.__trait_instance_method_list['readers']}.flatten
|
269
|
+
#--}}}
|
270
|
+
end
|
271
|
+
%w(
|
272
|
+
instance_reader_traits
|
273
|
+
instance_reader_trait
|
274
|
+
reader_traits
|
275
|
+
reader_trait
|
276
|
+
rtraits
|
277
|
+
rtrait
|
278
|
+
r_traits
|
279
|
+
r_trait
|
280
|
+
has_readers
|
281
|
+
has_reader
|
282
|
+
has_r
|
283
|
+
).each{|meth| alias_method meth, '__trait_define_instance_reader_traits'}
|
284
|
+
|
285
|
+
def __trait_define_instance_writer_traits(*args, &block)
|
286
|
+
#--{{{
|
287
|
+
if __trait_singleton?
|
288
|
+
return(__trait_singleton_super.__trait_define_singleton_writer_traits(*args, &block))
|
289
|
+
end
|
290
|
+
argf = __trait_arg_filter args, &block
|
291
|
+
defaults = __trait_instance_method_defaults
|
292
|
+
list = __trait_instance_method_list
|
293
|
+
mhooks = __trait_instance_method_hooks
|
294
|
+
argf['names_and_defaults'].each do |name, default|
|
295
|
+
__trait_define_writer_trait name, default, defaults, list
|
296
|
+
end
|
297
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
298
|
+
__trait_search_path.map{|ta| ta.__trait_instance_method_list['writers']}.flatten
|
299
|
+
#--}}}
|
300
|
+
end
|
301
|
+
%w(
|
302
|
+
instance_writer_traits
|
303
|
+
instance_writer_trait
|
304
|
+
writer_traits
|
305
|
+
writer_trait
|
306
|
+
wtraits
|
307
|
+
wtrait
|
308
|
+
w_traits
|
309
|
+
w_trait
|
310
|
+
has_writers
|
311
|
+
has_writer
|
312
|
+
has_w
|
313
|
+
).each{|meth| alias_method meth, '__trait_define_instance_writer_traits'}
|
314
|
+
|
315
|
+
def __trait_define_instance_traits(*args, &block)
|
316
|
+
#--{{{
|
317
|
+
writers = __trait_define_instance_writer_traits(*args, &block)
|
318
|
+
readers = __trait_define_instance_reader_traits(*args, &block)
|
319
|
+
#[readers, writers]
|
320
|
+
wr = writers.inject({}){|h,k| h.update k.delete('=') => k}
|
321
|
+
readers.map{|r| [r, wr[r]]}
|
322
|
+
#--}}}
|
323
|
+
end
|
324
|
+
%w(
|
325
|
+
instance_traits
|
326
|
+
instance_trait
|
327
|
+
traits
|
328
|
+
trait
|
329
|
+
has
|
330
|
+
).each{|meth| alias_method meth, '__trait_define_instance_traits'}
|
331
|
+
|
332
|
+
def __trait_define_class_reader_traits(*args, &block)
|
333
|
+
#--{{{
|
334
|
+
__trait_define_singleton_reader_traits(*args, &block)
|
335
|
+
#--}}}
|
336
|
+
end
|
337
|
+
%w(
|
338
|
+
class_reader_traits
|
339
|
+
class_reader_trait
|
340
|
+
class_rtraits
|
341
|
+
class_rtrait
|
342
|
+
class_r_traits
|
343
|
+
class_r_trait
|
344
|
+
class_has_readers
|
345
|
+
class_has_reader
|
346
|
+
class_has_r
|
347
|
+
c_has_readers
|
348
|
+
c_has_reader
|
349
|
+
c_has_r
|
350
|
+
).each{|meth| alias_method meth, '__trait_define_class_reader_traits'}
|
351
|
+
|
352
|
+
def __trait_define_class_writer_traits(*args, &block)
|
353
|
+
#--{{{
|
354
|
+
__trait_define_singleton_writer_traits(*args, &block)
|
355
|
+
#--}}}
|
356
|
+
end
|
357
|
+
%w(
|
358
|
+
class_writer_traits
|
359
|
+
class_writer_trait
|
360
|
+
class_wtraits
|
361
|
+
class_wtrait
|
362
|
+
class_w_traits
|
363
|
+
class_w_trait
|
364
|
+
class_has_writers
|
365
|
+
class_has_writer
|
366
|
+
class_has_w
|
367
|
+
c_has_writers
|
368
|
+
c_has_writer
|
369
|
+
c_has_w
|
370
|
+
).each{|meth| alias_method meth, '__trait_define_class_writer_traits'}
|
371
|
+
|
372
|
+
def __trait_define_class_traits(*args, &block)
|
373
|
+
#--{{{
|
374
|
+
__trait_define_singleton_traits(*args, &block)
|
375
|
+
#--}}}
|
376
|
+
end
|
377
|
+
%w(
|
378
|
+
class_traits
|
379
|
+
class_trait
|
380
|
+
class_has
|
381
|
+
c_has
|
382
|
+
).each{|meth| alias_method meth, '__trait_define_class_traits'}
|
383
|
+
|
384
|
+
def __trait_define_reader_trait name, default, defaults, list
|
385
|
+
#--{{{
|
386
|
+
getter = "#{ name }"
|
387
|
+
setter = "#{ name }="
|
388
|
+
query = "#{ name }?"
|
389
|
+
|
390
|
+
defaults[getter] = default if default
|
391
|
+
list['readers'] << getter
|
392
|
+
list['readers'].uniq!
|
393
|
+
list['readers'].sort!
|
394
|
+
|
395
|
+
unless instance_methods.include? getter
|
396
|
+
code = __trait_gen_reader_code name, 'public'
|
397
|
+
__trait_module_eval code
|
398
|
+
end
|
399
|
+
unless instance_methods.include? setter
|
400
|
+
code = __trait_gen_writer_code name, 'private'
|
401
|
+
__trait_module_eval code
|
402
|
+
end
|
403
|
+
unless instance_methods.include? query
|
404
|
+
code = __trait_gen_query_code name, 'public'
|
405
|
+
__trait_module_eval code
|
406
|
+
end
|
407
|
+
#--}}}
|
408
|
+
end
|
409
|
+
|
410
|
+
def __trait_define_writer_trait name, default, defaults, list
|
411
|
+
#--{{{
|
412
|
+
reader = "#{ name }"
|
413
|
+
writer = "#{ name }="
|
414
|
+
query = "#{ name }?"
|
415
|
+
|
416
|
+
defaults[reader] = default if default
|
417
|
+
list['writers'] << writer
|
418
|
+
list['writers'].uniq!
|
419
|
+
list['writers'].sort!
|
420
|
+
|
421
|
+
unless instance_methods.include? reader
|
422
|
+
code = __trait_gen_reader_code name, 'private'
|
423
|
+
__trait_module_eval code
|
424
|
+
end
|
425
|
+
unless instance_methods.include? writer
|
426
|
+
code = __trait_gen_writer_code name, 'public'
|
427
|
+
__trait_module_eval code
|
428
|
+
end
|
429
|
+
unless instance_methods.include? query
|
430
|
+
code = __trait_gen_query_code name, 'private'
|
431
|
+
__trait_module_eval code
|
432
|
+
end
|
433
|
+
#--}}}
|
434
|
+
end
|
435
|
+
|
436
|
+
def __trait_gen_reader_code name, access_protection = 'public'
|
437
|
+
#--{{{
|
438
|
+
s = __trait_singleton?
|
439
|
+
klass = s ? 'self' : 'self.class'
|
440
|
+
defaults = s ? '__trait_singleton_method_defaults' : '__trait_instance_method_defaults'
|
441
|
+
search_ancestors = s ? 'true' : 'false'
|
442
|
+
|
443
|
+
getter_meth = "#{ name }"
|
444
|
+
setter_meth = "#{ name }="
|
445
|
+
query_meth = "#{ name }?"
|
446
|
+
ivar = "@#{ name }"
|
447
|
+
getter = "'#{ name }'"
|
448
|
+
setter = "'#{ name }='"
|
449
|
+
|
450
|
+
reader_code = <<-code
|
451
|
+
def #{ name }(*a, &b)
|
452
|
+
unless a.empty?
|
453
|
+
send('#{ name }=', *a, &b)
|
454
|
+
else
|
455
|
+
unless(defined?(@________#{ name }_set) and @________#{ name }_set)
|
456
|
+
#{ klass }::__trait_search_path.each do |obj|
|
457
|
+
defaults = obj.#{ defaults }
|
458
|
+
if defaults.has_key? '#{ name }'
|
459
|
+
d = defaults['#{ name }']
|
460
|
+
if d.respond_to? '__trait_default'
|
461
|
+
d = instance_eval &d
|
462
|
+
end
|
463
|
+
return(send('#{ name }=', d))
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
case self
|
468
|
+
when Class
|
469
|
+
if defined? @#{ name }
|
470
|
+
@#{ name }
|
471
|
+
else
|
472
|
+
__trait_search_path.each do |obj|
|
473
|
+
if self != obj and obj.respond_to? '#{ name }'
|
474
|
+
return(obj.send('#{ name }', *a, &b))
|
475
|
+
end
|
476
|
+
end
|
477
|
+
return nil
|
478
|
+
end
|
479
|
+
else
|
480
|
+
@#{ name }
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
#{ access_protection } '#{ name }'.intern
|
485
|
+
code
|
486
|
+
puts reader_code if $__TRAIT_DEBUG__
|
487
|
+
reader_code
|
488
|
+
#--}}}
|
489
|
+
end
|
490
|
+
|
491
|
+
def __trait_gen_writer_code name, access_protection = 'public'
|
492
|
+
#--{{{
|
493
|
+
s = __trait_singleton?
|
494
|
+
klass = s ? 'self' : 'self.class'
|
495
|
+
hooks = s ? '__trait_singleton_method_hooks' : '__trait_instance_method_hooks'
|
496
|
+
|
497
|
+
writer_code = <<-code
|
498
|
+
def #{ name }=(head, *tail)
|
499
|
+
value = tail.empty? ? head : [head] + tail
|
500
|
+
|
501
|
+
hooks = {}
|
502
|
+
hook_types = %w( pre munge cast type ducktype validate post )
|
503
|
+
|
504
|
+
#{ klass }::__trait_search_path.each do |obj|
|
505
|
+
break if hooks.values_at(*hook_types).compact.size == hook_types.size
|
506
|
+
hook_types.each{|ht| hooks[ht] ||= obj.#{ hooks }['#{ name }'][ht]}
|
507
|
+
end
|
508
|
+
|
509
|
+
pre_hook, munge_hook, cast_hook, type_hook, ducktype_hook, validate_hook, post_hook =
|
510
|
+
hooks.values_at(*hook_types)
|
511
|
+
|
512
|
+
if pre_hook
|
513
|
+
[ pre_hook ].flatten.each do |pre|
|
514
|
+
if Proc === pre
|
515
|
+
case pre.arity
|
516
|
+
when 0
|
517
|
+
__trait_evaluate &pre
|
518
|
+
when 1
|
519
|
+
__trait_evaluate value, &pre
|
520
|
+
else
|
521
|
+
__trait_evaluate "#{ name }", value, &pre
|
522
|
+
end
|
523
|
+
else
|
524
|
+
case method("\#{ pre }").arity
|
525
|
+
when 0
|
526
|
+
send "\#{ pre }"
|
527
|
+
when 1
|
528
|
+
send "\#{ pre }", value
|
529
|
+
else
|
530
|
+
send "\#{ pre }", "#{ name }", value
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
if cast_hook
|
537
|
+
[ cast_hook ].flatten.each do |cast|
|
538
|
+
value =
|
539
|
+
if Proc === cast
|
540
|
+
__trait_evaluate value, &cast
|
541
|
+
else
|
542
|
+
send cast, value
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
if munge_hook
|
548
|
+
[ munge_hook ].flatten.each do |munge|
|
549
|
+
value =
|
550
|
+
if Proc === munge
|
551
|
+
__trait_evaluate value, &munge
|
552
|
+
else
|
553
|
+
value.send munge
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
if type_hook
|
559
|
+
[ type_hook ].flatten.each do |type|
|
560
|
+
is_valid =
|
561
|
+
if Proc === type
|
562
|
+
__trait_evaluate(value, &type) === value
|
563
|
+
else
|
564
|
+
type === value
|
565
|
+
end
|
566
|
+
raise ArgumentError,
|
567
|
+
"validation of <\#{ value.inspect }> failed!" unless is_valid
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
if ducktype_hook
|
572
|
+
[ ducktype_hook ].flatten.each do |ducktype|
|
573
|
+
is_valid =
|
574
|
+
if Proc === ducktype
|
575
|
+
value.respond_to? __trait_evaluate(value, &ducktype)
|
576
|
+
else
|
577
|
+
value.respond_to? ducktype
|
578
|
+
end
|
579
|
+
raise ArgumentError,
|
580
|
+
"validation of <\#{ value.inspect }> failed!" unless is_valid
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
if validate_hook
|
585
|
+
[ validate_hook ].flatten.each do |validate|
|
586
|
+
is_valid =
|
587
|
+
if Proc === validate
|
588
|
+
__trait_evaluate value, &validate
|
589
|
+
else
|
590
|
+
send "\#{ validate }", value
|
591
|
+
end
|
592
|
+
raise ArgumentError,
|
593
|
+
"validation of <\#{ value.inspect }> failed!" unless is_valid
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
@#{ name } = value
|
598
|
+
|
599
|
+
@________#{ name }_set = true
|
600
|
+
|
601
|
+
if post_hook
|
602
|
+
[ post_hook ].flatten.each do |post|
|
603
|
+
if Proc === post
|
604
|
+
case post.arity
|
605
|
+
when 0
|
606
|
+
__trait_evaluate &post
|
607
|
+
when 1
|
608
|
+
__trait_evaluate value, &post
|
609
|
+
else
|
610
|
+
__trait_evaluate "#{ name }", value, &post
|
611
|
+
end
|
612
|
+
else
|
613
|
+
case method("\#{ post }").arity
|
614
|
+
when 0
|
615
|
+
send "\#{ post }"
|
616
|
+
when 1
|
617
|
+
send "\#{ post }", value
|
618
|
+
else
|
619
|
+
send "\#{ post }", "#{ name }", value
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
@#{ name }
|
626
|
+
end
|
627
|
+
#{ access_protection } '#{ name }='.intern
|
628
|
+
code
|
629
|
+
puts writer_code if $__TRAIT_DEBUG__
|
630
|
+
writer_code
|
631
|
+
#--}}}
|
632
|
+
end
|
633
|
+
|
634
|
+
def __trait_gen_query_code name, access_protection = 'public'
|
635
|
+
#--{{{
|
636
|
+
query_code = <<-code
|
637
|
+
def #{ name }?
|
638
|
+
send('#{ name }') ? true : false
|
639
|
+
end
|
640
|
+
# #{ access_protection } '#{ name }?'.intern
|
641
|
+
code
|
642
|
+
puts query_code if $__TRAIT_DEBUG__
|
643
|
+
query_code
|
644
|
+
#--}}}
|
645
|
+
end
|
646
|
+
|
647
|
+
def __trait_gen_access_protection_code name, access_protection = nil
|
648
|
+
#--{{{
|
649
|
+
access_protection ||= 'public'
|
650
|
+
access_protection_code =
|
651
|
+
case access_protection
|
652
|
+
when %r/private/
|
653
|
+
"private '#{ name }'.intern"
|
654
|
+
when %r/protected/
|
655
|
+
"protected '#{ name }'.intern"
|
656
|
+
else
|
657
|
+
"public '#{ name }'.intern"
|
658
|
+
end
|
659
|
+
puts access_protection_code if $__TRAIT_DEBUG__
|
660
|
+
access_protection_code
|
661
|
+
#--}}}
|
662
|
+
end
|
663
|
+
#--}}}
|
664
|
+
end
|
data/lib/traits.rb
ADDED
@@ -0,0 +1,664 @@
|
|
1
|
+
$__TRAIT_DEBUG__ = ENV['__TRAIT_DEBUG__'] || ENV['TRAIT_DEBUG'] || ENV['DEBUG']
|
2
|
+
$__TRAIT_VERSION__ = "0.8.0"
|
3
|
+
|
4
|
+
class Object
|
5
|
+
#--{{{
|
6
|
+
def singleton_method_added(*a, &b)
|
7
|
+
#--{{{
|
8
|
+
obj = self
|
9
|
+
obj.__trait_singleton_class.__trait_module_eval{ @__trait_singleton_super = obj }
|
10
|
+
#--}}}
|
11
|
+
end
|
12
|
+
def __trait_singleton_class
|
13
|
+
#--{{{
|
14
|
+
@__trait_singleton_class ||= class << self;self;end
|
15
|
+
#--}}}
|
16
|
+
end
|
17
|
+
def __trait_singleton?
|
18
|
+
#--{{{
|
19
|
+
@__is_trait_singleton ||=
|
20
|
+
((Class === self) and (@__is_trait_singleton ||= (not self.ancestors.include?(self))))
|
21
|
+
#--}}}
|
22
|
+
end
|
23
|
+
def __trait_search_path
|
24
|
+
#--{{{
|
25
|
+
#((Class === self and not __trait_singleton?) ? ancestors : [self])
|
26
|
+
(__trait_singleton? or not respond_to? 'ancestors') ? [self] : ancestors
|
27
|
+
#--}}}
|
28
|
+
end
|
29
|
+
def __trait_getopt opts, key, default = nil
|
30
|
+
#--{{{
|
31
|
+
return opts.delete(key) if opts.has_key? key
|
32
|
+
|
33
|
+
key = "#{ key }"
|
34
|
+
return opts.delete(key) if opts.has_key? key
|
35
|
+
|
36
|
+
key = key.intern
|
37
|
+
return opts.delete(key) if opts.has_key? key
|
38
|
+
|
39
|
+
key = "#{ key }s"
|
40
|
+
return opts.delete(key) if opts.has_key? key
|
41
|
+
|
42
|
+
key = key.intern
|
43
|
+
return opts.delete(key) if opts.has_key? key
|
44
|
+
|
45
|
+
key = "#{ key }es"
|
46
|
+
return opts.delete(key) if opts.has_key? key
|
47
|
+
|
48
|
+
key = key.intern
|
49
|
+
return opts.delete(key) if opts.has_key? key
|
50
|
+
|
51
|
+
return default
|
52
|
+
#--}}}
|
53
|
+
end
|
54
|
+
def __trait_arg_filter(*args, &block)
|
55
|
+
#--{{{
|
56
|
+
pre = nil
|
57
|
+
post = nil
|
58
|
+
validate = nil
|
59
|
+
cast = nil
|
60
|
+
munge = nil
|
61
|
+
type = nil
|
62
|
+
ducktype = nil
|
63
|
+
default = nil
|
64
|
+
names_and_defaults = nil
|
65
|
+
|
66
|
+
if block and not block.respond_to? :__trait_default
|
67
|
+
block.__trait_singleton_class.class_eval{ attr '__trait_default' }
|
68
|
+
end
|
69
|
+
|
70
|
+
list, hashes = [ args ].flatten.partition{|arg| not Hash === arg}
|
71
|
+
opts = hashes.inject({}){|accum,h| accum.update h}
|
72
|
+
|
73
|
+
pre = __trait_getopt opts, 'pre'
|
74
|
+
post = __trait_getopt opts, 'post'
|
75
|
+
validate = __trait_getopt opts, 'validate'
|
76
|
+
cast = __trait_getopt opts, 'cast'
|
77
|
+
munge = __trait_getopt opts, 'munge'
|
78
|
+
type = __trait_getopt(opts, 'type', __trait_getopt(opts, 'case'))
|
79
|
+
ducktype = __trait_getopt opts, 'ducktype'
|
80
|
+
default = __trait_getopt opts, 'default'
|
81
|
+
|
82
|
+
names_and_defaults = opts
|
83
|
+
|
84
|
+
raise ArgumentError,
|
85
|
+
"cannot specify both 'default' keyword and 'default' block" if
|
86
|
+
block and default
|
87
|
+
|
88
|
+
default ||= block
|
89
|
+
|
90
|
+
list.each{|name| names_and_defaults[name] = default}
|
91
|
+
|
92
|
+
names = list + (names_and_defaults.keys - list)
|
93
|
+
|
94
|
+
hooks = {
|
95
|
+
'pre' => pre,
|
96
|
+
'cast' => cast,
|
97
|
+
'munge' => munge,
|
98
|
+
'type' => type,
|
99
|
+
'ducktype' => ducktype,
|
100
|
+
'validate' => validate,
|
101
|
+
'post' => post,
|
102
|
+
}
|
103
|
+
|
104
|
+
names_and_hooks = names.inject({}){|h, name| h.update name => hooks}
|
105
|
+
|
106
|
+
{
|
107
|
+
'names' => names,
|
108
|
+
'names_and_defaults' => names_and_defaults,
|
109
|
+
'names_and_hooks' => names_and_hooks,
|
110
|
+
'hooks' => hooks,
|
111
|
+
#'pre' => pre, 'post' => post, 'validate' => validate, 'munge' => munge, 'cast' => cast,
|
112
|
+
'default' => default,
|
113
|
+
}.update hooks
|
114
|
+
#--}}}
|
115
|
+
end
|
116
|
+
def __trait_instance_method_list
|
117
|
+
#--{{{
|
118
|
+
@__trait_instance_method_list ||= {'writers' => [], 'readers' => [], }
|
119
|
+
#--}}}
|
120
|
+
end
|
121
|
+
def __trait_singleton_method_list
|
122
|
+
#--{{{
|
123
|
+
@__trait_singleton_method_list ||= {'writers' => [], 'readers' => [], }
|
124
|
+
#--}}}
|
125
|
+
end
|
126
|
+
def __trait_instance_method_defaults
|
127
|
+
#--{{{
|
128
|
+
@__trait_instance_method_defaults ||= {}
|
129
|
+
#--}}}
|
130
|
+
end
|
131
|
+
def __trait_singleton_method_defaults
|
132
|
+
#--{{{
|
133
|
+
@__trait_singleton_method_defaults ||= {}
|
134
|
+
#--}}}
|
135
|
+
end
|
136
|
+
def __trait_instance_method_hooks
|
137
|
+
#--{{{
|
138
|
+
@__trait_instance_method_hooks ||=
|
139
|
+
#Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil, 'munge' => nil, 'cast' => nil} }
|
140
|
+
Hash::new{ |h,name| h[name] = {} }
|
141
|
+
#--}}}
|
142
|
+
end
|
143
|
+
def __trait_singleton_method_hooks
|
144
|
+
#--{{{
|
145
|
+
@__trait_singleton_method_hooks ||=
|
146
|
+
#Hash::new{ |h,name| h[name] = {'pre' => nil, 'post' => nil, 'validate' => nil, 'munge' => nil, 'cast' => nil} }
|
147
|
+
Hash::new{ |h,name| h[name] = {} }
|
148
|
+
#--}}}
|
149
|
+
end
|
150
|
+
def __trait_evaluate(*a, &b)
|
151
|
+
#--{{{
|
152
|
+
m = "__trait_evaluate__#{ Thread::current.object_id.abs }__#{ rand 42 }__#{ rand 666 }__"
|
153
|
+
__trait_singleton_class.module_eval{ define_method m, &b }
|
154
|
+
begin
|
155
|
+
send m, *a
|
156
|
+
ensure
|
157
|
+
__trait_singleton_class.module_eval{ remove_method m }
|
158
|
+
end
|
159
|
+
#--}}}
|
160
|
+
end
|
161
|
+
|
162
|
+
def __trait_define_singleton_reader_traits(*args, &block)
|
163
|
+
#--{{{
|
164
|
+
argf = __trait_arg_filter args, &block
|
165
|
+
defaults = __trait_singleton_method_defaults
|
166
|
+
list = __trait_singleton_method_list
|
167
|
+
mhooks = __trait_singleton_method_hooks
|
168
|
+
argf['names_and_defaults'].each do |name, default|
|
169
|
+
__trait_singleton_class.__trait_define_reader_trait name, default, defaults, list
|
170
|
+
end
|
171
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
172
|
+
__trait_search_path.map{|ta| ta.__trait_singleton_method_list['readers']}.flatten
|
173
|
+
#--}}}
|
174
|
+
end
|
175
|
+
def __trait_define_singleton_writer_traits(*args, &block)
|
176
|
+
#--{{{
|
177
|
+
argf = __trait_arg_filter args, &block
|
178
|
+
defaults = __trait_singleton_method_defaults
|
179
|
+
list = __trait_singleton_method_list
|
180
|
+
mhooks = __trait_singleton_method_hooks
|
181
|
+
argf['names_and_defaults'].each do |name, default|
|
182
|
+
__trait_singleton_class.__trait_define_writer_trait name, default, defaults, list
|
183
|
+
end
|
184
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
185
|
+
__trait_search_path.map{|ta| ta.__trait_singleton_method_list['writers']}.flatten
|
186
|
+
#--}}}
|
187
|
+
end
|
188
|
+
def __trait_define_singleton_traits(*args, &block)
|
189
|
+
#--{{{
|
190
|
+
writers = __trait_define_singleton_writer_traits(*args, &block)
|
191
|
+
readers = __trait_define_singleton_reader_traits(*args, &block)
|
192
|
+
wr = writers.inject({}){|h,k| h.update k.delete('=') => k}
|
193
|
+
readers.map{|r| [r, wr[r]]}
|
194
|
+
#--}}}
|
195
|
+
end
|
196
|
+
%w(
|
197
|
+
instance_reader_traits
|
198
|
+
instance_reader_trait
|
199
|
+
reader_traits
|
200
|
+
reader_trait
|
201
|
+
r_traits
|
202
|
+
r_trait
|
203
|
+
has_readers
|
204
|
+
has_reader
|
205
|
+
has_r
|
206
|
+
|
207
|
+
instance_writer_traits
|
208
|
+
instance_writer_trait
|
209
|
+
writer_traits
|
210
|
+
writer_trait
|
211
|
+
w_traits
|
212
|
+
w_trait
|
213
|
+
has_writers
|
214
|
+
has_writer
|
215
|
+
has_w
|
216
|
+
|
217
|
+
instance_traits
|
218
|
+
instance_trait
|
219
|
+
traits
|
220
|
+
trait
|
221
|
+
has
|
222
|
+
).each do |meth|
|
223
|
+
eval <<-def
|
224
|
+
def #{ meth }(*a, &b)
|
225
|
+
__trait_singleton_class.send('#{ meth }', *a, &b)
|
226
|
+
end
|
227
|
+
def
|
228
|
+
end
|
229
|
+
#--}}}
|
230
|
+
end
|
231
|
+
class Class
|
232
|
+
#--{{{
|
233
|
+
def __trait_singleton_super
|
234
|
+
#--{{{
|
235
|
+
class_eval{ def __________trait_singleton_super_init;end } unless defined? @__trait_singleton_super
|
236
|
+
@__trait_singleton_super
|
237
|
+
#--}}}
|
238
|
+
end
|
239
|
+
#--}}}
|
240
|
+
end
|
241
|
+
class Module
|
242
|
+
#--{{{
|
243
|
+
|
244
|
+
def __trait_module_eval(*a, &b)
|
245
|
+
#--{{{
|
246
|
+
begin
|
247
|
+
module_eval(*a, &b)
|
248
|
+
rescue Exception => e
|
249
|
+
STDERR.puts([a, b].inspect) if $__TRAIT_DEBUG__
|
250
|
+
raise
|
251
|
+
end
|
252
|
+
#--}}}
|
253
|
+
end
|
254
|
+
|
255
|
+
def __trait_define_instance_reader_traits(*args, &block)
|
256
|
+
#--{{{
|
257
|
+
if __trait_singleton?
|
258
|
+
return(__trait_singleton_super.__trait_define_singleton_reader_traits(*args, &block))
|
259
|
+
end
|
260
|
+
argf = __trait_arg_filter args, &block
|
261
|
+
defaults = __trait_instance_method_defaults
|
262
|
+
list = __trait_instance_method_list
|
263
|
+
mhooks = __trait_instance_method_hooks
|
264
|
+
argf['names_and_defaults'].each do |name, default|
|
265
|
+
__trait_define_reader_trait name, default, defaults, list
|
266
|
+
end
|
267
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
268
|
+
__trait_search_path.map{|ta| ta.__trait_instance_method_list['readers']}.flatten
|
269
|
+
#--}}}
|
270
|
+
end
|
271
|
+
%w(
|
272
|
+
instance_reader_traits
|
273
|
+
instance_reader_trait
|
274
|
+
reader_traits
|
275
|
+
reader_trait
|
276
|
+
rtraits
|
277
|
+
rtrait
|
278
|
+
r_traits
|
279
|
+
r_trait
|
280
|
+
has_readers
|
281
|
+
has_reader
|
282
|
+
has_r
|
283
|
+
).each{|meth| alias_method meth, '__trait_define_instance_reader_traits'}
|
284
|
+
|
285
|
+
def __trait_define_instance_writer_traits(*args, &block)
|
286
|
+
#--{{{
|
287
|
+
if __trait_singleton?
|
288
|
+
return(__trait_singleton_super.__trait_define_singleton_writer_traits(*args, &block))
|
289
|
+
end
|
290
|
+
argf = __trait_arg_filter args, &block
|
291
|
+
defaults = __trait_instance_method_defaults
|
292
|
+
list = __trait_instance_method_list
|
293
|
+
mhooks = __trait_instance_method_hooks
|
294
|
+
argf['names_and_defaults'].each do |name, default|
|
295
|
+
__trait_define_writer_trait name, default, defaults, list
|
296
|
+
end
|
297
|
+
argf['names_and_hooks'].each{|name, hooks| mhooks[name].update hooks}
|
298
|
+
__trait_search_path.map{|ta| ta.__trait_instance_method_list['writers']}.flatten
|
299
|
+
#--}}}
|
300
|
+
end
|
301
|
+
%w(
|
302
|
+
instance_writer_traits
|
303
|
+
instance_writer_trait
|
304
|
+
writer_traits
|
305
|
+
writer_trait
|
306
|
+
wtraits
|
307
|
+
wtrait
|
308
|
+
w_traits
|
309
|
+
w_trait
|
310
|
+
has_writers
|
311
|
+
has_writer
|
312
|
+
has_w
|
313
|
+
).each{|meth| alias_method meth, '__trait_define_instance_writer_traits'}
|
314
|
+
|
315
|
+
def __trait_define_instance_traits(*args, &block)
|
316
|
+
#--{{{
|
317
|
+
writers = __trait_define_instance_writer_traits(*args, &block)
|
318
|
+
readers = __trait_define_instance_reader_traits(*args, &block)
|
319
|
+
#[readers, writers]
|
320
|
+
wr = writers.inject({}){|h,k| h.update k.delete('=') => k}
|
321
|
+
readers.map{|r| [r, wr[r]]}
|
322
|
+
#--}}}
|
323
|
+
end
|
324
|
+
%w(
|
325
|
+
instance_traits
|
326
|
+
instance_trait
|
327
|
+
traits
|
328
|
+
trait
|
329
|
+
has
|
330
|
+
).each{|meth| alias_method meth, '__trait_define_instance_traits'}
|
331
|
+
|
332
|
+
def __trait_define_class_reader_traits(*args, &block)
|
333
|
+
#--{{{
|
334
|
+
__trait_define_singleton_reader_traits(*args, &block)
|
335
|
+
#--}}}
|
336
|
+
end
|
337
|
+
%w(
|
338
|
+
class_reader_traits
|
339
|
+
class_reader_trait
|
340
|
+
class_rtraits
|
341
|
+
class_rtrait
|
342
|
+
class_r_traits
|
343
|
+
class_r_trait
|
344
|
+
class_has_readers
|
345
|
+
class_has_reader
|
346
|
+
class_has_r
|
347
|
+
c_has_readers
|
348
|
+
c_has_reader
|
349
|
+
c_has_r
|
350
|
+
).each{|meth| alias_method meth, '__trait_define_class_reader_traits'}
|
351
|
+
|
352
|
+
def __trait_define_class_writer_traits(*args, &block)
|
353
|
+
#--{{{
|
354
|
+
__trait_define_singleton_writer_traits(*args, &block)
|
355
|
+
#--}}}
|
356
|
+
end
|
357
|
+
%w(
|
358
|
+
class_writer_traits
|
359
|
+
class_writer_trait
|
360
|
+
class_wtraits
|
361
|
+
class_wtrait
|
362
|
+
class_w_traits
|
363
|
+
class_w_trait
|
364
|
+
class_has_writers
|
365
|
+
class_has_writer
|
366
|
+
class_has_w
|
367
|
+
c_has_writers
|
368
|
+
c_has_writer
|
369
|
+
c_has_w
|
370
|
+
).each{|meth| alias_method meth, '__trait_define_class_writer_traits'}
|
371
|
+
|
372
|
+
def __trait_define_class_traits(*args, &block)
|
373
|
+
#--{{{
|
374
|
+
__trait_define_singleton_traits(*args, &block)
|
375
|
+
#--}}}
|
376
|
+
end
|
377
|
+
%w(
|
378
|
+
class_traits
|
379
|
+
class_trait
|
380
|
+
class_has
|
381
|
+
c_has
|
382
|
+
).each{|meth| alias_method meth, '__trait_define_class_traits'}
|
383
|
+
|
384
|
+
def __trait_define_reader_trait name, default, defaults, list
|
385
|
+
#--{{{
|
386
|
+
getter = "#{ name }"
|
387
|
+
setter = "#{ name }="
|
388
|
+
query = "#{ name }?"
|
389
|
+
|
390
|
+
defaults[getter] = default if default
|
391
|
+
list['readers'] << getter
|
392
|
+
list['readers'].uniq!
|
393
|
+
list['readers'].sort!
|
394
|
+
|
395
|
+
unless instance_methods.include? getter
|
396
|
+
code = __trait_gen_reader_code name, 'public'
|
397
|
+
__trait_module_eval code
|
398
|
+
end
|
399
|
+
unless instance_methods.include? setter
|
400
|
+
code = __trait_gen_writer_code name, 'private'
|
401
|
+
__trait_module_eval code
|
402
|
+
end
|
403
|
+
unless instance_methods.include? query
|
404
|
+
code = __trait_gen_query_code name, 'public'
|
405
|
+
__trait_module_eval code
|
406
|
+
end
|
407
|
+
#--}}}
|
408
|
+
end
|
409
|
+
|
410
|
+
def __trait_define_writer_trait name, default, defaults, list
|
411
|
+
#--{{{
|
412
|
+
reader = "#{ name }"
|
413
|
+
writer = "#{ name }="
|
414
|
+
query = "#{ name }?"
|
415
|
+
|
416
|
+
defaults[reader] = default if default
|
417
|
+
list['writers'] << writer
|
418
|
+
list['writers'].uniq!
|
419
|
+
list['writers'].sort!
|
420
|
+
|
421
|
+
unless instance_methods.include? reader
|
422
|
+
code = __trait_gen_reader_code name, 'private'
|
423
|
+
__trait_module_eval code
|
424
|
+
end
|
425
|
+
unless instance_methods.include? writer
|
426
|
+
code = __trait_gen_writer_code name, 'public'
|
427
|
+
__trait_module_eval code
|
428
|
+
end
|
429
|
+
unless instance_methods.include? query
|
430
|
+
code = __trait_gen_query_code name, 'private'
|
431
|
+
__trait_module_eval code
|
432
|
+
end
|
433
|
+
#--}}}
|
434
|
+
end
|
435
|
+
|
436
|
+
def __trait_gen_reader_code name, access_protection = 'public'
|
437
|
+
#--{{{
|
438
|
+
s = __trait_singleton?
|
439
|
+
klass = s ? 'self' : 'self.class'
|
440
|
+
defaults = s ? '__trait_singleton_method_defaults' : '__trait_instance_method_defaults'
|
441
|
+
search_ancestors = s ? 'true' : 'false'
|
442
|
+
|
443
|
+
getter_meth = "#{ name }"
|
444
|
+
setter_meth = "#{ name }="
|
445
|
+
query_meth = "#{ name }?"
|
446
|
+
ivar = "@#{ name }"
|
447
|
+
getter = "'#{ name }'"
|
448
|
+
setter = "'#{ name }='"
|
449
|
+
|
450
|
+
reader_code = <<-code
|
451
|
+
def #{ name }(*a, &b)
|
452
|
+
unless a.empty?
|
453
|
+
send('#{ name }=', *a, &b)
|
454
|
+
else
|
455
|
+
unless(defined?(@________#{ name }_set) and @________#{ name }_set)
|
456
|
+
#{ klass }::__trait_search_path.each do |obj|
|
457
|
+
defaults = obj.#{ defaults }
|
458
|
+
if defaults.has_key? '#{ name }'
|
459
|
+
d = defaults['#{ name }']
|
460
|
+
if d.respond_to? '__trait_default'
|
461
|
+
d = instance_eval &d
|
462
|
+
end
|
463
|
+
return(send('#{ name }=', d))
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
case self
|
468
|
+
when Class
|
469
|
+
if defined? @#{ name }
|
470
|
+
@#{ name }
|
471
|
+
else
|
472
|
+
__trait_search_path.each do |obj|
|
473
|
+
if self != obj and obj.respond_to? '#{ name }'
|
474
|
+
return(obj.send('#{ name }', *a, &b))
|
475
|
+
end
|
476
|
+
end
|
477
|
+
return nil
|
478
|
+
end
|
479
|
+
else
|
480
|
+
@#{ name }
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
#{ access_protection } '#{ name }'.intern
|
485
|
+
code
|
486
|
+
puts reader_code if $__TRAIT_DEBUG__
|
487
|
+
reader_code
|
488
|
+
#--}}}
|
489
|
+
end
|
490
|
+
|
491
|
+
def __trait_gen_writer_code name, access_protection = 'public'
|
492
|
+
#--{{{
|
493
|
+
s = __trait_singleton?
|
494
|
+
klass = s ? 'self' : 'self.class'
|
495
|
+
hooks = s ? '__trait_singleton_method_hooks' : '__trait_instance_method_hooks'
|
496
|
+
|
497
|
+
writer_code = <<-code
|
498
|
+
def #{ name }=(head, *tail)
|
499
|
+
value = tail.empty? ? head : [head] + tail
|
500
|
+
|
501
|
+
hooks = {}
|
502
|
+
hook_types = %w( pre munge cast type ducktype validate post )
|
503
|
+
|
504
|
+
#{ klass }::__trait_search_path.each do |obj|
|
505
|
+
break if hooks.values_at(*hook_types).compact.size == hook_types.size
|
506
|
+
hook_types.each{|ht| hooks[ht] ||= obj.#{ hooks }['#{ name }'][ht]}
|
507
|
+
end
|
508
|
+
|
509
|
+
pre_hook, munge_hook, cast_hook, type_hook, ducktype_hook, validate_hook, post_hook =
|
510
|
+
hooks.values_at(*hook_types)
|
511
|
+
|
512
|
+
if pre_hook
|
513
|
+
[ pre_hook ].flatten.each do |pre|
|
514
|
+
if Proc === pre
|
515
|
+
case pre.arity
|
516
|
+
when 0
|
517
|
+
__trait_evaluate &pre
|
518
|
+
when 1
|
519
|
+
__trait_evaluate value, &pre
|
520
|
+
else
|
521
|
+
__trait_evaluate "#{ name }", value, &pre
|
522
|
+
end
|
523
|
+
else
|
524
|
+
case method("\#{ pre }").arity
|
525
|
+
when 0
|
526
|
+
send "\#{ pre }"
|
527
|
+
when 1
|
528
|
+
send "\#{ pre }", value
|
529
|
+
else
|
530
|
+
send "\#{ pre }", "#{ name }", value
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
if cast_hook
|
537
|
+
[ cast_hook ].flatten.each do |cast|
|
538
|
+
value =
|
539
|
+
if Proc === cast
|
540
|
+
__trait_evaluate value, &cast
|
541
|
+
else
|
542
|
+
send cast, value
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
if munge_hook
|
548
|
+
[ munge_hook ].flatten.each do |munge|
|
549
|
+
value =
|
550
|
+
if Proc === munge
|
551
|
+
__trait_evaluate value, &munge
|
552
|
+
else
|
553
|
+
value.send munge
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
if type_hook
|
559
|
+
[ type_hook ].flatten.each do |type|
|
560
|
+
is_valid =
|
561
|
+
if Proc === type
|
562
|
+
__trait_evaluate(value, &type) === value
|
563
|
+
else
|
564
|
+
type === value
|
565
|
+
end
|
566
|
+
raise ArgumentError,
|
567
|
+
"validation of <\#{ value.inspect }> failed!" unless is_valid
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
if ducktype_hook
|
572
|
+
[ ducktype_hook ].flatten.each do |ducktype|
|
573
|
+
is_valid =
|
574
|
+
if Proc === ducktype
|
575
|
+
value.respond_to? __trait_evaluate(value, &ducktype)
|
576
|
+
else
|
577
|
+
value.respond_to? ducktype
|
578
|
+
end
|
579
|
+
raise ArgumentError,
|
580
|
+
"validation of <\#{ value.inspect }> failed!" unless is_valid
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
if validate_hook
|
585
|
+
[ validate_hook ].flatten.each do |validate|
|
586
|
+
is_valid =
|
587
|
+
if Proc === validate
|
588
|
+
__trait_evaluate value, &validate
|
589
|
+
else
|
590
|
+
send "\#{ validate }", value
|
591
|
+
end
|
592
|
+
raise ArgumentError,
|
593
|
+
"validation of <\#{ value.inspect }> failed!" unless is_valid
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
@#{ name } = value
|
598
|
+
|
599
|
+
@________#{ name }_set = true
|
600
|
+
|
601
|
+
if post_hook
|
602
|
+
[ post_hook ].flatten.each do |post|
|
603
|
+
if Proc === post
|
604
|
+
case post.arity
|
605
|
+
when 0
|
606
|
+
__trait_evaluate &post
|
607
|
+
when 1
|
608
|
+
__trait_evaluate value, &post
|
609
|
+
else
|
610
|
+
__trait_evaluate "#{ name }", value, &post
|
611
|
+
end
|
612
|
+
else
|
613
|
+
case method("\#{ post }").arity
|
614
|
+
when 0
|
615
|
+
send "\#{ post }"
|
616
|
+
when 1
|
617
|
+
send "\#{ post }", value
|
618
|
+
else
|
619
|
+
send "\#{ post }", "#{ name }", value
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
@#{ name }
|
626
|
+
end
|
627
|
+
#{ access_protection } '#{ name }='.intern
|
628
|
+
code
|
629
|
+
puts writer_code if $__TRAIT_DEBUG__
|
630
|
+
writer_code
|
631
|
+
#--}}}
|
632
|
+
end
|
633
|
+
|
634
|
+
def __trait_gen_query_code name, access_protection = 'public'
|
635
|
+
#--{{{
|
636
|
+
query_code = <<-code
|
637
|
+
def #{ name }?
|
638
|
+
send('#{ name }') ? true : false
|
639
|
+
end
|
640
|
+
# #{ access_protection } '#{ name }?'.intern
|
641
|
+
code
|
642
|
+
puts query_code if $__TRAIT_DEBUG__
|
643
|
+
query_code
|
644
|
+
#--}}}
|
645
|
+
end
|
646
|
+
|
647
|
+
def __trait_gen_access_protection_code name, access_protection = nil
|
648
|
+
#--{{{
|
649
|
+
access_protection ||= 'public'
|
650
|
+
access_protection_code =
|
651
|
+
case access_protection
|
652
|
+
when %r/private/
|
653
|
+
"private '#{ name }'.intern"
|
654
|
+
when %r/protected/
|
655
|
+
"protected '#{ name }'.intern"
|
656
|
+
else
|
657
|
+
"public '#{ name }'.intern"
|
658
|
+
end
|
659
|
+
puts access_protection_code if $__TRAIT_DEBUG__
|
660
|
+
access_protection_code
|
661
|
+
#--}}}
|
662
|
+
end
|
663
|
+
#--}}}
|
664
|
+
end
|
metadata
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: traits
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.8.0
|
7
|
+
date: 2005-11-03 00:00:00.000000 -07:00
|
8
|
+
summary: traits
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: ara.t.howard@noaa.gov
|
12
|
+
homepage: http://codeforpeople.com/lib/ruby/traits/
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: traits
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Ara T. Howard
|
31
|
+
files:
|
32
|
+
- lib/traits.rb
|
33
|
+
- lib/traits-0.8.0.rb
|
34
|
+
test_files: []
|
35
|
+
rdoc_options: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
executables: []
|
38
|
+
extensions: []
|
39
|
+
requirements: []
|
40
|
+
dependencies: []
|