countloc 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/{LICENSE.txt → LICENSE} +0 -0
- data/README +90 -0
- data/lib/countloc.rb +288 -134
- data/setup.rb +1585 -0
- data/test/tc_ruby.rb +2 -0
- metadata +5 -4
- data/README.txt +0 -74
    
        data/{LICENSE.txt → LICENSE}
    RENAMED
    
    | 
            File without changes
         | 
    
        data/README
    ADDED
    
    | @@ -0,0 +1,90 @@ | |
| 1 | 
            +
            == Contents
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * Overview
         | 
| 4 | 
            +
            * Download
         | 
| 5 | 
            +
            * Installation
         | 
| 6 | 
            +
            * Usage
         | 
| 7 | 
            +
            * Release Notes
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            == Overview
         | 
| 10 | 
            +
            CountLOC is a utility program, implemented in Ruby that provides support for 
         | 
| 11 | 
            +
            generating LOC metrics for source code.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Initial releases will support counting lines of code in Ruby source code.
         | 
| 14 | 
            +
            Subsequent releases will add support for other programming languages such as
         | 
| 15 | 
            +
            Python, C, C++, C#, Java, Perl, etc. ...
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            == Download
         | 
| 18 | 
            +
            The latest release can be downloaded from: http://rubyforge.org/frs/?group_id=7555&release_id=29931
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            == Installation
         | 
| 21 | 
            +
            CountLOC is packaged as a Ruby gem and as a .zip file. 
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            .gem:
         | 
| 24 | 
            +
            	% gem install countloc-x.y.z.gem	
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            .zip:
         | 
| 27 | 
            +
            	% unzip countloc-x.y.z.zip
         | 
| 28 | 
            +
            	% cd countloc-x.y.z
         | 
| 29 | 
            +
            	% ruby setup.rb install 
         | 
| 30 | 
            +
             
         | 
| 31 | 
            +
            .tgz:
         | 
| 32 | 
            +
            	% tar zxf countloc-x.y.z.tgz
         | 
| 33 | 
            +
            	% cd countloc-x.y.z
         | 
| 34 | 
            +
            	% ruby setup.rb install 
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            == Usage
         | 
| 37 | 
            +
            For full listing of options and usage:
         | 
| 38 | 
            +
            	% countloc.rb --help
         | 
| 39 | 
            +
            	
         | 
| 40 | 
            +
            To get the LOC metrics for a single Ruby file:
         | 
| 41 | 
            +
            	% countloc.rb some_file.rb
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            To get the LOC metrics for multiple Ruby files:
         | 
| 44 | 
            +
            	% countloc.rb some_file.rb some_other_file.rb
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            To get the LOC metrics for all Ruby files in the current directory:
         | 
| 47 | 
            +
            	% countloc.rb *.rb
         | 
| 48 | 
            +
            or	
         | 
| 49 | 
            +
            	% countloc.rb .
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            To get the LOC metrics for all Ruby files in a directory tree with recursion
         | 
| 52 | 
            +
            into subdirectories:
         | 
| 53 | 
            +
            	% countloc.rb -r .
         | 
| 54 | 
            +
            	
         | 
| 55 | 
            +
            To export the results to a html file:
         | 
| 56 | 
            +
            	% countloc.rb -r --html countloc.html .
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            To export the results to a csv file:
         | 
| 59 | 
            +
            	% countloc.rb -r --csv countloc.csv .
         | 
| 60 | 
            +
             | 
| 61 | 
            +
             | 
| 62 | 
            +
            == Release Notes
         | 
| 63 | 
            +
            === Release 0.2.0:
         | 
| 64 | 
            +
            Features
         | 
| 65 | 
            +
            * Added support for exporting results in csv and html format.
         | 
| 66 | 
            +
            * Improved error handling - e.g. incorrect/missing command line options, file errors, etc.
         | 
| 67 | 
            +
            * Added setup.rb for ease of installation from the .zip/.tgz release formats.
         | 
| 68 | 
            +
            * Added CountLOC module to encapsulate methods and classes.
         | 
| 69 | 
            +
             
         | 
| 70 | 
            +
            Bugfixes: 
         | 
