jsmetric4java 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +7 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +8 -0
  4. data/README +16 -0
  5. data/Rakefile +37 -0
  6. data/bin/jsmetric4java +20 -0
  7. data/boot.rb +5 -0
  8. data/build +1 -0
  9. data/features/cyclometric_complexity/boolean_complexity_counting.feature +46 -0
  10. data/features/cyclometric_complexity/case_complexity_counting.feature +117 -0
  11. data/features/cyclometric_complexity/exception_complexity_counting.feature +81 -0
  12. data/features/cyclometric_complexity/function_detection.feature +128 -0
  13. data/features/cyclometric_complexity/if_else_complexity_counting.feature +178 -0
  14. data/features/cyclometric_complexity/loop_complexity_counting.feature +81 -0
  15. data/features/graphing/draw_basic_graph.feature +14 -0
  16. data/features/reporting/report.feature +13 -0
  17. data/features/sample_js_files_for_test/foobar.js +30 -0
  18. data/features/step_definitions/cyclometric_complexity_steps.rb +31 -0
  19. data/features/step_definitions/graph_steps.rb +10 -0
  20. data/features/step_definitions/reporting_steps.rb +14 -0
  21. data/features/support/env.rb +1 -0
  22. data/jsgraphlib/Curry-1.0.1.js +29 -0
  23. data/jsgraphlib/dracula_algorithms.js +599 -0
  24. data/jsgraphlib/dracula_graffle.js +106 -0
  25. data/jsgraphlib/dracula_graph.js +534 -0
  26. data/jsgraphlib/graphtest.html +57 -0
  27. data/jsgraphlib/jquery-1.4.2.min.js +154 -0
  28. data/jsgraphlib/jsgraphsource.js +12 -0
  29. data/jsgraphlib/raphael-min.js +7 -0
  30. data/jsgraphlib/seedrandom.js +266 -0
  31. data/jsmetric.gemspec +23 -0
  32. data/lib/cc_report.rb +24 -0
  33. data/lib/complexity_analyser.rb +90 -0
  34. data/lib/fulljslint.js +6100 -0
  35. data/lib/graphing/graph_analyser.rb +19 -0
  36. data/lib/js_lint.rb +23 -0
  37. data/lib/json2.js +480 -0
  38. data/lib/options.js +24 -0
  39. data/lib/report.rb +26 -0
  40. data/lib/utils.rb +18 -0
  41. data/lib/version.rb +3 -0
  42. data/spec/spec_helper.rb +1 -0
  43. data/tasks/dev.rb +4 -0
  44. data/tasks/run.rb +55 -0
  45. metadata +129 -0
@@ -0,0 +1,266 @@
1
+ // seedrandom.js
2
+ // Author: David Bau 3/11/2010
3
+ //
4
+ // Defines a method Math.seedrandom() that, when called, substitutes
5
+ // an explicitly seeded RC4-based algorithm for Math.random(). Also
6
+ // supports automatic seeding from local or network sources of entropy.
7
+ //
8
+ // Usage:
9
+ //
10
+ // <script src=http://davidbau.com/encode/seedrandom-min.js></script>
11
+ //
12
+ // Math.seedrandom('yipee'); Sets Math.random to a function that is
13
+ // initialized using the given explicit seed.
14
+ //
15
+ // Math.seedrandom(); Sets Math.random to a function that is
16
+ // seeded using the current time, dom state,
17
+ // and other accumulated local entropy.
18
+ // The generated seed string is returned.
19
+ //
20
+ // Math.seedrandom('yowza', true);
21
+ // Seeds using the given explicit seed mixed
22
+ // together with accumulated entropy.
23
+ //
24
+ // <script src="http://bit.ly/srandom-512"></script>
25
+ // Seeds using physical random bits downloaded
26
+ // from random.org.
27
+ //
28
+ // Examples:
29
+ //
30
+ // Math.seedrandom("hello"); // Use "hello" as the seed.
31
+ // document.write(Math.random()); // Always 0.5463663768140734
32
+ // document.write(Math.random()); // Always 0.43973793770592234
33
+ // var rng1 = Math.random; // Remember the current prng.
34
+ //
35
+ // var autoseed = Math.seedrandom(); // New prng with an automatic seed.
36
+ // document.write(Math.random()); // Pretty much unpredictable.
37
+ //
38
+ // Math.random = rng1; // Continue "hello" prng sequence.
39
+ // document.write(Math.random()); // Always 0.554769432473455
40
+ //
41
+ // Math.seedrandom(autoseed); // Restart at the previous seed.
42
+ // document.write(Math.random()); // Repeat the 'unpredictable' value.
43
+ //
44
+ // Notes:
45
+ //
46
+ // Each time seedrandom('arg') is called, entropy from the passed seed
47
+ // is accumulated in a pool to help generate future seeds for the
48
+ // zero-argument form of Math.seedrandom, so entropy can be injected over
49
+ // time by calling seedrandom with explicit data repeatedly.
50
+ //
51
+ // On speed - This javascript implementation of Math.random() is about
52
+ // 3-10x slower than the built-in Math.random() because it is not native
53
+ // code, but this is typically fast enough anyway. Seeding is more expensive,
54
+ // especially if you use auto-seeding. Some details (timings on Chrome 4):
55
+ //
56
+ // Our Math.random() - avg less than 0.002 milliseconds per call
57
+ // seedrandom('explicit') - avg less than 0.5 milliseconds per call
58
+ // seedrandom('explicit', true) - avg less than 2 milliseconds per call
59
+ // seedrandom() - avg about 38 milliseconds per call
60
+ //
61
+ // LICENSE (BSD):
62
+ //
63
+ // Copyright 2010 David Bau, all rights reserved.
64
+ //
65
+ // Redistribution and use in source and binary forms, with or without
66
+ // modification, are permitted provided that the following conditions are met:
67
+ //
68
+ // 1. Redistributions of source code must retain the above copyright
69
+ // notice, this list of conditions and the following disclaimer.
70
+ //
71
+ // 2. Redistributions in binary form must reproduce the above copyright
72
+ // notice, this list of conditions and the following disclaimer in the
73
+ // documentation and/or other materials provided with the distribution.
74
+ //
75
+ // 3. Neither the name of this module nor the names of its contributors may
76
+ // be used to endorse or promote products derived from this software
77
+ // without specific prior written permission.
78
+ //
79
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
80
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
81
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
82
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
83
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
84
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
85
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
86
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
87
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
88
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
89
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
90
+ //
91
+ /**
92
+ * All code is in an anonymous closure to keep the global namespace clean.
93
+ *
94
+ * @param {number=} overflow
95
+ * @param {number=} startdenom
96
+ */
97
+ (function (pool, math, width, chunks, significance, overflow, startdenom) {
98
+
99
+
100
+ //
101
+ // seedrandom()
102
+ // This is the seedrandom function described above.
103
+ //
104
+ math['seedrandom'] = function seedrandom(seed, use_entropy) {
105
+ var key = [];
106
+ var arc4;
107
+
108
+ // Flatten the seed string or build one from local entropy if needed.
109
+ seed = mixkey(flatten(
110
+ use_entropy ? [seed, pool] :
111
+ arguments.length ? seed :
112
+ [new Date().getTime(), pool, window], 3), key);
113
+
114
+ // Use the seed to initialize an ARC4 generator.
115
+ arc4 = new ARC4(key);
116
+
117
+ // Mix the randomness into accumulated entropy.
118
+ mixkey(arc4.S, pool);
119
+
120
+ // Override Math.random
121
+
122
+ // This function returns a random double in [0, 1) that contains
123
+ // randomness in every bit of the mantissa of the IEEE 754 value.
124
+
125
+ math['random'] = function random() { // Closure to return a random double:
126
+ var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48
127
+ var d = startdenom; // and denominator d = 2 ^ 48.
128
+ var x = 0; // and no 'extra last byte'.
129
+ while (n < significance) { // Fill up all significant digits by
130
+ n = (n + x) * width; // shifting numerator and
131
+ d *= width; // denominator and generating a
132
+ x = arc4.g(1); // new least-significant-byte.
133
+ }
134
+ while (n >= overflow) { // To avoid rounding up, before adding
135
+ n /= 2; // last byte, shift everything
136
+ d /= 2; // right using integer math until
137
+ x >>>= 1; // we have exactly the desired bits.
138
+ }
139
+ return (n + x) / d; // Form the number within [0, 1).
140
+ };
141
+
142
+ // Return the seed that was used
143
+ return seed;
144
+ };
145
+
146
+ //
147
+ // ARC4
148
+ //
149
+ // An ARC4 implementation. The constructor takes a key in the form of
150
+ // an array of at most (width) integers that should be 0 <= x < (width).
151
+ //
152
+ // The g(count) method returns a pseudorandom integer that concatenates
153
+ // the next (count) outputs from ARC4. Its return value is a number x
154
+ // that is in the range 0 <= x < (width ^ count).
155
+ //
156
+ /** @constructor */
157
+ function ARC4(key) {
158
+ var t, u, me = this, keylen = key.length;
159
+ var i = 0, j = me.i = me.j = me.m = 0;
160
+ me.S = [];
161
+ me.c = [];
162
+
163
+ // The empty key [] is treated as [0].
164
+ if (!keylen) { key = [keylen++]; }
165
+
166
+ // Set up S using the standard key scheduling algorithm.
167
+ while (i < width) { me.S[i] = i++; }
168
+ for (i = 0; i < width; i++) {
169
+ t = me.S[i];
170
+ j = lowbits(j + t + key[i % keylen]);
171
+ u = me.S[j];
172
+ me.S[i] = u;
173
+ me.S[j] = t;
174
+ }
175
+
176
+ // The "g" method returns the next (count) outputs as one number.
177
+ me.g = function getnext(count) {
178
+ var s = me.S;
179
+ var i = lowbits(me.i + 1); var t = s[i];
180
+ var j = lowbits(me.j + t); var u = s[j];
181
+ s[i] = u;
182
+ s[j] = t;
183
+ var r = s[lowbits(t + u)];
184
+ while (--count) {
185
+ i = lowbits(i + 1); t = s[i];
186
+ j = lowbits(j + t); u = s[j];
187
+ s[i] = u;
188
+ s[j] = t;
189
+ r = r * width + s[lowbits(t + u)];
190
+ }
191
+ me.i = i;
192
+ me.j = j;
193
+ return r;
194
+ };
195
+ // For robust unpredictability discard an initial batch of values.
196
+ // See http://www.rsa.com/rsalabs/node.asp?id=2009
197
+ me.g(width);
198
+ }
199
+
200
+ //
201
+ // flatten()
202
+ // Converts an object tree to nested arrays of strings.
203
+ //
204
+ /** @param {Object=} result
205
+ * @param {string=} prop */
206
+ function flatten(obj, depth, result, prop) {
207
+ result = [];
208
+ if (depth && typeof(obj) == 'object') {
209
+ for (prop in obj) {
210
+ if (prop.indexOf('S') < 5) { // Avoid FF3 bug (local/sessionStorage)
211
+ try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
212
+ }
213
+ }
214
+ }
215
+ return result.length ? result : '' + obj;
216
+ }
217
+
218
+ //
219
+ // mixkey()
220
+ // Mixes a string seed into a key that is an array of integers, and
221
+ // returns a shortened string seed that is equivalent to the result key.
222
+ //
223
+ /** @param {number=} smear
224
+ * @param {number=} j */
225
+ function mixkey(seed, key, smear, j) {
226
+ seed += ''; // Ensure the seed is a string
227
+ smear = 0;
228
+ for (j = 0; j < seed.length; j++) {
229
+ key[lowbits(j)] =
230
+ lowbits((smear ^= key[lowbits(j)] * 19) + seed.charCodeAt(j));
231
+ }
232
+ seed = '';
233
+ for (j in key) { seed += String.fromCharCode(key[j]); }
234
+ return seed;
235
+ }
236
+
237
+ //
238
+ // lowbits()
239
+ // A quick "n mod width" for width a power of 2.
240
+ //
241
+ function lowbits(n) { return n & (width - 1); }
242
+
243
+ //
244
+ // The following constants are related to IEEE 754 limits.
245
+ //
246
+ startdenom = math.pow(width, chunks);
247
+ significance = math.pow(2, significance);
248
+ overflow = significance * 2;
249
+
250
+ //
251
+ // When seedrandom.js is loaded, we immediately mix a few bits
252
+ // from the built-in RNG into the entropy pool. Because we do
253
+ // not want to intefere with determinstic PRNG state later,
254
+ // seedrandom will not call math.random on its own again after
255
+ // initialization.
256
+ //
257
+ mixkey(math.random(), pool);
258
+
259
+ // End anonymous scope, and pass initial values.
260
+ })(
261
+ [], // pool: entropy pool starts empty
262
+ Math, // math: package containing random, pow, and seedrandom
263
+ 256, // width: each RC4 output is 0 <= x < 256
264
+ 6, // chunks: at least six RC4 outputs for each double
265
+ 52 // significance: there are 52 significant digits in a double
266
+ );
data/jsmetric.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "jsmetric4java"
7
+ s.version = Jsmetric4Java::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Nigel Fernandes"]
10
+ s.email = ["jsmetric@nigel.in"]
11
+ s.homepage = ""
12
+ s.summary = %q{Cyclometric complexity analyser for Javascript}
13
+ s.description = %q{Cyclometric complexity analyser for Javascript}
14
+
15
+ s.rubyforge_project = "jsmetric"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency('therubyrhino', '1.72.7 ')
23
+ end
data/lib/cc_report.rb ADDED
@@ -0,0 +1,24 @@
1
+ require "complexity_analyser"
2
+
3
+ class CCReport
4
+
5
+ def initialize source
6
+ @output = ""
7
+ @analyser = ComplexityAnalyser.new
8
+ @source = source
9
+ end
10
+
11
+ def as_csv
12
+ begin
13
+ @analyser.parse @source
14
+ @output += "Name, CC"
15
+ @analyser.functions.each do |function|
16
+ @output += "\n#{function[:name]},#{function[:complexity]}"
17
+ end
18
+ rescue Exception => e
19
+ @output = "WARNING: Could not parse \n#{@source} \n: SKIPPED"
20
+ end
21
+ @output
22
+ end
23
+
24
+ end
@@ -0,0 +1,90 @@
1
+ require "js_lint"
2
+
3
+ class ComplexityAnalyser
4
+
5
+ attr_accessor :functions
6
+
7
+ def parse code
8
+ @functions = []
9
+ @js_lint = JSLint.new code
10
+ parse_multiple_expressions @js_lint.tree
11
+ end
12
+
13
+
14
+ # Fixme: Arrrg... this code is crazy. Need to refactor.
15
+ private
16
+
17
+ def parse_single_expression node
18
+ return unless node
19
+
20
+ if ["if", "for", "while", "do", "&&", "||", "?", "default", "case"].include?(node["value"])
21
+ @functions.last[:complexity] += 1 unless @functions.empty?
22
+ end
23
+
24
+ if node["value"].eql?("try")
25
+ @functions.last[:complexity] += 1 if node["second"]
26
+ @functions.last[:complexity] += 1 if node["third"]
27
+ end
28
+
29
+ if node['value'] and node['value'].eql?("function") and not node['arity'].eql?("string")
30
+ function_name = node["name"].empty? ? "Annonymous" : node["name"]
31
+ @functions << {:name => function_name, :complexity => 1}
32
+ parse_multiple_expressions(node["block"])
33
+ @functions.unshift(@functions.pop)
34
+ return
35
+ end
36
+
37
+ if node['value'] and
38
+ node['value'].eql?("var") and
39
+ node["arity"] and
40
+ node["arity"].eql?("statement")
41
+ parse_multiple_expressions node["first"] if node["first"]
42
+ return
43
+ end
44
+
45
+
46
+ if node["arity"] and node["arity"].eql?("infix") and node["value"].eql?("=")
47
+ expression = node["second"]
48
+ if expression and expression["value"].eql?("function") and expression["arity"].eql?("function")
49
+ @functions << {:name => extract_name_from(node["first"]), :complexity => 1}
50
+ parse_multiple_expressions(expression["block"])
51
+ @functions.unshift(@functions.pop)
52
+ return
53
+ end
54
+
55
+ if expression and expression["arity"].eql?("prefix") and expression["value"].eql?("{")
56
+ expression["first"].each do |inner_expression|
57
+ inner_expression["first"]["name"] = extract_name_from inner_expression
58
+ end
59
+ end
60
+ end
61
+
62
+ iterate_and_compute_for node["first"]
63
+ iterate_and_compute_for node["second"]
64
+ iterate_and_compute_for node["third"]
65
+ iterate_and_compute_for node["block"]
66
+ iterate_and_compute_for node["else"]
67
+ end
68
+
69
+ def parse_multiple_expressions array_of_expressions
70
+ return unless array_of_expressions
71
+ array_of_expressions.each do |node|
72
+ parse_single_expression node
73
+ end
74
+ end
75
+
76
+ def extract_name_from node
77
+ return node["value"] unless node["value"].eql?(".") and node["arity"].eql?("infix")
78
+ return "" + extract_name_from(node["first"]) + "." + extract_name_from(node["second"])
79
+ end
80
+
81
+ def iterate_and_compute_for expression
82
+ if expression.is_a?(Array)
83
+ parse_multiple_expressions expression
84
+ else
85
+ parse_single_expression expression
86
+ end
87
+ end
88
+
89
+ end
90
+