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