heroxav
heroxav

Reputation: 1467

Ruby: Iterating through dir's and files

I wrote the following script to iterate through a directory, it's subdirectories and their files:

    def self.search_files_in_dir_for(dir, strings)
        results = {}
        puts "Initializing test ..."
        Dir.foreach(dir) do |file|
            next if file == '.' or file == '..'
            puts 'TEST: Testing dir "' + dir + "/" + file + '"'
            if File.file?(file)
                puts 'TEST: Testing "' + dir + "/" + file + '"'
                line_number = 0
                IO.foreach(file) do |line|
                    line_number = line_number + 1
                    if strings.any? { |string| line.include?(string) }
                        string = strings.detect { |string| line.include?(string) }
                        puts source = file + ":" + line_number.to_s
                        results[source] = string
                    end
                end
            elsif File.directory?(file)
                # Search child directories
                search_files_in_dir_for(File.join(dir, file), strings)
            end
        end
    end

Given the followiing dir + file structure:

- views
  - application
    - abcdefg
      - _partial2.html.erb
    - _partial1.html.erb
  - layouts
    - application.html.erb

and when passing the path of the views directory as dir, I get that output:

Initializing test ...
TEST: Testing dir "views/application"
TEST: Testing dir "views/layouts"

I would expect something like this:

Initializing test ...
TEST: Testing dir "views/application"
TEST: Testing dir "views/application/abcdefg"
TEST: Testing "views/application/abcdefg/_partial2.html.erb"
TEST: Testing "views/application/_partial1.html.erb"
TEST: Testing dir "views/layouts"
TEST: Testing "views/layouts/application.html.erb"

What am I doing wrong in that script?

Upvotes: 2

Views: 1055

Answers (1)

Eric Duminil
Eric Duminil

Reputation: 54223

Pathname#Glob

A noticeably shorter version, using Pathname and Pathname.glob:

require 'pathname'
files, dirs = Pathname.glob('**/*').partition(&:file?)

It gives you two arrays : one with all the files in the current directory, the other with all the subfolders.

For a specific dir :

files, dirs = Pathname.glob(File.join(dir, '**/*')).partition(&:file?)

You'd just need to parse the content of files

Grep or ack?

It looks like you're trying to replicate grep, ack or git grep

Your code, repaired

Here's a modified version of your code. The biggest problem was that file was a relative path. File.file?(file) was always returning false :

@results = {}
def search_files_in_dir_for(dir, strings)
  Dir.foreach(dir) do |file|
    complete_path = File.join(dir, file)
    next if file == '.' or file == '..'
    if File.file?(complete_path)
      puts "TEST: Testing '#{complete_path}'"
      line_number = 0
      IO.foreach(complete_path) do |line|
        line_number = line_number + 1
        if strings.any? { |string| line.include?(string) }
          string = strings.detect { |string| line.include?(string) }
          source = complete_path + ":" + line_number.to_s
          @results[source] = string
        end
      end
    else
      # Search child directories
      search_files_in_dir_for(complete_path, strings)
    end
  end
end

search_files_in_dir_for(..., [..., ...])

p @results

Upvotes: 2

Related Questions