rubycritic 0.0.5 → 0.0.16
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.
- checksums.yaml +4 -4
- data/.travis.yml +10 -0
- data/README.md +72 -11
- data/bin/rubycritic +2 -0
- data/lib/rubycritic/adapters/complexity/flog.rb +22 -0
- data/lib/rubycritic/adapters/smell/flay.rb +68 -0
- data/lib/rubycritic/adapters/smell/flog.rb +62 -0
- data/lib/rubycritic/adapters/smell/reek.rb +44 -0
- data/lib/rubycritic/analysers/churn.rb +19 -0
- data/lib/rubycritic/analysers/config.reek +8 -0
- data/lib/rubycritic/analysers/flay.rb +15 -0
- data/lib/rubycritic/analysers/flog.rb +1 -2
- data/lib/rubycritic/analysers/stats.rb +31 -0
- data/lib/rubycritic/analysers_runner.rb +15 -14
- data/lib/rubycritic/cli.rb +35 -14
- data/lib/rubycritic/configuration.rb +24 -0
- data/lib/rubycritic/core/analysed_file.rb +50 -0
- data/lib/rubycritic/{location.rb → core/location.rb} +6 -2
- data/lib/rubycritic/core/rating.rb +22 -0
- data/lib/rubycritic/{smell.rb → core/smell.rb} +5 -12
- data/lib/rubycritic/files_initializer.rb +15 -0
- data/lib/rubycritic/orchestrator.rb +23 -0
- data/lib/rubycritic/report_generators/assets/javascripts/application.js +87 -8
- data/lib/rubycritic/report_generators/assets/javascripts/highcharts.src-4.0.1.js +17672 -0
- data/lib/rubycritic/report_generators/assets/javascripts/jquery.floatThead-v1.2.7.js +754 -0
- data/lib/rubycritic/report_generators/assets/javascripts/jquery.scrollTo-1.4.11.js +186 -0
- data/lib/rubycritic/report_generators/assets/javascripts/jquery.tablesorter-2.0.js +1031 -0
- data/lib/rubycritic/report_generators/assets/javascripts/jquery.timeago-v1.4.1.js +214 -0
- data/lib/rubycritic/report_generators/assets/stylesheets/application.css +204 -1
- data/lib/rubycritic/report_generators/assets/stylesheets/prettify.custom_theme.css +1 -4
- data/lib/rubycritic/report_generators/base.rb +49 -0
- data/lib/rubycritic/report_generators/code_file.rb +38 -0
- data/lib/rubycritic/report_generators/code_index.rb +24 -0
- data/lib/rubycritic/report_generators/current_code_file.rb +17 -0
- data/lib/rubycritic/report_generators/line.rb +31 -0
- data/lib/rubycritic/report_generators/overview.rb +25 -0
- data/lib/rubycritic/report_generators/smells_index.rb +24 -0
- data/lib/rubycritic/report_generators/templates/code_file.html.erb +36 -0
- data/lib/rubycritic/report_generators/templates/code_index.html.erb +26 -0
- data/lib/rubycritic/report_generators/templates/layouts/application.html.erb +27 -16
- data/lib/rubycritic/report_generators/templates/overview.html.erb +5 -0
- data/lib/rubycritic/report_generators/templates/smells_index.html.erb +20 -0
- data/lib/rubycritic/report_generators/view_helpers.rb +28 -9
- data/lib/rubycritic/reporters/base.rb +24 -0
- data/lib/rubycritic/reporters/main.rb +52 -0
- data/lib/rubycritic/reporters/mini.rb +30 -0
- data/lib/rubycritic/revision_comparator.rb +21 -28
- data/lib/rubycritic/serializer.rb +32 -0
- data/lib/rubycritic/smells_status_setter.rb +7 -16
- data/lib/rubycritic/source_control_systems/base.rb +60 -0
- data/lib/rubycritic/source_control_systems/double.rb +19 -0
- data/lib/rubycritic/source_control_systems/git.rb +47 -37
- data/lib/rubycritic/source_locator.rb +8 -12
- data/lib/rubycritic/turbulence.rb +17 -0
- data/lib/rubycritic/version.rb +1 -1
- data/lib/rubycritic.rb +2 -27
- data/rubycritic.gemspec +3 -0
- data/test/lib/rubycritic/adapters/complexity/flog_test.rb +18 -0
- data/test/lib/rubycritic/adapters/smell/flay_test.rb +34 -0
- data/test/lib/rubycritic/adapters/smell/flog_test.rb +26 -0
- data/test/lib/rubycritic/adapters/smell/reek_test.rb +35 -0
- data/test/lib/rubycritic/analysers/churn_test.rb +38 -0
- data/test/lib/rubycritic/configuration_test.rb +17 -0
- data/test/lib/rubycritic/core/analysed_file_test.rb +71 -0
- data/test/lib/rubycritic/{location_test.rb → core/location_test.rb} +8 -4
- data/test/lib/rubycritic/core/smell_test.rb +73 -0
- data/test/lib/rubycritic/{smells_array_test.rb → core/smells_array_test.rb} +1 -1
- data/test/lib/rubycritic/smells_status_setter_test.rb +5 -5
- data/test/lib/rubycritic/source_control_systems/source_control_system_test.rb +5 -11
- data/test/lib/rubycritic/source_locator_test.rb +26 -17
- data/test/lib/rubycritic/turbulence_test.rb +17 -0
- data/test/lib/rubycritic/version_test.rb +1 -0
- data/test/samples/flay/smelly.rb +17 -0
- data/test/samples/flog/complex.rb +11 -0
- data/test/samples/flog/smelly.rb +7 -2
- data/test/samples/reek/not_smelly.rb +31 -3
- data/test/test_helper.rb +1 -0
- metadata +97 -32
- data/SPEC.md +0 -58
- data/lib/rubycritic/report_generators/base_generator.rb +0 -42
- data/lib/rubycritic/report_generators/file_generator.rb +0 -42
- data/lib/rubycritic/report_generators/index_generator.rb +0 -28
- data/lib/rubycritic/report_generators/line_generator.rb +0 -27
- data/lib/rubycritic/report_generators/reporter.rb +0 -45
- data/lib/rubycritic/report_generators/templates/file.html.erb +0 -3
- data/lib/rubycritic/report_generators/templates/index.html.erb +0 -14
- data/lib/rubycritic/smell_adapters/flog.rb +0 -41
- data/lib/rubycritic/smell_adapters/reek.rb +0 -35
- data/lib/rubycritic/smells_aggregator.rb +0 -29
- data/lib/rubycritic/smelly_pathnames_serializer.rb +0 -34
- data/lib/rubycritic/source_control_systems/source_control_system.rb +0 -42
- data/test/lib/rubycritic/metric_adapters/flog_adapter_test.rb +0 -25
- data/test/lib/rubycritic/metric_adapters/reek_adapter_test.rb +0 -34
- data/test/lib/rubycritic/smell_test.rb +0 -71
- data/test/lib/rubycritic/smells_aggregator_test.rb +0 -47
- /data/lib/rubycritic/report_generators/assets/javascripts/{prettify.js → prettify-4-Mar-2013.js} +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeago is a jQuery plugin that makes it easy to support automatically
|
|
3
|
+
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
|
4
|
+
*
|
|
5
|
+
* @name timeago
|
|
6
|
+
* @version 1.4.1
|
|
7
|
+
* @requires jQuery v1.2.3+
|
|
8
|
+
* @author Ryan McGeary
|
|
9
|
+
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
|
10
|
+
*
|
|
11
|
+
* For usage and examples, visit:
|
|
12
|
+
* http://timeago.yarp.com/
|
|
13
|
+
*
|
|
14
|
+
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
(function (factory) {
|
|
18
|
+
if (typeof define === 'function' && define.amd) {
|
|
19
|
+
// AMD. Register as an anonymous module.
|
|
20
|
+
define(['jquery'], factory);
|
|
21
|
+
} else {
|
|
22
|
+
// Browser globals
|
|
23
|
+
factory(jQuery);
|
|
24
|
+
}
|
|
25
|
+
}(function ($) {
|
|
26
|
+
$.timeago = function(timestamp) {
|
|
27
|
+
if (timestamp instanceof Date) {
|
|
28
|
+
return inWords(timestamp);
|
|
29
|
+
} else if (typeof timestamp === "string") {
|
|
30
|
+
return inWords($.timeago.parse(timestamp));
|
|
31
|
+
} else if (typeof timestamp === "number") {
|
|
32
|
+
return inWords(new Date(timestamp));
|
|
33
|
+
} else {
|
|
34
|
+
return inWords($.timeago.datetime(timestamp));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var $t = $.timeago;
|
|
38
|
+
|
|
39
|
+
$.extend($.timeago, {
|
|
40
|
+
settings: {
|
|
41
|
+
refreshMillis: 60000,
|
|
42
|
+
allowPast: true,
|
|
43
|
+
allowFuture: false,
|
|
44
|
+
localeTitle: false,
|
|
45
|
+
cutoff: 0,
|
|
46
|
+
strings: {
|
|
47
|
+
prefixAgo: null,
|
|
48
|
+
prefixFromNow: null,
|
|
49
|
+
suffixAgo: "ago",
|
|
50
|
+
suffixFromNow: "from now",
|
|
51
|
+
inPast: 'any moment now',
|
|
52
|
+
seconds: "less than a minute",
|
|
53
|
+
minute: "about a minute",
|
|
54
|
+
minutes: "%d minutes",
|
|
55
|
+
hour: "about an hour",
|
|
56
|
+
hours: "about %d hours",
|
|
57
|
+
day: "a day",
|
|
58
|
+
days: "%d days",
|
|
59
|
+
month: "about a month",
|
|
60
|
+
months: "%d months",
|
|
61
|
+
year: "about a year",
|
|
62
|
+
years: "%d years",
|
|
63
|
+
wordSeparator: " ",
|
|
64
|
+
numbers: []
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
inWords: function(distanceMillis) {
|
|
69
|
+
if(!this.settings.allowPast && ! this.settings.allowFuture) {
|
|
70
|
+
throw 'timeago allowPast and allowFuture settings can not both be set to false.';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
var $l = this.settings.strings;
|
|
74
|
+
var prefix = $l.prefixAgo;
|
|
75
|
+
var suffix = $l.suffixAgo;
|
|
76
|
+
if (this.settings.allowFuture) {
|
|
77
|
+
if (distanceMillis < 0) {
|
|
78
|
+
prefix = $l.prefixFromNow;
|
|
79
|
+
suffix = $l.suffixFromNow;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if(!this.settings.allowPast && distanceMillis >= 0) {
|
|
84
|
+
return this.settings.strings.inPast;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
var seconds = Math.abs(distanceMillis) / 1000;
|
|
88
|
+
var minutes = seconds / 60;
|
|
89
|
+
var hours = minutes / 60;
|
|
90
|
+
var days = hours / 24;
|
|
91
|
+
var years = days / 365;
|
|
92
|
+
|
|
93
|
+
function substitute(stringOrFunction, number) {
|
|
94
|
+
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
|
|
95
|
+
var value = ($l.numbers && $l.numbers[number]) || number;
|
|
96
|
+
return string.replace(/%d/i, value);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
|
|
100
|
+
seconds < 90 && substitute($l.minute, 1) ||
|
|
101
|
+
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
|
|
102
|
+
minutes < 90 && substitute($l.hour, 1) ||
|
|
103
|
+
hours < 24 && substitute($l.hours, Math.round(hours)) ||
|
|
104
|
+
hours < 42 && substitute($l.day, 1) ||
|
|
105
|
+
days < 30 && substitute($l.days, Math.round(days)) ||
|
|
106
|
+
days < 45 && substitute($l.month, 1) ||
|
|
107
|
+
days < 365 && substitute($l.months, Math.round(days / 30)) ||
|
|
108
|
+
years < 1.5 && substitute($l.year, 1) ||
|
|
109
|
+
substitute($l.years, Math.round(years));
|
|
110
|
+
|
|
111
|
+
var separator = $l.wordSeparator || "";
|
|
112
|
+
if ($l.wordSeparator === undefined) { separator = " "; }
|
|
113
|
+
return $.trim([prefix, words, suffix].join(separator));
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
parse: function(iso8601) {
|
|
117
|
+
var s = $.trim(iso8601);
|
|
118
|
+
s = s.replace(/\.\d+/,""); // remove milliseconds
|
|
119
|
+
s = s.replace(/-/,"/").replace(/-/,"/");
|
|
120
|
+
s = s.replace(/T/," ").replace(/Z/," UTC");
|
|
121
|
+
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
|
|
122
|
+
s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
|
|
123
|
+
return new Date(s);
|
|
124
|
+
},
|
|
125
|
+
datetime: function(elem) {
|
|
126
|
+
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
|
|
127
|
+
return $t.parse(iso8601);
|
|
128
|
+
},
|
|
129
|
+
isTime: function(elem) {
|
|
130
|
+
// jQuery's `is()` doesn't play well with HTML5 in IE
|
|
131
|
+
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// functions that can be called via $(el).timeago('action')
|
|
136
|
+
// init is default when no action is given
|
|
137
|
+
// functions are called with context of a single element
|
|
138
|
+
var functions = {
|
|
139
|
+
init: function(){
|
|
140
|
+
var refresh_el = $.proxy(refresh, this);
|
|
141
|
+
refresh_el();
|
|
142
|
+
var $s = $t.settings;
|
|
143
|
+
if ($s.refreshMillis > 0) {
|
|
144
|
+
this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
update: function(time){
|
|
148
|
+
var parsedTime = $t.parse(time);
|
|
149
|
+
$(this).data('timeago', { datetime: parsedTime });
|
|
150
|
+
if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString());
|
|
151
|
+
refresh.apply(this);
|
|
152
|
+
},
|
|
153
|
+
updateFromDOM: function(){
|
|
154
|
+
$(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
|
|
155
|
+
refresh.apply(this);
|
|
156
|
+
},
|
|
157
|
+
dispose: function () {
|
|
158
|
+
if (this._timeagoInterval) {
|
|
159
|
+
window.clearInterval(this._timeagoInterval);
|
|
160
|
+
this._timeagoInterval = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
$.fn.timeago = function(action, options) {
|
|
166
|
+
var fn = action ? functions[action] : functions.init;
|
|
167
|
+
if(!fn){
|
|
168
|
+
throw new Error("Unknown function name '"+ action +"' for timeago");
|
|
169
|
+
}
|
|
170
|
+
// each over objects here and call the requested function
|
|
171
|
+
this.each(function(){
|
|
172
|
+
fn.call(this, options);
|
|
173
|
+
});
|
|
174
|
+
return this;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
function refresh() {
|
|
178
|
+
var data = prepareData(this);
|
|
179
|
+
var $s = $t.settings;
|
|
180
|
+
|
|
181
|
+
if (!isNaN(data.datetime)) {
|
|
182
|
+
if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
|
|
183
|
+
$(this).text(inWords(data.datetime));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function prepareData(element) {
|
|
190
|
+
element = $(element);
|
|
191
|
+
if (!element.data("timeago")) {
|
|
192
|
+
element.data("timeago", { datetime: $t.datetime(element) });
|
|
193
|
+
var text = $.trim(element.text());
|
|
194
|
+
if ($t.settings.localeTitle) {
|
|
195
|
+
element.attr("title", element.data('timeago').datetime.toLocaleString());
|
|
196
|
+
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
|
|
197
|
+
element.attr("title", text);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return element.data("timeago");
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function inWords(date) {
|
|
204
|
+
return $t.inWords(distance(date));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function distance(date) {
|
|
208
|
+
return (new Date().getTime() - date.getTime());
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// fix for IE6 suckage
|
|
212
|
+
document.createElement("abbr");
|
|
213
|
+
document.createElement("time");
|
|
214
|
+
}));
|
|
@@ -1,8 +1,211 @@
|
|
|
1
|
+
.group:after {
|
|
2
|
+
content: '';
|
|
3
|
+
display: table;
|
|
4
|
+
clear: both;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
html {
|
|
8
|
+
overflow-y: scroll;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.project-header {
|
|
12
|
+
padding: 20px 0 20px 60px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.logo {
|
|
16
|
+
float: left;
|
|
17
|
+
margin: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.logo-link {
|
|
21
|
+
color: black;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.project-nav {
|
|
26
|
+
float: left;
|
|
27
|
+
margin-left: 100px;
|
|
28
|
+
line-height: 2.5em;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.project-nav-item {
|
|
32
|
+
color: black;
|
|
33
|
+
margin-right: 40px;
|
|
34
|
+
text-decoration: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.chart-container {
|
|
38
|
+
max-width: 1000px;
|
|
39
|
+
margin: 0 auto;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.index-table {
|
|
43
|
+
width: 100%;
|
|
44
|
+
border-collapse: collapse;
|
|
45
|
+
table-layout: fixed;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.index-table th {
|
|
49
|
+
text-align: left;
|
|
50
|
+
padding: 8px 10px;
|
|
51
|
+
border-bottom: 1px solid silver;
|
|
52
|
+
font-size: 1.55em;
|
|
53
|
+
font-weight: normal;
|
|
54
|
+
background-color: white;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.index-table .circle {
|
|
58
|
+
width: 28px;
|
|
59
|
+
height: 28px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.index-table .circled-rating {
|
|
63
|
+
display: inline-block;
|
|
64
|
+
line-height: 28px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.sortable-table .headerSortUp,
|
|
68
|
+
.sortable-table .headerSortDown {
|
|
69
|
+
border: 1px solid silver;
|
|
70
|
+
border-bottom: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.sortable-table th:hover {
|
|
74
|
+
background-color: #ECECEC;
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.index-table td {
|
|
79
|
+
padding: 12px 10px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.index-table .first-cell {
|
|
83
|
+
padding-left: 60px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.index-table .last-cell {
|
|
87
|
+
padding-right: 60px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.index-table .numeric-cell {
|
|
91
|
+
text-align: right;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.index-table .centered-cell {
|
|
95
|
+
text-align: center;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.button {
|
|
99
|
+
margin: 0;
|
|
100
|
+
padding: 0.5em 1em;
|
|
101
|
+
border: 1px solid black;
|
|
102
|
+
font-size: 0.9em;
|
|
103
|
+
border-radius: 0.2em;
|
|
104
|
+
cursor: pointer;
|
|
105
|
+
transition-property: background-color;
|
|
106
|
+
-webkit-transition-duration: 0.5s;
|
|
107
|
+
transition-duration: 0.5s;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.circle {
|
|
111
|
+
display: block;
|
|
112
|
+
border-radius: 50%;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.circled-rating {
|
|
116
|
+
text-align: center;
|
|
117
|
+
color: white;
|
|
118
|
+
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
|
|
119
|
+
font-weight: bold;
|
|
120
|
+
-webkit-user-select: none;
|
|
121
|
+
-moz-user-select: none;
|
|
122
|
+
-ms-user-select: none;
|
|
123
|
+
user-select: none;
|
|
124
|
+
cursor: default;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.file-header {
|
|
128
|
+
position: relative;
|
|
129
|
+
padding: 0 0 10px 60px;
|
|
130
|
+
border-bottom: 1px solid silver;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.file-header .circle {
|
|
134
|
+
width: 50px;
|
|
135
|
+
height: 50px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.file-header .circled-rating {
|
|
139
|
+
float: left;
|
|
140
|
+
line-height: 50px;
|
|
141
|
+
font-size: 32px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.rating-a {
|
|
145
|
+
background-color: #2ECC40;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.rating-b {
|
|
149
|
+
background-color: #2ECC40;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.rating-c {
|
|
153
|
+
background-color: #FFDC00;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.rating-d {
|
|
157
|
+
background-color: #FF851B;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.rating-f {
|
|
161
|
+
background-color: #FF4136;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.file-name {
|
|
165
|
+
float: left;
|
|
166
|
+
margin: 0 0 0 20px;
|
|
167
|
+
line-height: 50px;
|
|
168
|
+
font-weight: normal;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.file-committed-at {
|
|
172
|
+
float: left;
|
|
173
|
+
margin: 20px 0 0 28px;
|
|
174
|
+
font-size: 13px;
|
|
175
|
+
color: #666666;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.file-stats {
|
|
179
|
+
clear: both;
|
|
180
|
+
margin-left: 68px;
|
|
181
|
+
width: 300px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.file-stat {
|
|
185
|
+
float: left;
|
|
186
|
+
margin: 3px;
|
|
187
|
+
width: 130px;
|
|
188
|
+
font-size: 12px;
|
|
189
|
+
white-space: nowrap;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.smells-toggle-button {
|
|
193
|
+
position: absolute;
|
|
194
|
+
right: 64px;
|
|
195
|
+
bottom: -17px;
|
|
196
|
+
border-color: silver;
|
|
197
|
+
background-color: #EEEBE9;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.smells-toggle-button:hover {
|
|
201
|
+
background-color: #D1CFCD;
|
|
202
|
+
}
|
|
203
|
+
|
|
1
204
|
.smells {
|
|
2
205
|
margin: 2px 0 22px 0;
|
|
3
206
|
padding-left: 0;
|
|
4
207
|
border: 1px solid #000;
|
|
5
|
-
background-color: #
|
|
208
|
+
background-color: #EEEBE9;
|
|
6
209
|
white-space: normal;
|
|
7
210
|
list-style-type: disc;
|
|
8
211
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require "erb"
|
|
2
|
+
require "rubycritic/report_generators/view_helpers"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Generator
|
|
6
|
+
|
|
7
|
+
class Base
|
|
8
|
+
def self.erb_template(template_path)
|
|
9
|
+
ERB.new(File.read(File.join(TEMPLATES_DIR, template_path)))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
TEMPLATES_DIR = File.expand_path("../templates", __FILE__)
|
|
13
|
+
LAYOUT_TEMPLATE = erb_template(File.join("layouts", "application.html.erb"))
|
|
14
|
+
|
|
15
|
+
include ViewHelpers
|
|
16
|
+
|
|
17
|
+
def file_href
|
|
18
|
+
"file://#{file_pathname}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def file_pathname
|
|
22
|
+
File.join(file_directory, file_name)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def file_directory
|
|
26
|
+
@file_directory ||= root_directory
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def file_name
|
|
30
|
+
raise NotImplementedError.new("The #{self.class} class must implement the #{__method__} method.")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def render
|
|
34
|
+
raise NotImplementedError.new("The #{self.class} class must implement the #{__method__} method.")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def root_directory
|
|
40
|
+
@root_directory ||= Pathname.new(::Rubycritic.configuration.root)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def get_binding
|
|
44
|
+
binding
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require "rubycritic/report_generators/base"
|
|
2
|
+
require "rubycritic/report_generators/line"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Generator
|
|
6
|
+
|
|
7
|
+
class CodeFile < Base
|
|
8
|
+
LINE_NUMBER_OFFSET = 1
|
|
9
|
+
TEMPLATE = erb_template("code_file.html.erb")
|
|
10
|
+
|
|
11
|
+
def initialize(analysed_file)
|
|
12
|
+
@analysed_file = analysed_file
|
|
13
|
+
@pathname = @analysed_file.pathname
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def file_directory
|
|
17
|
+
@file_directory ||= root_directory + @pathname.dirname
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def file_name
|
|
21
|
+
@pathname.basename.sub_ext(".html")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def render
|
|
25
|
+
file_code = ""
|
|
26
|
+
File.readlines(@pathname).each.with_index(LINE_NUMBER_OFFSET) do |line_text, line_number|
|
|
27
|
+
location = Location.new(@pathname, line_number)
|
|
28
|
+
line_smells = @analysed_file.smells_at_location(location)
|
|
29
|
+
file_code << Line.new(file_directory, line_text, line_smells).render
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
file_body = TEMPLATE.result(get_binding { file_code })
|
|
33
|
+
LAYOUT_TEMPLATE.result(get_binding { file_body })
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "rubycritic/report_generators/base"
|
|
2
|
+
|
|
3
|
+
module Rubycritic
|
|
4
|
+
module Generator
|
|
5
|
+
|
|
6
|
+
class CodeIndex < Base
|
|
7
|
+
TEMPLATE = erb_template("code_index.html.erb")
|
|
8
|
+
|
|
9
|
+
def initialize(analysed_files)
|
|
10
|
+
@analysed_files = analysed_files
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def file_name
|
|
14
|
+
"code_index.html"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render
|
|
18
|
+
index_body = TEMPLATE.result(get_binding)
|
|
19
|
+
LAYOUT_TEMPLATE.result(get_binding { index_body })
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require "rubycritic/report_generators/code_file"
|
|
2
|
+
|
|
3
|
+
module Rubycritic
|
|
4
|
+
module Generator
|
|
5
|
+
|
|
6
|
+
class CurrentCodeFile < CodeFile
|
|
7
|
+
def file_directory
|
|
8
|
+
@file_directory ||= root_directory
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def file_name
|
|
12
|
+
"current_file.html"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "rubycritic/report_generators/base"
|
|
2
|
+
require "cgi"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Generator
|
|
6
|
+
|
|
7
|
+
class Line < Base
|
|
8
|
+
NORMAL_TEMPLATE = erb_template("line.html.erb")
|
|
9
|
+
SMELLY_TEMPLATE = erb_template("smelly_line.html.erb")
|
|
10
|
+
|
|
11
|
+
attr_reader :file_directory
|
|
12
|
+
|
|
13
|
+
def initialize(file_directory, text, smells)
|
|
14
|
+
@file_directory = file_directory
|
|
15
|
+
@text = CGI::escapeHTML(text.chomp)
|
|
16
|
+
@smells = smells
|
|
17
|
+
@template =
|
|
18
|
+
if @smells.empty?
|
|
19
|
+
NORMAL_TEMPLATE
|
|
20
|
+
else
|
|
21
|
+
SMELLY_TEMPLATE
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def render
|
|
26
|
+
@template.result(binding).delete("\n") + "\n"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "rubycritic/report_generators/base"
|
|
2
|
+
require "rubycritic/turbulence"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Generator
|
|
6
|
+
|
|
7
|
+
class Overview < Base
|
|
8
|
+
TEMPLATE = erb_template("overview.html.erb")
|
|
9
|
+
|
|
10
|
+
def initialize(analysed_files)
|
|
11
|
+
@turbulence_data = Turbulence.data(analysed_files)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def file_name
|
|
15
|
+
"overview.html"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def render
|
|
19
|
+
index_body = TEMPLATE.result(get_binding)
|
|
20
|
+
LAYOUT_TEMPLATE.result(get_binding { index_body })
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "rubycritic/report_generators/base"
|
|
2
|
+
|
|
3
|
+
module Rubycritic
|
|
4
|
+
module Generator
|
|
5
|
+
|
|
6
|
+
class SmellsIndex < Base
|
|
7
|
+
TEMPLATE = erb_template("smells_index.html.erb")
|
|
8
|
+
|
|
9
|
+
def initialize(smells)
|
|
10
|
+
@smells = smells
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def file_name
|
|
14
|
+
"smells_index.html"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render
|
|
18
|
+
index_body = TEMPLATE.result(get_binding)
|
|
19
|
+
LAYOUT_TEMPLATE.result(get_binding { index_body })
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<div class="file-header group">
|
|
2
|
+
<span class="rating-<%= @analysed_file.rating.to_s.downcase %> circled-rating circle "><%= @analysed_file.rating %></span>
|
|
3
|
+
<h2 class="file-name"><%= @analysed_file.name %></h2>
|
|
4
|
+
|
|
5
|
+
<span class="file-committed-at">
|
|
6
|
+
<% if @analysed_file.committed_at %>
|
|
7
|
+
Updated <%= timeago_tag(@analysed_file.committed_at) %></span>
|
|
8
|
+
<% else %>
|
|
9
|
+
Never committed
|
|
10
|
+
<% end %>
|
|
11
|
+
</span>
|
|
12
|
+
|
|
13
|
+
<div class="file-stats group">
|
|
14
|
+
<div class="file-stat">
|
|
15
|
+
<%= @analysed_file.complexity %> complexity
|
|
16
|
+
</div>
|
|
17
|
+
<div class="file-stat">
|
|
18
|
+
<%= @analysed_file.complexity_per_method %> complexity per method
|
|
19
|
+
</div>
|
|
20
|
+
<div class="file-stat">
|
|
21
|
+
<%= @analysed_file.churn %> churn
|
|
22
|
+
</div>
|
|
23
|
+
<div class="file-stat">
|
|
24
|
+
<%= @analysed_file.methods_count %> methods
|
|
25
|
+
</div>
|
|
26
|
+
<div class="file-stat">
|
|
27
|
+
<%= @analysed_file.duplication %> duplication
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<% if @analysed_file.has_smells? %>
|
|
32
|
+
<button id="js-toggle-smells" class="smells-toggle-button button">Toggle Smells</button>
|
|
33
|
+
<% end %>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<code class="prettyprint linenums lang-ruby file-code js-file-code"><%= yield %></code>
|