edit: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/predefined_spec.rb;C1086571
File: predefined_spec.rb
===================================================================
--- $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/predefined_spec.rb;C1086571  (server)    3/12/2010 10:02 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/predefined_spec.rb;scl
@@ -1,4 +1,5 @@
 require File.dirname(__FILE__) + '/../spec_helper'
+require File.dirname(__FILE__) + '/fixtures/classes'
 require 'stringio'
 
 # The following tables are excerpted from Programming Ruby: The Pragmatic Programmer's Guide'
@@ -567,3 +568,124 @@
     Object.const_defined?(:TOPLEVEL_BINDING).should == true
   end
 end
+
+describe "SCRIPT_LINES__" do
+  it "can be set" do
+    LanguageSpecs.preserving_script_lines do
+      SCRIPT_LINES__ = {}
+      Object.constants.include?(LanguageSpecs::SCRIPT_LINES_NAME).should be_true      
+    end
+  end
+  
+  it "records file name" do
+    filename = LanguageSpecs.script_lines_target_file
+    LanguageSpecs.get_script_lines(filename).keys[0].should == filename
+  end
+  
+  it "records the contents of the file" do
+    filename = LanguageSpecs.script_lines_target_file
+    script_lines = LanguageSpecs.get_script_lines filename
+    script_lines.values[0].class.should == Array
+    script_lines.values[0][0].should == File.open(filename) {|f| f.readline }
+  end
+
+  ruby_version_is "" ... "1.9" do
+    it "records reloads" do
+      LanguageSpecs.preserving_script_lines do
+        SCRIPT_LINES__ = {}
+        filename = LanguageSpecs.script_lines_target_file
+        load filename
+        SCRIPT_LINES__.clear
+        load filename
+        SCRIPT_LINES__.size.should == 1
+      end
+    end
+  end
+
+  ruby_version_is "1.9" do
+    it "does not record reloads" do
+      LanguageSpecs.preserving_script_lines do
+        SCRIPT_LINES__ = {}
+        filename = LanguageSpecs.script_lines_target_file
+        load filename
+        SCRIPT_LINES__.clear
+        load filename
+        SCRIPT_LINES__.size.should == 0
+      end
+    end
+  end
+
+  ruby_version_is "" ... "1.9" do
+    it "records the module load even if the module load fails" do
+      LanguageSpecs.preserving_script_lines do
+        SCRIPT_LINES__ = {}
+        lambda { load fixture(__FILE__, 'raise.rb') }.should raise_error
+        SCRIPT_LINES__.size.should == 1
+      end
+    end
+  end
+
+  ruby_version_is "1.9" do
+    it "does not record the module load if the module load fails" do
+      LanguageSpecs.preserving_script_lines do
+        SCRIPT_LINES__ = {}
+        lambda { load fixture(__FILE__, 'raise.rb') }.should raise_error
+        SCRIPT_LINES__.size.should == 0
+      end
+    end
+  end
+
+  it "can be set on a module mixed in to Object" do
+    defined?(SCRIPT_LINES__).should be_nil
+    begin
+      Kernel.const_set :SCRIPT_LINES__, {}
+      load LanguageSpecs.script_lines_target_file
+      Kernel.const_get(:SCRIPT_LINES__).size.should > 0
+    ensure
+      Kernel.module_eval { remove_const :SCRIPT_LINES__ if Kernel.constants.include? LanguageSpecs::SCRIPT_LINES_NAME }
+    end
+  end
+
+  ruby_version_is "1.9" do
+    it "is not honored as an autoload constant" do
+      begin
+        ScratchPad.clear
+        Object.autoload :SCRIPT_LINES__, fixture(__FILE__, 'autoload_script_lines.rb')
+        ScratchPad.recorded.should be_nil
+        load LanguageSpecs.script_lines_target_file
+        ScratchPad.recorded.should be_nil
+        SCRIPT_LINES__.size.should == 0
+      ensure
+        Object.class_eval { remove_const :SCRIPT_LINES__ }
+      end
+    end
+  end
+  
+  ruby_version_is "" ... "1.9" do
+    it "can be set to a Hash subclass" do
+      LanguageSpecs.preserving_script_lines do
+        SCRIPT_LINES__ = LanguageSpecs::MyHash.new
+        load LanguageSpecs.script_lines_target_file
+        SCRIPT_LINES__.size.should == 1
+      end
+    end
+  end
+
+  ruby_version_is "1.9" do
+    it "cannot be set to a Hash subclass" do
+      LanguageSpecs.preserving_script_lines do
+        SCRIPT_LINES__ = LanguageSpecs::MyHash.new
+        load LanguageSpecs.script_lines_target_file
+        SCRIPT_LINES__.size.should == 0
+      end
+    end
+  end
+
+  it "can be set to any type" do
+    LanguageSpecs.preserving_script_lines do
+      SCRIPT_LINES__ = mock("mock")
+      load LanguageSpecs.script_lines_target_file
+      SCRIPT_LINES__.class.should == MockObject
+    end
+  end
+end
\ No newline at end of file
===================================================================
add: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/autoload_script_lines.rb
File: autoload_script_lines.rb
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/autoload_script_lines.rb;scl
@@ -1,0 +1,2 @@
+ScratchPad.record :autoload_script_lines
+SCRIPT_LINES__ = {}
===================================================================
edit: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/classes.rb;C966724
File: classes.rb
===================================================================
--- $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/classes.rb;C966724  (server)    3/12/2010 10:44 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/classes.rb;scl
@@ -17,6 +17,42 @@
     undef :to_s
   end
   
