self-flagellation 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.
- data/History.txt +4 -0
- data/Manifest.txt +19 -0
- data/README.txt +53 -0
- data/Rakefile +18 -0
- data/bin/flagellate +32 -0
- data/lib/self-flagellation.rb +56 -0
- data/lib/self-flagellation/flagellate.rb +491 -0
- data/tasks/ann.rake +81 -0
- data/tasks/bones.rake +21 -0
- data/tasks/gem.rake +121 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/notes.rake +28 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +266 -0
- data/tasks/spec.rake +55 -0
- data/tasks/svn.rake +48 -0
- data/tasks/test.rake +38 -0
- metadata +74 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/flagellate
|
6
|
+
lib/self-flagellation.rb
|
7
|
+
lib/self-flagellation/flagellate.rb
|
8
|
+
tasks/ann.rake
|
9
|
+
tasks/bones.rake
|
10
|
+
tasks/gem.rake
|
11
|
+
tasks/manifest.rake
|
12
|
+
tasks/notes.rake
|
13
|
+
tasks/post_load.rake
|
14
|
+
tasks/rdoc.rake
|
15
|
+
tasks/rubyforge.rake
|
16
|
+
tasks/setup.rb
|
17
|
+
tasks/spec.rake
|
18
|
+
tasks/svn.rake
|
19
|
+
tasks/test.rake
|
data/README.txt
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
self-flagellation
|
2
|
+
by Ben Scofield
|
3
|
+
http://github.com/bscofield/self-flagellation
|
4
|
+
original flog code
|
5
|
+
by Ryan Davis, Seattle.rb
|
6
|
+
http://ruby.sadi.st/
|
7
|
+
http://rubyforge.org/projects/seattlerb
|
8
|
+
|
9
|
+
== DESCRIPTION:
|
10
|
+
|
11
|
+
Self-flagellation is an addition/extension of Ryan Davis's flog, which
|
12
|
+
allows you to specify a customized set of complexity metrics (instead
|
13
|
+
of just using the defaults built into the gem)
|
14
|
+
|
15
|
+
== FEATURES/PROBLEMS:
|
16
|
+
|
17
|
+
All the features of flog are here, with the addition of a -f option
|
18
|
+
available on the commandline.
|
19
|
+
|
20
|
+
== SYNOPSIS:
|
21
|
+
|
22
|
+
> ./bin/flagellate -f=data/scores.yml bin/flagellate
|
23
|
+
Total Score: xxx
|
24
|
+
|
25
|
+
== INSTALL:
|
26
|
+
|
27
|
+
sudo gem install self-flagellation
|
28
|
+
|
29
|
+
== LICENSE:
|
30
|
+
|
31
|
+
(The MIT License)
|
32
|
+
|
33
|
+
Copyright (c) 2008 Ben Scofield
|
34
|
+
(original flog code Copyright (c) 2007 Ryan Davis)
|
35
|
+
|
36
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
37
|
+
a copy of this software and associated documentation files (the
|
38
|
+
'Software'), to deal in the Software without restriction, including
|
39
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
40
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
41
|
+
permit persons to whom the Software is furnished to do so, subject to
|
42
|
+
the following conditions:
|
43
|
+
|
44
|
+
The above copyright notice and this permission notice shall be
|
45
|
+
included in all copies or substantial portions of the Software.
|
46
|
+
|
47
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
48
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
49
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
50
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
51
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
52
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
53
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
load 'tasks/setup.rb'
|
5
|
+
|
6
|
+
ensure_in_path 'lib'
|
7
|
+
require 'self-flagellation'
|
8
|
+
|
9
|
+
PROJ.version = SelfFlagellation::VERSION
|
10
|
+
PROJ.name = 'self-flagellation'
|
11
|
+
PROJ.authors = 'Ben Scofield'
|
12
|
+
PROJ.email = 'bscofield@gmail.com'
|
13
|
+
PROJ.url = 'http://github.com/bscofield/self-flagellation'
|
14
|
+
PROJ.rubyforge.name = 'viget'
|
15
|
+
|
16
|
+
PROJ.spec.opts << '--color'
|
17
|
+
|
18
|
+
# EOF
|
data/bin/flagellate
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(
|
4
|
+
File.join(File.dirname(__FILE__), '..', 'lib', 'self-flagellation'))
|
5
|
+
|
6
|
+
ARGV.push "-" if ARGV.empty?
|
7
|
+
|
8
|
+
if defined? $h then
|
9
|
+
puts "#{File.basename $0} options dirs_or_files"
|
10
|
+
puts " -a display all flog results, not top 60%"
|
11
|
+
puts " -f=path use complexity scores from YAML file in PATH"
|
12
|
+
puts " -h display help"
|
13
|
+
puts " -I=path extend $LOAD_PATH with path"
|
14
|
+
puts " -s display total score only"
|
15
|
+
puts " -v verbosely display progress and errors"
|
16
|
+
exit 0
|
17
|
+
end
|
18
|
+
|
19
|
+
if defined? $I and String === $I then
|
20
|
+
$I.split(/:/).each do |dir|
|
21
|
+
$: << dir
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
flogger = SelfFlagellation::Flagellate.new
|
26
|
+
|
27
|
+
if defined? $f and String === $f then
|
28
|
+
flogger.reset_scores $f
|
29
|
+
end
|
30
|
+
|
31
|
+
flogger.flog_files ARGV
|
32
|
+
flogger.report
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# $Id$
|
2
|
+
|
3
|
+
# Equivalent to a header guard in C/C++
|
4
|
+
# Used to prevent the class/module from being loaded more than once
|
5
|
+
unless defined? SelfFlagellation
|
6
|
+
|
7
|
+
module SelfFlagellation
|
8
|
+
|
9
|
+
# :stopdoc:
|
10
|
+
VERSION = '1.0.0'
|
11
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
12
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
13
|
+
# :startdoc:
|
14
|
+
|
15
|
+
# Returns the version string for the library.
|
16
|
+
#
|
17
|
+
def self.version
|
18
|
+
VERSION
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the library path for the module. If any arguments are given,
|
22
|
+
# they will be joined to the end of the libray path using
|
23
|
+
# <tt>File.join</tt>.
|
24
|
+
#
|
25
|
+
def self.libpath( *args )
|
26
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, *args)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the lpath for the module. If any arguments are given,
|
30
|
+
# they will be joined to the end of the path using
|
31
|
+
# <tt>File.join</tt>.
|
32
|
+
#
|
33
|
+
def self.path( *args )
|
34
|
+
args.empty? ? PATH : ::File.join(PATH, *args)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Utility method used to rquire all files ending in .rb that lie in the
|
38
|
+
# directory below this file that has the same name as the filename passed
|
39
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
40
|
+
# the _filename_ does not have to be equivalent to the directory.
|
41
|
+
#
|
42
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
43
|
+
dir ||= ::File.basename(fname, '.*')
|
44
|
+
search_me = ::File.expand_path(
|
45
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
46
|
+
|
47
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
48
|
+
end
|
49
|
+
|
50
|
+
end # module SelfFlagellation
|
51
|
+
|
52
|
+
SelfFlagellation.require_all_libs_relative_to __FILE__
|
53
|
+
|
54
|
+
end # unless defined?
|
55
|
+
|
56
|
+
# EOF
|
@@ -0,0 +1,491 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'parse_tree'
|
4
|
+
require 'sexp_processor'
|
5
|
+
require 'unified_ruby'
|
6
|
+
|
7
|
+
$a ||= false
|
8
|
+
$s ||= false
|
9
|
+
$v ||= false
|
10
|
+
|
11
|
+
module SelfFlagellation
|
12
|
+
class Flagellate < SexpProcessor
|
13
|
+
include UnifiedRuby
|
14
|
+
|
15
|
+
THRESHOLD = $a ? 1.0 : 0.60
|
16
|
+
SCORES = Hash.new(1)
|
17
|
+
BRANCHING = [ :and, :case, :else, :if, :or, :rescue, :until, :when, :while ]
|
18
|
+
|
19
|
+
# various non-call constructs
|
20
|
+
OTHER_SCORES = {
|
21
|
+
:alias => 2,
|
22
|
+
:assignment => 1,
|
23
|
+
:block => 1,
|
24
|
+
:branch => 1,
|
25
|
+
:lit_fixnum => 0.25,
|
26
|
+
:sclass => 5,
|
27
|
+
:super => 1,
|
28
|
+
:to_proc_icky! => 10,
|
29
|
+
:to_proc_normal => 5,
|
30
|
+
:yield => 1,
|
31
|
+
}
|
32
|
+
|
33
|
+
# eval forms
|
34
|
+
SCORES.merge!(:define_method => 5,
|
35
|
+
:eval => 5,
|
36
|
+
:module_eval => 5,
|
37
|
+
:class_eval => 5,
|
38
|
+
:instance_eval => 5)
|
39
|
+
|
40
|
+
# various "magic" usually used for "clever code"
|
41
|
+
SCORES.merge!(:alias_method => 2,
|
42
|
+
:extend => 2,
|
43
|
+
:include => 2,
|
44
|
+
:instance_method => 2,
|
45
|
+
:instance_methods => 2,
|
46
|
+
:method_added => 2,
|
47
|
+
:method_defined? => 2,
|
48
|
+
:method_removed => 2,
|
49
|
+
:method_undefined => 2,
|
50
|
+
:private_class_method => 2,
|
51
|
+
:private_instance_methods => 2,
|
52
|
+
:private_method_defined? => 2,
|
53
|
+
:protected_instance_methods => 2,
|
54
|
+
:protected_method_defined? => 2,
|
55
|
+
:public_class_method => 2,
|
56
|
+
:public_instance_methods => 2,
|
57
|
+
:public_method_defined? => 2,
|
58
|
+
:remove_method => 2,
|
59
|
+
:send => 3,
|
60
|
+
:undef_method => 2)
|
61
|
+
|
62
|
+
# calls I don't like and usually see being abused
|
63
|
+
SCORES.merge!(:inject => 2)
|
64
|
+
|
65
|
+
@@no_class = :main
|
66
|
+
@@no_method = :none
|
67
|
+
|
68
|
+
attr_reader :calls
|
69
|
+
|
70
|
+
def initialize
|
71
|
+
super
|
72
|
+
@pt = ParseTree.new(false)
|
73
|
+
@klasses = []
|
74
|
+
@methods = []
|
75
|
+
self.auto_shift_type = true
|
76
|
+
self.require_empty = false # HACK
|
77
|
+
self.reset
|
78
|
+
end
|
79
|
+
|
80
|
+
def reset_scores(path = nil)
|
81
|
+
if path
|
82
|
+
yaml = YAML.load_file(path)
|
83
|
+
@other_scores = yaml['OTHER_SCORES']
|
84
|
+
@scores = Hash.new(1)
|
85
|
+
@scores.merge!(yaml['SCORES'])
|
86
|
+
end
|
87
|
+
rescue
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_to_score(name, score)
|
92
|
+
@calls["#{self.klass_name}##{self.method_name}"][name] += score * @multiplier
|
93
|
+
end
|
94
|
+
|
95
|
+
def bad_dog! bonus
|
96
|
+
@multiplier += bonus
|
97
|
+
yield 42
|
98
|
+
@multiplier -= bonus
|
99
|
+
end
|
100
|
+
|
101
|
+
def bleed exp
|
102
|
+
process exp.shift until exp.empty?
|
103
|
+
end
|
104
|
+
|
105
|
+
def flog_files *files
|
106
|
+
files.flatten.each do |file|
|
107
|
+
if File.directory? file then
|
108
|
+
flog_files Dir["#{file}/**/*.rb"]
|
109
|
+
else
|
110
|
+
warn "** flogging #{file}" if $v
|
111
|
+
ruby = file == "-" ? $stdin.read : File.read(file)
|
112
|
+
begin
|
113
|
+
sexp = @pt.parse_tree_for_string(ruby, file)
|
114
|
+
process Sexp.from_array(sexp).first
|
115
|
+
rescue SyntaxError => e
|
116
|
+
if e.inspect =~ /<%|%>/ then
|
117
|
+
warn e.inspect + " at " + e.backtrace.first(5).join(', ')
|
118
|
+
warn "...stupid lemmings and their bad erb templates... skipping"
|
119
|
+
else
|
120
|
+
raise e
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def klass name
|
128
|
+
@klasses.unshift name
|
129
|
+
yield
|
130
|
+
@klasses.shift
|
131
|
+
end
|
132
|
+
|
133
|
+
def klass_name
|
134
|
+
@klasses.first || @@no_class
|
135
|
+
end
|
136
|
+
|
137
|
+
def method name
|
138
|
+
@methods.unshift name
|
139
|
+
yield
|
140
|
+
@methods.shift
|
141
|
+
end
|
142
|
+
|
143
|
+
def method_name
|
144
|
+
@methods.first || @@no_method
|
145
|
+
end
|
146
|
+
|
147
|
+
def report io = $stdout
|
148
|
+
current = 0
|
149
|
+
total_score = self.total
|
150
|
+
max = total_score * THRESHOLD
|
151
|
+
totals = self.totals
|
152
|
+
|
153
|
+
if $s then
|
154
|
+
io.puts total_score
|
155
|
+
exit 0
|
156
|
+
end
|
157
|
+
|
158
|
+
io.puts "Total score = #{total_score}"
|
159
|
+
io.puts
|
160
|
+
|
161
|
+
@calls.sort_by { |k,v| -totals[k] }.each do |klass_method, calls|
|
162
|
+
total = totals[klass_method]
|
163
|
+
io.puts "%s: (%.1f)" % [klass_method, total]
|
164
|
+
calls.sort_by { |k,v| -v }.each do |call, count|
|
165
|
+
io.puts " %6.1f: %s" % [count, call]
|
166
|
+
end
|
167
|
+
|
168
|
+
current += total
|
169
|
+
break if current >= max
|
170
|
+
end
|
171
|
+
ensure
|
172
|
+
self.reset
|
173
|
+
end
|
174
|
+
|
175
|
+
def reset
|
176
|
+
@totals = @total_score = nil
|
177
|
+
@multiplier = 1.0
|
178
|
+
@calls = Hash.new { |h,k| h[k] = Hash.new 0 }
|
179
|
+
end
|
180
|
+
|
181
|
+
def total
|
182
|
+
self.totals unless @total_score # calculates total_score as well
|
183
|
+
|
184
|
+
@total_score
|
185
|
+
end
|
186
|
+
|
187
|
+
def totals
|
188
|
+
unless @totals then
|
189
|
+
@total_score = 0
|
190
|
+
@totals = Hash.new(0)
|
191
|
+
self.calls.each do |meth, tally|
|
192
|
+
a, b, c = 0, 0, 0
|
193
|
+
tally.each do |cat, score|
|
194
|
+
case cat
|
195
|
+
when :assignment then a += score
|
196
|
+
when :branch then b += score
|
197
|
+
else c += score
|
198
|
+
end
|
199
|
+
end
|
200
|
+
score = Math.sqrt(a*a + b*b + c*c)
|
201
|
+
@totals[meth] = score
|
202
|
+
@total_score += score
|
203
|
+
end
|
204
|
+
end
|
205
|
+
@totals
|
206
|
+
end
|
207
|
+
|
208
|
+
def other_scores
|
209
|
+
@other_scores || OTHER_SCORES
|
210
|
+
end
|
211
|
+
|
212
|
+
def scores
|
213
|
+
@scores || SCORES
|
214
|
+
end
|
215
|
+
|
216
|
+
############################################################
|
217
|
+
# Process Methods:
|
218
|
+
|
219
|
+
def process_alias(exp)
|
220
|
+
process exp.shift
|
221
|
+
process exp.shift
|
222
|
+
add_to_score :alias, other_scores[:alias]
|
223
|
+
s()
|
224
|
+
end
|
225
|
+
|
226
|
+
def process_and(exp)
|
227
|
+
add_to_score :branch, other_scores[:branch]
|
228
|
+
bad_dog! 0.1 do
|
229
|
+
process exp.shift # lhs
|
230
|
+
process exp.shift # rhs
|
231
|
+
end
|
232
|
+
s()
|
233
|
+
end
|
234
|
+
|
235
|
+
def process_attrasgn(exp)
|
236
|
+
add_to_score :assignment, other_scores[:assignment]
|
237
|
+
process exp.shift # lhs
|
238
|
+
exp.shift # name
|
239
|
+
process exp.shift # rhs
|
240
|
+
s()
|
241
|
+
end
|
242
|
+
|
243
|
+
def process_attrset(exp)
|
244
|
+
add_to_score :assignment, other_scores[:assignment]
|
245
|
+
raise exp.inspect
|
246
|
+
s()
|
247
|
+
end
|
248
|
+
|
249
|
+
def process_block(exp)
|
250
|
+
bad_dog! 0.1 do
|
251
|
+
bleed exp
|
252
|
+
end
|
253
|
+
s()
|
254
|
+
end
|
255
|
+
|
256
|
+
# [:block_pass, [:lit, :blah], [:fcall, :foo]]
|
257
|
+
def process_block_pass(exp)
|
258
|
+
arg = exp.shift
|
259
|
+
call = exp.shift
|
260
|
+
|
261
|
+
add_to_score :block_pass, other_scores[:block]
|
262
|
+
|
263
|
+
case arg.first
|
264
|
+
when :lvar, :dvar, :ivar, :cvar, :self, :const, :nil then
|
265
|
+
# do nothing
|
266
|
+
when :lit, :call then
|
267
|
+
add_to_score :to_proc_normal, other_scores[:to_proc_normal]
|
268
|
+
when :iter, *BRANCHING then
|
269
|
+
add_to_score :to_proc_icky!, other_scores[:to_proc_icky!]
|
270
|
+
else
|
271
|
+
raise({:block_pass => [arg, call]}.inspect)
|
272
|
+
end
|
273
|
+
|
274
|
+
process arg
|
275
|
+
process call
|
276
|
+
|
277
|
+
s()
|
278
|
+
end
|
279
|
+
|
280
|
+
def process_call(exp)
|
281
|
+
bad_dog! 0.2 do
|
282
|
+
recv = process exp.shift
|
283
|
+
end
|
284
|
+
name = exp.shift
|
285
|
+
bad_dog! 0.2 do
|
286
|
+
args = process exp.shift
|
287
|
+
end
|
288
|
+
|
289
|
+
score = scores[name]
|
290
|
+
add_to_score name, score
|
291
|
+
|
292
|
+
s()
|
293
|
+
end
|
294
|
+
|
295
|
+
def process_case(exp)
|
296
|
+
add_to_score :branch, other_scores[:branch]
|
297
|
+
process exp.shift # recv
|
298
|
+
bad_dog! 0.1 do
|
299
|
+
bleed exp
|
300
|
+
end
|
301
|
+
s()
|
302
|
+
end
|
303
|
+
|
304
|
+
def process_class(exp)
|
305
|
+
self.klass exp.shift do
|
306
|
+
bad_dog! 1.0 do
|
307
|
+
supr = process exp.shift
|
308
|
+
end
|
309
|
+
bleed exp
|
310
|
+
end
|
311
|
+
s()
|
312
|
+
end
|
313
|
+
|
314
|
+
def process_dasgn_curr(exp)
|
315
|
+
add_to_score :assignment, other_scores[:assignment]
|
316
|
+
exp.shift # name
|
317
|
+
process exp.shift # assigment, if any
|
318
|
+
s()
|
319
|
+
end
|
320
|
+
|
321
|
+
def process_defn(exp)
|
322
|
+
self.method exp.shift do
|
323
|
+
bleed exp
|
324
|
+
end
|
325
|
+
s()
|
326
|
+
end
|
327
|
+
|
328
|
+
def process_defs(exp)
|
329
|
+
process exp.shift
|
330
|
+
self.method exp.shift do
|
331
|
+
bleed exp
|
332
|
+
end
|
333
|
+
s()
|
334
|
+
end
|
335
|
+
|
336
|
+
def process_else(exp)
|
337
|
+
add_to_score :branch, other_scores[:branch]
|
338
|
+
bad_dog! 0.1 do
|
339
|
+
bleed exp
|
340
|
+
end
|
341
|
+
s()
|
342
|
+
end
|
343
|
+
|
344
|
+
def process_iasgn(exp)
|
345
|
+
add_to_score :assignment, other_scores[:assignment]
|
346
|
+
exp.shift # name
|
347
|
+
process exp.shift # rhs
|
348
|
+
s()
|
349
|
+
end
|
350
|
+
|
351
|
+
def process_if(exp)
|
352
|
+
add_to_score :branch, other_scores[:branch]
|
353
|
+
process exp.shift # cond
|
354
|
+
bad_dog! 0.1 do
|
355
|
+
process exp.shift # true
|
356
|
+
process exp.shift # false
|
357
|
+
end
|
358
|
+
s()
|
359
|
+
end
|
360
|
+
|
361
|
+
def process_iter(exp)
|
362
|
+
context = (self.context - [:class, :module, :scope])
|
363
|
+
if context.uniq.sort_by {|s|s.to_s} == [:block, :iter] then
|
364
|
+
recv = exp.first
|
365
|
+
if recv[0] == :call and recv[1] == nil and recv.arglist[1] and [:lit, :str].include? recv.arglist[1][0] then
|
366
|
+
msg = recv[2]
|
367
|
+
submsg = recv.arglist[1][1]
|
368
|
+
self.method submsg do
|
369
|
+
self.klass msg do
|
370
|
+
bleed exp
|
371
|
+
end
|
372
|
+
end
|
373
|
+
return s()
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
add_to_score :branch, other_scores[:branch]
|
378
|
+
|
379
|
+
process exp.shift # no penalty for LHS
|
380
|
+
|
381
|
+
bad_dog! 0.1 do
|
382
|
+
bleed exp
|
383
|
+
end
|
384
|
+
|
385
|
+
s()
|
386
|
+
end
|
387
|
+
|
388
|
+
def process_lasgn(exp)
|
389
|
+
add_to_score :assignment, other_scores[:assignment]
|
390
|
+
exp.shift # name
|
391
|
+
process exp.shift # rhs
|
392
|
+
s()
|
393
|
+
end
|
394
|
+
|
395
|
+
def process_lit(exp)
|
396
|
+
value = exp.shift
|
397
|
+
case value
|
398
|
+
when 0, -1 then
|
399
|
+
# ignore those because they're used as array indicies instead of first/last
|
400
|
+
when Integer then
|
401
|
+
add_to_score :lit_fixnum, other_scores[:lit_fixnum]
|
402
|
+
when Float, Symbol, Regexp, Range then
|
403
|
+
# do nothing
|
404
|
+
else
|
405
|
+
raise value.inspect
|
406
|
+
end
|
407
|
+
s()
|
408
|
+
end
|
409
|
+
|
410
|
+
def process_masgn(exp)
|
411
|
+
add_to_score :assignment, other_scores[:assignment]
|
412
|
+
process exp.shift # lhs
|
413
|
+
process exp.shift # rhs
|
414
|
+
s()
|
415
|
+
end
|
416
|
+
|
417
|
+
def process_module(exp)
|
418
|
+
self.klass exp.shift do
|
419
|
+
bleed exp
|
420
|
+
end
|
421
|
+
s()
|
422
|
+
end
|
423
|
+
|
424
|
+
def process_or(exp)
|
425
|
+
add_to_score :branch, other_scores[:branch]
|
426
|
+
bad_dog! 0.1 do
|
427
|
+
process exp.shift # lhs
|
428
|
+
process exp.shift # rhs
|
429
|
+
end
|
430
|
+
s()
|
431
|
+
end
|
432
|
+
|
433
|
+
def process_rescue(exp)
|
434
|
+
add_to_score :branch, other_scores[:branch]
|
435
|
+
bad_dog! 0.1 do
|
436
|
+
bleed exp
|
437
|
+
end
|
438
|
+
s()
|
439
|
+
end
|
440
|
+
|
441
|
+
def process_sclass(exp)
|
442
|
+
bad_dog! 0.5 do
|
443
|
+
recv = process exp.shift
|
444
|
+
bleed exp
|
445
|
+
end
|
446
|
+
|
447
|
+
add_to_score :sclass, other_scores[:sclass]
|
448
|
+
s()
|
449
|
+
end
|
450
|
+
|
451
|
+
def process_super(exp)
|
452
|
+
add_to_score :super, other_scores[:super]
|
453
|
+
bleed exp
|
454
|
+
s()
|
455
|
+
end
|
456
|
+
|
457
|
+
def process_until(exp)
|
458
|
+
add_to_score :branch, other_scores[:branch]
|
459
|
+
bad_dog! 0.1 do
|
460
|
+
process exp.shift # cond
|
461
|
+
process exp.shift # body
|
462
|
+
end
|
463
|
+
exp.shift # pre/post
|
464
|
+
s()
|
465
|
+
end
|
466
|
+
|
467
|
+
def process_when(exp)
|
468
|
+
add_to_score :branch, other_scores[:branch]
|
469
|
+
bad_dog! 0.1 do
|
470
|
+
bleed exp
|
471
|
+
end
|
472
|
+
s()
|
473
|
+
end
|
474
|
+
|
475
|
+
def process_while(exp)
|
476
|
+
add_to_score :branch, other_scores[:branch]
|
477
|
+
bad_dog! 0.1 do
|
478
|
+
process exp.shift # cond
|
479
|
+
process exp.shift # body
|
480
|
+
end
|
481
|
+
exp.shift # pre/post
|
482
|
+
s()
|
483
|
+
end
|
484
|
+
|
485
|
+
def process_yield(exp)
|
486
|
+
add_to_score :yield, other_scores[:yield]
|
487
|
+
bleed exp
|
488
|
+
s()
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|