Class: RubyRequireInline::DepsWalk

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_require_inline/depswalk.rb

Instance Method Summary collapse

Constructor Details

#initialize(deps_paths, entry_point) ⇒ DepsWalk

Returns a new instance of DepsWalk.



7
8
9
10
11
12
13
# File 'lib/ruby_require_inline/depswalk.rb', line 7

def initialize deps_paths, entry_point
  @cache = {}
  @entry_point = entry_point
  @deps_paths = deps_paths

  @deps_paths.unshift "."
end

Instance Method Details

#dep_path(dep, parent) ⇒ Object

Return a full path to a dependency, or nil if file not found. It doesn’t look in $LOAD_PATH.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ruby_require_inline/depswalk.rb', line 54

def dep_path dep, parent
  return nil unless dep

  @deps_paths.each do |path|
    [".rb", ""].each do |idx|
      file = dep.first + idx
      if dep[1]
        # dep.first is relative to a parent dep
        file = File.join File.dirname(parent), file
      else
        file = File.join path, file
      end

      return File.realpath file if File.readable?(file) && File.file?(file)
    end
  end

  #  puts "#{dep.first} not found"
  nil
end

#require_parse(sexp) ⇒ Object

Return a 1st param of ‘require’ & relative flag or nil.

Examples:

‘foo’, nil’
‘../bar, ’true’


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
# File 'lib/ruby_require_inline/depswalk.rb', line 81

def require_parse sexp
  return nil unless sexp

  # valid node example: s(:call, nil, :require, s(:str, "getoptlong"))
  is_require_node = -> (node) {
    return nil unless node.is_a? Sexp
    node.sexp_type == :call \
    && sexp.sexp_body[2] && sexp.sexp_body[2].sexp_type == :str \
    && (node.sexp_body[1] == :require || \
        node.sexp_body[1] == :require_relative || \
        node.sexp_body[1] == :load)
  }

  return nil unless is_require_node.call sexp

  is_relative_path = -> (node) {
    node.sexp_body[2].sexp_body.first.match(/^(\.{1,2})?\//)
  }
  is_relative = -> (node) {
    node.sexp_body[1] == :require_relative || is_relative_path.call(node)
  }

  if sexp.sexp_body[2]
    return [sexp.sexp_body[2].sexp_body.first, is_relative.call(sexp)]
  end

  nil
end

#start(&block) ⇒ Object



15
16
17
# File 'lib/ruby_require_inline/depswalk.rb', line 15

def start &block
  walk_deps @entry_point, &block
end

#walk_deps(file, level = 0, stop = false) {|file, level, stop| ... } ⇒ Object

Yields:

  • (file, level, stop)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/ruby_require_inline/depswalk.rb', line 19

def walk_deps file, level = 0, stop = false, &block
  file = File.realpath file if level == 0
  return if @cache.key?(file)
  @cache[file] = true

  yield file, level, stop if block_given?
  return if stop

  sexp = RubyParser.new.parse IO.read(file)

  walk_sexp(sexp) do |node|
    dep = require_parse node
    if dep
      path = dep_path dep, file
      if path
        walk_deps path, level+1, false, &block # recursion!
      else
        # this will do &block and return
        walk_deps dep.first, level+1, true, &block # recursion!
      end
    end
  end
end

#walk_sexp(sexp, &block) ⇒ Object



43
44
45
46
47
48
49
50
# File 'lib/ruby_require_inline/depswalk.rb', line 43

def walk_sexp sexp, &block
  return unless sexp.is_a?(Sexp)

  sexp.sexp_body.each do |node|
    yield node if block_given?
    walk_sexp(node, &block) if node.is_a?(Sexp) # recursion!
  end
end