From 456f251675305e97e6238f866249289d12e5ca66 Mon Sep 17 00:00:00 2001 From: Kyrylo Silin Date: Sun, 28 Oct 2018 16:12:39 +0800 Subject: [PATCH] prompt: refactor to reduce duplication Since we always need to define two procs that look almost the same, duplication was unavoidable. With help of method wrappers around procs we can reduce it. As a bonus, the class has some YARD annotations now. --- lib/pry/prompt.rb | 124 ++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 59 deletions(-) diff --git a/lib/pry/prompt.rb b/lib/pry/prompt.rb index 63941bd5..5ec3656f 100644 --- a/lib/pry/prompt.rb +++ b/lib/pry/prompt.rb @@ -1,37 +1,75 @@ class Pry - class Prompt + # Prompt represents the Pry prompt and holds necessary procs and constants to + # be used with Readline-like libraries. + # + # @since v0.11.0 + # @api private + module Prompt + # @return [String] DEFAULT_NAME = 'pry'.freeze + # @return [Array] the list of objects that are known to have a + # 1-line #inspect output suitable for prompt SAFE_CONTEXTS = [String, Numeric, Symbol, nil, true, false].freeze # @return [String] DEFAULT_TEMPLATE = "[%s] %s(%s)%s%s ".freeze + # @return [String] + SHELL_TEMPLATE = "%s %s:%s %s ".freeze + + # @return [String] + NAV_TEMPLATE = "[%s] (%s) %s: %s> ".freeze + + class << self + private + + # @return [Proc] the default prompt + def default(separator) + proc do |context, nesting, _pry_| + format( + DEFAULT_TEMPLATE, + in_count: _pry_.input_ring.count, + name: _pry_.config.prompt_name, + context: Pry.view_clip(context), + nesting: (nesting > 0 ? ":#{nesting}" : ''), + separator: separator + ) + end + end + + # @return [Proc] the shell prompt + def shell(separator) + proc do |context, _nesting, _pry_| + format( + SHELL_TEMPLATE, + name: _pry_.config.prompt_name, + context: Pry.view_clip(context), + pwd: Dir.pwd, + separator: separator + ) + end + end + + # @return [Proc] the nav prompt + def nav + proc do |_context, _nesting, _pry_| + tree = _pry_.binding_stack.map { |b| Pry.view_clip(b.eval('self')) } + format( + NAV_TEMPLATE, + in_count: _pry_.input_ring.count, + name: _pry_.config.prompt_name, + tree: tree.join(' / '), + stack_size: _pry_.binding_stack.size - 1 + ) + end + end + end + # The default Pry prompt, which includes the context and nesting level. # @return [Array] - DEFAULT = [ - proc { |context, nesting, _pry_| - format( - DEFAULT_TEMPLATE, - in_count: _pry_.input_ring.count, - name: _pry_.config.prompt_name, - context: Pry.view_clip(context), - nesting: (nesting > 0 ? ":#{nesting}" : ''), - separator: '>' - ) - }, - proc { |context, nesting, _pry_| - format( - DEFAULT_TEMPLATE, - in_count: _pry_.input_ring.count, - name: _pry_.config.prompt_name, - context: Pry.view_clip(context), - nesting: (nesting > 0 ? ":#{nesting}" : ''), - separator: '*' - ) - } - ].freeze + DEFAULT = [default('>'), default('*')].freeze # Simple prompt doesn't display target or nesting level. # @return [Array] @@ -40,46 +78,14 @@ class Pry # @return [Array] NO_PROMPT = Array.new(2) { proc { '' } }.freeze - SHELL_TEMPLATE = "%s %s:%s %s ".freeze - - SHELL = [ - proc do |context, _nesting, _pry_| - format( - SHELL_TEMPLATE, - name: _pry_.config.prompt_name, - context: Pry.view_clip(context), - pwd: Dir.pwd, - separator: '$' - ) - end, - proc do |context, _nesting, _pry_| - format( - SHELL_TEMPLATE, - name: _pry_.config.prompt_name, - context: Pry.view_clip(context), - pwd: Dir.pwd, - separator: '*' - ) - end - ].freeze - - NAV_TEMPLATE = "[%s] (%s) %s: %s> ".freeze + # @return [Array] + SHELL = [shell('$'), shell('*')].freeze # A prompt that includes the full object path as well as # input/output (_in_ and _out_) information. Good for navigation. - NAV = Array.new(2) do - proc do |_context, _nesting, _pry_| - tree = _pry_.binding_stack.map { |b| Pry.view_clip(b.eval('self')) } - format( - NAV_TEMPLATE, - in_count: _pry_.input_ring.count, - name: _pry_.config.prompt_name, - tree: tree.join(' / '), - stack_size: _pry_.binding_stack.size - 1 - ) - end - end.freeze + NAV = Array.new(2) { nav }.freeze + # @return [Hash{String=>Hash}] MAP = { "default" => { value: DEFAULT,