traits 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/traits-0.8.0.rb +664 -0
  2. data/lib/traits.rb +664 -0
  3. metadata +40 -0
@@ -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
@@ -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: []