File: breakpoints.rb

package info (click to toggle)
ruby-pry-byebug 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 324 kB
  • sloc: ruby: 1,171; makefile: 4
file content (167 lines) | stat: -rw-r--r-- 3,664 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# frozen_string_literal: true

class Pry
  module Byebug
    #
    # Wrapper for Byebug.breakpoints that respects our Processor and has better
    # failure behavior. Acts as an Enumerable.
    #
    module Breakpoints
      extend Enumerable
      extend self

      #
      # Breakpoint in a file:line location
      #
      class FileBreakpoint < SimpleDelegator
        def source_code
          Pry::Code.from_file(source).around(pos, 3).with_marker(pos)
        end

        def to_s
          "#{source} @ #{pos}"
        end
      end

      #
      # Breakpoint in a Class#method location
      #
      class MethodBreakpoint < SimpleDelegator
        def initialize(byebug_bp, method)
          __setobj__ byebug_bp
          @method = method
        end

        def source_code
          Pry::Code.from_method(Pry::Method.from_str(@method))
        end

        def to_s
          @method
        end
      end

      def breakpoints
        @breakpoints ||= []
      end

      #
      # Adds a method breakpoint.
      #
      def add_method(method, expression = nil)
        validate_expression expression
        owner, name = method.split(/[\.#]/)
        byebug_bp = ::Byebug::Breakpoint.add(owner, name.to_sym, expression)
        bp = MethodBreakpoint.new byebug_bp, method
        breakpoints << bp
        bp
      end

      #
      # Adds a file breakpoint.
      #
      def add_file(file, line, expression = nil)
        real_file = (file != Pry.eval_path)
        raise(ArgumentError, "Invalid file!") if real_file && !File.exist?(file)

        validate_expression expression

        path = (real_file ? File.expand_path(file) : file)
        bp = FileBreakpoint.new ::Byebug::Breakpoint.add(path, line, expression)
        breakpoints << bp
        bp
      end

      #
      # Changes the conditional expression for a breakpoint.
      #
      def change(id, expression = nil)
        validate_expression expression

        breakpoint = find_by_id(id)
        breakpoint.expr = expression
        breakpoint
      end

      #
      # Deletes an existing breakpoint with the given ID.
      #
      def delete(id)
        deleted =
          ::Byebug::Breakpoint.remove(id) &&
          breakpoints.delete(find_by_id(id))

        raise(ArgumentError, "No breakpoint ##{id}") unless deleted
      end

      #
      # Deletes all breakpoints.
      #
      def delete_all
        @breakpoints = []
        ::Byebug.breakpoints.clear
      end

      #
      # Enables a disabled breakpoint with the given ID.
      #
      def enable(id)
        change_status id, true
      end

      #
      # Disables a breakpoint with the given ID.
      #
      def disable(id)
        change_status id, false
      end

      #
      # Disables all breakpoints.
      #
      def disable_all
        each do |breakpoint|
          breakpoint.enabled = false
        end
      end

      def to_a
        breakpoints
      end

      def size
        to_a.size
      end

      def each(&block)
        to_a.each(&block)
      end

      def last
        to_a.last
      end

      def find_by_id(id)
        breakpoint = find { |b| b.id == id }
        raise(ArgumentError, "No breakpoint ##{id}!") unless breakpoint

        breakpoint
      end

      private

      def change_status(id, enabled = true)
        breakpoint = find_by_id(id)
        breakpoint.enabled = enabled
        breakpoint
      end

      def validate_expression(exp)
        valid = exp && (exp.empty? || !Pry::Code.complete_expression?(exp))
        return unless valid

        raise("Invalid breakpoint conditional: #{expression}")
      end
    end
  end
end