loc_counter 0.1

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.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ /.yardoc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in loc_counter.gemspec
4
+ gemspec
@@ -0,0 +1,55 @@
1
+ # loc_counter
2
+
3
+ `loc_counter` is a command-line tool for measuring LOC (line-of-code) count in your Ruby project or some set of arbitrary Ruby source files.
4
+
5
+ ## Installation
6
+
7
+ ``` bash
8
+ gem install loc_counter
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ The gem install a single executable `loc_counter`.
14
+
15
+ ### On a project
16
+
17
+ If you want to count LOCs in your Rails app or in a gem, you can just pass a path to that project's directory to `loc_counter`:
18
+
19
+ ``` bash
20
+ $ loc_counter /path/to/project
21
+ 48 files processed
22
+ Total 1826 lines
23
+ Empty 331 lines
24
+ Comments 372 lines
25
+ Code 1123 lines
26
+ ```
27
+
28
+ In 'project mode' it scans `app`, `bin`, `config`, `lib` and top-level directories of your project, processing the following files:
29
+
30
+ - `Capfile`
31
+ - `Gemfile`
32
+ - `Rakefile`
33
+ - `*.gemspec`
34
+ - `*.rake`
35
+ - `*.rb`
36
+ - `*` in `bin` directory
37
+
38
+ ### On arbitrary files
39
+
40
+ You can also give `loc_counter` any files you want to measure.
41
+
42
+ ``` bash
43
+ $ loc_counter ~/*.rb
44
+ 5 files processed
45
+ Total 118 lines
46
+ Empty 27 lines
47
+ Comments 4 lines
48
+ Code 87 lines
49
+ ```
50
+
51
+ ## Contributing
52
+
53
+ If you want to contribute to the project, fork the repository, push your changes to a topic branch and send me a pull request.
54
+
55
+ `loc_counter` is tested under MRI `1.8.7`, `1.9.2` and `1.9.3`. If something is working incorrectly or not working at all in one of these environments, this should be considered a bug. Any bug reports are welcome at Github issues.
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.rspec_opts = '--color --format doc'
6
+ end
7
+
8
+ task :default => :spec
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thor/group'
4
+ require 'active_support/inflector'
5
+ require 'loc_counter'
6
+
7
+ module LOCCounter
8
+ class CLI < Thor::Group
9
+ include Thor::Actions
10
+
11
+ desc 'Scans the project or individual files for Ruby source files and outputs LOC counts.'
12
+ argument :paths, :type => :array
13
+ def project
14
+ if paths.empty?
15
+ # no arguments received
16
+ say 'No path was given'
17
+ elsif paths.count == 1 && File.directory?(paths.first)
18
+ # received one argument which is a directory path
19
+ print_results LOCCounter::Project.new(paths.first).counts
20
+ else
21
+ # received one or more file paths
22
+ print_results LOCCounter::FilesCollection.new(paths).counts
23
+ end
24
+ end
25
+
26
+ def self.banner
27
+ "loc_counter /path/to/project # scan the whole project\n" +
28
+ " or\n" +
29
+ " loc_counter /some/filename/mask/**/*.rb # scan only specified files"
30
+ end
31
+ private
32
+ def print_results(counts)
33
+ # '46 files processed'
34
+ say pluralized_noun(counts.delete(:files), 'file') + ' processed'
35
+
36
+ results = counts.map do |type, count|
37
+ type = type.to_s.capitalize
38
+ count = pluralized_noun(count, 'line')
39
+ [type, count]
40
+ end
41
+
42
+ print_table(results)
43
+ end
44
+
45
+ # pluralized_noun(53, 'octopus') # => '53 octopi'
46
+ def pluralized_noun(number, noun)
47
+ "#{number} #{noun.pluralize(number)}"
48
+ end
49
+ end
50
+ end
51
+
52
+ LOCCounter::CLI.start
@@ -0,0 +1,8 @@
1
+ require 'loc_counter/version'
2
+ require 'loc_counter/source_file'
3
+ require 'loc_counter/files_collection'
4
+ require 'loc_counter/project'
5
+
6
+ module LOCCounter
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,45 @@
1
+ module LOCCounter
2
+ # A class representing a collection of arbitrary files.
3
+ class FilesCollection
4
+ # All parsed files in the collection.
5
+ # @return [Array]
6
+ attr_reader :files
7
+
8
+ # Regexp for Ruby source file paths
9
+ RUBY_FILES = /((Cap|Gem|Rake)file|\.(gemspec|rake|rb)|bin\/\w+)$/
10
+
11
+ # @param [Array] file_paths Paths to files being processed
12
+ def initialize(file_paths)
13
+ @files = []
14
+ file_paths.each do |path|
15
+ @files << SourceFile.new(path) if path =~ RUBY_FILES
16
+ end
17
+ end
18
+
19
+ # Summarized line counts for all files in the collection.
20
+ # @example
21
+ # project = LOCCounter::Project.new(path)
22
+ # project.counts
23
+ # # => {
24
+ # # :total => 1606,
25
+ # # :empty => 292,
26
+ # # :comments => 360,
27
+ # # :code => 954,
28
+ # # :files => 43
29
+ # # }
30
+ # @return [ActiveSupport::OrderedHash]
31
+ # @see LOCCounter::SourceFile#counts
32
+ def counts
33
+ total_counts = ActiveSupport::OrderedHash.new
34
+ [:total, :empty, :comments, :code].each { |type| total_counts[type] = 0 }
35
+
36
+ @files.each do |file|
37
+ total_counts.keys.each do |type|
38
+ total_counts[type] += file.counts[type]
39
+ end
40
+ end
41
+
42
+ total_counts.merge(:files => @files.count)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,27 @@
1
+ require 'active_support/ordered_hash'
2
+ module LOCCounter
3
+ # A class representing a project.
4
+ class Project < FilesCollection
5
+ # Dir.glob patterns for project source code files paths
6
+ SOURCE_FILES = [
7
+ '*.{rb,gemspec}',
8
+ '{Cap,Gem,Rake}file',
9
+ 'bin/*',
10
+ '{app,config,lib}/**/*.{gemspec,rake,rb}'
11
+ ]
12
+
13
+ # @param [String] dir_name Path to the project directory
14
+ def initialize(dir_name)
15
+ raise ArgumentError, "Directory '#{dir_name}' not found" unless File.exists?(dir_name)
16
+
17
+ @files = []
18
+ SOURCE_FILES.each do |pattern|
19
+ full_pattern = File.join(dir_name, pattern)
20
+
21
+ @files += Dir.glob(full_pattern).map do |filename|
22
+ SourceFile.new(filename)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,52 @@
1
+ module LOCCounter
2
+ # A class representing a source code file.
3
+ class SourceFile
4
+ # All lines in a file.
5
+ # @return [Array]
6
+ attr_reader :lines
7
+
8
+ # A regexp for empty lines
9
+ EMPTY_PATTERN = /^\s*$/
10
+ # A regexp for lines containing just comments
11
+ COMMENT_PATTERN = /^\s*\#.*$/
12
+
13
+ # @param [String] filename Full path to the file being processed
14
+ def initialize(filename)
15
+ raise ArgumentError, "File '#{filename}' not found" unless File.exists?(filename)
16
+
17
+ @lines = File.readlines(filename)
18
+ end
19
+
20
+ # Line counts broken by the line type.
21
+ #
22
+ # Returns a hash with 4 elements:
23
+ # - :total is total line count
24
+ # - :empty is a number of empty lines
25
+ # - :comments is a number of lines containing only a comment
26
+ # - :code is a number of lines containing any code
27
+ # @return [Hash]
28
+ def counts
29
+ @counts ||= begin
30
+ counts = {
31
+ :total => @lines.count,
32
+ :empty => 0,
33
+ :comments => 0,
34
+ :code => 0
35
+ }
36
+
37
+ @lines.each do |line|
38
+ case line
39
+ when EMPTY_PATTERN
40
+ counts[:empty] += 1
41
+ when COMMENT_PATTERN
42
+ counts[:comments] += 1
43
+ else
44
+ counts[:code] += 1
45
+ end
46
+ end
47
+
48
+ counts
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module LOCCounter
2
+ VERSION = '0.1'
3
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ $: << File.expand_path('../lib', __FILE__)
3
+ require 'loc_counter/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'loc_counter'
7
+ s.version = LOCCounter::VERSION
8
+ s.authors = ['Vsevolod Romashov']
9
+ s.email = ['7@7vn.ru']
10
+ s.homepage = ''
11
+ s.summary = 'CLI LOC counter for a Ruby project'
12
+ s.description = 'A simple line-of-code counter for Ruby projects'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
17
+ s.require_paths = ['lib']
18
+
19
+ s.add_runtime_dependency 'thor'
20
+ s.add_runtime_dependency 'activesupport', '~> 3.0'
21
+
22
+ s.add_development_dependency 'rake'
23
+ s.add_development_dependency 'pry'
24
+ s.add_development_dependency 'awesome_print'
25
+ s.add_development_dependency 'rspec'
26
+ end
@@ -0,0 +1,7 @@
1
+ First.line
2
+ Second.line
3
+
4
+ Some.new.line
5
+ # a comment
6
+
7
+ More.code # and a comment
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe LOCCounter::FilesCollection do
4
+ before(:each) do
5
+ stub_files
6
+ File.stub(:exists?).and_return(true)
7
+ end
8
+
9
+ describe "#initialize" do
10
+ before(:each) do
11
+ @filename1.stub(:=~).and_return(true)
12
+ @filename2.stub(:=~).and_return(false)
13
+ end
14
+
15
+ it "puts the filtered files list to @files" do
16
+ collection = LOCCounter::FilesCollection.new(@filenames)
17
+ collection.files.should == [@file1]
18
+ end
19
+ end
20
+
21
+ describe "#counts" do
22
+ before(:each) do
23
+ @file1_counts = {
24
+ :total => 5,
25
+ :empty => 0,
26
+ :comments => 1,
27
+ :code => 4
28
+ }
29
+ @file1.stub(:counts => @file1_counts)
30
+
31
+ @file2_counts = {
32
+ :total => 8,
33
+ :empty => 1,
34
+ :comments => 2,
35
+ :code => 5
36
+ }
37
+ @file2.stub(:counts => @file2_counts)
38
+ end
39
+
40
+ it "sums line counts from all files and returns them in a hash" do
41
+ collection = LOCCounter::FilesCollection.new(@filenames)
42
+ collection.instance_variable_set(:@files, @files)
43
+ counts = collection.counts
44
+
45
+ counts[:total].should == @file1_counts[:total] + @file2_counts[:total]
46
+ counts[:empty].should == @file1_counts[:empty] + @file2_counts[:empty]
47
+ counts[:comments].should == @file1_counts[:comments] + @file2_counts[:comments]
48
+ counts[:code].should == @file1_counts[:code] + @file2_counts[:code]
49
+ counts[:files].should == @files.count
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe LOCCounter::Project do
4
+ before(:each) do
5
+ stub_files
6
+ @dir_path = '/path/to/project'
7
+ end
8
+
9
+ describe "#initialize" do
10
+ context "with a non-existent directory" do
11
+ it "raises an ArgumentError" do
12
+ expect {
13
+ LOCCounter::Project.new('foo')
14
+ }.to raise_error(ArgumentError)
15
+ end
16
+ end
17
+
18
+ context "with an existing directory" do
19
+ before(:each) do
20
+ File.stub(:exists?).and_return(true)
21
+ Dir.stub(:glob).and_return(@filenames)
22
+ end
23
+
24
+ it "puts the files list from Dir.glob to @files" do
25
+ Dir.should_receive(:glob).with(@dir_path + '/' + LOCCounter::Project::SOURCE_FILES.first)
26
+ project = LOCCounter::Project.new(@dir_path)
27
+ project.files.should == [@file1, @file2] * LOCCounter::Project::SOURCE_FILES.count
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe LOCCounter::SourceFile do
4
+ before(:each) do
5
+ path = File.expand_path('../../fixtures/test.rb', __FILE__)
6
+ @file = LOCCounter::SourceFile.new(path)
7
+ end
8
+
9
+ describe "#initialize" do
10
+ before(:each) do
11
+ @filename = stub("Filename")
12
+ @lines = stub("Source lines")
13
+ File.stub(:readlines).and_return(@lines)
14
+ end
15
+
16
+ context "with a non-existent file" do
17
+ it "raises an ArgumentError" do
18
+ expect {
19
+ LOCCounter::SourceFile.new('foo')
20
+ }.to raise_error(ArgumentError)
21
+ end
22
+ end
23
+
24
+ context "with an existing file" do
25
+ before(:each) do
26
+ File.stub(:exists?).and_return(true)
27
+ end
28
+
29
+ it "puts the result of File.readlines to @lines" do
30
+ File.should_receive(:readlines).with(@filename)
31
+ file = LOCCounter::SourceFile.new(@filename)
32
+ file.lines.should == @lines
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#counts" do
38
+ before(:each) do
39
+ @counts = @file.counts
40
+ @lines = @file.lines
41
+ end
42
+
43
+ describe "[:total]" do
44
+ it "returns total lines count" do
45
+ @counts[:total].should == @lines.count
46
+ end
47
+ end
48
+
49
+ describe "[:empty]" do
50
+ it "returns a number of empty lines" do
51
+ empty_lines = @lines.find_all do |line|
52
+ line =~ LOCCounter::SourceFile::EMPTY_PATTERN
53
+ end
54
+
55
+ @counts[:empty].should == empty_lines.count
56
+ end
57
+ end
58
+
59
+ describe "[:comments]" do
60
+ it "returns a number of lines containing just a comment" do
61
+ comments_lines = @lines.find_all do |line|
62
+ line =~ LOCCounter::SourceFile::COMMENT_PATTERN
63
+ end
64
+
65
+ @counts[:comments].should == comments_lines.count
66
+ end
67
+ end
68
+
69
+ describe "[:code]" do
70
+ it "returns a number of lines containing any code" do
71
+ code_lines = @lines.reject do |line|
72
+ line =~ LOCCounter::SourceFile::EMPTY_PATTERN || line =~ LOCCounter::SourceFile::COMMENT_PATTERN
73
+ end
74
+
75
+ @counts[:code].should == code_lines.count
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe LOCCounter do
4
+
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'loc_counter'
2
+
3
+ support_dir = File.expand_path('../support', __FILE__)
4
+ Dir.glob("#{support_dir}/**/*.rb").each { |file| require file }
5
+
6
+ RSpec.configure do |config|
7
+ config.include FilesCollectionHelpers
8
+ end
@@ -0,0 +1,19 @@
1
+ module FilesCollectionHelpers
2
+ # setting filenames, files and LOCCounter::SourceFile.new
3
+ def stub_files
4
+ @filename1 = stub("First file name")
5
+ @filename2 = stub("Second file name")
6
+ @filenames = [@filename1, @filename2]
7
+
8
+ @file1 = stub("LOCCounter::SourceFile instance for filename1")
9
+ @file2 = stub("LOCCounter::SourceFile instance for filename2")
10
+ @files = [@file1, @file2]
11
+
12
+ LOCCounter::SourceFile.stub(:new) do |filename|
13
+ case filename
14
+ when @filename1 then @file1
15
+ when @filename2 then @file2
16
+ end
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loc_counter
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vsevolod Romashov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &70252920255280 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70252920255280
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &70252920277240 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70252920277240
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70252920276760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70252920276760
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry
49
+ requirement: &70252920276020 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70252920276020
58
+ - !ruby/object:Gem::Dependency
59
+ name: awesome_print
60
+ requirement: &70252920274440 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70252920274440
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: &70252920273520 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70252920273520
80
+ description: A simple line-of-code counter for Ruby projects
81
+ email:
82
+ - 7@7vn.ru
83
+ executables:
84
+ - loc_counter
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - Gemfile
90
+ - README.md
91
+ - Rakefile
92
+ - bin/loc_counter
93
+ - lib/loc_counter.rb
94
+ - lib/loc_counter/files_collection.rb
95
+ - lib/loc_counter/project.rb
96
+ - lib/loc_counter/source_file.rb
97
+ - lib/loc_counter/version.rb
98
+ - loc_counter.gemspec
99
+ - spec/fixtures/test.rb
100
+ - spec/loc_counter/files_collection_spec.rb
101
+ - spec/loc_counter/project_spec.rb
102
+ - spec/loc_counter/source_file_spec.rb
103
+ - spec/loc_counter_spec.rb
104
+ - spec/spec_helper.rb
105
+ - spec/support/files_collection_helpers.rb
106
+ homepage: ''
107
+ licenses: []
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ segments:
119
+ - 0
120
+ hash: 2459367167302849776
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ segments:
128
+ - 0
129
+ hash: 2459367167302849776
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.10
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: CLI LOC counter for a Ruby project
136
+ test_files:
137
+ - spec/fixtures/test.rb
138
+ - spec/loc_counter/files_collection_spec.rb
139
+ - spec/loc_counter/project_spec.rb
140
+ - spec/loc_counter/source_file_spec.rb
141
+ - spec/loc_counter_spec.rb
142
+ - spec/spec_helper.rb
143
+ - spec/support/files_collection_helpers.rb