00001
00002
00003
00004
00005
00006 #include "ruby/ruby.h"
00007 #include "vm_core.h"
00008
00009
00010 static const char prelude_name0[] = "<internal:prelude>";
00011 static const char prelude_code0[] =
00012 "class Mutex\n"
00013 " # call-seq:\n"
00014 " # mutex.synchronize { ... }\n"
00015 " #\n"
00016 " # Obtains a lock, runs the block, and releases the lock when the\n"
00017 " # block completes. See the example under Mutex.\n"
00018 " def synchronize\n"
00019 " self.lock\n"
00020 " begin\n"
00021 " yield\n"
00022 " ensure\n"
00023 " self.unlock rescue nil\n"
00024 " end\n"
00025 " end\n"
00026 "end\n"
00027 "\n"
00028 "class Thread\n"
00029 " MUTEX_FOR_THREAD_EXCLUSIVE = Mutex.new # :nodoc:\n"
00030 "\n"
00031 " # call-seq:\n"
00032 " # Thread.exclusive { block } => obj\n"
00033 " # \n"
00034 " # Wraps a block in Thread.critical, restoring the original value\n"
00035 " # upon exit from the critical section, and returns the value of the\n"
00036 " # block.\n"
00037 " def self.exclusive\n"
00038 " MUTEX_FOR_THREAD_EXCLUSIVE.synchronize{\n"
00039 " yield\n"
00040 " }\n"
00041 " end\n"
00042 "end\n"
00043 ;
00044
00045 static const char prelude_name1[] = "<internal:enc/prelude>";
00046 static const char prelude_code1[] =
00047 "%w'enc/encdb.so enc/trans/transdb.so'.each do |init|\n"
00048 " begin\n"
00049 " require(init)\n"
00050 " rescue LoadError\n"
00051 " end\n"
00052 "end\n"
00053 ;
00054
00055 static const char prelude_name2[] = "<internal:gem_prelude>";
00056 static const char prelude_code2[] =
00057 "# depends on: array.rb dir.rb env.rb file.rb hash.rb module.rb regexp.rb\n"
00058 "# vim: filetype=ruby\n"
00059 "\n"
00060 "# NOTICE: Ruby is during initialization here.\n"
00061 "# * Encoding.default_external does not reflects -E.\n"
00062 "# * Should not expect Encoding.default_internal.\n"
00063 "# * Locale encoding is available.\n"
00064 "\n"
00065 "if defined?(Gem) then\n"
00066 "\n"
00067 " # :stopdoc:\n"
00068 "\n"
00069 " module Kernel\n"
00070 "\n"
00071 " def gem(gem_name, *version_requirements)\n"
00072 " Gem::QuickLoader.load_full_rubygems_library\n"
00073 " gem gem_name, *version_requirements\n"
00074 " end\n"
00075 " private :gem\n"
00076 " end\n"
00077 "\n"
00078 " module Gem\n"
00079 "\n"
00080 " ConfigMap = {\n"
00081 " :EXEEXT => \"\",\n"
00082 " :RUBY_SO_NAME => \"ruby\",\n"
00083 " :arch => \"i686-linux\",\n"
00084 " :bindir => \"#{TMP_RUBY_PREFIX}/bin\",\n"
00085 " :libdir => \"#{TMP_RUBY_PREFIX}/lib\",\n"
00086 " :ruby_install_name => \"ruby\",\n"
00087 " :ruby_version => \"1.9.1\",\n"
00088 " :rubylibprefix => \"#{TMP_RUBY_PREFIX}/lib/ruby\",\n"
00089 " :sitedir => \"#{TMP_RUBY_PREFIX}/lib/ruby/site_ruby\",\n"
00090 " :sitelibdir => \"#{TMP_RUBY_PREFIX}/lib/ruby/site_ruby/1.9.1\",\n"
00091 " }\n"
00092 "\n"
00093 " def self.dir\n"
00094 " @gem_home ||= nil\n"
00095 " set_home(ENV['GEM_HOME'] || default_dir) unless @gem_home\n"
00096 " @gem_home\n"
00097 " end\n"
00098 "\n"
00099 " def self.path\n"
00100 " @gem_path ||= nil\n"
00101 " unless @gem_path\n"
00102 " paths = [ENV['GEM_PATH'] || default_path]\n"
00103 " paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME\n"
00104 " set_paths(paths.compact.join(File::PATH_SEPARATOR))\n"
00105 " end\n"
00106 " @gem_path\n"
00107 " end\n"
00108 "\n"
00109 " def self.post_install(&hook)\n"
00110 " @post_install_hooks << hook\n"
00111 " end\n"
00112 "\n"
00113 " def self.post_uninstall(&hook)\n"
00114 " @post_uninstall_hooks << hook\n"
00115 " end\n"
00116 "\n"
00117 " def self.pre_install(&hook)\n"
00118 " @pre_install_hooks << hook\n"
00119 " end\n"
00120 "\n"
00121 " def self.pre_uninstall(&hook)\n"
00122 " @pre_uninstall_hooks << hook\n"
00123 " end\n"
00124 "\n"
00125 " def self.set_home(home)\n"
00126 " home = home.dup.force_encoding(Encoding.find('filesystem'))\n"
00127 " home.gsub!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR\n"
00128 " @gem_home = home\n"
00129 " end\n"
00130 "\n"
00131 " def self.set_paths(gpaths)\n"
00132 " if gpaths\n"
00133 " @gem_path = gpaths.split(File::PATH_SEPARATOR)\n"
00134 "\n"
00135 " if File::ALT_SEPARATOR then\n"
00136 " @gem_path.map! do |path|\n"
00137 " path.gsub File::ALT_SEPARATOR, File::SEPARATOR\n"
00138 " end\n"
00139 " end\n"
00140 "\n"
00141 " @gem_path << Gem.dir\n"
00142 " else\n"
00143 " # TODO: should this be Gem.default_path instead?\n"
00144 " @gem_path = [Gem.dir]\n"
00145 " end\n"
00146 "\n"
00147 " @gem_path.uniq!\n"
00148 " @gem_path.map!{|x|x.force_encoding(Encoding.find('filesystem'))}\n"
00149 " end\n"
00150 "\n"
00151 " def self.user_home\n"
00152 " @user_home ||= File.expand_path(\"~\").force_encoding(Encoding.find('filesystem'))\n"
00153 " rescue\n"
00154 " if File::ALT_SEPARATOR then\n"
00155 " \"C:/\"\n"
00156 " else\n"
00157 " \"/\"\n"
00158 " end\n"
00159 " end\n"
00160 "\n"
00161 " # begin rubygems/defaults\n"
00162 " # NOTE: this require will be replaced with in-place eval before compilation.\n"
00163 " TMP_RUBY_PREFIX.require(3)\n"
00164 " # end rubygems/defaults\n"
00165 "\n"
00166 "\n"
00167 " ##\n"
00168 " # Methods before this line will be removed when QuickLoader is replaced\n"
00169 " # with the real RubyGems\n"
00170 "\n"
00171 " GEM_PRELUDE_METHODS = Gem.methods(false)\n"
00172 "\n"
00173 " begin\n"
00174 " verbose, debug = $VERBOSE, $DEBUG\n"
00175 " $VERBOSE = $DEBUG = nil\n"
00176 "\n"
00177 " begin\n"
00178 " require 'rubygems/defaults/operating_system'\n"
00179 " rescue ::LoadError\n"
00180 " end\n"
00181 "\n"
00182 " if defined?(RUBY_ENGINE) then\n"
00183 " begin\n"
00184 " require \"rubygems/defaults/#{RUBY_ENGINE}\"\n"
00185 " rescue ::LoadError\n"
00186 " end\n"
00187 " end\n"
00188 " ensure\n"
00189 " $VERBOSE, $DEBUG = verbose, debug\n"
00190 " end\n"
00191 "\n"
00192 " module QuickLoader\n"
00193 "\n"
00194 " @loaded_full_rubygems_library = false\n"
00195 "\n"
00196 " def self.remove\n"
00197 " return if @loaded_full_rubygems_library\n"
00198 "\n"
00199 " @loaded_full_rubygems_library = true\n"
00200 "\n"
00201 " class << Gem\n"
00202 " undef_method(*Gem::GEM_PRELUDE_METHODS)\n"
00203 " end\n"
00204 "\n"
00205 " remove_method :const_missing\n"
00206 " remove_method :method_missing\n"
00207 "\n"
00208 " Kernel.module_eval do\n"
00209 " undef_method :gem if method_defined? :gem\n"
00210 " end\n"
00211 " end\n"
00212 "\n"
00213 " def self.load_full_rubygems_library\n"
00214 " return false if @loaded_full_rubygems_library\n"
00215 "\n"
00216 " remove\n"
00217 "\n"
00218 " $\".delete path_to_full_rubygems_library\n"
00219 " if $\".any? {|path| path.end_with?('/rubygems.rb')}\n"
00220 " raise LoadError, \"another rubygems is already loaded from #{path}\"\n"
00221 " end\n"
00222 "\n"
00223 " require 'rubygems'\n"
00224 "\n"
00225 " return true\n"
00226 " end\n"
00227 "\n"
00228 " def self.path_to_full_rubygems_library\n"
00229 " installed_path = File.join(Gem::ConfigMap[:rubylibprefix], Gem::ConfigMap[:ruby_version])\n"
00230 " if $:.include?(installed_path)\n"
00231 " return File.join(installed_path, 'rubygems.rb')\n"
00232 " else # e.g., on test-all\n"
00233 " $:.each do |dir|\n"
00234 " if File.exist?( path = File.join(dir, 'rubygems.rb') )\n"
00235 " return path\n"
00236 " end\n"
00237 " end\n"
00238 " raise LoadError, 'rubygems.rb'\n"
00239 " end\n"
00240 " end\n"
00241 "\n"
00242 " def const_missing(constant)\n"
00243 " QuickLoader.load_full_rubygems_library\n"
00244 "\n"
00245 " if Gem.const_defined?(constant) then\n"
00246 " Gem.const_get constant\n"
00247 " else\n"
00248 " super\n"
00249 " end\n"
00250 " end\n"
00251 "\n"
00252 " def method_missing(method, *args, &block)\n"
00253 " QuickLoader.load_full_rubygems_library\n"
00254 " super unless Gem.respond_to?(method)\n"
00255 " Gem.send(method, *args, &block)\n"
00256 " end\n"
00257 " end\n"
00258 "\n"
00259 " extend QuickLoader\n"
00260 "\n"
00261 " def self.try_activate(path)\n"
00262 " # This method is only hit when the custom require is hit the first time.\n"
00263 " # So we go off and dutifully load all of rubygems and retry the call\n"
00264 " # to Gem.try_activate. We retry because full rubygems replaces this\n"
00265 " # method with one that actually tries to find a gem for +path+ and load it.\n"
00266 " #\n"
00267 " # This is conditional because in the course of loading rubygems, the custom\n"
00268 " # require will call back into here before all of rubygems is loaded. So\n"
00269 " # we must not always retry the call. We only redo the call when\n"
00270 " # load_full_rubygems_library returns true, which it only does the first\n"
00271 " # time it's called.\n"
00272 " #\n"
00273 " if QuickLoader.load_full_rubygems_library\n"
00274 " return Gem.try_activate(path)\n"
00275 " end\n"
00276 "\n"
00277 " return false\n"
00278 " end\n"
00279 "\n"
00280 " end\n"
00281 "\n"
00282 " begin\n"
00283 " TMP_RUBY_PREFIX.require(4)\n"
00284 " rescue Exception => e\n"
00285 " puts \"Error loading gem paths on load path in gem_prelude\"\n"
00286 " puts e\n"
00287 " puts e.backtrace.join(\"\\n\")\n"
00288 " end\n"
00289 "\n"
00290 "end\n"
00291 "\n"
00292 ;
00293
00294 static const char prelude_name3[] = "<internal:lib/rubygems/defaults>";
00295 static const char prelude_code3[] =
00296 "module Gem\n"
00297 "\n"
00298 " @post_install_hooks ||= []\n"
00299 " @post_uninstall_hooks ||= []\n"
00300 " @pre_uninstall_hooks ||= []\n"
00301 " @pre_install_hooks ||= []\n"
00302 "\n"
00303 " ##\n"
00304 " # An Array of the default sources that come with RubyGems\n"
00305 "\n"
00306 " def self.default_sources\n"
00307 " %w[http://rubygems.org/]\n"
00308 " end\n"
00309 "\n"
00310 " ##\n"
00311 " # Default home directory path to be used if an alternate value is not\n"
00312 " # specified in the environment\n"
00313 "\n"
00314 " def self.default_dir\n"
00315 " if defined? RUBY_FRAMEWORK_VERSION then\n"
00316 " File.join File.dirname(ConfigMap[:sitedir]), 'Gems',\n"
00317 " ConfigMap[:ruby_version]\n"
00318 " elsif ConfigMap[:rubylibprefix] then\n"
00319 " File.join(ConfigMap[:rubylibprefix], 'gems',\n"
00320 " ConfigMap[:ruby_version])\n"
00321 " else\n"
00322 " File.join(ConfigMap[:libdir], ruby_engine, 'gems',\n"
00323 " ConfigMap[:ruby_version])\n"
00324 " end\n"
00325 " end\n"
00326 "\n"
00327 " ##\n"
00328 " # Path for gems in the user's home directory\n"
00329 "\n"
00330 " def self.user_dir\n"
00331 " File.join Gem.user_home, '.gem', ruby_engine, ConfigMap[:ruby_version]\n"
00332 " end\n"
00333 "\n"
00334 " ##\n"
00335 " # Default gem load path\n"
00336 "\n"
00337 " def self.default_path\n"
00338 " if File.exist? Gem.user_home then\n"
00339 " [user_dir, default_dir]\n"
00340 " else\n"
00341 " [default_dir]\n"
00342 " end\n"
00343 " end\n"
00344 "\n"
00345 " ##\n"
00346 " # Deduce Ruby's --program-prefix and --program-suffix from its install name\n"
00347 "\n"
00348 " def self.default_exec_format\n"
00349 " exec_format = ConfigMap[:ruby_install_name].sub('ruby', '%s') rescue '%s'\n"
00350 "\n"
00351 " unless exec_format =~ /%s/ then\n"
00352 " raise Gem::Exception,\n"
00353 " \"[BUG] invalid exec_format #{exec_format.inspect}, no %s\"\n"
00354 " end\n"
00355 "\n"
00356 " exec_format\n"
00357 " end\n"
00358 "\n"
00359 " ##\n"
00360 " # The default directory for binaries\n"
00361 "\n"
00362 " def self.default_bindir\n"
00363 " if defined? RUBY_FRAMEWORK_VERSION then # mac framework support\n"
00364 " '/usr/bin'\n"
00365 " else # generic install\n"
00366 " ConfigMap[:bindir]\n"
00367 " end\n"
00368 " end\n"
00369 "\n"
00370 " ##\n"
00371 " # The default system-wide source info cache directory\n"
00372 "\n"
00373 " def self.default_system_source_cache_dir\n"
00374 " File.join Gem.dir, 'source_cache'\n"
00375 " end\n"
00376 "\n"
00377 " ##\n"
00378 " # The default user-specific source info cache directory\n"
00379 "\n"
00380 " def self.default_user_source_cache_dir\n"
00381 " File.join Gem.user_home, '.gem', 'source_cache'\n"
00382 " end\n"
00383 "\n"
00384 " ##\n"
00385 " # A wrapper around RUBY_ENGINE const that may not be defined\n"
00386 "\n"
00387 " def self.ruby_engine\n"
00388 " if defined? RUBY_ENGINE then\n"
00389 " RUBY_ENGINE\n"
00390 " else\n"
00391 " 'ruby'\n"
00392 " end\n"
00393 " end\n"
00394 "\n"
00395 "end\n"
00396 "\n"
00397 ;
00398
00399 static const char prelude_name4[] = "<internal:lib/rubygems/custom_require>";
00400 static const char prelude_code4[] =
00401 "#--\n"
00402 "# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.\n"
00403 "# All rights reserved.\n"
00404 "# See LICENSE.txt for permissions.\n"
00405 "#++\n"
00406 "\n"
00407 "module Kernel\n"
00408 "\n"
00409 " ##\n"
00410 " # The Kernel#require from before RubyGems was loaded.\n"
00411 "\n"
00412 " alias gem_original_require require\n"
00413 "\n"
00414 " ##\n"
00415 " # When RubyGems is required, Kernel#require is replaced with our own which\n"
00416 " # is capable of loading gems on demand.\n"
00417 " #\n"
00418 " # When you call <tt>require 'x'</tt>, this is what happens:\n"
00419 " # * If the file can be loaded from the existing Ruby loadpath, it\n"
00420 " # is.\n"
00421 " # * Otherwise, installed gems are searched for a file that matches.\n"
00422 " # If it's found in gem 'y', that gem is activated (added to the\n"
00423 " # loadpath).\n"
00424 " #\n"
00425 " # The normal <tt>require</tt> functionality of returning false if\n"
00426 " # that file has already been loaded is preserved.\n"
00427 "\n"
00428 " def require(path) # :doc:\n"
00429 " gem_original_require path\n"
00430 " rescue LoadError => load_error\n"
00431 " if load_error.message.end_with?(path)\n"
00432 " if Gem.try_activate(path)\n"
00433 " return gem_original_require(path)\n"
00434 " end\n"
00435 " end\n"
00436 "\n"
00437 " raise load_error\n"
00438 " end\n"
00439 "\n"
00440 " private :require\n"
00441 " private :gem_original_require\n"
00442 "\n"
00443 "end unless Kernel.private_method_defined?(:gem_original_require)\n"
00444 "\n"
00445 ;
00446
00447 #define PRELUDE_COUNT 5
00448
00449 struct prelude_env {
00450 volatile VALUE prefix_path;
00451 #if PRELUDE_COUNT > 0
00452 char loaded[PRELUDE_COUNT];
00453 #endif
00454 };
00455
00456 static VALUE
00457 prelude_prefix_path(VALUE self)
00458 {
00459 struct prelude_env *ptr = DATA_PTR(self);
00460 return ptr->prefix_path;
00461 }
00462
00463 VALUE rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE filepath, VALUE line, VALUE opt);
00464
00465 static void
00466 prelude_eval(VALUE code, VALUE name, VALUE line)
00467 {
00468 rb_iseq_eval(rb_iseq_compile_with_option(code, name, Qnil, line, Qtrue));
00469 }
00470
00471 static VALUE
00472 prelude_require(VALUE self, VALUE nth)
00473 {
00474 struct prelude_env *ptr = DATA_PTR(self);
00475 VALUE code, name;
00476 int n = FIX2INT(nth);
00477
00478 if (n > PRELUDE_COUNT) return Qfalse;
00479 if (ptr->loaded[n]) return Qfalse;
00480 ptr->loaded[n] = 1;
00481 switch (n) {
00482 case 3:
00483 code = rb_usascii_str_new(prelude_code3, sizeof(prelude_code3) - 1);
00484 name = rb_usascii_str_new(prelude_name3, sizeof(prelude_name3) - 1);
00485 break;
00486 case 4:
00487 code = rb_usascii_str_new(prelude_code4, sizeof(prelude_code4) - 1);
00488 name = rb_usascii_str_new(prelude_name4, sizeof(prelude_name4) - 1);
00489 break;
00490 default:
00491 return Qfalse;
00492 }
00493 prelude_eval(code, name, INT2FIX(1));
00494 return Qtrue;
00495 }
00496
00497 void
00498 Init_prelude(void)
00499 {
00500 struct prelude_env memo;
00501 ID name = rb_intern("TMP_RUBY_PREFIX");
00502 VALUE prelude = Data_Wrap_Struct(rb_cData, 0, 0, &memo);
00503
00504 memo.prefix_path = rb_const_remove(rb_cObject, name);
00505 rb_const_set(rb_cObject, name, prelude);
00506 rb_define_singleton_method(prelude, "to_s", prelude_prefix_path, 0);
00507 memset(memo.loaded, 0, sizeof(memo.loaded));
00508 rb_define_singleton_method(prelude, "require", prelude_require, 1);
00509 prelude_eval(
00510 rb_usascii_str_new(prelude_code0, sizeof(prelude_code0) - 1),
00511 rb_usascii_str_new(prelude_name0, sizeof(prelude_name0) - 1),
00512 INT2FIX(1));
00513 prelude_eval(
00514 rb_usascii_str_new(prelude_code1, sizeof(prelude_code1) - 1),
00515 rb_usascii_str_new(prelude_name1, sizeof(prelude_name1) - 1),
00516 INT2FIX(1));
00517 prelude_eval(
00518 rb_usascii_str_new(prelude_code2, sizeof(prelude_code2) - 1),
00519 rb_usascii_str_new(prelude_name2, sizeof(prelude_name2) - 1),
00520 INT2FIX(1));
00521 rb_gc_force_recycle(prelude);
00522
00523 #if 0
00524 puts(prelude_code0);
00525 puts(prelude_code1);
00526 puts(prelude_code2);
00527 puts(prelude_code3);
00528 puts(prelude_code4);
00529 #endif
00530 }
00531