rails_stats 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/Rakefile +2 -0
- data/lib/rails_stats/app_statistics.rb +61 -0
- data/lib/rails_stats/code_statistics.rb +160 -0
- data/lib/rails_stats/code_statistics_calculator.rb +89 -0
- data/lib/rails_stats/cucumber_statistics.rb +46 -0
- data/lib/rails_stats/gem_statistics.rb +31 -0
- data/lib/rails_stats/inflector.rb +605 -0
- data/lib/rails_stats/rake.rb +37 -0
- data/lib/rails_stats/root_statistics.rb +42 -0
- data/lib/rails_stats/spec_statistics.rb +74 -0
- data/lib/rails_stats/util.rb +97 -0
- data/lib/rails_stats/version.rb +3 -0
- data/lib/rails_stats.rb +20 -0
- data/rails_stats.gemspec +24 -0
- data/stats.thor +8 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 944d0c8334fdcb76cec1a8f46b4df162318e79a8
|
4
|
+
data.tar.gz: 937553b382a844f1eaf2e7aade385ba8440ec1b6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8ab477ff73f0e87134f71761397358388fb10947f8afad91da6ddc828c235eaf872116097be0747273a3c40d441808528e507c6e7814a89b5ea9da9702db832d
|
7
|
+
data.tar.gz: 5803869bde15c3d38e2e41b6f1f279dc4993187cfe77e2d4148f67093b6b82fceab9e966e895e2ce0a874b1e80dbeb43b0084c555e34f868808257d97e4d4b81
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 TODO: Write your name
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# RailsStats
|
2
|
+
|
3
|
+
See stuff about a Rails app.
|
4
|
+
|
5
|
+
```bash
|
6
|
+
$ bundle exec thor stats:calculate ~/path/to/app/
|
7
|
+
|
8
|
+
Directory: ~/path/to/app/
|
9
|
+
|
10
|
+
+----------------------+-------+-------+---------+---------+-----+-------+
|
11
|
+
| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
|
12
|
+
+----------------------+-------+-------+---------+---------+-----+-------+
|
13
|
+
| Controllers | 1848 | 1483 | 32 | 174 | 5 | 6 |
|
14
|
+
| Helpers | 2257 | 1892 | 45 | 245 | 5 | 5 |
|
15
|
+
| Jobs | 399 | 295 | 11 | 33 | 3 | 6 |
|
16
|
+
| Models | 4584 | 3509 | 61 | 526 | 8 | 4 |
|
17
|
+
| Observers | 42 | 22 | 2 | 5 | 2 | 2 |
|
18
|
+
| Libraries | 2987 | 2272 | 30 | 287 | 9 | 5 |
|
19
|
+
| Configuration | 1233 | 669 | 4 | 17 | 4 | 37 |
|
20
|
+
| Spec Support | 1416 | 1152 | 4 | 30 | 7 | 36 |
|
21
|
+
| Integration Tests | 91 | 73 | 0 | 1 | 0 | 71 |
|
22
|
+
| Lib Tests | 101 | 83 | 0 | 1 | 0 | 81 |
|
23
|
+
| Model Tests | 3397 | 2522 | 0 | 18 | 0 | 138 |
|
24
|
+
| Cucumber Support | 739 | 521 | 0 | 1 | 0 | 519 |
|
25
|
+
| Cucumber Features | 2711 | 2487 | 29 | 145 | 5 | 15 |
|
26
|
+
+----------------------+-------+-------+---------+---------+-----+-------+
|
27
|
+
| Total | 21805 | 16980 | 218 | 1483 | 6 | 9 |
|
28
|
+
+----------------------+-------+-------+---------+---------+-----+-------+
|
29
|
+
Code LOC: 10142 Test LOC: 6838 Code to Test Ratio: 1:0.7
|
30
|
+
|
31
|
+
```
|
32
|
+
|
33
|
+
### TODO
|
34
|
+
|
35
|
+
* option to print out by app directory (stats per engine)
|
36
|
+
* Add views (jbuilder, erb, haml) but don't count towards ratios
|
37
|
+
* Support JS for projects that have it in public
|
38
|
+
* Add css but don't count towards ratios
|
39
|
+
* output other metrics like number of tables and columns
|
40
|
+
* test unit support
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module RailsStats
|
2
|
+
class AppStatistics
|
3
|
+
attr_reader :statistics, :total, :test
|
4
|
+
|
5
|
+
def initialize(directory)
|
6
|
+
@test = false
|
7
|
+
@directory = directory
|
8
|
+
@statistics = calculate_statistics
|
9
|
+
@total = calculate_total
|
10
|
+
end
|
11
|
+
|
12
|
+
def key_concepts
|
13
|
+
directories.collect{ |path| File.basename(path) }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def calculate_total
|
19
|
+
out = CodeStatisticsCalculator.new
|
20
|
+
@statistics.each do |key, stats|
|
21
|
+
out.add(stats)
|
22
|
+
end
|
23
|
+
out
|
24
|
+
end
|
25
|
+
|
26
|
+
def calculate_statistics
|
27
|
+
Util.calculate_statistics(directories)
|
28
|
+
end
|
29
|
+
|
30
|
+
def directories
|
31
|
+
return @directories if @directories
|
32
|
+
out = []
|
33
|
+
Dir.foreach(@directory) do |file_name|
|
34
|
+
path = File.join(@directory, file_name)
|
35
|
+
next unless File.directory?(path)
|
36
|
+
next if (/^\./ =~ file_name)
|
37
|
+
next if file_name == "assets" # doing separately
|
38
|
+
next if file_name == "views" # TODO
|
39
|
+
out << path
|
40
|
+
end
|
41
|
+
|
42
|
+
assets = File.join(@directory, "assets")
|
43
|
+
if File.directory?(assets)
|
44
|
+
Dir.foreach(assets) do |file_name|
|
45
|
+
path = File.join(assets, file_name)
|
46
|
+
next unless File.directory?(path)
|
47
|
+
next if (/^\./ =~ file_name)
|
48
|
+
|
49
|
+
case file_name
|
50
|
+
when "javascripts"
|
51
|
+
out << path
|
52
|
+
# TODO when "css"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
out
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# railties/lib/rails/code_statistics.rb
|
2
|
+
|
3
|
+
module RailsStats
|
4
|
+
class CodeStatistics
|
5
|
+
|
6
|
+
RAILS_APP_FOLDERS = ['models',
|
7
|
+
'controllers',
|
8
|
+
'helpers',
|
9
|
+
'mailers',
|
10
|
+
'views',
|
11
|
+
'assets']
|
12
|
+
|
13
|
+
def initialize(root_directory)
|
14
|
+
@root_directory = root_directory
|
15
|
+
@key_concepts = calculate_key_concepts
|
16
|
+
@projects = calculate_projects
|
17
|
+
@statistics = calculate_statistics
|
18
|
+
@total = calculate_total
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
print_header
|
23
|
+
@statistics.each { |key, stats| print_line(key, stats) }
|
24
|
+
print_splitter
|
25
|
+
|
26
|
+
if @total
|
27
|
+
print_line("Total", @total)
|
28
|
+
print_splitter
|
29
|
+
end
|
30
|
+
|
31
|
+
print_code_test_stats
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def calculate_key_concepts
|
36
|
+
# returns names of main things like models, controllers, services, etc
|
37
|
+
concepts = {}
|
38
|
+
app_projects.each do |project|
|
39
|
+
project.key_concepts.each do |key|
|
40
|
+
concepts[key] = true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# TODO: maybe gem names?
|
45
|
+
|
46
|
+
concepts.keys
|
47
|
+
end
|
48
|
+
|
49
|
+
def calculate_projects
|
50
|
+
out = []
|
51
|
+
out += app_projects
|
52
|
+
out += calculate_root_projects
|
53
|
+
out += calculate_gem_projects
|
54
|
+
out += calculate_spec_projects
|
55
|
+
out += calculate_test_projects
|
56
|
+
out += calculate_cucumber_projects
|
57
|
+
out
|
58
|
+
end
|
59
|
+
|
60
|
+
def app_projects
|
61
|
+
@app_projects ||= calculate_app_projects
|
62
|
+
end
|
63
|
+
|
64
|
+
def calculate_app_projects
|
65
|
+
apps = Util.calculate_projects(@root_directory, "**", "app", RAILS_APP_FOLDERS)
|
66
|
+
apps.collect do |root_path|
|
67
|
+
AppStatistics.new(root_path)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def calculate_gem_projects
|
72
|
+
gems = Util.calculate_projects(@root_directory, "**", "*.gemspec")
|
73
|
+
gems.collect do |root_path|
|
74
|
+
GemStatistics.new(root_path)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def calculate_spec_projects
|
79
|
+
specs = Util.calculate_projects(@root_directory, "**", "spec", "spec_helper.rb")
|
80
|
+
specs.collect do |root_path|
|
81
|
+
SpecStatistics.new(root_path, @key_concepts)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def calculate_test_projects
|
86
|
+
[] # TODO: test unit
|
87
|
+
end
|
88
|
+
|
89
|
+
def calculate_root_projects
|
90
|
+
[RootStatistics.new(@root_directory)]
|
91
|
+
end
|
92
|
+
|
93
|
+
def calculate_cucumber_projects
|
94
|
+
cukes = Util.calculate_projects(@root_directory, "**", "*.feature")
|
95
|
+
cukes.collect do |root_path|
|
96
|
+
CucumberStatistics.new(root_path)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def calculate_statistics
|
101
|
+
out = {}
|
102
|
+
@projects.each do |project|
|
103
|
+
project.statistics.each do |key, stats|
|
104
|
+
out[key] ||= CodeStatisticsCalculator.new(project.test)
|
105
|
+
out[key].add(stats)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
out
|
109
|
+
end
|
110
|
+
|
111
|
+
def calculate_total
|
112
|
+
@statistics.each_with_object(CodeStatisticsCalculator.new) do |pair, total|
|
113
|
+
total.add(pair.last)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def calculate_code
|
118
|
+
code_loc = 0
|
119
|
+
@statistics.each { |k, v| code_loc += v.code_lines unless v.test }
|
120
|
+
code_loc
|
121
|
+
end
|
122
|
+
|
123
|
+
def calculate_tests
|
124
|
+
test_loc = 0
|
125
|
+
@statistics.each { |k, v| test_loc += v.code_lines if v.test }
|
126
|
+
test_loc
|
127
|
+
end
|
128
|
+
|
129
|
+
def print_header
|
130
|
+
print_splitter
|
131
|
+
puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
|
132
|
+
print_splitter
|
133
|
+
end
|
134
|
+
|
135
|
+
def print_splitter
|
136
|
+
puts "+----------------------+-------+-------+---------+---------+-----+-------+"
|
137
|
+
end
|
138
|
+
|
139
|
+
def print_line(name, statistics)
|
140
|
+
m_over_c = (statistics.methods / statistics.classes) rescue m_over_c = 0
|
141
|
+
loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue loc_over_m = 0
|
142
|
+
|
143
|
+
puts "| #{name.ljust(20)} " \
|
144
|
+
"| #{statistics.lines.to_s.rjust(5)} " \
|
145
|
+
"| #{statistics.code_lines.to_s.rjust(5)} " \
|
146
|
+
"| #{statistics.classes.to_s.rjust(7)} " \
|
147
|
+
"| #{statistics.methods.to_s.rjust(7)} " \
|
148
|
+
"| #{m_over_c.to_s.rjust(3)} " \
|
149
|
+
"| #{loc_over_m.to_s.rjust(5)} |"
|
150
|
+
end
|
151
|
+
|
152
|
+
def print_code_test_stats
|
153
|
+
code = calculate_code
|
154
|
+
tests = calculate_tests
|
155
|
+
|
156
|
+
puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
|
157
|
+
puts ""
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# railties/lib/rails/code_statistics_calculator.rb
|
2
|
+
|
3
|
+
module RailsStats
|
4
|
+
class CodeStatisticsCalculator #:nodoc:
|
5
|
+
attr_reader :lines, :code_lines, :classes, :methods, :test
|
6
|
+
|
7
|
+
PATTERNS = {
|
8
|
+
rb: {
|
9
|
+
line_comment: /^\s*#/,
|
10
|
+
begin_block_comment: /^=begin/,
|
11
|
+
end_block_comment: /^=end/,
|
12
|
+
class: /^\s*class\s+[_A-Z]/,
|
13
|
+
method: /^\s*def\s+[_a-z]/,
|
14
|
+
},
|
15
|
+
js: {
|
16
|
+
line_comment: %r{^\s*//},
|
17
|
+
begin_block_comment: %r{^\s*/\*},
|
18
|
+
end_block_comment: %r{\*/},
|
19
|
+
method: /function(\s+[_a-zA-Z][\da-zA-Z]*)?\s*\(/,
|
20
|
+
},
|
21
|
+
coffee: {
|
22
|
+
line_comment: /^\s*#/,
|
23
|
+
begin_block_comment: /^\s*###/,
|
24
|
+
end_block_comment: /^\s*###/,
|
25
|
+
class: /^\s*class\s+[_A-Z]/,
|
26
|
+
method: /[-=]>/,
|
27
|
+
},
|
28
|
+
feature: {
|
29
|
+
class: /^\s*Feature:/,
|
30
|
+
method: /^\s*Scenario:/,
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
def initialize(test=false)
|
35
|
+
@test = test
|
36
|
+
@lines = 0
|
37
|
+
@code_lines = 0
|
38
|
+
@classes = 0
|
39
|
+
@methods = 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def add(code_statistics_calculator)
|
43
|
+
@lines += code_statistics_calculator.lines
|
44
|
+
@code_lines += code_statistics_calculator.code_lines
|
45
|
+
@classes += code_statistics_calculator.classes
|
46
|
+
@methods += code_statistics_calculator.methods
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_by_file_path(file_path)
|
50
|
+
File.open(file_path) do |f|
|
51
|
+
self.add_by_io(f, file_type(file_path))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_by_io(io, file_type)
|
56
|
+
patterns = PATTERNS[file_type] || {}
|
57
|
+
|
58
|
+
comment_started = false
|
59
|
+
|
60
|
+
while line = io.gets
|
61
|
+
@lines += 1
|
62
|
+
|
63
|
+
if comment_started
|
64
|
+
if patterns[:end_block_comment] && line =~ patterns[:end_block_comment]
|
65
|
+
comment_started = false
|
66
|
+
end
|
67
|
+
next
|
68
|
+
else
|
69
|
+
if patterns[:begin_block_comment] && line =~ patterns[:begin_block_comment]
|
70
|
+
comment_started = true
|
71
|
+
next
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@classes += 1 if patterns[:class] && line =~ patterns[:class]
|
76
|
+
@methods += 1 if patterns[:method] && line =~ patterns[:method]
|
77
|
+
if line !~ /^\s*$/ && (patterns[:line_comment].nil? || line !~ patterns[:line_comment])
|
78
|
+
@code_lines += 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
def file_type(file_path)
|
85
|
+
File.extname(file_path).sub(/\A\./, '').downcase.to_sym
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RailsStats
|
2
|
+
class CucumberStatistics
|
3
|
+
attr_reader :statistics, :total, :test
|
4
|
+
|
5
|
+
def initialize(directory)
|
6
|
+
@test = true
|
7
|
+
@directory = directory
|
8
|
+
@statistics = calculate_statistics
|
9
|
+
@total = calculate_total
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def calculate_total
|
15
|
+
out = CodeStatisticsCalculator.new(true)
|
16
|
+
@statistics.each do |key, stats|
|
17
|
+
out.add(stats)
|
18
|
+
end
|
19
|
+
out
|
20
|
+
end
|
21
|
+
|
22
|
+
def calculate_statistics
|
23
|
+
out = {}
|
24
|
+
categorize_files.each do |key, list|
|
25
|
+
out[key] = Util.calculate_file_statistics(list)
|
26
|
+
end
|
27
|
+
out
|
28
|
+
end
|
29
|
+
|
30
|
+
def categorize_files
|
31
|
+
out = {}
|
32
|
+
Dir[File.join(@directory, "**", "*.rb")].each do |file_path|
|
33
|
+
out["Cucumber Support"] ||= []
|
34
|
+
out["Cucumber Support"] << file_path
|
35
|
+
end
|
36
|
+
|
37
|
+
Dir[File.join(@directory, "**", "*.feature")].each do |file_path|
|
38
|
+
out["Cucumber Features"] ||= []
|
39
|
+
out["Cucumber Features"] << file_path
|
40
|
+
end
|
41
|
+
|
42
|
+
out
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RailsStats
|
2
|
+
class GemStatistics
|
3
|
+
attr_reader :statistics, :total, :test
|
4
|
+
|
5
|
+
def initialize(directory)
|
6
|
+
@test = false
|
7
|
+
@directory = directory
|
8
|
+
@statistics = calculate_statistics
|
9
|
+
@total = calculate_total
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def calculate_total
|
15
|
+
out = CodeStatisticsCalculator.new
|
16
|
+
@statistics.each do |key, stats|
|
17
|
+
out.add(stats)
|
18
|
+
end
|
19
|
+
out
|
20
|
+
end
|
21
|
+
|
22
|
+
def calculate_statistics
|
23
|
+
# ignore gem/app so as to not double-count engines
|
24
|
+
lib = File.join(@directory, "lib")
|
25
|
+
Util.calculate_statistics([lib]) do |path|
|
26
|
+
"Gems"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|