Counting words / lines in Ruby 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} &lt;file&gt; words|lines"
  puts "       #{$0} &lt;file&gt; find &lt;what-to-find&gt;"
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 &gt; 0   
      @matches &lt;&lt; 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 &amp;&amp; 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
Some notes: 


Those counter classes are probably overkill, keep it simple. 
Ruby is an OOP language, but it's not necessary to create a bunch of classes  for simple scripts like this.
Idiomatic: if not x -> if !x
Idiomatic: { ... } for one-line blocks, do/end for multi-line.


I'd write:

fail("Usage: #{0} PATH (lines|words|find REGEXP)") unless ARGV.size &gt;= 2
path, mode, optional_regexp = ARGV

open(path) do |fd|
  case mode
  when "lines"
    puts(fd.lines.count)
  when "words"
    puts(fd.lines.map { |line| line.split.size }.reduce(0, :+))
  when "find"
    if optional_regexp
      fd.lines.each { |line| puts(line) if line.match(optional_regexp) }
    else
      fail("mode find requires a REGEXP argument")
    end
  else
    fail("Unknown mode: #{mode}")
  end
end