patternrubyMinor
Simple Ruby directory navigator functions
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
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
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
endIn 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 —
I'm not convinced that splitting up the
With more effective string formatting, the code is simple enough to fit in one function.
Note that you haven't done any validation on the input. If the input doesn't look like a number, then
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 isnil.
- 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.