| 71 | 
            +
            * None
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            === Release 0.1.0:
         | 
| 74 | 
            +
            Features
         | 
| 75 | 
            +
            * Added support for processing multiple files at once.
         | 
| 76 | 
            +
            * Added support for processing all .rb files in a directory.
         | 
| 77 | 
            +
            * Added support for recursing into directory trees.
         | 
| 78 | 
            +
            * Improved formatting of output.
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            Bugfixes: 
         | 
| 81 | 
            +
            * #23380 - Not suppressing path information in the program name in the usage string.
         | 
| 82 | 
            +
            * #23379 - Incorrectly counting a # inside a single quoted string as a comment.
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            === Release 0.0.1:
         | 
| 85 | 
            +
            Features
         | 
| 86 | 
            +
            * Initial release.
         | 
| 87 | 
            +
            * Supports generating LOC metrics for Ruby source code for a single 
         | 
| 88 | 
            +
              file at a time.
         | 
| 89 | 
            +
            * Handles multi-line and single line comments.
         | 
| 90 | 
            +
            * Handles mixed lines of both code and comments.
         | 
    
        data/lib/countloc.rb
    CHANGED
    
    | @@ -23,149 +23,283 @@ | |
| 23 23 |  | 
| 24 24 |  | 
| 25 25 | 
             
            require 'optparse'
         | 
| 26 | 
            +
            require 'time'
         | 
| 26 27 |  | 
| 27 | 
            -
             | 
| 28 | 
            +
            #
         | 
| 29 | 
            +
            # CountLOC module that encapsulates the methods and classes used to gather
         | 
| 30 | 
            +
            # code metrics.
         | 
| 31 | 
            +
            #
         | 
| 32 | 
            +
            module CountLOC
         | 
| 28 33 |  | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
            #  | 
| 32 | 
            -
            #  | 
| 33 | 
            -
            #  | 
| 34 | 
            -
            class  | 
| 35 | 
            -
               | 
| 36 | 
            -
               | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 34 | 
            +
              VERSION = '0.2.0'
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              # Class that gathers the metrics. 
         | 
| 37 | 
            +
              # 
         | 
| 38 | 
            +
              # This class design & implementation is based heavily on Stefan Lang's 
         | 
| 39 | 
            +
              # ScriptLines class from the "Ruby Cookbook" - Recipe 19.5 "Gathering 
         | 
| 40 | 
            +
              # Statistics About Your Code".
         | 
| 41 | 
            +
              class LineCounter
         | 
| 42 | 
            +
                attr_reader :name
         | 
| 43 | 
            +
                attr_accessor :code, :comments, :blank, :lines
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                SINGLE_LINE_FULL_PATTERN = /^\s*#/
         | 
| 46 | 
            +
                SINGLE_LINE_MIXED_PATTERN = /#/
         | 
| 47 | 
            +
                MULTI_LINE_BEGIN_PATTERN = /=begin(\s|$)/
         | 
| 48 | 
            +
                MULTI_LINE_END_PATTERN = /=end(\s|$)/
         | 
| 49 | 
            +
                BLANK_LINE_PATTERN = /^\s*$/
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                LINE_FORMAT = '%8s %8s %8s %8s %12s    %s'
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                #
         | 
| 54 | 
            +
                # Generate a string that contains the column headers for the metrics
         | 
| 55 | 
            +
                # printed with to_s
         | 
| 56 | 
            +
                #
         | 
| 57 | 
            +
                def self.headline
         | 
| 58 | 
            +
                  sprintf LINE_FORMAT, "LOC", "COMMENTS", "BLANK", "LINES", "CODE:COMMENT", "FILE"
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                #
         | 
| 62 | 
            +
                # Return an array containing the column names for the counters collected.
         | 
| 63 | 
            +
                #
         | 
| 64 | 
            +
                def self.columnNames
         | 
| 65 | 
            +
                  self.headline.split(' ', 6)
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def initialize(name)
         | 
| 69 | 
            +
                  @name = name
         | 
| 70 | 
            +
                  @code = 0
         | 
| 71 | 
            +
                  @comments = 0
         | 
