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.
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: []