diff --git a/lib/pry/code.rb b/lib/pry/code.rb index 5655d394..ec72c0eb 100644 --- a/lib/pry/code.rb +++ b/lib/pry/code.rb @@ -1,5 +1,6 @@ require 'pry/code/loc' require 'pry/code/code_range' +require 'pry/code/code_file' class Pry class << self @@ -29,26 +30,6 @@ class Pry # arbitrary chaining of formatting methods without mutating the original # object. class Code - - # List of all supported languages. - # @return [Hash] - EXTENSIONS = { - %w(.py) => :python, - %w(.js) => :javascript, - %w(.css) => :css, - %w(.xml) => :xml, - %w(.php) => :php, - %w(.html) => :html, - %w(.diff) => :diff, - %w(.java) => :java, - %w(.json) => :json, - %w(.c .h) => :c, - %w(.rhtml) => :rhtml, - %w(.yaml .yml) => :yaml, - %w(.cpp .hpp .cc .h cxx) => :cpp, - %w(.rb .ru .irbrc .gemspec .pryrc) => :ruby, - } - class << self include MethodSource::CodeHelpers @@ -58,17 +39,10 @@ class Pry # @param [String] filename The name of a file, or "(pry)". # @param [Symbol] code_type The type of code the file contains. # @return [Code] - def from_file(filename, code_type = type_from_filename(filename)) - code = if filename == Pry.eval_path - Pry.line_buffer.drop(1) - elsif Pry::Method::Patcher.code_for(filename) - Pry::Method::Patcher.code_for(filename) - elsif RbxPath.is_core_path?(filename) - File.read RbxPath.convert_path_to_full(filename) - else - File.read(abs_path(filename)) - end - new(code, 1, code_type) + def from_file(filename, code_type = nil) + code_file = CodeFile.new(filename, code_type) + # binding.pry + new(code_file.code, 1, code_file.code_type) end # Instantiate a `Code` object containing code extracted from a @@ -98,35 +72,6 @@ class Pry start_line ||= candidate.line new(candidate.source, start_line, :ruby) end - - protected - - # Guess the CodeRay type of a file from its extension, or nil if - # unknown. - # - # @param [String] filename - # @param [Symbol] default (:ruby) the file type to assume if none could be - # detected. - # @return [Symbol, nil] - def type_from_filename(filename, default = :ruby) - _, type = Pry::Code::EXTENSIONS.find do |k, _| - k.any? { |ext| ext == File.extname(filename) } - end - - type || default - end - - # @param [String] filename - # @raise [MethodSource::SourceNotFoundError] if the +filename+ is not - # readable for some reason. - # @return [String] absolute path for the given +filename+. - def abs_path(filename) - abs_path = [File.expand_path(filename, Dir.pwd), - File.expand_path(filename, Pry::INITIAL_PWD) - ].detect { |path| File.readable?(path) } - abs_path or raise MethodSource::SourceNotFoundError, - "Cannot open #{filename.inspect} for reading." - end end # @return [Symbol] The type of code stored in this wrapper. diff --git a/lib/pry/code/code_file.rb b/lib/pry/code/code_file.rb new file mode 100644 index 00000000..f40dcd50 --- /dev/null +++ b/lib/pry/code/code_file.rb @@ -0,0 +1,95 @@ +class Pry + class CodeFile + DEFAULT_EXT = '.rb' + + # List of all supported languages. + # @return [Hash] + EXTENSIONS = { + %w(.py) => :python, + %w(.js) => :javascript, + %w(.css) => :css, + %w(.xml) => :xml, + %w(.php) => :php, + %w(.html) => :html, + %w(.diff) => :diff, + %w(.java) => :java, + %w(.json) => :json, + %w(.c .h) => :c, + %w(.rhtml) => :rhtml, + %w(.yaml .yml) => :yaml, + %w(.cpp .hpp .cc .h cxx) => :cpp, + %w(.rb .ru .irbrc .gemspec .pryrc) => :ruby, + } + + # @return [Symbol] The type of code stored in this wrapper. + attr_reader :code_type + + # @param [String] filename The name of a file with code to be detected + # @param [Symbol] code_type The type of code the `filename` contains + def initialize(filename, code_type = type_from_filename(filename)) + @filename = filename + @code_type = code_type + end + + # @return [String] The code contained in the current `@filename`. + def code + if @filename == Pry.eval_path + Pry.line_buffer.drop(1) + elsif Pry::Method::Patcher.code_for(@filename) + Pry::Method::Patcher.code_for(@filename) + elsif RbxPath.is_core_path?(@filename) + File.read(RbxPath.convert_path_to_full(@filename)) + else + abs_path = abs_path(@filename) + @code_type = type_from_filename(abs_path) + File.read(abs_path) + end + end + + private + + # @param [String] filename + # @raise [MethodSource::SourceNotFoundError] if the `filename` is not + # readable for some reason. + # @return [String] absolute path for the given `filename`. + def abs_path(filename) + find_abs_path(filename) or + raise MethodSource::SourceNotFoundError, + "Cannot open #{filename.inspect} for reading." + end + + def find_abs_path(filename) + code_path(filename).detect { |path| readable?(path) } + end + + # @param [String] path + # @return [Boolean] if the path, with or without the default ext, + # is a readable file then `true`, otherwise `false`. + def readable?(path) + File.readable?(path) && !File.directory?(path) or + File.readable?(path << DEFAULT_EXT) + end + + # @return [Array] All the paths that contain code that Pry can use for its + # API's. Skips directories. + def code_path(filename) + [File.expand_path(filename, Dir.pwd), + File.expand_path(filename, Pry::INITIAL_PWD), + *$LOAD_PATH.map { |path| File.expand_path(filename, path) }] + end + + # @param [String] filename + # @param [Symbol] default (:unknown) the file type to assume if none could be + # detected. + # @return [Symbol, nil] The CodeRay type of a file from its extension, or + # `nil` if `:unknown`. + def type_from_filename(filename, default = :unknown) + _, @code_type = EXTENSIONS.find do |k, _| + k.any? { |ext| ext == File.extname(filename) } + end + + code_type || default + end + + end +end diff --git a/lib/pry/commands/cat.rb b/lib/pry/commands/cat.rb index a6f96267..f3b45514 100644 --- a/lib/pry/commands/cat.rb +++ b/lib/pry/commands/cat.rb @@ -45,7 +45,14 @@ class Pry end def complete(search) - super + Bond::Rc.files(search.split(" ").last || '') + search_term = search.split.last || '' + super + + Bond::Rc.files(search_term) + + $LOAD_PATH.flat_map do |path| + Bond::Rc.files(File.join(path.dup, search_term)).map do |file_path| + File.basename(file_path) + end + end end end diff --git a/lib/pry/commands/cat/file_formatter.rb b/lib/pry/commands/cat/file_formatter.rb index c60c55e8..03226dfb 100644 --- a/lib/pry/commands/cat/file_formatter.rb +++ b/lib/pry/commands/cat/file_formatter.rb @@ -9,13 +9,14 @@ class Pry @file_with_embedded_line = file_with_embedded_line @opts = opts @_pry_ = _pry_ + @code_from_file = Pry::Code.from_file(file_name) 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)) + decorate(@code_from_file) end private @@ -23,7 +24,7 @@ class Pry 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] + [file_name, line_num ? line_num.to_i : nil] end def file_name @@ -47,36 +48,18 @@ class Pry 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 + code_type = @code_from_file.code_type + + if code_type == :unknown + name, ext = File.basename(file_name).split('.', 2) case name when "Rakefile", "Gemfile" :ruby else :text end + else + code_type end end end diff --git a/spec/code_spec.rb b/spec/code_spec.rb index 520df34d..51b626f6 100644 --- a/spec/code_spec.rb +++ b/spec/code_spec.rb @@ -11,9 +11,9 @@ describe Pry::Code do Pry::Code.from_file('(pry)').grep(/:hay_guys/).length.should == 1 end - should 'default to Ruby' do + should 'default to unknown' do temp_file('') do |f| - Pry::Code.from_file(f.path).code_type.should == :ruby + Pry::Code.from_file(f.path).code_type.should == :unknown end end @@ -23,12 +23,6 @@ describe Pry::Code do end end - should 'use the provided extension' do - temp_file('.c') do |f| - Pry::Code.from_file(f.path, :ruby).code_type.should == :ruby - end - end - should 'raise an error if the file doesn\'t exist' do proc do Pry::Code.from_file('/knalkjsdnalsd/alkjdlkq') @@ -41,11 +35,51 @@ describe Pry::Code do end end + should 'check for Ruby files relative to origin pwd with `.rb` omitted' do + Dir.chdir('spec') do |f| + Pry::Code.from_file('spec/' + File.basename(__FILE__, '.*')).code_type.should == :ruby + end + end + should 'find files that are relative to the current working directory' do Dir.chdir('spec') do |f| Pry::Code.from_file(File.basename(__FILE__)).code_type.should == :ruby end end + + describe 'find Ruby files relative to $LOAD_PATH' do + before do + $LOAD_PATH << 'spec/fixtures' + end + + after do + $LOAD_PATH.delete 'spec/fixtures' + end + + it 'finds files with `.rb` extension' do + Pry::Code.from_file('slinky.rb').code_type.should == :ruby + end + + it 'finds files with `.rb` omitted' do + Pry::Code.from_file('slinky').code_type.should == :ruby + end + + it 'finds files in a relative directory with `.rb` extension' do + Pry::Code.from_file('../helper.rb').code_type.should == :ruby + end + + it 'finds files in a relative directory with `.rb` omitted' do + Pry::Code.from_file('../helper').code_type.should == :ruby + end + + it "doesn't confuse files with the same name, but without an extension" do + Pry::Code.from_file('cat_load_path').code_type.should == :unknown + end + + it "doesn't confuse files with the same name, but with an extension" do + Pry::Code.from_file('cat_load_path.rb').code_type.should == :ruby + end + end end describe '.from_method' do diff --git a/spec/fixtures/cat_load_path b/spec/fixtures/cat_load_path new file mode 100644 index 00000000..e69de29b diff --git a/spec/fixtures/cat_load_path.rb b/spec/fixtures/cat_load_path.rb new file mode 100644 index 00000000..e69de29b diff --git a/spec/fixtures/slinky.rb b/spec/fixtures/slinky.rb new file mode 100644 index 00000000..e69de29b diff --git a/spec/fixtures/slinky/stinky.rb b/spec/fixtures/slinky/stinky.rb new file mode 100644 index 00000000..e69de29b