Rubyisms wanted to shorten code in search program

Hi,

Search on WindowsXP/SP2 didn’t seem to locate a file is looking for.
As someone relatively new to Ruby, I wonder whether there are any
Rubyisms I could have used to cut down the the 80+ lines I took to
accomplish this task, given the USAGE requirement I posed in the
code.

Thanks in Advance,
Richard

Search.rb

K:/_Projects/Ruby/_Ruby_Tests/TestSearchDir/SearchWithArgs

USAGE: Search.rb -d DirPath [-f regexpFileNameSought] [-t

regexpTextSought]

require ‘find’

def Match(path, reTxt)
open(path) { |f|
f.each_line { |line|
if (line =~ reTxt)
puts “MATCH found in following line”
puts line
return true
end
}
}
return false
end

def ShowQuit(msg, arg = ‘’)
puts "ERROR " + “=”*10,
msg + ": " + arg,
“=”*16
exit
end

argPrefix = ‘-’
argFlags = %{d f t} # reDirectory, reFilename, reText
argVals=Hash.new

#args = “-d K:/_Projects/Ruby/_Ruby_Tests -f search.*[.]rb$ -t
curArg”.split(’ ‘)
args = “-d K:/_Projects/Ruby/_Ruby_Tests -t curArg”.split(’ ‘)
puts args.join(’ ')
ix = 0

while( ix<args.size ) do
curArg = args[ix]

Is current arg. a valid flag?

ShowQuit(“Invalid flag”, curArg) unless
(curArg.size==2 && argFlags.include?(curArg[1,1]))

Has the current argument been seen?

if (argVals.keys.include?(curArg))
ShowQuit(“Duplicate flag”, curArg)
end

Initialize hash for this flag; increment index;

argVals[curArg] = nil
ix += 1

If argument value follows flag and is not, itself, a flag

if (args[ix] && args[ix][0,1] != argPrefix)
argVals[curArg] = args[ix]
ix += 1
end
end

puts “Succes in getting arguments!”
p argVals

ShowQuit(“No dirname(-d) argument”) unless argVals[’-d’]
ShowQuit(“Dirname(-d) argument does not identify a directory”) unless
File.directory?(argVals[’-d’] )
if (reFnIn = argVals[’-f’])
reFn = Regexp.new(reFnIn, Regexp::IGNORECASE)
ShowQuit(“Invalid filename expression”) unless
reFn.class.to_s==‘Regexp’
end
if (reTxtIn = argVals[’-t’])
reTxt = Regexp.new(reTxtIn, Regexp::IGNORECASE)
ShowQuit(“Invalid text expression”) unless reTxt.class.to_s==‘Regexp’
end

Find.find(argVals[’-d’]) { |path|
fbn = File.basename(path)
next if(fbn =~ /^[.][.]?$/)
next if(reFnIn && fbn !~ reFn)
if ( argVals[’-t’] && File.file?(path) )
puts path if Match(path, reTxt)
end
}

On Dec 3, 10:03 pm, RichardOnRails
[email protected] wrote:

Search on WindowsXP/SP2 didn’t seem to locate a file is looking for.

FWIW, I use this script on both my macs and windows boxes. (I know
this isn’t what you asked, but I thought I’d share this as moderately
related.)

Slim2:~ phrogz$ cat /usr/local/bin/findfile
#!/usr/bin/env ruby

USAGE = <<ENDUSAGE
Usage:
findfile [-d max_depth] [-a] [-c] [-i] name_regexp
[content_regexp]
-d,–depth the maximum depth to recurse to (defaults to no
limit)
-a,–showall with content_regexp, show every match per file
(defaults to only show the first-match per file)
-c,–usecase with content_regexp, use case-sensitive matching
(defaults to case-insensitive)
-i,–includedirs also find directories matching name_regexp
(defaults to files only; incompatible with
content_regexp)
-h,–help show some help examples
ENDUSAGE

EXAMPLES = <<ENDEXAMPLES

Examples:
findfile foo

Print the path to all files with ‘foo’ in the name

findfile -i foo

Print the path to all files and directories with ‘foo’ in the

name

findfile js$

Print the path to all files whose name ends in “js”

findfile js$ vector

Print the path to all files ending in “js” with “Vector” or

“vector”

(or “vEcTOr”, “VECTOR”, etc.) in the contents, and print some of

the

first line that has that content.

findfile js$ -c Vector

Like above, but must match exactly “Vector” (not ‘vector’ or

‘VECTOR’).

findfile . vector -a

Print the path to every file with “Vector” (any case) in it

somewhere

printing every line in those files (with line numbers) with that

content.

findfile -d 0 .

Print the path to every file that is in the current directory.

findfile -d 1 .

Print the path to every file that is in the current directory or

any

of its child directories (but no subdirectories of the children).

ENDEXAMPLES

ARGS = {}
UNFLAGGED_ARGS = [ :name_regexp, :content_regexp ]
next_arg = UNFLAGGED_ARGS.first
ARGV.each{ |arg|
case arg
when ‘-d’,’–depth’
next_arg = :max_depth
when ‘-a’,’–showall’
ARGS[:showall] = true
when ‘-c’,’–usecase’
ARGS[:usecase] = true
when ‘-i’,’–includedirs’
ARGS[:includedirs] = true
when ‘-h’,’–help’
ARGS[:help] = true
else
if next_arg
if next_arg==:max_depth
arg = arg.to_i + 1
end
ARGS[next_arg] = arg
UNFLAGGED_ARGS.delete( next_arg )
end
next_arg = UNFLAGGED_ARGS.first
end
}

if ARGS[:help] or !ARGS[:name_regexp]
puts USAGE
puts EXAMPLES if ARGS[:help]
exit
end

class Dir
def self.crawl( path, max_depth=nil, include_directories=false,
depth=0, &block )
return if max_depth && depth > max_depth
begin
if File.directory?( path )
yield( path, depth ) if include_directories
files = Dir.entries( path ).select{ |f| true unless f=~/^.
{1,2}$/ }
unless files.empty?
files.collect!{ |file_path|
Dir.crawl( path+’/’+file_path, max_depth,
include_directories, depth+1, &block )
}.flatten!
end
return files
else
yield( path, depth )
end
rescue SystemCallError => the_error
warn “ERROR: #{the_error}”
end
end

end

start_time = Time.new
name_match = Regexp.new(ARGS[:name_regexp], true )
content_match = ARGS[:content_regexp] && Regexp.new( “.
{0,20}#{ARGS[:content_regexp]}.{0,20}”, !ARGS[:usecase] )

file_count = 0
matching_count = 0
Dir.crawl( ‘.’, ARGS[:max_depth], ARGS[:includedirs] && !
content_match){ |file_path, depth|
if File.split( file_path )[ 1 ] =~ name_match
if content_match
if ARGS[:showall]
shown_file = false
IO.readlines( file_path ).each_with_index{ |
line_text,line_number|
if match = line_text[content_match]
unless shown_file
puts file_path
matching_count += 1
shown_file = true
end
puts ( “%5d: " % line_number ) + match
end
}
puts " " if shown_file
elsif IO.read( file_path ) =~ content_match
puts file_path,” #{$~}"," "
matching_count += 1
end
else
puts file_path
matching_count += 1
end
end
file_count += 1
}
elapsed = Time.new - start_time
puts “Found #{matching_count} file#{matching_count==1?’’:‘s’} (out of
#{file_count}) in #{elapsed} seconds”

2007/12/4, RichardOnRails
[email protected]:

Search.rb

K:/_Projects/Ruby/_Ruby_Tests/TestSearchDir/SearchWithArgs

USAGE: Search.rb -d DirPath [-f regexpFileNameSought] [-t

regexpTextSought]

Just a quick hack without command line processing.

dir = …
name_regexp = … # may be null
content_regexp = … # may be null

require ‘find’

Find.find dir do |file|
path, base = File.split file
next if name_regexp && name_regexp !~ base or
content_regexp && context_regexp !~ File.read(file)
puts file
end

For command line processing I’d use OptionParser.

Kind regards

robert

On Dec 4, 2007 5:07 PM, Robert K. [email protected]
wrote:

Richard
name_regexp = … # may be null
content_regexp = … # may be null
Are we losing Robert to the Java community? stay with us and nil please
:wink:
YARo

http://ruby-smalltalk.blogspot.com/


All truth passes through three stages. First, it is ridiculed. Second,
it is violently opposed. Third, it is accepted as being self-evident.
Schopenhauer (attr.)

On Dec 4, 12:50 am, Phrogz [email protected] wrote:

#!/usr/bin/env ruby
(defaults to case-insensitive)

Print the path to all files with ‘foo’ in the name

“vector”
somewhere
ENDEXAMPLES
when ‘-c’,’–usecase’
ARGS[next_arg] = arg
exit
{1,2}$/ }
rescue SystemCallError => the_error

       if match = line_text[content_match]
     puts file_path,"  #{$~}"," "

puts “Found #{matching_count} file#{matching_count==1?’’:‘s’} (out of
#{file_count}) in #{elapsed} seconds”

Hi Phrogz,

I know this isn’t what you asked, but
I thought I’d share this as moderately related.

It’s of course very much related. It incorporates a number of nice
features. I’m going to keep it in anticipation of adding such
features in the future.

As I mentioned, I wrote the posted code out of frustration with
Windows Explorer’s Search feature’s failure to find a file I had just
saved a day of two earlier.

Having done that and gotten the desired result, I was disappointed in
my code’s bloat. For now, I’m trying to unlearn my procedural
programming style in favor of the succinct Ruby style.

Thank you for sharing your code with me.

Best wishes,
Richard

On Dec 4, 11:07 am, Robert K. [email protected] wrote:

code.
Just a quick hack without command line processing.
content_regexp && context_regexp !~ File.read(file)
puts file
end

For command line processing I’d use OptionParser.

Kind regards

robert

Hi Robert,

Your algorithm’s concept is excellent … just what I hoped to learn
in order to escape my procedural-programming heritage and start to
code like a Rubyist.

OptionParser

Thanks for that reference. I’ll look into it.

Just for the record, I had to tweak your code to get your concept
working. I thought of it as “earning my keep.” Below is my test
code.

Again, thanks for your guidance.

Best wishes,
Richard

dir = ‘K:/_Projects/Ruby/_Ruby_Tests’
name_regexp = nil # may be null
content_regexp = Regexp.new(‘curArg’) # may be null

require ‘find’

Find.find dir do |file|
path, base = File.split file
next if name_regexp && name_regexp !~ base or
content_regexp && (!File.file?(file) || File.read(file) !~
content_regexp)
puts file
end

On Dec 4, 2007 2:05 PM, RichardOnRails
[email protected] wrote:

Hi,

Search on WindowsXP/SP2 didn’t seem to locate a file is looking for.
As someone relatively new to Ruby, I wonder whether there are any
Rubyisms I could have used to cut down the the 80+ lines I took to
accomplish this task, given the USAGE requirement I posed in the
code.

Quick implementation of what i could read from your code…
http://rafb.net/p/GyzZxJ94.html

2007/12/5, RichardOnRails
[email protected]:

accomplish this task, given the USAGE requirement I posed in the

next if name_regexp && name_regexp !~ base or
Hi Robert,
working. I thought of it as “earning my keep.” Below is my test
code.

Oh, yes. Sorry for that. But then again, you should probably globally
“next” if it is not a file because otherwise the name regexp will also
match directories and behavior is a bit inconsistent.

Kind regards

robert

On Dec 4, 1:17 pm, Robert D. [email protected] wrote:


All truth passes through three stages. First, it is ridiculed. Second,
it is violently opposed. Third, it is accepted as being self-evident.
Schopenhauer (attr.)

Hi Robert,

I liked your blog. I’ve bookmarked it for now. I’m going to have to
code more pedestrian approaches before I tackle the subtleties your
address.

Best wishes,
Richard

On Dec 5, 3:00 am, Michael F. [email protected] wrote:

Quick implementation of what i could read from your code…http://rafb.net/p/GyzZxJ94.html

Hi Michael,

Great code! You interpreted my intent perfectly. And your code
worked perfectly (though, in case someone else uses it, I think I had
to tweak something before I got it to work, though I can’t remember
what it was and I might be confusing this with someone else’s
offering. )

The option-handling is package is great, though it’s going to take me
a few days to understand its nuances … maybe quite a few days :slight_smile:

Thanks for showing me some of the elegant heights of Ruby.

After I’m satisfied with my understanding of the package, I’m going
to try adding -cra --created_after, -cha --changed_after, etc. It
seems to me that we should be able specify more than RE comparisons
with an option-handler package.

Best wishes,
Richard

On Dec 5, 3:21 am, Robert K. [email protected] wrote:

As someone relatively new to Ruby, I wonder whether there are any

USAGE: Search.rb -d DirPath [-f regexpFileNameSought] [-t

Find.find dir do |file|
robert

robert


use.inject do |as, often| as.you_can - without end

Hi Robert,

Oh, yes. Sorry for that.

Please, no apologies. Your few words of insight were worth
everything. It’s our obligation to work out the details, not yours!

you should probably globally “next” if it is not a file …

Thanks for that additional observation. I only superficially tested
the code to confirm that it found the files I expected in my original
search.

Again, thank you for taking the time to offer your guidance.

Best wishes,
Richard

On Dec 7, 2007 10:15 AM, RichardOnRails
[email protected] wrote:

code.

The option-handling is package is great, though it’s going to take me
a few days to understand its nuances … maybe quite a few days :slight_smile:

Thanks for showing me some of the elegant heights of Ruby.

After I’m satisfied with my understanding of the package, I’m going
to try adding -cra --created_after, -cha --changed_after, etc. It
seems to me that we should be able specify more than RE comparisons
with an option-handler package.

Thank you as well, it was a fun little quiz :slight_smile:
I usually use the GNU tools grep and awk to get the same results, but
i’m not sure if they are available for windows.
Anyway, hope i helped you in your understanding of ruby itself, some
idioms, code-style and overall flow…
Ruby code usually is well done when you cannot suppress the urge to
frame and hang it up on in your room :slight_smile:

^ manveru

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs