3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
# File 'lib/use.rb', line 3
def use(*args)
valid_keys = %w/include exclude alias/
excluded = []
included = []
aliased = []
mod = args.shift.clone
if args.empty?
included.concat(mod.instance_methods)
end
m = Module.new
args.each{ |arg|
if arg.kind_of?(Hash)
arg.each{ |key, val|
case key.to_s
when "include"
if val.respond_to?(:each)
val.each{ |arg| included.push(arg.to_s) }
else
included.push(val.to_s)
end
when "exclude"
if val.respond_to?(:each)
val.each{ |arg| excluded.push(arg.to_s) }
else
excluded.push(val.to_s)
end
when "alias"
aliased.push(val)
else
raise "invalid key '#{key}'"
end
}
else
included.push(arg.to_s)
end
}
unless included.empty? || excluded.empty?
err = "you cannot include and exclude in the same statement"
raise ArgumentError, err
end
imethods = mod.instance_methods
unless excluded.empty?
(imethods & excluded).each{ |meth|
mod.module_eval{ remove_method(meth) }
}
end
aliased.each{ |pair|
pair.each{ |old, new|
included.push(old) mod.module_eval{
alias_method(new, old)
remove_method(old)
}
}
}
unless included.empty?
(imethods - included).each{ |meth|
mod.module_eval{ undef_method(meth) rescue nil }
}
end
m.module_eval{ include mod }
if $VERBOSE
imethods = instance_methods(true)
m.instance_methods.each{ |meth|
next unless imethods.include?(meth)
warn "method '#{meth}' aliased, shadows old '#{meth}'"
}
end
include m
end
|