flog 1.0.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.
Files changed (6) hide show
  1. data/History.txt +5 -0
  2. data/Manifest.txt +5 -0
  3. data/README.txt +57 -0
  4. data/Rakefile +15 -0
  5. data/bin/flog +211 -0
  6. metadata +61 -0
@@ -0,0 +1,5 @@
1
+ == 1.0.0 / 2007-08-01
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
5
+
@@ -0,0 +1,5 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/flog
@@ -0,0 +1,57 @@
1
+ flog
2
+ by Ryan Davis, Seattle.rb
3
+ http://seattlerb.rubyforge.org/
4
+ http://rubyforge.org/projects/seattlerb
5
+
6
+ == DESCRIPTION:
7
+
8
+ Flog reports the most tortured code in an easy to read pain
9
+ report. The higher the score, the more pain the code is in.
10
+
11
+ == FEATURES/PROBLEMS:
12
+
13
+ * Rough around the edges.
14
+
15
+ == SYNOPSIS:
16
+
17
+ % ./bin/flog bin/flog
18
+ Total score = 128.7
19
+
20
+ Flog#report: (21)
21
+ 4: puts
22
+ 2: sort_by
23
+ ...
24
+
25
+ == REQUIREMENTS:
26
+
27
+ * ruby2ruby
28
+ * parse_tree
29
+
30
+ == INSTALL:
31
+
32
+ * sudo gem install -y flog
33
+
34
+ == LICENSE:
35
+
36
+ (The MIT License)
37
+
38
+ Copyright (c) 2007 Ryan Davis, Seattle.rb
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining
41
+ a copy of this software and associated documentation files (the
42
+ 'Software'), to deal in the Software without restriction, including
43
+ without limitation the rights to use, copy, modify, merge, publish,
44
+ distribute, sublicense, and/or sell copies of the Software, and to
45
+ permit persons to whom the Software is furnished to do so, subject to
46
+ the following conditions:
47
+
48
+ The above copyright notice and this permission notice shall be
49
+ included in all copies or substantial portions of the Software.
50
+
51
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
52
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
53
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
54
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
55
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
56
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
57
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ load './bin/flog'
6
+
7
+ Hoe.new('flog', Flog::VERSION) do |p|
8
+ p.rubyforge_name = 'seattlerb'
9
+ p.summary = p.paragraphs_of('README.txt', 2).first
10
+ p.description = p.paragraphs_of('README.txt', 2, 6).join("\n\n")
11
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/).last.strip
12
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
13
+ end
14
+
15
+ # vim: syntax=Ruby
@@ -0,0 +1,211 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'rubygems'
4
+ require 'parse_tree'
5
+ require 'sexp_processor'
6
+ require 'unified_ruby'
7
+
8
+ class Flog < SexpProcessor
9
+ VERSION = '1.0.0'
10
+
11
+ include UnifiedRuby
12
+
13
+ THRESHOLD = 0.60
14
+
15
+ SCORES = Hash.new(1)
16
+
17
+ SCORES.merge!(:define_method => 5,
18
+ :eval => 5,
19
+ :module_eval => 5,
20
+ :class_eval => 5,
21
+ :instance_eval => 5)
22
+
23
+ SCORES.merge!(:alias_method => 2,
24
+ :include => 2,
25
+ :extend => 2,
26
+ :instance_method => 2,
27
+ :instance_methods => 2,
28
+ :method_added => 2,
29
+ :method_defined? => 2,
30
+ :method_removed => 2,
31
+ :method_undefined => 2,
32
+ :private_class_method => 2,
33
+ :private_instance_methods => 2,
34
+ :private_method_defined? => 2,
35
+ :protected_instance_methods => 2,
36
+ :protected_method_defined? => 2,
37
+ :public_class_method => 2,
38
+ :public_instance_methods => 2,
39
+ :public_method_defined? => 2,
40
+ :remove_method => 2,
41
+ :undef_method => 2)
42
+
43
+ @@no_class = :none
44
+ @@no_method = :none
45
+
46
+ def initialize
47
+ super
48
+ @pt = ParseTree.new(false)
49
+ @klass_name, @method_name = @@no_class, @@no_method
50
+ self.auto_shift_type = true
51
+ self.require_empty = false # HACK
52
+ @totals = Hash.new 0
53
+ @multiplier = 1.0
54
+
55
+ @calls = Hash.new { |h,k| h[k] = Hash.new 0 }
56
+ end
57
+
58
+ def process_files *files
59
+ files.flatten.each do |file|
60
+ next unless File.file? file or file == "-"
61
+ ruby = file == "-" ? $stdin.read : File.read(file)
62
+ sexp = @pt.parse_tree_for_string(ruby, file)
63
+ process Sexp.from_array(sexp)
64
+ end
65
+ end
66
+
67
+ def report
68
+ total_score = @totals.values.inject(0) { |sum,n| sum + n }
69
+ max = total_score * THRESHOLD
70
+ current = 0
71
+
72
+ puts "Total score = #{total_score}"
73
+ puts
74
+
75
+ @calls.sort_by { |k,v| -@totals[k] }.each do |klass_method, calls|
76
+ total = @totals[klass_method]
77
+ puts "%s: (%d)" % [klass_method, total]
78
+ calls.sort_by { |k,v| -v }.each do |call, count|
79
+ puts " %4d: %s" % [count, call]
80
+ end
81
+
82
+ current += total
83
+ break if current >= max
84
+ end
85
+ rescue
86
+ # do nothing
87
+ end
88
+
89
+ def add_to_score(name, score)
90
+ @totals["#{@klass_name}##{@method_name}"] += score * @multiplier
91
+ @calls["#{@klass_name}##{@method_name}"][name] += score * @multiplier
92
+ end
93
+
94
+ def bad_dog! bonus
95
+ @multiplier += bonus
96
+ yield
97
+ @multiplier -= bonus
98
+ end
99
+
100
+ ############################################################
101
+ # Process Methods:
102
+
103
+ def process_alias(exp)
104
+ process exp.shift
105
+ process exp.shift
106
+ add_to_score :alias, 2
107
+ s()
108
+ end
109
+
110
+ # [:block_pass, [:lit, :blah], [:fcall, :foo]]
111
+ def process_block_pass(exp)
112
+ arg = exp.shift
113
+ call = exp.shift
114
+
115
+ case arg.first
116
+ when :iter then
117
+ add_to_score :to_proc_iter_wtf?, 6
118
+ when :lit, :call, :iter then
119
+ add_to_score :to_proc, 3
120
+ when :lvar, :dvar, :ivar, :nil then
121
+ # do nothing
122
+ else
123
+ raise({:block_pass => [call, arg]}.inspect)
124
+ end
125
+
126
+ call = process call
127
+ s()
128
+ end
129
+
130
+ def process_call(exp)
131
+ bad_dog! 0.2 do
132
+ recv = process exp.shift
133
+ end
134
+ name = exp.shift
135
+ bad_dog! 0.2 do
136
+ args = process exp.shift
137
+ end
138
+
139
+ score = SCORES[name]
140
+ add_to_score name, score
141
+
142
+ s()
143
+ end
144
+
145
+ def process_class(exp)
146
+ @klass_name = exp.shift
147
+ bad_dog! 1.0 do
148
+ supr = process exp.shift
149
+ end
150
+ until exp.empty?
151
+ process exp.shift
152
+ end
153
+ @klass_name = @@no_class
154
+ s()
155
+ end
156
+
157
+ def process_defn(exp)
158
+ @method_name = exp.shift
159
+ process exp.shift until exp.empty?
160
+ @method_name = @@no_method
161
+ s()
162
+ end
163
+
164
+ def process_defs(exp)
165
+ process exp.shift
166
+ @method_name = exp.shift
167
+ process exp.shift until exp.empty?
168
+ @method_name = @@no_method
169
+ s()
170
+ end
171
+
172
+ def process_lit(exp)
173
+ value = exp.shift
174
+ case value
175
+ when 0, -1 then
176
+ # ignore those because they're used as array indicies instead of first/last
177
+ when Integer then
178
+ add_to_score :lit_fixnum, 0.25
179
+ when Float, Symbol, Regexp, Range then
180
+ # do nothing
181
+ else
182
+ raise value.inspect
183
+ end
184
+ s()
185
+ end
186
+
187
+ def process_module(exp)
188
+ @klass_name = exp.shift
189
+ until exp.empty?
190
+ process exp.shift
191
+ end
192
+ @klass_name = @@no_class
193
+ s()
194
+ end
195
+
196
+ def process_sclass(exp)
197
+ bad_dog! 0.5 do
198
+ recv = process exp.shift
199
+ process exp.shift until exp.empty?
200
+ end
201
+
202
+ add_to_score :sclass, 5
203
+ s()
204
+ end
205
+ end
206
+
207
+ if $0 == __FILE__ then
208
+ flogger = Flog.new
209
+ flogger.process_files ARGV
210
+ flogger.report
211
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: flog
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2007-08-01 00:00:00 -07:00
8
+ summary: Flog reports the most tortured code in an easy to read pain report. The higher the score, the more pain the code is in.
9
+ require_paths:
10
+ - lib
11
+ email: ryand-ruby@zenspider.com
12
+ homepage: http://rubyforge.org/projects/seattlerb
13
+ rubyforge_project: seattlerb
14
+ description: "Flog reports the most tortured code in an easy to read pain report. The higher the score, the more pain the code is in. % ./bin/flog bin/flog Total score = 128.7 Flog#report: (21) 4: puts 2: sort_by ..."
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Ryan Davis
31
+ files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - Rakefile
36
+ - bin/flog
37
+ test_files: []
38
+
39
+ rdoc_options:
40
+ - --main
41
+ - README.txt
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.txt
46
+ executables:
47
+ - flog
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies:
53
+ - !ruby/object:Gem::Dependency
54
+ name: hoe
55
+ version_requirement:
56
+ version_requirements: !ruby/object:Gem::Version::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.2.2
61
+ version: