rubycritic 0.0.5 → 1.4.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +593 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.md +45 -0
  5. data/CONTRIBUTING.md +67 -15
  6. data/README.md +105 -14
  7. data/Rakefile +9 -6
  8. data/bin/rubycritic +3 -1
  9. data/lib/rubycritic/analysers/attributes.rb +21 -0
  10. data/lib/rubycritic/analysers/churn.rb +21 -0
  11. data/lib/rubycritic/analysers/complexity.rb +22 -0
  12. data/lib/rubycritic/analysers/helpers/ast_node.rb +69 -0
  13. data/lib/rubycritic/analysers/{config.reek → helpers/config.reek} +8 -0
  14. data/lib/rubycritic/analysers/helpers/flay.rb +13 -0
  15. data/lib/rubycritic/analysers/helpers/flog.rb +17 -0
  16. data/lib/rubycritic/analysers/helpers/methods_counter.rb +25 -0
  17. data/lib/rubycritic/analysers/helpers/modules_locator.rb +43 -0
  18. data/lib/rubycritic/analysers/helpers/parser.rb +12 -0
  19. data/lib/rubycritic/analysers/helpers/reek.rb +17 -0
  20. data/lib/rubycritic/analysers/smells/flay.rb +68 -0
  21. data/lib/rubycritic/analysers/smells/flog.rb +62 -0
  22. data/lib/rubycritic/analysers/smells/reek.rb +44 -0
  23. data/lib/rubycritic/analysers_runner.rb +21 -10
  24. data/lib/rubycritic/cli/application.rb +24 -0
  25. data/lib/rubycritic/cli/options.rb +79 -0
  26. data/lib/rubycritic/commands/ci.rb +26 -0
  27. data/lib/rubycritic/commands/default.rb +28 -0
  28. data/lib/rubycritic/commands/help.rb +13 -0
  29. data/lib/rubycritic/commands/version.rb +11 -0
  30. data/lib/rubycritic/configuration.rb +33 -0
  31. data/lib/rubycritic/core/analysed_module.rb +66 -0
  32. data/lib/rubycritic/{location.rb → core/location.rb} +17 -2
  33. data/lib/rubycritic/core/rating.rb +30 -0
  34. data/lib/rubycritic/{smell.rb → core/smell.rb} +22 -13
  35. data/lib/rubycritic/generators/html/assets/javascripts/application.js +104 -0
  36. data/lib/rubycritic/generators/html/assets/javascripts/highcharts.src-4.0.1.js +17672 -0
  37. data/lib/rubycritic/generators/html/assets/javascripts/jquery.floatThead-v1.2.7.js +754 -0
  38. data/lib/rubycritic/generators/html/assets/javascripts/jquery.scrollTo-1.4.11.js +186 -0
  39. data/lib/rubycritic/generators/html/assets/javascripts/jquery.tablesorter.js +2089 -0
  40. data/lib/rubycritic/generators/html/assets/javascripts/jquery.timeago-v1.4.1.js +214 -0
  41. data/lib/rubycritic/generators/html/assets/stylesheets/application.css +303 -0
  42. data/lib/rubycritic/{report_generators → generators/html}/assets/stylesheets/prettify.custom_theme.css +1 -4
  43. data/lib/rubycritic/generators/html/base.rb +52 -0
  44. data/lib/rubycritic/generators/html/code_file.rb +40 -0
  45. data/lib/rubycritic/generators/html/code_index.rb +26 -0
  46. data/lib/rubycritic/generators/html/line.rb +37 -0
  47. data/lib/rubycritic/generators/html/overview.rb +27 -0
  48. data/lib/rubycritic/generators/html/smells_index.rb +38 -0
  49. data/lib/rubycritic/generators/html/templates/code_file.html.erb +38 -0
  50. data/lib/rubycritic/generators/html/templates/code_index.html.erb +30 -0
  51. data/lib/rubycritic/generators/html/templates/layouts/application.html.erb +34 -0
  52. data/lib/rubycritic/generators/html/templates/overview.html.erb +5 -0
  53. data/lib/rubycritic/generators/html/templates/smells_index.html.erb +26 -0
  54. data/lib/rubycritic/{report_generators → generators/html}/templates/smelly_line.html.erb +1 -1
  55. data/lib/rubycritic/generators/html/turbulence.rb +17 -0
  56. data/lib/rubycritic/generators/html/view_helpers.rb +43 -0
  57. data/lib/rubycritic/generators/html_report.rb +66 -0
  58. data/lib/rubycritic/generators/json/simple.rb +30 -0
  59. data/lib/rubycritic/generators/json_report.rb +23 -0
  60. data/lib/rubycritic/reporter.rb +20 -0
  61. data/lib/rubycritic/revision_comparator.rb +27 -29
  62. data/lib/rubycritic/serializer.rb +32 -0
  63. data/lib/rubycritic/smells_status_setter.rb +7 -16
  64. data/lib/rubycritic/source_control_systems/base.rb +37 -0
  65. data/lib/rubycritic/source_control_systems/double.rb +18 -0
  66. data/lib/rubycritic/source_control_systems/git.rb +41 -37
  67. data/lib/rubycritic/source_control_systems/mercurial.rb +29 -0
  68. data/lib/rubycritic/source_locator.rb +25 -13
  69. data/lib/rubycritic/version.rb +1 -1
  70. data/lib/rubycritic.rb +17 -22
  71. data/rubycritic.gemspec +10 -7
  72. data/test/analysers_test_helper.rb +3 -0
  73. data/test/lib/rubycritic/analysers/churn_test.rb +33 -0
  74. data/test/lib/rubycritic/analysers/complexity_test.rb +16 -0
  75. data/test/lib/rubycritic/analysers/helpers/methods_counter_test.rb +29 -0
  76. data/test/lib/rubycritic/analysers/helpers/modules_locator_test.rb +53 -0
  77. data/test/lib/rubycritic/analysers/smells/flay_test.rb +39 -0
  78. data/test/lib/rubycritic/analysers/smells/flog_test.rb +26 -0
  79. data/test/lib/rubycritic/analysers/smells/reek_test.rb +33 -0
  80. data/test/lib/rubycritic/configuration_test.rb +29 -0
  81. data/test/lib/rubycritic/core/analysed_module_test.rb +88 -0
  82. data/test/lib/rubycritic/{location_test.rb → core/location_test.rb} +8 -4
  83. data/test/lib/rubycritic/core/smell_test.rb +72 -0
  84. data/test/lib/rubycritic/{smells_array_test.rb → core/smells_array_test.rb} +1 -1
  85. data/test/lib/rubycritic/report_generators/turbulence_test.rb +17 -0
  86. data/test/lib/rubycritic/report_generators/view_helpers_test.rb +83 -0
  87. data/test/lib/rubycritic/smells_status_setter_test.rb +5 -5
  88. data/test/lib/rubycritic/source_control_systems/base_test.rb +29 -0
  89. data/test/lib/rubycritic/source_control_systems/double_test.rb +11 -0
  90. data/test/lib/rubycritic/source_control_systems/git_test.rb +13 -0
  91. data/test/lib/rubycritic/source_control_systems/interfaces/basic.rb +7 -0
  92. data/test/lib/rubycritic/source_control_systems/interfaces/time_travel.rb +7 -0
  93. data/test/lib/rubycritic/source_control_systems/mercurial_test.rb +11 -0
  94. data/test/lib/rubycritic/source_locator_test.rb +42 -18
  95. data/test/lib/rubycritic/version_test.rb +1 -0
  96. data/test/samples/empty.rb +0 -0
  97. data/test/samples/flay/smelly.rb +8 -0
  98. data/test/samples/flay/smelly2.rb +8 -0
  99. data/test/samples/flog/complex.rb +11 -0
  100. data/test/samples/flog/smelly.rb +7 -2
  101. data/test/samples/location/file0_symlink.rb +0 -0
  102. data/test/samples/methods_count.rb +7 -0
  103. data/test/samples/module_names.rb +18 -0
  104. data/test/samples/reek/not_smelly.rb +31 -3
  105. data/test/samples/unparsable.rb +1 -0
  106. data/test/test_helper.rb +39 -0
  107. metadata +178 -53
  108. data/SPEC.md +0 -58
  109. data/lib/rubycritic/analysers/flog.rb +0 -20
  110. data/lib/rubycritic/analysers/reek.rb +0 -15
  111. data/lib/rubycritic/cli.rb +0 -25
  112. data/lib/rubycritic/report_generators/assets/javascripts/application.js +0 -25
  113. data/lib/rubycritic/report_generators/assets/stylesheets/application.css +0 -26
  114. data/lib/rubycritic/report_generators/base_generator.rb +0 -42
  115. data/lib/rubycritic/report_generators/file_generator.rb +0 -42
  116. data/lib/rubycritic/report_generators/index_generator.rb +0 -28
  117. data/lib/rubycritic/report_generators/line_generator.rb +0 -27
  118. data/lib/rubycritic/report_generators/reporter.rb +0 -45
  119. data/lib/rubycritic/report_generators/templates/file.html.erb +0 -3
  120. data/lib/rubycritic/report_generators/templates/index.html.erb +0 -14
  121. data/lib/rubycritic/report_generators/templates/layouts/application.html.erb +0 -19
  122. data/lib/rubycritic/report_generators/view_helpers.rb +0 -26
  123. data/lib/rubycritic/smell_adapters/flog.rb +0 -41
  124. data/lib/rubycritic/smell_adapters/reek.rb +0 -35
  125. data/lib/rubycritic/smells_aggregator.rb +0 -29
  126. data/lib/rubycritic/smelly_pathnames_serializer.rb +0 -34
  127. data/lib/rubycritic/source_control_systems/source_control_system.rb +0 -42
  128. data/test/lib/rubycritic/metric_adapters/flog_adapter_test.rb +0 -25
  129. data/test/lib/rubycritic/metric_adapters/reek_adapter_test.rb +0 -34
  130. data/test/lib/rubycritic/smell_test.rb +0 -71
  131. data/test/lib/rubycritic/smells_aggregator_test.rb +0 -47
  132. data/test/lib/rubycritic/source_control_systems/source_control_system_test.rb +0 -26
  133. /data/lib/rubycritic/{report_generators → generators/html}/assets/javascripts/jquery-2.1.0.js +0 -0
  134. /data/lib/rubycritic/{report_generators/assets/javascripts/prettify.js → generators/html/assets/javascripts/prettify-4-Mar-2013.js} +0 -0
  135. /data/lib/rubycritic/{report_generators → generators/html}/templates/line.html.erb +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
