rails_stats 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rails_stats.gemspec
4
+ gemspec
5
+
6
+ gem 'debugger'
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,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -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