Class: Rbpacker::SourceBundler

Inherits:
Object
  • Object
show all
Defined in:
lib/rbpacker/source_bundler.rb,
sig/rbpacker/source_bundler.rbs

Overview

Note:

Bundling evaluates the input files to capture nested require_relative calls, so running this on untrusted sources can execute arbitrary code.

Bundles Ruby source files into a single script by resolving require_relative.

Constant Summary collapse

REQUIRE_RELATIVE_PATTERN =

Returns:

  • (Regexp)
/
  (?<separator>\A|[;\n])
  [ \t]*
  require_relative
  [ \t]*
  \(?
  [ \t]*
  (?<quote>["'])
  (?:\\.|(?!\k<quote>).)*
  \k<quote>
  [ \t]*
  \)?
  [ \t]*
  (?=;|\n|\z)
/x
LEADING_COMMENT_LINES_PATTERN =

Returns:

  • (Regexp)
/\A(?<comments>(?:[ \t]*#.*\n)+)(?<blank_lines>(?:[ \t]*\n)*)/

Instance Method Summary collapse

Constructor Details

#initializeSourceBundler

Returns a new instance of SourceBundler.



27
28
29
30
31
32
33
# File 'lib/rbpacker/source_bundler.rb', line 27

def initialize
  @loaded_files = Set.new
  @collected_sources = [] #: Array[String]
  @depth = 0
  @original_require_relative = Kernel.instance_method(:require_relative)
  @entrypoint_comments_collected = false
end

Instance Method Details

#bundle(filepath) ⇒ SourceBundler

Parameters:

  • filepath (String)

Returns:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rbpacker/source_bundler.rb', line 38

def bundle(filepath)
  filepath += ".rb" unless filepath.end_with?(".rb")
  abs_path = File.expand_path(filepath)

  return self if @loaded_files.include?(abs_path)

  @loaded_files.add(abs_path)
  code = File.read(abs_path)

  with_require_relative_hook do
    eval_and_collect_source(code, abs_path)
  end

  self
end

#resultString

Returns:

  • (String)


55
56
57
# File 'lib/rbpacker/source_bundler.rb', line 55

def result
  @collected_sources.join
end