+ }));
@@ -0,0 +1,303 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ .group:after {
6
+ content: '';
7
+ display: table;
8
+ clear: both;
9
+ }
10
+
11
+ html {
12
+ overflow-y: scroll;
13
+ font-family: "Droid Sans", Arial, "Helvetica Neue", Helvetica, sans-serif;
14
+ font-size: 1em;
15
+ }
16
+
17
+ html, body {
18
+ margin: 0;
19
+ padding: 0;
20
+ }
21
+
22
+ a {
23
+ color: #00adc4;
24
+ text-decoration: none;
25
+ }
26
+
27
+ a:hover {
28
+ border-bottom: 1px solid;
29
+ }
30
+
31
+ a:visited {
32
+ color: #4E6072;
33
+ }
34
+
35
+ .container {
36
+ width: 100%;
37
+ max-width: 80em;
38
+ margin: 0 auto;
39
+ }
40
+
41
+ .project-header {
42
+ padding: 1em 0 1em 0;
43
+ margin-bottom: 2em;
44
+ background-color: #F2F1EE;
45
+ }
46
+
47
+ .project-header .container {
48
+ padding: 0 2rem;
49
+ }
50
+
51
+ .logo {
52
+ float: left;
53
+ margin: 0;
54
+ }
55
+
56
+ a.logo-link {
57
+ color: black;
58
+ }
59
+
60
+ .project-nav {
61
+ float: left;
62
+ margin-left: 4rem;
63
+ line-height: 2.5em;
64
+ }
65
+
66
+ a.project-nav-item {
67
+ color: #323333;
68
+ margin-right: 3rem;
69
+ }
70
+
71
+ a.project-nav-item:hover {
72
+ border-bottom: 1px solid;
73
+ }
74
+
75
+ .chart-container {
76
+ max-width: 1000px;
77
+ margin: 0 auto;
78
+ }
79
+
80
+ .index-table {
81
+ width: 100%;
82
+ border-collapse: collapse;
83
+ }
84
+
85
+ .index-table th {
86
+ text-align: left;
87
+ padding: 8px 10px;
88
+ border-bottom: 1px solid silver;
89
+ font-size: 1.55em;
90
+ font-weight: normal;
91
+ background-color: white;
92
+ }
93
+
94
+ .floatThead-container {
95
+ box-shadow: 0 3px 4px -2px rgb(224, 223, 223);
96
+ }
97
+
98
+ .index-table tr:nth-child(odd) {
99
+ background-color: #f9f9f9;
100
+ }
101
+
102
+ .index-table tr:hover {
103
+ background-color: #e9fafc;
104
+ }
105
+
106
+ .index-table .circle {
107
+ width: 28px;
108
+ height: 28px;
109
+ }
110
+
111
+ .index-table .circled-text {
112
+ display: inline-block;
113
+ line-height: 28px;
114
+ }
115
+
116
+ .tablesorter-headerAsc .tablesorter-header-inner:after,
117
+ .tablesorter-headerDesc .tablesorter-header-inner:after {
118
+ position: absolute;
119
+ }
120
+
121
+ .tablesorter-headerAsc .tablesorter-header-inner:after {
122
+ content: '\00A0\2191';
123
+ }
124
+ .tablesorter-headerDesc .tablesorter-header-inner:after {
125
+ content: '\00A0\2193';
126
+ }
127
+
128
+ .sortable-table th:focus {
129
+ outline: none;
130
+ }
131
+
132
+ .sortable-table th:hover {
133
+ cursor: pointer;
134
+ }
135
+
136
+ .index-table td, .index-table th {
137
+ padding: 1rem 2rem;
138
+ }
139
+
140
+ .index-table .numeric-cell {
141
+ text-align: right;
142
+ }
143
+
144
+ .index-table .centered-cell {
145
+ text-align: center;
146
+ }
147
+
148
+ .button {
149
+ margin: 0;
150
+ padding: 0.5em 1em;
151
+ border: 1px solid black;
152
+ font-size: 0.9em;
153
+ border-radius: 0.2em;
154
+ cursor: pointer;
155
+ transition-property: background-color;
156
+ -webkit-transition-duration: 0.5s;
157
+ transition-duration: 0.5s;
158
+ }
159
+
160
+ .circle {
161
+ display: block;
162
+ border-radius: 50%;
163
+ }
164
+
165
+ .circled-text {
166
+ text-align: center;
167
+ color: white;
168
+ font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
169
+ font-weight: bold;
170
+ -webkit-user-select: none;
171
+ -moz-user-select: none;
172
+ -ms-user-select: none;
173
+ user-select: none;
174
+ cursor: default;
175
+ }
176
+
177
+ .smells-index-table .circled-text {
178
+ font-size: 10px;
179
+ }
180
+
181
+ .status-old {
182
+ background-color: #FFDC00;
183
+ }
184
+
185
+ .status-new {
186
+ background-color: #FF4136;
187
+ }
188
+
189
+ .file-header {
190
+ position: relative;
191
+ padding: 0 0 10px 2rem;
192
+ border-bottom: 1px solid silver;
193
+ }
194
+
195
+ .file-header .circle {
196
+ width: 50px;
197
+ height: 50px;
198
+ }
199
+
200
+ .file-header .circled-text {
201
+ float: left;
202
+ line-height: 50px;
203
+ font-size: 32px;
204
+ }
205
+
206
+ .rating-a {
207
+ background-color: #2ECC40;
208
+ }
209
+
210
+ .rating-b {
211
+ background-color: #2ECC40;
212
+ }
213
+
214
+ .rating-c {
215
+ background-color: #FFDC00;
216
+ }
217
+
218
+ .rating-d {
219
+ background-color: #FF851B;
220
+ }
221
+
222
+ .rating-f {
223
+ background-color: #FF4136;
224
+ }
225
+
226
+ .file-name {
227
+ float: left;
228
+ margin: 0;
229
+ line-height: 50px;
230
+ font-weight: normal;
231
+ }
232
+
233
+ .file-committed-at {
234
+ float: left;
235
+ margin: 20px 0 0 28px;
236
+ font-size: 13px;
237
+ color: #666666;
238
+ }
239
+
240
+ .file-stats {
241
+ clear: both;
242
+ width: 300px;
243
+ }
244
+
245
+ .file-stat {
246
+ float: left;
247
+ margin: 3px;
248
+ width: 130px;
249
+ font-size: 12px;
250
+ white-space: nowrap;
251
+ }
252
+
253
+ .file-header.rated .file-stats {
254
+ margin-left: 68px;
255
+ }
256
+
257
+ .file-header.rated .file-name {
258
+ margin-left: 20px;
259
+ }
260
+
261
+ .file-header.unrated .rating {
262
+ display: none;
263
+ }
264
+
265
+ .smells-toggle-button {
266
+ position: absolute;
267
+ right: 64px;
268
+ bottom: -17px;
269
+ border-color: silver;
270
+ background-color: #EEEBE9;
271
+ }
272
+
273
+ .smells-toggle-button:hover {
274
+ background-color: #D1CFCD;
275
+ }
276
+
277
+ .smells {
278
+ font-family: "Droid Sans", Arial, "Helvetica Neue", Helvetica, sans-serif;
279
+ margin: 2px 0 22px 0;
280
+ padding-left: 0;
281
+ border: 1px solid #000;
282
+ background-color: #EEEBE9;
283
+ white-space: normal;
284
+ list-style-type: disc;
285
+ }
286
+
287
+ .smell {
288
+ margin: 5px 5px 5px 30px;
289
+ font-size: 24px;
290
+ }
291
+
292
+ .smell.new {
293
+ color: #F00;
294
+ }
295
+
296
+ .smell.old {
297
+ color: #FA0;
298
+ }
299
+
300
+ .smell .description {
301
+ color: #000;
302
+ font-size: initial;
303
+ }
@@ -57,10 +57,7 @@
57
57
 
