Class: Class

Inherits:
Object
  • Object
show all
Defined in:
lib/use.rb

Constant Summary collapse

USE_VERSION =
'1.2.1'

Instance Method Summary collapse

Instance Method Details

#use(*args) ⇒ Object



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 no arguments follow the module name, treat it as a standard include
   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

   # Remove excluded methods
   unless excluded.empty?
      (imethods & excluded).each{ |meth|
         mod.module_eval{ remove_method(meth) }
      }
   end

   # Alias methods
   aliased.each{ |pair|
      pair.each{ |old, new|
         included.push(old) # Aliased methods automatically included
         mod.module_eval{
            alias_method(new, old)
            remove_method(old)
         }
      }
   }

   # Remove all methods not specifically included.  The rescue was needed
   # for those cases where a module included another module.
   unless included.empty?
      (imethods - included).each{ |meth|
         mod.module_eval{ undef_method(meth) rescue nil }
      }
   end

   m.module_eval{ include mod }

   # Raise a warning if methods are shadowed (in $VERBOSE mode)
   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