Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I access the DATA from a required script in Ruby?

Tags:

ruby

Is it possible to access the text after __END__ in a ruby file other than the "main" script?

For example:

# b.rb
B_DATA = DATA.read
__END__
bbb

.

# a.rb
require 'b'
A_DATA = DATA.read
puts 'A_DATA: ' + A_DATA
puts 'B_DATA: ' + B_DATA
__END__
aaa

.

C:\Temp>ruby a.rb
A_DATA:
B_DATA: aaa

Is there any way to get at the "bbb" from b.rb?

like image 555
Chris Perkins Avatar asked Jan 28 '10 17:01

Chris Perkins


2 Answers

Unfortunately, the DATA global constant is set when the "main" script is loaded. A few things that might help:

You can at least get A_DATA to be correct. Just reverse the order of the first two operations in a.rb:

# a.rb
A_DATA = DATA.read
require 'b'
...

You can get the B_DATA to be correct if you go through a bit of rigamarole:

# load_data_regardless_of_main_script.rb
module LoadDataRegardlessOfMainScript
  def self.from(file)
    # the performance of this function could be
    # greatly improved by using a StringIO buffer
    # and only appending to it after seeing __END__.
    File.read(file).sub(/\A.*\n__END__\n/m, '')
  end
end

# b.rb:
require 'load_data_regardless_of_main_script'
B_DATA = LoadDataRegardlessOfMainScript.from(__FILE__)
like image 151
James A. Rosen Avatar answered Sep 30 '22 18:09

James A. Rosen


Implementing @James's suggestion to use StringIO:

require 'stringio'
module LoadDataRegardlessOfMainScript
  def self.from(filename)
    data = StringIO.new
    File.open(filename) do |f|
      begin
        line = f.gets
      end until line.match(/^__END__$/)
      while line = f.gets
        data << line 
      end
    end
    data.rewind
    data
  end
end

Then b.rb becomes

require 'load_data_regardless_of_main_script'
B_DATA = LoadDataRegardlessOfMainScript.from(__FILE__).read
like image 31
glenn jackman Avatar answered Sep 30 '22 18:09

glenn jackman