58
58
  /* Specify class=linenums on a pre to get line numbering */
59
59
  .prettyprint ol.linenums {
60
- margin-top: 0;
61
- margin-bottom: 0;
62
- background-color: #EEEBE9;
63
- padding-left: 66px;
60
+ padding-left: 60px;
64
61
  }
65
62
 
66
63
  .prettyprint li {
@@ -0,0 +1,52 @@
1
+ require "erb"
2
+ require "pathname"
3
+ require "rubycritic/generators/html/view_helpers"
4
+
5
+ module Rubycritic
6
+ module Generator
7
+ module Html
8
+
9
+ class Base
10
+ def self.erb_template(template_path)
11
+ ERB.new(File.read(File.join(TEMPLATES_DIR, template_path)))
12
+ end
13
+
14
+ TEMPLATES_DIR = File.expand_path("../templates", __FILE__)
15
+ LAYOUT_TEMPLATE = erb_template(File.join("layouts", "application.html.erb"))
16
+
17
+ include ViewHelpers
18
+
19
+ def file_href
20
+ "file://#{file_pathname}"
21
+ end
22
+
23
+ def file_pathname
24
+ File.join(file_directory, file_name)
25
+ end
26
+
27
+ def file_directory
28
+ @file_directory ||= root_directory
29
+ end
30
+
31
+ def file_name
32
+ raise NotImplementedError.new("The #{self.class} class must implement the #{__method__} method.")
33
+ end
34
+
35
+ def render
36
+ raise NotImplementedError.new("The #{self.class} class must implement the #{__method__} method.")
37
+ end
38
+
39
+ private
40
+
41
+ def root_directory
42
+ @root_directory ||= Pathname.new(Config.root)
43
+ end
44
+
45
+ def get_binding
46
+ binding
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ require "rubycritic/generators/html/base"
2
+ require "rubycritic/generators/html/line"
3
+
4
+ module Rubycritic
5
+ module Generator
6
+ module Html
7
+
8
+ class CodeFile < Base
9
+ LINE_NUMBER_OFFSET = 1
10
+ TEMPLATE = erb_template("code_file.html.erb")
11
+
12
+ def initialize(analysed_module)
13
+ @analysed_module = analysed_module
14
+ @pathname = @analysed_module.pathname
15
+ end
16
+
17
+ def file_directory
18
+ @file_directory ||= root_directory + @pathname.dirname
19
+ end
20
+
21
+ def file_name
22
+ @pathname.basename.sub_ext(".html")
23
+ end
24
+
25
+ def render
26
+ file_code = ""
27
+ File.readlines(@pathname).each.with_index(LINE_NUMBER_OFFSET) do |line_text, line_number|
28
+ location = Location.new(@pathname, line_number)
29
+ line_smells = @analysed_module.smells_at_location(location)
30
+ file_code << Line.new(file_directory, line_text, line_smells).render
31
+ end
32
+
33
+ file_body = TEMPLATE.result(get_binding { file_code })
34
+ LAYOUT_TEMPLATE.result(get_binding { file_body })
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ require "rubycritic/generators/html/base"
2
+
3
+ module Rubycritic
4
+ module Generator
5
+ module Html
6
+
7
+ class CodeIndex < Base
8
+ TEMPLATE = erb_template("code_index.html.erb")
9
+
10
+ def initialize(analysed_modules)
11
+ @analysed_modules = analysed_modules
12
+ end
13
+
14
+ def file_name
15
+ "code_index.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
26
+ end
@@ -0,0 +1,37 @@
1
+ require "cgi"
2
+ require "rubycritic/generators/html/base"
3
+
4
+ module Rubycritic
5
+ module Generator
6
+ module Html
7
+
8
+ class Line < Base
9
+ NORMAL_TEMPLATE = erb_template("line.html.erb")
10
+ SMELLY_TEMPLATE = erb_template("smelly_line.html.erb")
11
+
12
+ attr_reader :file_directory
13
+
14
+ def initialize(file_directory, text, smells)
15
+ @file_directory = file_directory
16
+ @text = CGI.escapeHTML(text.chomp)
17
+ @smells = smells
18
+ end
19
+
20
+ def render
21
+ template.result(binding).delete("\n") + "\n"
22
+ end
23
+
24
+ private
25
+
26
+ def template
27
+ if @smells.empty?
28
+ NORMAL_TEMPLATE
29
+ else
30
+ SMELLY_TEMPLATE
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ require "rubycritic/generators/html/base"
2
+ require "rubycritic/generators/html/turbulence"
3
+
4
+ module Rubycritic
5
+ module Generator
6
+ module Html
7
+
8
+ class Overview < Base
9
+ TEMPLATE = erb_template("overview.html.erb")
10
+
11
+ def initialize(analysed_modules)
12
+ @turbulence_data = Turbulence.data(analysed_modules)
13
+ end
14
+
15
+ def file_name
16
+ "overview.html"
17
+ end
18
+
19
+ def render
20
+ index_body = TEMPLATE.result(get_binding)
21
+ LAYOUT_TEMPLATE.result(get_binding { index_body })
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end