Class: CodeDuplicationAction
Instance Method Summary
collapse
Methods inherited from BuildAction
command_line_action_name, command_line_action_names, create_action_from_command_line_name, detailed_template_file, summary_template_file
#get_implementors
Constructor Details
Returns a new instance of CodeDuplicationAction.
46
47
48
49
|
# File 'lib/kwala/actions/code_duplication.rb', line 46
def initialize
@duplicates = nil
@file_count = 0
end
|
Instance Method Details
#build_action(context) ⇒ Object
51
52
53
54
55
56
57
|
# File 'lib/kwala/actions/code_duplication.rb', line 51
def build_action(context)
temporarily_remove_symlinks(context.project_directory) do |dir|
@duplicates = find_duplicate_code(dir)
end
@file_count = context.ruby_files.size + context.test_files.size
end
|
#cpd_command(dir) ⇒ Object
153
154
155
156
157
|
# File 'lib/kwala/actions/code_duplication.rb', line 153
def cpd_command(dir)
"java -Xmx256m -cp #{cpd_jar} net.sourceforge.pmd.cpd.CPD" +
" --minimum-tokens #{minimum_tokens} --files #{dir}" +
" --language ruby --format net.sourceforge.pmd.cpd.XMLRenderer"
end
|
#cpd_error?(stderr) ⇒ Boolean
167
168
169
170
171
172
173
174
175
|
# File 'lib/kwala/actions/code_duplication.rb', line 167
def cpd_error?(stderr)
lines = stderr.readlines
if !lines.empty?
STDERR.puts "code_duplication error with cpd:", lines
true
else
false
end
end
|
#cpd_jar ⇒ Object
159
160
161
|
# File 'lib/kwala/actions/code_duplication.rb', line 159
def cpd_jar
EXTERNAL_DIR + "pmd.jar"
end
|
#detailed_display(context) ⇒ Object
70
71
72
73
74
|
# File 'lib/kwala/actions/code_duplication.rb', line 70
def detailed_display(context)
det_res = expand_code_duplication_template(context.amrita_data[:duplicate_code_results])
det_file = "#{context.output_directory}/#{context.project_name}_code_duplication.html"
[det_file, det_res]
end
|
#expand_code_duplication_template(data) ⇒ Object
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
# File 'lib/kwala/actions/code_duplication.rb', line 116
def expand_code_duplication_template(data)
template = TemplateFile.new(self.class.detailed_template_file)
data[:duplicate_refs] = data[:duplicates].map do |d|
{
:entry_num => Amrita::a(:href=>"\##{d[:duplicate][:entry_num]}") {d[:duplicate][:entry_num]}
}
end
max_size = (data[:duplicates].size - 1)
data[:duplicates].each_with_index do |d, idx|
d[:duplicate][:entry_num] = Amrita::a(:name=>"#{d[:duplicate][:entry_num]}") {d[:duplicate][:entry_num]}
if idx > 0
d[:duplicate][:prev_entry_num] = Amrita::a(:href=>"\##{idx - 1}") { "Prev" }
end
if idx < max_size
d[:duplicate][:next_entry_num] = Amrita::a(:href=>"\##{idx + 1}") { "Next" }
end
end
ProjectBuilderUtils.expand_template(template, data)
end
|
#find_duplicate_code(dir = Dir.pwd) ⇒ Object
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
# File 'lib/kwala/actions/code_duplication.rb', line 86
def find_duplicate_code(dir=Dir.pwd)
require "rexml/document"
results = Array.new
Open3.popen3( cpd_command(dir) ) do |stdin, stdout, stderr|
xml = time_out_readlines(stdout)
if cpd_error?(stderr) || xml.first == "IO readlines timed out."
return results
end
doc = REXML::Document.new(xml.join("\n"))
doc.elements.each("pmd-cpd/duplication") do |dup|
results << {
:duplicate => {
:entry_num => results.size,
:lines => dup.attribute("lines").to_s,
:tokens => dup.attribute("tokens").to_s,
:code_fragement => highlight_code(dup.elements["codefragment"].cdatas.to_s),
:files => dup.get_elements("file").map { |f|
{
:path => f.attribute("path").to_s,
:line => f.attribute("line").to_s
}
},
}
}
end
end
results
end
|
#highlight_code(code) ⇒ Object
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
# File 'lib/kwala/actions/code_duplication.rb', line 136
def highlight_code(code)
cmd = "/usr/bin/enscript --color --language=html -Eruby --output=-"
out_data = nil
Open3.popen3(cmd) do |stdin, stdout, stderr|
stdin.puts code
stdin.close
out_data = time_out_readlines(stdout).join("")
end
if (out_data && ( m = /(<pre>.*<\/pre>)/im.match(out_data) ) )
code = Amrita::SanitizedString.new(m[1])
end
code
end
|
#minimum_tokens ⇒ Object
163
164
165
|
# File 'lib/kwala/actions/code_duplication.rb', line 163
def minimum_tokens
50
end
|
#score ⇒ Object
76
77
78
79
80
81
82
83
84
|
# File 'lib/kwala/actions/code_duplication.rb', line 76
def score
if @duplicates.size > @file_count
1
else
score_scaling(@duplicates.size, @file_count)
end
end
|
#summary_display(context) ⇒ Object
59
60
61
62
63
64
65
66
67
68
|
# File 'lib/kwala/actions/code_duplication.rb', line 59
def summary_display(context)
template = TemplateFile.new(self.class.summary_template_file)
context.amrita_data[:duplicate_code_results] = {
:duplicate_count => @duplicates.size,
:duplicates => @duplicates
}
context.amrita_data[:code_duplication_details] =
(Amrita::e(:a, :href=>"#{context.project_name}_code_duplication.html") { "Code Duplication Details" })
summary_expand(template, context)
end
|
#temporarily_remove_symlinks(dir) ⇒ Object
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
# File 'lib/kwala/actions/code_duplication.rb', line 177
def temporarily_remove_symlinks(dir)
symlinks = Hash.new
Find.find(dir) do |path|
if File.symlink?(path)
lnk = File.expand_path(path)
src = File.expand_path(File.readlink(path), File.dirname(lnk))
if src.index(dir) == 0
symlinks[lnk] = src
dircheck = File.directory?(path)
FileUtils.rm_f(path)
if dircheck
Find.prune
end
end
end
end
yield dir
ensure
symlinks.each do |sym, source|
begin
FileUtils.ln_s(source, sym)
rescue => err
STDERR.puts "Cannot restore link:", err
end
end
end
|