+  ruby_version_is("" ... "1.9") { SCRIPT_LINES_NAME = 'SCRIPT_LINES__' }
+  ruby_version_is("1.9") { SCRIPT_LINES_NAME = :SCRIPT_LINES__ }
+  
+  def self.script_lines_target_file
+    File.dirname(__FILE__) + '/empty.rb'
+  end
+  
+  def self.preserving_script_lines()
+    old_script_lines = if Object.constants.include? SCRIPT_LINES_NAME
+      Object.const_get SCRIPT_LINES_NAME
+    else
+      :undefined
+    end
+    
+    begin
+      yield
+    ensure
+      if old_script_lines == :undefined
+        Object.class_eval { remove_const SCRIPT_LINES_NAME if Object.constants.include? SCRIPT_LINES_NAME }
+      else
+        Object.const_set SCRIPT_LINES_NAME, old_script_lines
+      end
+    end
+  end
+  
+  def self.get_script_lines(filename)
+    preserving_script_lines do
+      Object.const_set :SCRIPT_LINES__, {}
+      load filename
+      SCRIPT_LINES__
+    end
+  end
+  
+  class MyHash < Hash
+  end
+  
   #############################################################################
   # Regexp support
   #############################################################################
===================================================================
add: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/empty.rb
File: empty.rb
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/empty.rb;scl
@@ -1,0 +1,1 @@
+# Just an empty file
===================================================================
add: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/raise.rb
File: raise.rb
===================================================================
--- [no source file]
+++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/rubyspec/language/fixtures/raise.rb;scl
@@ -1,0 +1,1 @@
+raise "raise.rb raising exception"
\ No newline at end of file
===================================================================
edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs;C1597865
File: Loader.cs
===================================================================
--- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs;C1597865  (server)    3/12/2010 11:18 AM
+++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs;scl
@@ -14,12 +14,14 @@
  * ***************************************************************************/
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Security;
+using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading;
 using IronRuby.Builtins;
@@ -106,6 +108,11 @@
         }
 
         /// <summary>
+        /// TODO: Thread safety: the user of this object is responsible for locking it.
+        /// </summary>
+        public object ScriptLines { get; set; }
+
+        /// <summary>
         /// Contains all loaded foreign language scripts. Maps path to scope created for each loaded script.
         /// A script is published here as soon as its scopr is created just before it is executed.
         /// </summary>
@@ -541,6 +548,8 @@
                 _unfinishedFiles.Push(pathWithExtension.ToString());
 
                 if (file.SourceUnit != null) {
+                    AddScriptLines(file.SourceUnit);
+
                     ScriptCode compiledCode;
                     if (file.SourceUnit.LanguageContext == _context) {
                         compiledCode = CompileRubySource(file.SourceUnit, flags);
@@ -812,6 +821,27 @@
             }
         }
 
+        private void AddScriptLines(SourceUnit file) {            
+            MutableString path = MutableString.Create(file.Document.FileName, _context.GetPathEncoding());
+            ConstantStorage storage;
+            if (_context.ObjectClass.TryResolveConstant(null, "SCRIPT_LINES__", out storage)) {
+                IDictionary scriptLines = storage.Value as IDictionary;
+                if (scriptLines != null) {
+                    lock (scriptLines) {
+                        if (!scriptLines.Contains(path)) {
+                            Encoding encoding;
+                            string[] lines = file.GetCodeLines(1, int.MaxValue, out encoding);
+                            RubyArray linesArray = new RubyArray(lines.Length);
+                            foreach (string line in lines) {
+                                linesArray.Add(MutableString.Create(line + '\n', RubyEncoding.GetRubyEncoding(encoding)));
+                            }
+                            scriptLines[path] = linesArray;
+                        }
+                    }
+                }
+            }
+        }
+
         internal object[]/*!*/ GetLoadedFiles() {
             lock (_loadedFiles) {
                 return _loadedFiles.ToArray();
===================================================================