| 72 | 
            +
                  @blank = 0
         | 
| 73 | 
            +
                  @lines = 0
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                # 
         | 
| 77 | 
            +
                # Iterates over all the lines in io (io might be a file or a string),
         | 
| 78 | 
            +
                # analyzes them and appropriately increases the counter attributes.
         | 
| 79 | 
            +
                #
         | 
| 80 | 
            +
                def read(io)
         | 
| 81 | 
            +
                  in_multiline_comment = false
         | 
| 82 | 
            +
                  io.each do |line| 
         | 
| 83 | 
            +
                    @lines += 1
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    # Process the line to avoid matching comment characters within quoted
         | 
| 86 | 
            +
                    # strings or regular expressions.
         | 
| 87 | 
            +
                    line.gsub!(/\'.*?\'/, "X")  # Single quoted string
         | 
| 88 | 
            +
                    line.gsub!(/\".*?\"/, "X")  # Double quoted string
         | 
| 89 | 
            +
                    line.gsub!(/\/.*?\//, "X")  # Regular expression
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                    case line
         | 
| 92 | 
            +
                    when MULTI_LINE_BEGIN_PATTERN
         | 
| 93 | 
            +
                      in_multiline_comment = true
         | 
| 94 | 
            +
                      @comments += 1
         | 
| 95 | 
            +
                    when MULTI_LINE_END_PATTERN
         | 
| 96 | 
            +
                      in_multiline_comment = false
         | 
| 97 | 
            +
                      @comments += 1
         | 
| 98 | 
            +
                    when BLANK_LINE_PATTERN
         | 
| 99 | 
            +
                      @blank += 1
         | 
| 100 | 
            +
                    when SINGLE_LINE_FULL_PATTERN
         | 
| 101 | 
            +
                      @comments += 1
         | 
| 102 | 
            +
                    when SINGLE_LINE_MIXED_PATTERN
         | 
| 103 | 
            +
                      @comments += 1
         | 
| 104 | 
            +
                      @code += 1
         | 
| 105 | 
            +
                    else
         | 
| 106 | 
            +
                      if in_multiline_comment
         | 
| 107 | 
            +
                        @comments += 1
         | 
| 108 | 
            +
                      else
         | 
| 109 | 
            +
                        @code += 1
         | 
| 110 | 
            +
                      end # if
         | 
| 111 | 
            +
                    end # case
         | 
| 112 | 
            +
                  end # read
         | 
| 113 | 
            +
                end # class LineCounter
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                #
         | 
| 116 | 
            +
                # Get a new LineCounter instance whose counters hold the sum of self
         | 
| 117 | 
            +
                # and other.
         | 
| 118 | 
            +
                #
         | 
| 119 | 
            +
                def +(other)
         | 
| 120 | 
            +
                  sum = self.dup
         | 
| 121 | 
            +
                  sum.code += other.code
         | 
| 122 | 
            +
                  sum.comments += other.comments
         | 
| 123 | 
            +
                  sum.blank += other.blank
         | 
| 124 | 
            +
                  sum.lines += other.lines
         | 
| 125 | 
            +
                  return sum
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                #
         | 
| 129 | 
            +
                # Get a formatted string containing all counter numbers and the name of
         | 
| 130 | 
            +
                # this instance.
         | 
| 131 | 
            +
                #
         | 
| 132 | 
            +
                def to_s
         | 
| 133 | 
            +
                  codeCommentRatio = (sprintf "%0.2f", @code.to_f/@comments if @comments > 0) || '--'
         | 
| 134 | 
            +
                  sprintf LINE_FORMAT, @code, @comments, @blank, @lines, codeCommentRatio, @name
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                #
         | 
| 138 | 
            +
                # Get a formatted string containing all counter numbers and the name of
         | 
| 139 | 
            +
                # this instance.
         | 
| 140 | 
            +
                #
         | 
| 141 | 
            +
                def to_a
         | 
| 142 | 
            +
                  self.to_s.split(' ', 6)
         | 
| 143 | 
            +
                end
         | 
| 43 144 |  | 
| 44 | 
            -
               | 
| 145 | 
            +
              end
         | 
| 45 146 |  | 
| 46 147 | 
             
              #
         | 
| 47 | 
            -
              #  | 
| 48 | 
            -
              # printed with to_s
         | 
| 148 | 
            +
              # Container class to store results from each file.
         | 
| 49 149 | 
             
              #
         | 
| 50 | 
            -
               | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
                 | 
| 58 | 
            -
             | 
| 59 | 
            -
                 | 
| 150 | 
            +
              class Results < Array
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                # Return a string containing all the results.
         | 
| 153 | 
            +
                def to_s
         | 
| 154 | 
            +
                  str = LineCounter.headline + "\n"
         | 
| 155 | 
            +
                  self.each { |result| str += result.to_s + "\n"}
         | 
| 156 | 
            +
                  str
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                # Return a string containing all the results in csv format.
         | 
| 160 | 
            +
                # The first row is a header row of the column names.
         | 
| 161 | 
            +
                # Each subsequent row corresponds to a result from the results array.
         | 
| 162 | 
            +
                def to_csv
         | 
| 163 | 
            +
                  csvString = LineCounter.columnNames.join(',') + "\n"
         | 
| 164 | 
            +
                  self.each { |result| csvString += result.to_a.join(',')  + "\n"}
         | 
| 165 | 
            +
                  csvString
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                # Return a string containing the results formatted as a html table.
         | 
| 169 | 
            +
                # The first row is a header row of the column names.
         | 
| 170 | 
            +
                # Each subsequent row corresponds to a result from the results array.
         | 
| 171 | 
            +
                def to_html
         | 
| 172 | 
            +
                  htmlString = %{<table border="1" cellspacing="0" cellpadding="2">}
         | 
| 173 | 
            +
                  htmlString += %{<tr>}
         | 
| 174 | 
            +
                  LineCounter.columnNames.each { |name| htmlString += %{<th>#{name}</th>} }
         | 
| 175 | 
            +
                  htmlString += %{</tr>}
         | 
| 176 | 
            +
                  self.each do |result|
         | 
| 177 | 
            +
                    htmlString += %{<tr>}
         | 
| 178 | 
            +
                    result.to_a.each { |cell| htmlString += %{<td>#{cell}</td> } }
         | 
| 179 | 
            +
                    htmlString += %{</tr>}
         | 
| 180 | 
            +
                  end
         | 
| 181 | 
            +
                  htmlString += %{</table>}
         | 
| 182 | 
            +
                  htmlString += %{<p><em>Generated by } +
         | 
| 183 | 
            +
                  %{<a href="http://countloc.rubyforge.org">countloc</a> version #{VERSION} } +
         | 
| 184 | 
            +
                  %{on #{Time.now.asctime}</em></p>}
         | 
| 185 | 
            +
                end
         | 
| 186 | 
            +
             | 
| 60 187 | 
             
              end
         | 
| 61 188 |  | 
| 62 | 
            -
              # 
         | 
| 63 | 
            -
              # Iterates over all the lines in io (io might be a file or a string),
         | 
| 64 | 
            -
              # analyzes them and appropriately increases the counter attributes.
         | 
| 65 | 
            -
              #
         | 
| 66 | 
            -
              def read(io)
         | 
| 67 | 
            -
                in_multiline_comment = false
         | 
| 68 | 
            -
                io.each do |line| 
         | 
| 69 | 
            -
                  @lines += 1
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                  # Process the line to avoid matching comment characters within quoted
         | 
| 72 | 
            -
                  # strings or regular expressions.
         | 
| 73 | 
            -
                  line.gsub!(/\'.*?\'/, "X")  # Single quoted string
         | 
| 74 | 
            -
                  line.gsub!(/\".*?\"/, "X")  # Double quoted string
         | 
| 75 | 
            -
                  line.gsub!(/\/.*?\//, "X")  # Regular expression
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                  case line
         | 
| 78 | 
            -
                  when MULTI_LINE_BEGIN_PATTERN
         | 
| 79 | 
            -
                    in_multiline_comment = true
         | 
| 80 | 
            -
                    @comments += 1
         | 
| 81 | 
            -
                  when MULTI_LINE_END_PATTERN
         | 
| 82 | 
            -
                    in_multiline_comment = false
         | 
| 83 | 
            -
                    @comments += 1
         | 
| 84 | 
            -
                  when BLANK_LINE_PATTERN
         | 
| 85 | 
            -
                    @blank += 1
         | 
| 86 | 
            -
                  when SINGLE_LINE_FULL_PATTERN
         | 
| 87 | 
            -
                    @comments += 1
         | 
| 88 | 
            -
                  when SINGLE_LINE_MIXED_PATTERN
         | 
| 89 | 
            -
                    @comments += 1
         | 
| 90 | 
            -
                    @code += 1
         | 
| 91 | 
            -
                  else
         | 
| 92 | 
            -
                    if in_multiline_comment
         | 
| 93 | 
            -
                      @comments += 1
         | 
| 94 | 
            -
                    else
         | 
| 95 | 
            -
                      @code += 1
         | 
| 96 | 
            -
                    end # if
         | 
| 97 | 
            -
                  end # case
         | 
| 98 | 
            -
                end # read
         | 
| 99 | 
            -
              end # class LineCounter
         | 
| 100 | 
            -
              
         | 
| 101 189 | 
             
              #
         | 
| 102 | 
            -
              #  | 
| 103 | 
            -
              # and other.
         | 
| 190 | 
            +
              # Class that writes to the Console
         | 
| 104 191 | 
             
              #
         | 
| 105 | 
            -
               | 
| 106 | 
            -
                 | 
| 107 | 
            -
                 | 
| 108 | 
            -
             | 
| 109 | 
            -
                 | 
| 110 | 
            -
                sum.lines += other.lines
         | 
| 111 | 
            -
                return sum
         | 
| 192 | 
            +
              class ConsoleWriter
         | 
| 193 | 
            +
                # Write the data to the console
         | 
| 194 | 
            +
                def write(data)
         | 
| 195 | 
            +
                  puts data
         | 
| 196 | 
            +
                end  
         | 
| 112 197 | 
             
              end
         | 
| 113 | 
            -
             | 
| 198 | 
            +
             | 
| 114 199 | 
             
              #
         | 
| 115 | 
            -
              #  | 
| 116 | 
            -
              # this instance.
         | 
| 200 | 
            +
              # Class that writes to a csv file
         | 
| 117 201 | 
             
              #
         | 
| 118 | 
            -
               | 
| 119 | 
            -
             | 
| 202 | 
            +
              class CsvFileWriter
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                def initialize(filename)
         | 
| 205 | 
            +
                  @filename = filename
         | 
| 206 | 
            +
                end
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                # Write the csv file, including the data contents (via 
         | 
| 209 | 
            +
                # the to_csv method on the data)
         | 
| 210 | 
            +
                def write(data)
         | 
| 211 | 
            +
                  begin
         | 
| 212 | 
            +
                    File.open(@filename, "wb") { |file| file.puts data.to_csv }
         | 
| 213 | 
            +
                  rescue 
         | 
| 214 | 
            +
                    puts "Error: " + $!
         | 
| 215 | 
            +
                  end    
         | 
| 216 | 
            +
                end
         | 
| 217 | 
            +
             | 
| 120 218 | 
             
              end
         | 
| 121 | 
            -
              
         | 
| 122 | 
            -
            end
         | 
| 123 219 |  | 
| 124 | 
            -
            #
         | 
| 125 | 
            -
            #  | 
| 126 | 
            -
            #
         | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
                 | 
| 220 | 
            +
              #
         | 
| 221 | 
            +
              # Class that writes to a html file
         | 
| 222 | 
            +
              #
         | 
| 223 | 
            +
              class HtmlFileWriter
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                def initialize(filename)
         | 
| 226 | 
            +
                  @filename = filename
         | 
| 227 | 
            +
                end
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                # Write the html file, including the data contents (via 
         | 
| 230 | 
            +
                # the to_html method on the data)
         | 
| 231 | 
            +
                def write(data)
         | 
| 232 | 
            +
                  begin
         | 
| 233 | 
            +
                    File.open(@filename, "w") { |file| file.puts data.to_html }
         | 
| 234 | 
            +
                  rescue 
         | 
| 235 | 
            +
                    puts "Error: " + $!
         | 
| 236 | 
            +
                  end    
         | 
| 237 | 
            +
                end
         | 
| 238 | 
            +
             | 
| 141 239 | 
             
              end
         | 
| 142 240 |  | 
| 143 | 
            -
              # | 
| 144 | 
            -
              files | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 241 | 
            +
              #
         | 
| 242 | 
            +
              # Generates LOC metrics for the specified files and sends the results to the console.
         | 
| 243 | 
            +
              #
         | 
| 244 | 
            +
              def countloc(files, options = nil)
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                # Setup the output writers based on the options
         | 
| 247 | 
            +
                writers = [ConsoleWriter.new]
         | 
| 248 | 
            +
                writers << CsvFileWriter.new(options.csvFilename) if options.csv
         | 
| 249 | 
            +
                writers << HtmlFileWriter.new(options.htmlFilename) if options.html
         | 
| 250 | 
            +
             | 
| 251 | 
            +
                # Expand directories into the appropriate file lists
         | 
| 252 | 
            +
                dirs = files.select { |filename| File.directory?(filename) }
         | 
| 253 | 
            +
                if dirs.size > 0
         | 
| 254 | 
            +
                  recursePattern = ("**" if options.recurse) || ""
         | 
| 255 | 
            +
                  files -= dirs
         | 
| 256 | 
            +
                  files += dirs.collect { |dirname| Dir.glob(File.join(dirname, recursePattern, "*.rb"))}.flatten      
         | 
| 257 | 
            +
                end
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                # Sum will keep the running total
         | 
| 260 | 
            +
                sum = LineCounter.new("TOTAL")
         | 
| 261 | 
            +
             | 
| 262 | 
            +
                # Container to hold the results
         | 
| 263 | 
            +
                results = Results.new
         | 
| 264 | 
            +
             | 
| 265 | 
            +
                # Generate metrics for each file
         | 
| 266 | 
            +
                files.each do |filename|
         | 
| 267 | 
            +
                  begin
         | 
| 268 | 
            +
                    File.open(filename) do |file|
         | 
| 269 | 
            +
                      counter = LineCounter.new(filename)
         | 
| 270 | 
            +
                      counter.read(file)
         | 
| 271 | 
            +
                      sum += counter
         | 
| 272 | 
            +
                      results << counter
         | 
| 273 | 
            +
                    end
         | 
| 274 | 
            +
                  rescue
         | 
| 275 | 
            +
                    puts "Error: " + $!
         | 
| 276 | 
            +
                  end
         | 
| 150 277 | 
             
                end
         | 
| 278 | 
            +
             | 
| 279 | 
            +
                # Add the totals to the results
         | 
| 280 | 
            +
                results << sum
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                # Write the metrics to the required files in the appropriate formats
         | 
| 283 | 
            +
                writers.each { |writer| writer.write(results) }
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                return results
         | 
| 151 286 | 
             
              end
         | 
| 152 287 |  | 
| 153 | 
            -
               | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
            end
         | 
| 288 | 
            +
              module_function :countloc
         | 
| 289 | 
            +
             | 
| 290 | 
            +
            end # module
         | 
| 157 291 |  | 
| 158 292 | 
             
            #
         | 
| 159 293 | 
             
            # When run as a standalone script ...
         | 
| 160 294 | 
             
            #
         | 
| 161 295 | 
             
            if $0 == __FILE__:
         | 
| 162 | 
            -
             | 
| 296 | 
            +
             | 
| 163 297 | 
             
              require 'ostruct'
         | 
| 164 | 
            -
             | 
| 298 | 
            +
             | 
| 165 299 | 
             
              class CmdLineOptParser
         | 
| 166 | 
            -
             | 
| 300 | 
            +
             | 
| 167 301 | 
             
                def self.usage 
         | 
| 168 | 
            -
                  "Usage: #{File.basename($0)} [options] <file>"
         | 
| 302 | 
            +
                  "Usage: #{File.basename($0)} [-h|--help] [options] <file> ... <file>"
         | 
| 169 303 | 
             
                end
         | 
| 170 304 |  | 
| 171 305 | 
             
                #
         | 
| @@ -176,37 +310,57 @@ if $0 == __FILE__: | |
| 176 310 | 
             
                  # Setup the defaults here
         | 
| 177 311 | 
             
                  options = OpenStruct.new
         | 
| 178 312 | 
             
                  options.recurse = false
         | 
| 313 | 
            +
                  options.csv = false
         | 
| 314 | 
            +
                  options.csvFilename = ""
         | 
| 315 | 
            +
                  options.html = false
         | 
| 316 | 
            +
                  options.htmlFilename = ""
         | 
| 179 317 |  | 
| 180 | 
            -
                   | 
| 181 | 
            -
                     | 
| 318 | 
            +
                  begin
         | 
| 319 | 
            +
                    OptionParser.new do |opts|
         | 
| 320 | 
            +
                      opts.banner = usage
         | 
| 182 321 |  | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
             | 
| 322 | 
            +
                      opts.on('-r', '--recurse', 'Recurse into subdirectories') do
         | 
| 323 | 
            +
                        options.recurse = true
         | 
| 324 | 
            +
                      end
         | 
| 186 325 |  | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 326 | 
            +
                      opts.on('-v', '--version', 'Display version number') do 
         | 
| 327 | 
            +
                        puts "#{File.basename($0)}, version: #{VERSION}"
         | 
| 328 | 
            +
                        exit
         | 
| 329 | 
            +
                      end
         | 
| 330 | 
            +
             | 
| 331 | 
            +
                      opts.on('--csv csvFilename', 'Generate csv file') do |csvFilename|
         | 
| 332 | 
            +
                        options.csvFilename = csvFilename
         | 
| 333 | 
            +
                        options.csv = true
         | 
| 334 | 
            +
                      end
         | 
| 335 | 
            +
             | 
| 336 | 
            +
                      opts.on('--html htmlFilename', 'Generate html file') do |htmlFilename|
         | 
| 337 | 
            +
                        options.htmlFilename = htmlFilename
         | 
| 338 | 
            +
                        options.html = true
         | 
| 339 | 
            +
                      end
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                      opts.on_tail('-h', '--help', 'Display this help and exit') do
         | 
| 342 | 
            +
                        puts opts
         | 
| 343 | 
            +
                        exit
         | 
| 344 | 
            +
                      end
         | 
| 345 | 
            +
             | 
| 346 | 
            +
                    end.parse!(args)
         | 
| 347 | 
            +
             | 
| 348 | 
            +
                  rescue
         | 
| 349 | 
            +
                    puts "Error: " + $!
         | 
| 350 | 
            +
                    exit
         | 
| 351 | 
            +
                  end
         | 
| 191 352 |  | 
| 192 | 
            -
                    opts.on_tail('-h', '--help', 'display this help and exit') do
         | 
| 193 | 
            -
                      puts opts
         | 
| 194 | 
            -
                      exit
         | 
| 195 | 
            -
                    end
         | 
| 196 | 
            -
                  
         | 
| 197 | 
            -
                  end.parse!(args)
         | 
| 198 | 
            -
                  
         | 
| 199 353 | 
             
                  options
         | 
| 200 354 | 
             
                end # parse()
         | 
| 201 355 | 
             
              end # class CmdLineOptParser
         | 
| 202 | 
            -
             | 
| 356 | 
            +
             | 
| 203 357 | 
             
              options = CmdLineOptParser.parse(ARGV)
         | 
| 204 | 
            -
             | 
| 358 | 
            +
             | 
| 205 359 | 
             
              if ARGV.length < 1
         | 
| 206 360 | 
             
                puts CmdLineOptParser.usage
         | 
| 207 361 | 
             
                exit
         | 
| 208 362 | 
             
              end
         | 
| 209 363 |  | 
| 210 | 
            -
              countloc(ARGV, options)
         | 
| 364 | 
            +
              CountLOC.countloc(ARGV, options)
         | 
| 211 365 |  | 
| 212 366 | 
             
            end
         |