summaryrefslogtreecommitdiff
path: root/gem_prelude.rb
blob: 1b4ef4409e221755d24dd3b4f3c3582eacf79767 (plain)
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# empty gem_prelude.rb
#
# p Gem::Enable

if defined?(Gem::Enable) && Gem::Enable
#t = Time.now
  
module Kernel

  def gem(gem_name, *version_requirements)
    Gem.push_gem_version_on_load_path(gem_name, *version_requirements)
  end

end

module Gem
  
  ConfigMap = {
    :sitedir => RbConfig::CONFIG["sitedir"],
    :ruby_version => RbConfig::CONFIG["ruby_version"],
    :libdir => RbConfig::CONFIG["libdir"],
    :sitelibdir => RbConfig::CONFIG["sitelibdir"],
    :arch => RbConfig::CONFIG["arch"],
    :bindir => RbConfig::CONFIG["bindir"],
    :EXEEXT => RbConfig::CONFIG["EXEEXT"],
    :RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
    :ruby_install_name => RbConfig::CONFIG["ruby_install_name"]
  }

  class << self

    def default_dir
      if defined? RUBY_FRAMEWORK_VERSION
        return File.join(File.dirname(ConfigMap[:sitedir]), "Gems")
      else
        File.join(ConfigMap[:libdir], 'ruby', 'gems', ConfigMap[:ruby_version])
      end
    end

    def dir
      @gem_home ||= nil
      set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home
      @gem_home
    end

    def path
      @gem_path ||= nil
      unless @gem_path
        paths = [ENV['GEM_PATH']]
        paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME
        set_paths(paths.compact.join(File::PATH_SEPARATOR))
      end
      @gem_path
    end

    # Set the Gem home directory (as reported by +dir+).
    def set_home(home)
      @gem_home = home
      ensure_gem_subdirectories(@gem_home)
    end

    def set_paths(gpaths)
      if gpaths
        @gem_path = gpaths.split(File::PATH_SEPARATOR)
        @gem_path << Gem.dir
      else
        @gem_path = [Gem.dir]
      end
      @gem_path.uniq!
      @gem_path.each do |gp| ensure_gem_subdirectories(gp) end
    end
    
    def ensure_gem_subdirectories(path)
    end

  end

  module QuickLoader

    class << self
      def load_full_rubygems_library
        class << Gem
          Gem.methods(false).each do |method_name|
            undef_method method_name
          end
        end

        Kernel.send :undef_method, :gem

        $".delete File.join(Gem::ConfigMap[:libdir], 'ruby',
                            Gem::ConfigMap[:ruby_version], 'rubygems.rb')

        require 'rubygems'
      end
    end

    GemPaths = {}
    GemVersions = {}
    
    def push_gem_version_on_load_path(gem_name, *version_requirements)
      if version_requirements.empty?
        unless GemPaths.has_key?(gem_name)
          raise LoadError.new("Could not find RubyGem #{gem_name} (>= 0)\n") 
        end
        # highest version gems already active
        return false
      else
        if version_requirements.length > 1
          QuickLoader.load_full_rubygems_library
          return gem(gem_name, *version_requirements)
        end
        requirement, version = version_requirements[0].split
        requirement.strip!
        if requirement == ">" || requirement == ">="
          if (GemVersions[gem_name] <=> Gem.calculate_integers_for_gem_version(version)) >= 0
            return false 
          end
        elsif requirement == "~>"
          loaded_version = GemVersions[gem_name]
          required_version = Gem.calculate_integers_for_gem_version(version)
          if loaded_version && (loaded_version[0] == required_version[0])
            return false
          end
        end
        QuickLoader.load_full_rubygems_library
        gem(gem_name, *version_requirements)
      end
    end

    def calculate_integers_for_gem_version(gem_version)
      numbers = gem_version.split(".").collect {|n| n.to_i}
      numbers.pop while numbers.last == 0
      numbers << 0 if numbers.empty?
      numbers
    end
  
    def push_all_highest_version_gems_on_load_path
      Gem.path.each do |path|
        gems_directory = File.join(path, "gems")
        if File.exist?(gems_directory)
          Dir.entries(gems_directory).each do |gem_directory_name|
            next if gem_directory_name == "." || gem_directory_name == ".."
            dash = gem_directory_name.rindex("-")
            next if dash.nil?
            gem_name = gem_directory_name[0...dash]
            current_version = GemVersions[gem_name]
            new_version = calculate_integers_for_gem_version(gem_directory_name[dash+1..-1])
            if current_version
              if (current_version <=> new_version) == -1
                GemVersions[gem_name] = new_version
                GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
              end
            else
              GemVersions[gem_name] = new_version
              GemPaths[gem_name] = File.join(gems_directory, gem_directory_name)
            end
          end
        end
      end
      require_paths = []
      GemPaths.values.each do |path|
        if File.exist?(File.join(path, ".require_paths"))
          require_paths.concat(File.read(File.join(path, ".require_paths")).split.map {|require_path| File.join(path, require_path)})
        else
          require_paths << File.join(path, "bin") if File.exist?(File.join(path, "bin"))
          require_paths << File.join(path, "lib") if File.exist?(File.join(path, "lib"))
        end
      end
      
      # "tag" the first require_path inserted into the $LOAD_PATH to enable
      # indexing correctly with rubygems proper when it inserts an explicitly
      # gem version
      unless require_paths.empty?
        require_paths.first.instance_variable_set(:@gem_prelude_index, true)
      end
      # gem directories must come after -I and ENV['RUBYLIB']
      $:[$:.index(ConfigMap[:sitelibdir]),0] = require_paths
    end

    def const_missing(constant)
      QuickLoader.load_full_rubygems_library
      Gem.const_get(constant)
    end

    def method_missing(method, *args, &block)
      QuickLoader.load_full_rubygems_library
      super unless Gem.respond_to?(method)
      Gem.send(method, *args, &block)
    end
  end
  
  extend QuickLoader

end

begin
  Gem.push_all_highest_version_gems_on_load_path
  $" << File.join(Gem::ConfigMap[:libdir], "ruby",
                  Gem::ConfigMap[:ruby_version], "rubygems.rb")
rescue Exception => e
  puts "Error loading gem paths on load path in gem_prelude"
  puts e
  puts e.backtrace.join("\n")
end

#puts "Gem load in #{Time.now - t} seconds"
end # Gem::Enable