jsmetric4java 0.1

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 (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
+