Permalink
Browse files

refactor cat command

Put each output formatter (input expression, exception, file) into its own class.
  • Loading branch information...
1 parent d77bfe2 commit 92fe82dbd6c6866d8ad107fb031d16c2f307148c @banister banister committed Jan 6, 2013
@@ -1,5 +1,10 @@
class Pry
class Command::Cat < Pry::ClassCommand
+ require 'pry/commands/cat/abstract_formatter.rb'
+ require 'pry/commands/cat/input_expression_formatter.rb'
+ require 'pry/commands/cat/exception_formatter.rb'
+ require 'pry/commands/cat/file_formatter.rb'
+
match 'cat'
group 'Input and Output'
description "Show code from a file, Pry's input buffer, or the last " \
@@ -21,160 +26,28 @@ class Command::Cat < Pry::ClassCommand
def options(opt)
opt.on :ex, "Show the context of the last exception.", :optional_argument => true, :as => Integer
opt.on :i, :in, "Show one or more entries from Pry's expression history.", :optional_argument => true, :as => Range, :default => -5..-1
-
opt.on :s, :start, "Starting line (defaults to the first line).", :optional_argument => true, :as => Integer
opt.on :e, :end, "Ending line (defaults to the last line).", :optional_argument => true, :as => Integer
opt.on :l, :'line-numbers', "Show line numbers."
opt.on :t, :type, "The file type for syntax highlighting (e.g., 'ruby' or 'python').", :argument => true, :as => Symbol
-
- opt.on :f, :flood, "Do not use a pager to view text longer than one screen."
end
def process
- handler = case
- when opts.present?(:ex)
- method :process_ex
- when opts.present?(:in)
- method :process_in
- else
- method :process_file
- end
-
- output = handler.call do |code|
- code.code_type = opts[:type] || :ruby
-
- code.between(opts[:start] || 1, opts[:end] || -1).
- with_line_numbers(opts.present?(:'line-numbers') || opts.present?(:ex))
- end
-
- render_output(output, opts)
- end
-
- def process_ex
- window_size = Pry.config.default_window_size || 5
- ex = _pry_.last_exception
-
- raise CommandError, "No exception found." unless ex
-
- if opts[:ex].nil?
- bt_index = ex.bt_index
- ex.inc_bt_index
- else
- bt_index = absolute_index_number(opts[:ex], ex.backtrace.size)
- ex.bt_index = bt_index
- ex.inc_bt_index
- end
-
- ex_file, ex_line = ex.bt_source_location_for(bt_index)
-
- raise CommandError, "The given backtrace level is out of bounds." unless ex_file
-
- if RbxPath.is_core_path?(ex_file)
- ex_file = RbxPath.convert_path_to_full(ex_file)
- end
-
- set_file_and_dir_locals(ex_file)
-
- start_line = ex_line - window_size
- start_line = 1 if start_line < 1
- end_line = ex_line + window_size
-
- header = unindent <<-HEADER
- #{text.bold 'Exception:'} #{ex.class}: #{ex.message}
- --
- #{text.bold('From:')} #{ex_file} @ line #{ex_line} @ #{text.bold("level: #{bt_index}")} of backtrace (of #{ex.backtrace.size - 1}).
-
- HEADER
-
- code = yield(Pry::Code.from_file(ex_file).
- between(start_line, end_line).
- with_marker(ex_line))
-
- "#{header}#{code}"
- end
-
- def process_in
- normalized_range = absolute_index_range(opts[:i], _pry_.input_array.length)
- input_items = _pry_.input_array[normalized_range] || []
-
- zipped_items = normalized_range.zip(input_items).reject { |_, s| s.nil? || s == "" }
-
- unless zipped_items.length > 0
- raise CommandError, "No expressions found."
- end
-
- if zipped_items.length > 1
- contents = ""
- zipped_items.each do |i, s|
- contents << "#{text.bold(i.to_s)}:\n"
- contents << yield(Pry::Code(s).with_indentation(2)).to_s
- end
- else
- contents = yield(Pry::Code(zipped_items.first.last))
- end
-
- contents
- end
-
- def process_file
- file_name = args.shift
-
- unless file_name
- raise CommandError, "Must provide a filename, --in, or --ex."
- end
-
- file_name, line_num = file_name.split(':')
- file_name = File.expand_path(file_name)
- set_file_and_dir_locals(file_name)
-
- code = yield(Pry::Code.from_file(file_name))
-
- code.code_type = opts[:type] || detect_code_type_from_file(file_name)
- if line_num
- code = code.around(line_num.to_i,
- Pry.config.default_window_size || 7)
- end
-
- code
+ output = case
+ when opts.present?(:ex)
+ ExceptionFormatter.new(_pry_.last_exception, _pry_, opts).format
+ when opts.present?(:in)
+ InputExpressionFormatter.new(_pry_.input_array, opts).format
+ else
+ FileFormatter.new(args.first, _pry_, opts).format
+ end
+
+ stagger_output(output)
end
def complete(search)
super + Bond::Rc.files(search.split(" ").last || '')
end
-
- def detect_code_type_from_file(file_name)
- name, ext = File.basename(file_name).split('.', 2)
-
- if ext
- case ext
- when "py"
- :python
- when "rb", "gemspec", "rakefile", "ru", "pryrc", "irbrc"
- :ruby
- when "js"
- return :javascript
- when "yml", "prytheme"
- :yaml
- when "groovy"
- :groovy
- when "c"
- :c
- when "cpp"
- :cpp
- when "java"
- :java
- else
- :text
- end
- else
- case name
- when "Rakefile", "Gemfile"
- :ruby
- else
- :text
- end
- end
- end
end
Pry::Commands.add_command(Pry::Command::Cat)
@@ -0,0 +1,27 @@
+class Pry
+ class Command::Cat
+ class AbstractFormatter
+ include Pry::Helpers::CommandHelpers
+ include Pry::Helpers::BaseHelpers
+
+ private
+ def decorate(content)
+ content.code_type = code_type
+ content.between(*between_lines).
+ with_line_numbers(use_line_numbers?)
+ end
+
+ def code_type
+ opts[:type] || :ruby
+ end
+
+ def use_line_numbers?
+ opts.present?(:'line-numbers') || opts.present?(:ex)
+ end
+
+ def between_lines
+ [opts[:start] || 1, opts[:end] || -1]
+ end
+ end
+ end
+end
@@ -0,0 +1,78 @@
+class Pry
+ class Command::Cat
+ class ExceptionFormatter < AbstractFormatter
+ attr_accessor :ex
+ attr_accessor :opts
+ attr_accessor :_pry_
+
+ def initialize(exception, _pry_, opts)
+ @ex = exception
+ @opts = opts
+ @_pry_ = _pry_
+ end
+
+ def format
+ check_for_errors
+ set_file_and_dir_locals(backtrace_file, _pry_, _pry_.current_context)
+ code = decorate(Pry::Code.from_file(backtrace_file).
+ between(*start_and_end_line_for_code_window).
+ with_marker(backtrace_line)).to_s
+ "#{header}#{code}"
+ end
+
+ private
+
+ def code_window_size
+ Pry.config.default_window_size || 5
+ end
+
+ def backtrace_level
+ return @backtrace_level if @backtrace_level
+
+ bl = if opts[:ex].nil?
+ ex.bt_index
+ else
+ ex.bt_index = absolute_index_number(opts[:ex], ex.backtrace.size)
+ end
+
+ increment_backtrace_level
+ @backtrace_level = bl
+ end
+
+ def increment_backtrace_level
+ ex.inc_bt_index
+ end
+
+ def backtrace_file
+ file = Array(ex.bt_source_location_for(backtrace_level)).first
+ (file && RbxPath.is_core_path?(file)) ? RbxPath.convert_path_to_full(file) : file
+ end
+
+ def backtrace_line
+ Array(ex.bt_source_location_for(backtrace_level)).last
+ end
+
+ def check_for_errors
+ raise CommandError, "No exception found." unless ex
+ raise CommandError, "The given backtrace level is out of bounds." unless backtrace_file
+ end
+
+ def start_and_end_line_for_code_window
+ start_line = backtrace_line - code_window_size
+ start_line = 1 if start_line < 1
+
+ [start_line, backtrace_line + code_window_size]
+ end
+
+ def header
+ unindent %{
+ #{Helpers::Text.bold 'Exception:'} #{ex.class}: #{ex.message}
+ --
+ #{Helpers::Text.bold('From:')} #{backtrace_file} @ line #{backtrace_line} @ #{Helpers::Text.bold("level: #{backtrace_level}")} of backtrace (of #{ex.backtrace.size - 1}).
+
+ }
+ end
+
+ end
+ end
+end
@@ -0,0 +1,84 @@
+class Pry
+ class Command::Cat
+ class FileFormatter < AbstractFormatter
+ attr_accessor :file_with_embedded_line
+ attr_accessor :opts
+ attr_accessor :_pry_
+
+ def initialize(file_with_embedded_line, _pry_, opts)
+ @file_with_embedded_line = file_with_embedded_line
+ @opts = opts
+ @_pry_ = _pry_
+ end
+
+ def file_and_line
+ file_name, line_num = file_with_embedded_line.split(':')
+
+ [File.expand_path(file_name), line_num ? line_num.to_i : nil]
+ end
+
+ def file_name
+ file_and_line.first
+ end
+
+ def line_number
+ file_and_line.last
+ end
+
+ def code_window_size
+ Pry.config.default_window_size || 7
+ end
+
+ def format
+ raise CommandError, "Must provide a filename, --in, or --ex." if !file_with_embedded_line
+
+ set_file_and_dir_locals(file_name, _pry_, _pry_.current_context)
+ decorate(Pry::Code.from_file(file_name))
+ end
+
+ private
+
+ def decorate(content)
+ line_number ? super.around(line_number, code_window_size) : super
+ end
+
+ def code_type
+ opts[:type] || detect_code_type_from_file(file_name)
+ end
+
+ def detect_code_type_from_file(file_name)
+ name, ext = File.basename(file_name).split('.', 2)
+
+ if ext
+ case ext
+ when "py"
+ :python
+ when "rb", "gemspec", "rakefile", "ru", "pryrc", "irbrc"
+ :ruby
+ when "js"
+ return :javascript
+ when "yml", "prytheme"
+ :yaml
+ when "groovy"
+ :groovy
+ when "c"
+ :c
+ when "cpp"
+ :cpp
+ when "java"
+ :java
+ else
+ :text
+ end
+ else
+ case name
+ when "Rakefile", "Gemfile"
+ :ruby
+ else
+ :text
+ end
+ end
+ end
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 92fe82d

Please sign in to comment.