HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

Simple Ruby directory navigator functions

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
directorysimplenavigatorrubyfunctions

Problem

In the process of writing scripts to work with CSVs and other files of the like I found myself in the need of a way to navigate and select files for various purposes. I wrote the following function for one of the scripts I needed to finish quickly and now I'm trying to get it into a more reusable form

def select_file()
  i = 1
  selection_set = Dir.glob("*") 
  puts "--------------------------------------------------------------------------"
  puts "Listing entries in #{File.basename(Dir.pwd)}:"
  puts
  selection_set.each do |entry|
    puts i.to_s + " - " + entry
    i = i+1 
  end
  print "Select File/Folder: "
  user_selection = gets.chomp
  selection = selection_set[user_selection.to_i - 1]
  puts "Selected: #{selection}"
  puts "--------------------------------------------------------------------------"
  selection
end


In an attempt to make this more reusable in the future I refactored this single function into a series of functions. Part of the motivation in doing it this way was to attempt to use this for displaying other sets of things the user may need to select. Was I better off sticking with the original approach or am I on a decent track but not quite doing it right? I get the sense this can all be done much simpler. Also I am deliberately avoiding using any kind of UI gem for no reason other than I am trying to learn.

```
def full_directory_navigator
selection_set = Dir.glob('*', File::FNM_DOTMATCH)
list_directory_entries(selection_set)
end

def dir_header(pattern)
100.times { |i| !(i == 99) ? print('-') : puts }
pattern_message = (pattern == '*') ? '' : "matching \"#{ pattern }\""
puts
puts "Listing entries in #{ File.basename(Dir.pwd) }#{ pattern_message }"
puts
puts 'Index Entry'
100.times { |i| !(i == 99) ? print('-') : puts }
end

def dir_select
print 'Select File/Folder: '
end

def spacer(i)
size = i.to_s.size
spacer = ''
(9 - size).times { spacer = ' ' + spacer }
spacer
end

def display_selection_s

Solution

Your two code samples are not exactly equivalent. The second one has nicer formatting (fixed-width numbering) and attempts to parameterize the glob pattern (but fails in that regard — full_directory_navigator should accept a pattern parameter and pass it to both Dir.glob and list_directory_entries).

I'm not convinced that splitting up the select_file function into six functions makes it any better. It's not any more readable or extensible than the original. The parameter passing just gets in the way. (If you had defined a class, there might be some advantage, in that a subclass could customize the behaviour by overriding one of the methods.)

With more effective string formatting, the code is simple enough to fit in one function.

  • To repeat a character, use string multiplication.



  • The ternary conditional could just be an if-qualified expression, since one of the outcomes is nil.



  • To make a fixed-width column of numbers, use '%-8d' % number.



def select_file(glob='*', glob_flags=File::FNM_DOTMATCH)
entries = Dir.glob(glob, glob_flags)

# Header
puts '-' * 79,
"Listing entries in #{File.basename(Dir.pwd)}#{
" matching \"#{glob}\"" if glob != '*'
}",
'',
'%-8s %s' % ['Index', 'Entry'],
'-' * 79

# Listing
entries.each_with_index { |entry, i| puts '%-8d - %s' % [i + 1, entry] }

# Prompt
print 'Select File/Folder: '
entries[gets.to_i - 1]
end

selection = select_file()
puts "Selected: #{selection}"


Note that you haven't done any validation on the input. If the input doesn't look like a number, then gets.to_i - 1 becomes 0 - 1, which refers to the last item in the array.

Context

StackExchange Code Review Q#85984, answer score: 2

Revisions (0)

No revisions yet.