Class: Pry::ObjectPath

Inherits:
Object show all
Defined in:
lib/pry/object_path.rb

Overview

ObjectPath implements the resolution of "object paths", which are strings that are similar to filesystem paths but meant for traversing Ruby objects. Examples of valid object paths include:

x
@foo/@bar
"string"/upcase
Pry/Method

Object paths are mostly relevant in the context of the cd command.

Constant Summary

SPECIAL_TERMS =
["", "::", ".", ".."]

Instance Method Summary collapse

Constructor Details

#initialize(path_string, current_stack) ⇒ ObjectPath

Returns a new instance of ObjectPath

Parameters:

  • path_string (String)

    The object path expressed as a string.

  • current_stack (Array<Binding>)

    The current state of the binding stack.



19
20
21
22
# File 'lib/pry/object_path.rb', line 19

def initialize(path_string, current_stack)
  @path_string   = path_string
  @current_stack = current_stack
end

Instance Method Details

#complete?(segment) ⇒ Boolean (private)

Returns:

  • (Boolean)


66
67
68
# File 'lib/pry/object_path.rb', line 66

def complete?(segment)
  SPECIAL_TERMS.include?(segment) || Pry::Code.complete_expression?(segment)
end

#handle_failure(context, err) ⇒ Object (private)



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/pry/object_path.rb', line 70

def handle_failure(context, err)
  msg = [
    "Bad object path: #{@path_string.inspect}",
    "Failed trying to resolve: #{context.inspect}",
    "Exception: #{err.inspect}"
  ].join("\n")

  raise CommandError.new(msg).tap { |e|
    e.set_backtrace err.backtrace
  }
end

#resolveArray<Binding>

Returns a new stack resulting from applying the given path to the current stack.

Returns:

  • (Array<Binding>)

    a new stack resulting from applying the given path to the current stack.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/pry/object_path.rb', line 26

def resolve
  scanner = StringScanner.new(@path_string.strip)
  stack   = @current_stack.dup

  begin
    next_segment  = ""

    loop do
      # Scan for as long as we don't see a slash
      next_segment << scanner.scan(/[^\/]*/)

      if complete?(next_segment) || scanner.eos?
        scanner.getch # consume the slash
        break
      else
        next_segment << scanner.getch # append the slash
      end
    end

    case next_segment.chomp
    when ""
      stack = [stack.first]
    when "::"
      stack.push(TOPLEVEL_BINDING)
    when "."
      next
    when ".."
      stack.pop unless stack.size == 1
    else
      stack.push(Pry.binding_for(stack.last.eval(next_segment)))
    end
  rescue RescuableException => e
    return handle_failure(next_segment, e)
  end until scanner.eos?

  stack
end