gregwebs / module-import

selectively import methods from modules

This URL has Read+Write access

module-import / lib / module-import.rb
100644 78 lines (66 sloc) 2.266 kb
1
2
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
class ImportError < Exception; end
 
module Kernel
 
  # abstraction:: only include the methods given by _meths_
  # implementation:: includes a duplicate of _mod_ with only the specified instance methods included. By default, all private methods will be included unless the option :import_private is set to false. If no methods are given,
  def import(mod, *methods_or_options)
    mod_dup = mod.dup
 
    unless methods_or_options.empty?
      # get list of methods to remove module
      ims = mod.instance_methods
 
      meths = []
      modifiers = []
      methods_or_options.each do |m_o|
        case m_o
        when Hash
          bool = m_o.delete(:import_private)
          if bool.nil?
            modifiers.push m_o
          else
            if meths.empty? and methods_or_options.size == 1 and m_o.empty?
              fail ArgumentError,
                "methods arguments required with :import_private flag"
            end
            if bool == false
              ims += mod.private_instance_methods
            end
          end
        else
          meths.push m_o
        end
      end
 
      ims.map! {|m| m.to_sym}
      removes = ims - meths
 
      if removes.size != (ims.size - meths.size)
        raise ImportError,
          "##{(meths - ims).join(' and #')} not found in #{mod}"
      end
 
      mod_dup.module_eval do
        keeps = []
        modifiers.each do |hash|
          hash.each_pair do |meths, modifier|
            meths = meths.is_a?(Array) ? meths : [meths]
            case modifier
            when :as_public
              public *meths
              keeps.concat meths
            when :as_private
              private *meths
              keeps.concat meths
 
            else # don't keep renamed methods
              unless meths.size == 1
                fail ArgumentError, "cannot alias multiple methods to the same alias"
              end
 
              m = modifier.to_s
              unless m[0..2] == 'as_' && m[3]
                raise ArgumentError, "expected as_ modifier"
              end
              alias_method :"#{m[3..-1]}", meths.first
            end
          end
        end
 
        (removes - keeps).each { |meth| remove_method meth }
      end
    end
 
    include mod_dup
  end
end