Skip to main content
Code Review

Return to Question

edited tags; edited title
Link
200_success
  • 145.5k
  • 22
  • 190
  • 479

Counting words / lines in Ruby - more compact / idiomatic way?

Tweeted twitter.com/#!/StackCodeReview/status/433640244559511553
Source Link

Counting words / lines in Ruby - more compact / idiomatic way?

I solved this problem in Ruby:

Write an utility that takes 3 command-line parameters P1, P2 and P3. P3 is OPTIONAL (see below) P1 is always a file path/name. P2 can take the values:

  • "lines"
  • "words"
  • "find"

Only P2 is "find", then P3 is relevant/needed, otherwise it is not.

So, the utility does the following:

  • If P2 is "rows" it says how many lines it has
  • If P2 is "words" it says how many words it has (the complete file)
  • If P2 is "find" it prints out the lines where P3 is present

My solution looks like this:

#!/usr/bin/env ruby
def print_usage
 puts "Usage: #{0ドル} <file> words|lines"
 puts " #{0ドル} <file> find <what-to-find>"
end
class LineCounter
 # Initialize instance variables
 def initialize
 @line_count = 0
 end
 def process(line)
 @line_count += 1
 end
 def print_result
 puts "#{@line_count} lines"
 end
end
class WordCounter
 # Initialize instance variables
 def initialize
 @word_count = 0
 end
 def process(line)
 @word_count += line.scan(/\w+/).size
 end
 def print_result
 puts "#{@word_count} words"
 end
end
class WordMatcher
 # Initialize instance variables, using constructor parameter
 def initialize(word_to_find)
 @matches = []
 @word_to_find = word_to_find
 end
 def process(line)
 if line.scan(/#{@word_to_find}/).size > 0 
 @matches << line
 end
 end
 def print_result
 @matches.each { |line|
 puts line
 }
 end 
end
# Main program
if __FILE__ == $PROGRAM_NAME
 processor = nil
 # Try to find a line-processor
 if ARGV.length == 2
 if ARGV[1] == "lines"
 processor = LineCounter.new
 elsif ARGV[1] == "words"
 processor = WordCounter.new
 end
 elsif ARGV.length == 3 && ARGV[1] == "find"
 word_to_find = ARGV[2]
 processor = WordMatcher.new(word_to_find)
 end
 if not processor
 # Print usage and exit if no processor found
 print_usage
 exit 1
 else
 # Process the lines and print result
 File.readlines(ARGV[0]).each { |line|
 processor.process(line)
 }
 processor.print_result
 end
end

My questions are:

  • Is there a more Ruby-esque way of solving it?
  • More compact, but still readable / elegant?

It seems checking for correct command-line parameter combinations takes up a lot of space...

Contrast it to the Scala version found here:

https://gist.github.com/anonymous/93a975cb7aba6dae5a91#file-counting-scala

lang-rb

AltStyle によって変換されたページ (->オリジナル) /