pry-remote-em 1.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'uri'
4
+ require 'readline'
5
+ require 'highline'
6
+ require 'pry-remote-em/client'
7
+ require 'optparse'
8
+
9
+ options = {}
10
+ OptionParser.new do |opts|
11
+ opts.on('-c', '--connect NAME', 'connect to the first pry remote em server matching NAME') do |name|
12
+ options[:connect] = name
13
+ end
14
+ opts.on('-p', '--proxy NAME', 'proxy through the broker to the first pry remote em server matching NAME') do |name|
15
+ options[:proxy] = name
16
+ end
17
+ opts.on('-P', '--proxy-by-default', 'show servers table with proxy mode enabled by default (ignored on -c or -p)') do |name|
18
+ options[:proxy_by_default] = true
19
+ end
20
+
21
+ opts.on('--fh HOST', '--filter-host HOST', 'only show servers listening at the given address (regexp)') do |host|
22
+ if host =~ /^pryems?:\/\//
23
+ ARGV.push(host)
24
+ else
25
+ options[:filter_host] = Regexp.new(host)
26
+ end
27
+ end
28
+ opts.on('--fn NAME', '--filter-name NAME', 'only show servers with a matching name (regexp)') do |name|
29
+ if name =~ /^pryems?:\/\//
30
+ ARGV.push(name)
31
+ else
32
+ options[:filter_name] = Regexp.new(name)
33
+ end
34
+ end
35
+ opts.on('--[no-]fs', '--[no-]filter-ssl', 'show only servers that support ssl') do |ssl|
36
+ options[:filter_ssl] = ssl
37
+ end
38
+
39
+ opts.on('--sh', '--sort-host', 'sort by host') { options[:sort] = :host }
40
+ opts.on('--sn', '--sort-name', 'sort by server name') { |name| options[:sort] = :name }
41
+ opts.on('--sp', '--sort-port', 'sort by port') { options[:sort] = :port }
42
+ opts.on('--ss', '--sort-ssl', 'sort by ssl support') { options[:sort] = :ssl }
43
+
44
+ opts.on('-d', '--details KEY', "show value from server's details option by given key instead of url in table, use @ to show all details") do |key|
45
+ options[:show_details] = key
46
+ end
47
+
48
+ opts.on('-m', '--metrics KEY', "show value from server's metrics by given key in a third column, use @ to show all metrics, default - errors (if any)") do |key|
49
+ options[:show_metrics] = key
50
+ end
51
+
52
+ opts.on('-i', '--ignore-localhost', 'filter out localhost urls from list') do
53
+ options[:ignore_localhost] = true
54
+ end
55
+
56
+ opts.parse!(ARGV)
57
+ end
58
+
59
+ uri = if ARGV[0].nil? || ARGV[0].empty?
60
+ host = ENV['PRYEMBROKER'].nil? || ENV['PRYEMBROKER'].empty? ? PryRemoteEm::DEFAULT_BROKER_HOST : ENV['PRYEMBROKER']
61
+ port = ENV['PRYEMBROKERPORT'].nil? || ENV['PRYEMBROKERPORT'].empty? ? PryRemoteEm::DEFAULT_BROKER_PORT : ENV['PRYEMBROKERPORT']
62
+ "pryem://#{host}:#{port}"
63
+ else
64
+ ARGV[0]
65
+ end
66
+ uri = URI.parse(uri)
67
+ unless %w(pryem pryems).include?(uri.scheme)
68
+ abort "only pryem URIs are currently supported\n usage: pryem[s]://#{PryRemoteEm::DEFAULT_BROKER_HOST}:#{PryRemoteEm::DEFAULT_BROKER_PORT}"
69
+ end
70
+ uri.port = PryRemoteEm::DEFAULT_BROKER_PORT unless uri.port
71
+
72
+ tried = 0
73
+ auth_proc = proc do
74
+ tried += 1
75
+ user = uri.user || ($stdin.tty? ? Readline.readline('user: ') : raise('username is require for authentication'))
76
+ pass = if !uri.password.nil? && tried <= 1
77
+ uri.password
78
+ elsif $stdin.tty?
79
+ HighLine.new.ask("#{user}'s password: ") { |q| q.echo = '*' }
80
+ else
81
+ raise 'password is required to authenticate'
82
+ end
83
+ [user, pass]
84
+ end
85
+
86
+ EM.run do
87
+ client_options = options.merge(auth: auth_proc, tls: uri.scheme == 'pryems')
88
+ PryRemoteEm::Client.start(uri.host, uri.port, client_options) { EM.stop }
89
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pry-remote-em/broker'
4
+ require 'optparse'
5
+
6
+ options = { tls: false }
7
+ OptionParser.new do |opts|
8
+ opts.on('-h', '--host HOST', 'host to bind broker server (same as PRYEMBROKER variable, default: "127.0.0.1")') do |host|
9
+ options[:host] = host
10
+ end
11
+
12
+ opts.on('-p', '--port PORT', 'port to bind broker server (same as PRYEMBROKERPORT variable, default: 6462)') do |port|
13
+ options[:port] = port
14
+ end
15
+
16
+ opts.on('-s', '--tls', 'use TLS for broker (default: false)') do
17
+ options[:tls] = true
18
+ end
19
+
20
+ opts.parse!(ARGV)
21
+ end
22
+
23
+
24
+ EM.run do
25
+ trap(:INT) { EM.stop }
26
+
27
+ PryRemoteEm::Broker.run options[:host], options[:port], tls: options[:tls], raise_if_port_in_use: true
28
+ end
@@ -0,0 +1,74 @@
1
+ begin
2
+ require 'openssl'
3
+ rescue LoadError
4
+ warn 'OpenSSL support is not available'
5
+ end
6
+ require 'socket'
7
+ require 'fiber'
8
+ require 'uri'
9
+ require 'eventmachine'
10
+ require 'pry-remote-em/version'
11
+ require 'pry-remote-em/proto'
12
+ require 'pry-remote-em/server'
13
+
14
+ module PryRemoteEm
15
+ DEFAULT_SERVER_HOST = '127.0.0.1'
16
+ DEFAULT_SERVER_PORT = 6463
17
+ DEFAULT_BROKER_HOST = '127.0.0.1'
18
+ DEFAULT_BROKER_PORT = 6462
19
+
20
+ NEGOTIATION_TIMEOUT = 15
21
+ HEARTBEAT_SEND_INTERVAL = 15
22
+ HEARTBEAT_CHECK_INTERVAL = 20
23
+ RECONNECT_TO_BROKER_TIMEOUT = 3
24
+
25
+ MAXIMUM_ERRORS_IN_SANDBOX = 100
26
+ end
27
+
28
+
29
+ class Object
30
+ def remote_pry_em(host = nil, port = nil, options = {}, &block)
31
+ host, options = nil, host if host.kind_of?(Hash) # Support for options hash as first argument instead of third
32
+
33
+ options = { target: self, host: host, port: port }.merge(options)
34
+ PryRemoteEm::Server.run(options, &block)
35
+ end
36
+
37
+ alias pry_remote_em remote_pry_em # source of common confusing
38
+ end
39
+
40
+
41
+ unless defined?(EventMachine.popen3)
42
+ module EventMachine
43
+ # @see http://eventmachine.rubyforge.org/EventMachine.html#M000491
44
+ # @see https://gist.github.com/535644/4d5b645b96764e07ccb53539529bea9270741e1a
45
+ def self.popen3(cmd, handler=nil, *args)
46
+ klass = klass_from_handler(Connection, handler, *args)
47
+ w = Shellwords::shellwords(cmd)
48
+ w.unshift(w.first) if w.first
49
+
50
+ new_stderr = $stderr.dup
51
+ rd, wr = IO::pipe
52
+
53
+ $stderr.reopen wr
54
+ s = invoke_popen(w)
55
+ $stderr.reopen new_stderr
56
+
57
+ klass.new(s, *args).tap do |c|
58
+ EM.attach(rd, Popen3StderrHandler, c)
59
+ @conns[s] = c
60
+ yield(c) if block_given?
61
+ end
62
+ end
63
+
64
+ class Popen3StderrHandler < EventMachine::Connection
65
+ def initialize(connection)
66
+ @connection = connection
67
+ end
68
+
69
+ def receive_data(data)
70
+ @connection.receive_stderr(data)
71
+ end
72
+ end # class::Popen3StderrHandler
73
+ end # module::EventMachine
74
+ end # defined?(EventMachine.popen3)
@@ -0,0 +1,229 @@
1
+ require 'logger'
2
+ require 'socket'
3
+ require 'pry-remote-em'
4
+ require 'pry-remote-em/client/broker'
5
+ require 'pry-remote-em/client/proxy'
6
+
7
+ module PryRemoteEm
8
+ module Broker
9
+ class << self
10
+ attr_reader :listening, :host, :port
11
+ alias :listening? :listening
12
+
13
+ def run(host = nil, port = nil, opts = {})
14
+ host ||= ENV['PRYEMBROKER'].nil? || ENV['PRYEMBROKER'].empty? ? DEFAULT_BROKER_HOST : ENV['PRYEMBROKER']
15
+ port ||= ENV['PRYEMBROKERPORT'].nil? || ENV['PRYEMBROKERPORT'].empty? ? DEFAULT_BROKER_PORT : ENV['PRYEMBROKERPORT']
16
+ port = port.to_i if port.kind_of?(String)
17
+ raise "root permission required for port below 1024 (#{port})" if port < 1024 && Process.euid != 0
18
+ @host = host
19
+ @port = port
20
+ opts = opts.dup
21
+ # Brokers cannot use SSL directly. If they do then when a proxy request to an SSL server is received
22
+ # the client and server will not be able to negotiate a SSL session. The proxied traffic can be SSL
23
+ # encrypted, but the SSL session will be between the client and the server.
24
+ opts[:tls] = false
25
+ @opts = opts
26
+ start_server(host, port, opts) unless @listening || ENV['PRYEMREMOTEBROKER'] || @opts[:remote_broker]
27
+ client { |c| yield self } if block_given?
28
+ end
29
+
30
+ def restart
31
+ log.info("[pry-remote-em broker] restarting on pryem://#{host}:#{port}")
32
+ @waiting = nil
33
+ @client = nil
34
+ run(@host, @port, @opts) do
35
+ PryRemoteEm.servers.each do |id, description|
36
+ next unless EM.get_sockname(description[:server])
37
+ register(
38
+ id: description[:id],
39
+ urls: description[:urls],
40
+ name: description[:name],
41
+ details: description[:details],
42
+ metrics: PryRemoteEm::Metrics.list
43
+ )
44
+ end
45
+ end
46
+ end
47
+
48
+ def opts
49
+ @opts ||= {}
50
+ end
51
+
52
+ def log
53
+ return opts[:logger] if opts[:logger]
54
+ @log ||= Logger.new(STDERR)
55
+ end
56
+
57
+ def servers
58
+ @servers ||= {}
59
+ end
60
+
61
+ def register(description)
62
+ client { |c| c.send_register_server(description[:id], description[:urls], description[:name], description[:details], description[:metrics]) }
63
+ end
64
+
65
+ def unregister(id)
66
+ client { |c| c.send_unregister_server(id) }
67
+ end
68
+
69
+ def register_server(id, description)
70
+ servers[id] = description
71
+ watch_heartbeats(id)
72
+ log.info("[pry-remote-em broker] registered #{id} #{description.inspect}")
73
+ end
74
+
75
+ def update_server(server, description)
76
+ server.update(urls: description[:urls], name: description[:name])
77
+ server[:details].update(description[:details])
78
+ server[:metrics].update(description[:metrics])
79
+ end
80
+
81
+ def unregister_server(id)
82
+ server = servers.delete(id) or return
83
+ log.warn("[pry-remote-em broker] unregister #{id} #{server.inspect}")
84
+ timer = timers.delete(id)
85
+ timer.cancel if timer
86
+ hbeats.delete(id)
87
+ end
88
+
89
+ def watch_heartbeats(id)
90
+ interval = ENV['PRYEMHBCHECK'].nil? || ENV['PRYEMHBCHECK'].empty? ? HEARTBEAT_CHECK_INTERVAL : ENV['PRYEMHBCHECK']
91
+ timers[id] ||= EM::PeriodicTimer.new(interval) do
92
+ if !hbeats[id] || (Time.new - hbeats[id]) > 20
93
+ unregister_server(id)
94
+ end
95
+ end
96
+ end
97
+
98
+ def timers
99
+ @timers ||= {}
100
+ end
101
+
102
+ def hbeats
103
+ @hbeats ||= {}
104
+ end
105
+
106
+ def connected?
107
+ @connected
108
+ end
109
+
110
+ private
111
+
112
+ def start_server(host, port, opts)
113
+ EM.start_server(host, port, PryRemoteEm::Broker, opts)
114
+ log.info("[pry-remote-em broker] listening on #{opts[:tls] ? 'pryems' : 'pryem'}://#{host}:#{port}")
115
+ @listening = true
116
+ rescue => error
117
+ if error.message.include?('port is in use')
118
+ if opts[:raise_if_port_in_use]
119
+ raise
120
+ else
121
+ # A broker is already listening on this port, we can do nothing
122
+ end
123
+ else
124
+ raise
125
+ end
126
+ end
127
+
128
+ def client(&blk)
129
+ raise ArgumentError.new('A block is required') unless block_given?
130
+ if @client
131
+ yield @client
132
+ return
133
+ end
134
+
135
+ if @waiting
136
+ @waiting << blk
137
+ else
138
+ @waiting = [blk]
139
+ EM.connect(host, port, Client::Broker, @opts) do |client|
140
+ client.errback { |e| raise(e || 'broker client error') }
141
+ client.callback do
142
+ @client = client
143
+ while (w = @waiting.shift)
144
+ w.call(client)
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end # class << self
151
+
152
+ include Proto
153
+
154
+ def receive_server_reload_list
155
+ send_server_list(Broker.servers)
156
+ end
157
+
158
+ def receive_register_server(id, urls, name, details, metrics)
159
+ @ids.push(id)
160
+ description = { urls: urls, name: name, details: details, metrics: metrics }
161
+ Broker.hbeats[id] = Time.new
162
+ server = Broker.servers[id]
163
+ if server
164
+ Broker.update_server(server, description)
165
+ else
166
+ Broker.register_server(id, description)
167
+ end
168
+ end
169
+
170
+ def receive_unregister_server(id)
171
+ server = Broker.servers[id]
172
+ Broker.unregister_server(id) if server
173
+ end
174
+
175
+ def receive_proxy_connection(url)
176
+ log.info("[pry-remote-em broker] proxying to #{url}")
177
+ url = URI.parse(url)
178
+ EM.connect(url.host, url.port, Client::Proxy, self)
179
+ end
180
+
181
+ def initialize(opts = {}, &blk)
182
+ @opts = opts
183
+ @ids = []
184
+ end
185
+
186
+ def log
187
+ Broker.log
188
+ end
189
+
190
+ def post_init
191
+ port, ip = Socket.unpack_sockaddr_in(get_peername)
192
+ log.info("[pry-remote-em broker] received client connection from #{ip}:#{port}")
193
+ send_banner("PryRemoteEm #{VERSION} #{@opts[:tls] ? 'pryems' : 'pryem'}")
194
+ @opts[:tls] ? start_tls : send_server_list(Broker.servers)
195
+ end
196
+
197
+ def start_tls
198
+ log.debug("[pry-remote-em broker] starting TLS (#{peer_ip}:#{peer_port})")
199
+ send_start_tls
200
+ super(@opts[:tls].is_a?(Hash) ? @opts[:tls] : {})
201
+ end
202
+
203
+ def peer_ip
204
+ return @peer_ip if @peer_ip
205
+ return '' if get_peername.nil?
206
+ @peer_port, @peer_ip = Socket.unpack_sockaddr_in(get_peername)
207
+ @peer_ip = '127.0.0.1' if @peer_ip == '::1' # Little hack to avoid segmentation fault in EventMachine 1.2.0.1 while connecting to PryRemoteEm Server from localhost with IPv6 address
208
+ @peer_ip
209
+ end
210
+
211
+ def peer_port
212
+ return @peer_port if @peer_port
213
+ return '' if get_peername.nil?
214
+ peer_ip # Fills peer_port too
215
+ @peer_port
216
+ end
217
+
218
+ def ssl_handshake_completed
219
+ log.info("[pry-remote-em broker] TLS connection established (#{peer_ip}:#{peer_port})")
220
+ send_server_list(Broker.servers)
221
+ end
222
+
223
+ def unbind
224
+ @ids.each do |id|
225
+ Broker.unregister_server(id)
226
+ end
227
+ end
228
+ end # module::Broker
229
+ end # module::PryRemoteEm
@@ -0,0 +1,233 @@
1
+ require 'uri'
2
+ require 'pry-remote-em'
3
+ require 'pry-remote-em/client/keyboard'
4
+ require 'pry-remote-em/client/generic'
5
+ require 'pry-remote-em/client/interactive_menu'
6
+ require 'pry'
7
+ #require 'pry-coolline' rescue require 'readline'
8
+
9
+ module PryRemoteEm
10
+ module Client
11
+ include EM::Deferrable
12
+ include Generic
13
+ include InteractiveMenu
14
+ include Pry::Helpers::BaseHelpers
15
+
16
+ class << self
17
+ def start(host = nil, port = nil, opts = {})
18
+ EM.connect(host || PryRemoteEm::DEFAULT_SERVER_HOST, port || PryRemoteEm::DEFAULT_SERVER_PORT, PryRemoteEm::Client, opts) do |c|
19
+ c.callback { yield if block_given? }
20
+ c.errback do |e|
21
+ Kernel.puts "[pry-remote-em] connection failed\n#{e}"
22
+ yield(e) if block_given?
23
+ end
24
+ end
25
+ end
26
+ end # class << self
27
+
28
+ attr_reader :opts
29
+
30
+ def initialize(opts = {})
31
+ @opts = opts
32
+ if (a = opts[:auth])
33
+ if a.respond_to?(:call)
34
+ @auth = a
35
+ else
36
+ @auth = lambda { a }
37
+ end
38
+ end
39
+ end
40
+
41
+ def post_init
42
+ @input = if defined?(PryCoolline)
43
+ PryCoolline.make_coolline
44
+ else
45
+ Pry.history.load if Pry.config.history.should_load
46
+ Readline
47
+ end
48
+ @input.completion_proc = method(:auto_complete)
49
+ end
50
+
51
+ def ssl_handshake_completed
52
+ log.info('[pry-remote-em] TLS connection established')
53
+ @opts[:tls] = true
54
+ end
55
+
56
+ def unbind
57
+ if (uri = @reconnect_to)
58
+ @reconnect_to = nil
59
+ tls = uri.scheme == 'pryems'
60
+ log.info("\033[35m[pry-remote-em] connection will not be encrypted\033[0m") if @opts[:tls] && !tls
61
+ @opts[:tls] = tls
62
+ @tls_started = false
63
+ reconnect(uri.host, uri.port)
64
+ else
65
+ @unbound = true
66
+ log.info('[pry-remote-em] session terminated')
67
+ error? ? fail : succeed
68
+ end
69
+ end
70
+
71
+ def receive_banner(name, version, scheme)
72
+ # Client::Generic#receive_banner
73
+ if super(name, version, scheme)
74
+ start_tls if @opts[:tls]
75
+ end
76
+ end
77
+
78
+ def receive_server_list(list)
79
+ if list.empty?
80
+ log.info("\033[33m[pry-remote-em] no servers are registered with the broker\033[0m")
81
+ Process.exit
82
+ end
83
+ url, proxy = choose_server(list)
84
+ return unless url
85
+ uri = URI.parse(url)
86
+ if proxy
87
+ @opts[:tls] = uri.scheme == 'pryems'
88
+ @negotiated = false
89
+ @tls_started = false
90
+ return send_proxy_connection(url)
91
+ end
92
+ @reconnect_to = uri
93
+ close_connection
94
+ end
95
+
96
+ def receive_auth(a)
97
+ return fail a if a.is_a?(String)
98
+ return authenticate if a == false
99
+ @authenticated = true if a == true
100
+ end
101
+
102
+ def receive_msg(m)
103
+ Kernel.puts "\033[1m! msg: " + m + "\033[0m"
104
+ end
105
+
106
+ def receive_msg_bcast(mb)
107
+ Kernel.puts "\033[1m!! msg: " + mb + "\033[0m"
108
+ end
109
+
110
+ def receive_shell_cmd(c)
111
+ Kernel.puts c
112
+ end
113
+
114
+ def receive_shell_result(c)
115
+ if @keyboard
116
+ @keyboard.bufferio(true)
117
+ @keyboard.close_connection
118
+ end
119
+ if c == 255 || c == 127
120
+ Kernel.puts 'command not found'
121
+ end
122
+ end
123
+
124
+ # TODO detect if the old pager behavior of Pry is supported and use it
125
+ # through Pry.pager. If it's not then use the SimplePager.
126
+ def pager
127
+ pager_class = ENV['PRYEMNOPAGER'] ? Pry::Pager::NullPager : @opts[:pager] || Pry::Pager::SimplePager
128
+ @pager ||= pager_class.new(Pry::Output.new(Pry))
129
+ end
130
+
131
+ def receive_raw(r)
132
+ pager.write(r)
133
+ rescue Pry::Pager::StopPaging
134
+ warn '[pry-remote-em] stop paging is not implemented, use PRYEMNOPAGER environment variable to avoid paging at all'
135
+ end
136
+
137
+ def receive_unknown(j)
138
+ warn "[pry-remote-em] received unexpected data: #{j.inspect}"
139
+ end
140
+
141
+ def authenticate
142
+ return fail('[pry-remote-em] authentication required') unless @auth
143
+ return fail("[pry-remote-em] can't authenticate before negotiation complete") unless @negotiated
144
+ user, pass = @auth.call
145
+ return fail("[pry-remote-em] expected #{@auth} to return a user and password") unless user && pass
146
+ send_auth([user, pass])
147
+ end # authenticate
148
+
149
+ def auto_complete(word)
150
+ word = word.completed_word if defined?(Coolline) && word.kind_of?(Coolline)
151
+
152
+ @waiting = Thread.current
153
+ EM.next_tick { send_completion(word) }
154
+ sleep
155
+ c = Thread.current[:completion]
156
+ Thread.current[:completion] = nil
157
+ c
158
+ end
159
+
160
+ def receive_completion(c)
161
+ return unless @waiting
162
+ @waiting[:completion] = c
163
+ @waiting, t = nil, @waiting
164
+ t.run
165
+ end
166
+
167
+ def receive_prompt(p)
168
+ readline(p)
169
+ end
170
+
171
+ def readline(prompt = @last_prompt)
172
+ @last_prompt = prompt
173
+ if @negotiated && !@unbound
174
+ operation = proc do
175
+ thread = Thread.current
176
+ old_trap = Signal.trap(:INT) { thread.raise Interrupt }
177
+ begin
178
+ @input.readline(prompt)
179
+ rescue Interrupt
180
+ send_clear_buffer
181
+ puts
182
+ :ignore_me
183
+ ensure
184
+ Signal.trap(:INT, old_trap)
185
+ end
186
+ end
187
+
188
+ callback = proc do |l|
189
+ next if l == :ignore_me
190
+
191
+ add_to_history(l) unless l.nil? || l.empty?
192
+
193
+ if l.nil?
194
+ readline
195
+ elsif '^^' == l[0..1]
196
+ send_msg_bcast(l[2..-1])
197
+ elsif '^' == l[0]
198
+ send_msg(l[1..-1])
199
+ elsif '.' == l[0]
200
+ send_shell_cmd(l[1..-1])
201
+ @keyboard = EM.open_keyboard(Keyboard, self)
202
+ elsif 'reset' == l.strip
203
+ # TODO work with 'bundle exec pry-remote-em ...'
204
+ # TODO work with 'ruby -I lib bin/pry-remote-em ...'
205
+ Kernel.puts "\033[1m#{$0} #{ARGV.join(' ')}\033[0m"
206
+ exec("#{$0} #{ARGV.join(' ')}")
207
+ else
208
+ send_raw(l)
209
+ end
210
+ end
211
+
212
+ EM.defer(operation, callback)
213
+ end
214
+ end # readline(prompt = @last_prompt)
215
+
216
+ def add_to_history(line)
217
+ if defined?(Readline) && @input == Readline
218
+ Readline::HISTORY.push(line)
219
+ end
220
+ # Nothing to do with Coolline, it just works
221
+ end
222
+ end # module::Client
223
+ end # module::PryRemoteEm
224
+
225
+ # TODO detect if the old pager behavior of Pry is supported and use it. If it's not
226
+ # then don't bother adding a pager accessor
227
+ # Pry::Helpers::BaseHelpers#stagger_output expects Pry.pager to be defined
228
+ class Pry
229
+ class << self
230
+ attr_accessor :pager unless respond_to?(:pager)
231
+ end
232
+ end
233
+ Pry.pager = true