rubrowser 2.5.0 → 2.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e67fd969c9155da49e88d2cc1fd703ac364064841a3800ad03c70bc7c922bfc7
4
- data.tar.gz: 478c3f44d920a685109f24630e17658f3854adc3db675596baa285e4ec8e4538
3
+ metadata.gz: 42ce16c03f4558e78873eb558f1c516e5ce9cad721b951d9f7ecdf31c14c3cc8
4
+ data.tar.gz: 5c39ffdef3e17fc6a13ee5a2ac12007983111686a557faa7c45143f9009527d1
5
5
  SHA512:
6
- metadata.gz: 454bcb581e7fa255cce469d2b82f4321aa0d9f2cf127d2439a99ab437836028587d05a75214b224e1930c971c8b93739aa85838f1a3588658c3909c9d7c84d50
7
- data.tar.gz: 5281d603a1ab859d8609fb05a04ecb63b923beb65977e89ce628a8e6716d17c817eae2ec43e53496f377d348aced37f923374022cf9b5540191157a332bc0f25
6
+ metadata.gz: dbbe9eb3162ec5570ef422675937c174852e16efd7fef2e761cb618cd53b932887dc8e9607ce521bd6a4fe3cb8d2ebf821b9f77ad3abb4361fbddc8afd015e35
7
+ data.tar.gz: bf19b719776bf0c35c60dc250fef2ce29225f2b7158632c19b0c2b1bbba5aec18d31b8e227d33443f89d278c3f84f995e06d399187dc3fa283b17e0b9d1ee45c
@@ -5,3 +5,7 @@ Style/Documentation:
5
5
  Enabled: false
6
6
  Style/FrozenStringLiteralComment:
7
7
  Enabled: false
8
+ Style/GlobalVars:
9
+ Enabled: false
10
+ Metrics/BlockLength:
11
+ Enabled: false
data/.rubrowser CHANGED
@@ -1 +1 @@
1
- [{"id":"Rubrowser::Data","x":905.0088057752334,"y":437.04147016200284},{"id":"Rubrowser","x":712.6220053486966,"y":770.3251873644217},{"id":"Rubrowser::Formatter::JSON","x":1114.4368770370438,"y":560.0312580369882},{"id":"Rubrowser::Formatter","x":1113.6584254066838,"y":601.6487084046246},{"id":"Graph","x":1115.7752854976002,"y":436.6211350242928},{"id":"Rubrowser::Parser::Definition::Base","x":-8.218934126737395,"y":322.74585638398685},{"id":"Rubrowser::Parser::Definition","x":-191.1839782278871,"y":318.6377197576412},{"id":"Rubrowser::Parser","x":713.688310910547,"y":660.9646559993857},{"id":"Rubrowser::Parser::Definition::Class","x":186.15033111747857,"y":246.30753307276427},{"id":"Rubrowser::Parser::Definition::Module","x":188.36911863082037,"y":324.35744429623855},{"id":"Rubrowser::Parser::Directory","x":786.9998045114313,"y":239.74214301898786},{"id":"Rubrowser::Parser::Factory","x":788.0050388528484,"y":325.70343641742613},{"id":"Rubrowser::Parser::File::Builder","x":506.8969046429671,"y":189.48025894394402},{"id":"Rubrowser::Parser::File","x":505.82216034587793,"y":322.6733725221146},{"id":"Rubrowser::Parser::Relation::Base","x":185.12905462589924,"y":402.5519743127113},{"id":"Rubrowser::Parser::Relation","x":187.0097719718301,"y":461.8654698954514},{"id":"Rubrowser::Renderer","x":905.2158605930458,"y":560.8807631671766}]
1
+ [{"id":"A","x":3145.151252107328,"y":1255.7202242818169},{"id":"B","x":3041.815436574058,"y":1133.5156582815155},{"id":"C","x":3199.274701857475,"y":1105.1153162475819},{"id":"ClassWithOneClassDependency","x":1557.2872222716092,"y":-43.47687773940923},{"id":"ModuleWithNoRelations","x":1306.9528557451522,"y":1102.2650375990502},{"id":"ClassWithOneIncludedMixin","x":1498.1264029065396,"y":1151.463703990889},{"id":"ClassWithOneExtendedMixin","x":1505.8925222231119,"y":1066.3427953527182},{"id":"ModuleWithOneClassDependency","x":1506.2730755201367,"y":108.22508398850451},{"id":"ClassWithNoRelations","x":1400.4239271808685,"y":-11.760907506717134},{"id":"Rubrowser::Data","x":905.0088057752334,"y":437.04147016200284},{"id":"Rubrowser","x":712.6220053486966,"y":770.3251873644217},{"id":"Rubrowser::Trace","x":197.20494882540459,"y":735.0751347963624},{"id":"Rubrowser::Monitor","x":430.7305845891392,"y":680.3256207864202},{"id":"Graph","x":1115.7752854976002,"y":436.6211350242928},{"id":"Rubrowser::Connection","x":4.873283667279907,"y":680.4067753374231},{"id":"Rubrowser::Channel","x":1366.414402671432,"y":185.96446885474367},{"id":"Rubrowser::Renderer","x":905.2158605930458,"y":560.8807631671766},{"id":"Rubrowser::Server","x":208.96464998862217,"y":631.2323207047698},{"id":"Rubrowser::Formatter::JSON","x":1114.4368770370438,"y":560.0312580369882},{"id":"Rubrowser::Formatter","x":1113.6584254066838,"y":601.6487084046246},{"id":"Rubrowser::Parser::Definition::Module","x":188.36911863082037,"y":324.35744429623855},{"id":"Rubrowser::Parser::Definition","x":-191.1839782278871,"y":318.6377197576412},{"id":"Rubrowser::Parser","x":713.688310910547,"y":660.9646559993857},{"id":"Rubrowser::Parser::Definition::Base","x":-8.218934126737395,"y":322.74585638398685},{"id":"Rubrowser::Parser::Definition::Class","x":186.15033111747857,"y":246.30753307276427},{"id":"Rubrowser::Parser::Relation::Base","x":185.12905462589924,"y":402.5519743127113},{"id":"Rubrowser::Parser::Relation","x":187.0097719718301,"y":461.8654698954514},{"id":"Rubrowser::Parser::Factory","x":788.0050388528484,"y":325.70343641742613},{"id":"Rubrowser::Parser::File::Builder","x":506.8969046429671,"y":189.48025894394402},{"id":"Rubrowser::Parser::File","x":505.82216034587793,"y":322.6733725221146},{"id":"Rubrowser::Parser::Directory","x":786.9998045114313,"y":239.74214301898786}]
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
4
+ - 2.3
5
+ - 2.4
6
+ - 2.5
@@ -1,55 +1,71 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubrowser (2.5.0)
5
- parser (~> 2.3, >= 2.3.0)
4
+ rubrowser (2.9.0)
5
+ litecable
6
+ parser
7
+ puma
8
+ websocket
6
9
 
7
10
  GEM
8
11
  remote: https://rubygems.org/
9
12
  specs:
10
- ast (2.2.0)
11
- byebug (9.0.6)
12
- diff-lcs (1.3)
13
- parallel (1.12.0)
14
- parser (2.4.0.0)
15
- ast (~> 2.2)
16
- powerpack (0.1.1)
17
- rainbow (2.2.2)
18
- rake
19
- rake (10.4.2)
20
- rspec (3.6.0)
21
- rspec-core (~> 3.6.0)
22
- rspec-expectations (~> 3.6.0)
23
- rspec-mocks (~> 3.6.0)
24
- rspec-core (3.6.0)
25
- rspec-support (~> 3.6.0)
26
- rspec-expectations (3.6.0)
13
+ anyway_config (2.0.6)
14
+ ruby-next-core (>= 0.8.0)
15
+ ast (2.4.1)
16
+ byebug (11.1.3)
17
+ diff-lcs (1.4.4)
18
+ litecable (0.7.0)
19
+ anyway_config (>= 1.0)
20
+ nio4r (2.5.2)
21
+ parallel (1.19.2)
22
+ parser (2.7.1.4)
23
+ ast (~> 2.4.1)
24
+ puma (4.3.5)
25
+ nio4r (~> 2.0)
26
+ rainbow (3.0.0)
27
+ rake (13.0.1)
28
+ regexp_parser (1.7.1)
29
+ rexml (3.2.4)
30
+ rspec (3.9.0)
31
+ rspec-core (~> 3.9.0)
32
+ rspec-expectations (~> 3.9.0)
33
+ rspec-mocks (~> 3.9.0)
34
+ rspec-core (3.9.2)
35
+ rspec-support (~> 3.9.3)
36
+ rspec-expectations (3.9.2)
27
37
  diff-lcs (>= 1.2.0, < 2.0)
28
- rspec-support (~> 3.6.0)
29
- rspec-mocks (3.6.0)
38
+ rspec-support (~> 3.9.0)
39
+ rspec-mocks (3.9.1)
30
40
  diff-lcs (>= 1.2.0, < 2.0)
31
- rspec-support (~> 3.6.0)
32
- rspec-support (3.6.0)
33
- rubocop (0.49.1)
41
+ rspec-support (~> 3.9.0)
42
+ rspec-support (3.9.3)
43
+ rubocop (0.88.0)
34
44
  parallel (~> 1.10)
35
- parser (>= 2.3.3.1, < 3.0)
36
- powerpack (~> 0.1)
37
- rainbow (>= 1.99.1, < 3.0)
45
+ parser (>= 2.7.1.1)
46
+ rainbow (>= 2.2.2, < 4.0)
47
+ regexp_parser (>= 1.7)
48
+ rexml
49
+ rubocop-ast (>= 0.1.0, < 1.0)
38
50
  ruby-progressbar (~> 1.7)
39
- unicode-display_width (~> 1.0, >= 1.0.1)
40
- ruby-progressbar (1.8.1)
41
- unicode-display_width (1.3.0)
51
+ unicode-display_width (>= 1.4.0, < 2.0)
52
+ rubocop-ast (0.3.0)
53
+ parser (>= 2.7.1.4)
54
+ ruby-next-core (0.9.2)
55
+ ruby-progressbar (1.10.1)
56
+ unicode-display_width (1.7.0)
57
+ websocket (1.2.8)
42
58
 
43
59
  PLATFORMS
44
60
  ruby
45
61
 
46
62
  DEPENDENCIES
47
- bundler (~> 1.14)
63
+ bundler
48
64
  byebug
49
- rake (~> 10.0)
65
+ rake
50
66
  rspec
51
67
  rubocop
52
68
  rubrowser!
53
69
 
54
70
  BUNDLED WITH
55
- 1.16.1
71
+ 2.1.4
@@ -12,20 +12,34 @@ options = {
12
12
  }
13
13
 
14
14
  OptionParser.new do |opts|
15
- opts.banner = "Usage: #{__FILE__} [options] [file] ..."
16
-
17
- opts.on('-oFILE', '--output=FILE', 'output file page, if not specified output will be written to stdout') do |output|
18
- options[:output] = output
19
- end
20
-
21
- opts.on('-lFILE', '--layout=FILE', 'layout file to apply on the resulting graph') do |layout|
22
- options[:layout] = layout
23
- end
15
+ opts.banner = "Usage: #{File.basename(__FILE__)} [options] [file] ..."
16
+
17
+ opts.on(
18
+ '-oFILE',
19
+ '--output=FILE',
20
+ 'output file page, if not specified output will be written to stdout'
21
+ ) { |output| options[:output] = output }
22
+
23
+ opts.on(
24
+ '-lFILE',
25
+ '--layout=FILE',
26
+ 'layout file to apply on the resulting graph'
27
+ ) { |layout| options[:layout] = layout }
28
+
29
+ opts.on(
30
+ '-sSERVER:PORT',
31
+ '--server=SERVER:PORT',
32
+ 'rubrowser server for execution monitoring'
33
+ ) { |server| options[:server] = server }
24
34
 
25
35
  opts.on('-T', '--no-toolbox', 'Don\'t display toolbox on the page') do
26
36
  options[:toolbox] = false
27
37
  end
28
38
 
39
+ opts.on('-j', '--json', 'Do export data as JSON instead of HTML') do
40
+ options[:json] = true
41
+ end
42
+
29
43
  opts.on('-v', '--version', 'Print Rubrowser version') do
30
44
  puts "Rubrowser #{Rubrowser::VERSION}"
31
45
  exit
@@ -1,4 +1,5 @@
1
1
  require 'rubrowser/version'
2
+ require 'rubrowser/monitor'
2
3
 
3
4
  module Rubrowser
4
5
  end
@@ -0,0 +1,9 @@
1
+ module Rubrowser
2
+ class Channel < LiteCable::Channel::Base
3
+ identifier :classes
4
+
5
+ def subscribed
6
+ stream_from 'classes'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ require 'rubrowser/channel'
2
+
3
+ module Rubrowser
4
+ class Connection < LiteCable::Connection::Base
5
+ identified_by :id
6
+
7
+ def connect
8
+ @id = rand(100_000)
9
+ self.class.initiate_reader
10
+ end
11
+
12
+ def self.initiate_reader
13
+ @reader ||= Thread.new do
14
+ $rd.each_line do |line|
15
+ LiteCable.broadcast('classes', message: line.strip)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubrowser/trace'
2
+ require 'rubrowser/server'
3
+
4
+ module Rubrowser
5
+ module Monitor
6
+ module_function
7
+
8
+ def run(path: '', port: 8080)
9
+ $rd, $wr = IO.pipe
10
+
11
+ if fork
12
+ $rd.close
13
+ Trace.new(path: path).run
14
+ else
15
+ $wr.close
16
+ Server.new(port: port).run
17
+ exit
18
+ end
19
+ end
20
+ end
21
+ end
@@ -12,20 +12,26 @@ module Rubrowser
12
12
  end
13
13
 
14
14
  def call
15
- output.write(erb(:index))
15
+ if @json
16
+ output.write(data)
17
+ else
18
+ output.write(erb(:index))
19
+ end
16
20
  end
17
21
 
18
22
  private
19
23
 
20
24
  include ERB::Util
21
25
 
22
- attr_reader :files, :output
26
+ attr_reader :files, :output, :server
23
27
 
24
28
  def initialize(options)
25
29
  @output = output_file(options[:output])
26
30
  @layout = options[:layout]
31
+ @server = options[:server]
27
32
  @files = options[:files]
28
33
  @toolbox = options[:toolbox]
34
+ @json = !!options[:json]
29
35
  end
30
36
 
31
37
  def output_file(path)
@@ -0,0 +1,43 @@
1
+ require 'lite_cable'
2
+ require 'lite_cable/server'
3
+ require 'puma/configuration'
4
+ require 'puma/launcher'
5
+ require 'rubrowser/connection'
6
+
7
+ module Rubrowser
8
+ class Server
9
+ def initialize(port: 8080)
10
+ @port = port
11
+ end
12
+
13
+ def run
14
+ launcher.run
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :port
20
+
21
+ def launcher
22
+ @launcher ||= Puma::Launcher.new(conf)
23
+ end
24
+
25
+ def conf
26
+ @conf ||= Puma::Configuration.new do |user_config|
27
+ user_config.threads(1, 1)
28
+ user_config.workers 1
29
+ user_config.port port
30
+ user_config.app(rack_app)
31
+ end
32
+ end
33
+
34
+ def rack_app
35
+ @app ||= Rack::Builder.new do
36
+ map '/' do
37
+ use LiteCable::Server::Middleware, connection_class: Connection
38
+ run(proc { |_| [200, { 'Content-Type' => 'text/plain' }, ['OK']] })
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module Rubrowser
2
+ class Trace
3
+ def initialize(path: '')
4
+ @path = path
5
+ end
6
+
7
+ def run
8
+ trace_point.enable
9
+ end
10
+
11
+ private
12
+
13
+ attr_reader :path
14
+
15
+ def trace_point
16
+ @trace_point ||= TracePoint.new(:call) do |tp|
17
+ $wr.puts tp.defined_class if tp.path.start_with?(path)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Rubrowser
2
- VERSION = '2.5.0'.freeze
2
+ VERSION = '2.9.0'.freeze
3
3
  end
@@ -4,18 +4,19 @@ html, body, .dependency_graph, .dependency_graph svg{
4
4
  padding: 0px;
5
5
  margin: 0px;
6
6
  font-size: 13px;
7
+ overflow: hidden;
7
8
  }
8
9
 
9
10
  .link {
10
- fill: none;
11
- stroke: #666;
12
- stroke-width: 1.5px;
11
+ fill: none;
12
+ stroke: #666;
13
+ stroke-width: 1.5px;
13
14
  }
14
15
 
15
16
  circle {
16
- fill: #fff;
17
- stroke: #333;
18
- stroke-width: 1.5px;
17
+ fill: #fff;
18
+ stroke: #333;
19
+ stroke-width: 1.5px;
19
20
  }
20
21
 
21
22
  .circular {
@@ -23,13 +24,13 @@ circle {
23
24
  }
24
25
 
25
26
  .fixed circle {
26
- stroke-width: 3px;
27
+ stroke-width: 3px;
27
28
  }
28
29
 
29
30
  text {
30
- font: 10px sans-serif;
31
- pointer-events: none;
32
- text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
31
+ font: 10px sans-serif;
32
+ pointer-events: none;
33
+ text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
33
34
  }
34
35
 
35
36
  text.type{
@@ -44,6 +45,11 @@ text.type{
44
45
  display: none;
45
46
  }
46
47
 
48
+ .running circle{
49
+ stroke: #18b738;
50
+ fill: #7dea93;
51
+ }
52
+
47
53
  .highlighted,
48
54
  .highlighted_by_namespace,
49
55
  .highlighted_by_path,
@@ -83,3 +89,24 @@ ul, ol{
83
89
  padding-left: 0px;
84
90
  overflow: auto;
85
91
  }
92
+
93
+ #information_panel{
94
+ position: fixed;
95
+ bottom: 0px;
96
+ left: 0px;
97
+ height: 5rem;
98
+ background: rgba(255,255,255,0.8);
99
+ width: 100%;
100
+ margin-left: 250px;
101
+ padding-right: 250px;
102
+ }
103
+
104
+ #information_panel div{
105
+ margin: 1rem;
106
+ display: inline-block;
107
+ }
108
+
109
+ #information_panel:hover{
110
+ height: 33%;
111
+ overflow: auto;
112
+ }
@@ -0,0 +1,613 @@
1
+ (function() {
2
+ var slice = [].slice;
3
+
4
+ this.ActionCable = {
5
+ INTERNAL: {
6
+ "message_types": {
7
+ "welcome": "welcome",
8
+ "ping": "ping",
9
+ "confirmation": "confirm_subscription",
10
+ "rejection": "reject_subscription"
11
+ },
12
+ "default_mount_path": "/cable",
13
+ "protocols": ["actioncable-v1-json", "actioncable-unsupported"]
14
+ },
15
+ WebSocket: window.WebSocket,
16
+ logger: window.console,
17
+ createConsumer: function(url) {
18
+ var ref;
19
+ if (url == null) {
20
+ url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path;
21
+ }
22
+ return new ActionCable.Consumer(this.createWebSocketURL(url));
23
+ },
24
+ getConfig: function(name) {
25
+ var element;
26
+ element = document.head.querySelector("meta[name='action-cable-" + name + "']");
27
+ return element != null ? element.getAttribute("content") : void 0;
28
+ },
29
+ createWebSocketURL: function(url) {
30
+ var a;
31
+ if (url && !/^wss?:/i.test(url)) {
32
+ a = document.createElement("a");
33
+ a.href = url;
34
+ a.href = a.href;
35
+ a.protocol = a.protocol.replace("http", "ws");
36
+ return a.href;
37
+ } else {
38
+ return url;
39
+ }
40
+ },
41
+ startDebugging: function() {
42
+ return this.debugging = true;
43
+ },
44
+ stopDebugging: function() {
45
+ return this.debugging = null;
46
+ },
47
+ log: function() {
48
+ var messages, ref;
49
+ messages = 1 <= arguments.length ? slice.call(arguments, 0) : [];
50
+ if (this.debugging) {
51
+ messages.push(Date.now());
52
+ return (ref = this.logger).log.apply(ref, ["[ActionCable]"].concat(slice.call(messages)));
53
+ }
54
+ }
55
+ };
56
+
57
+ }).call(this);
58
+ (function() {
59
+ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
60
+
61
+ ActionCable.ConnectionMonitor = (function() {
62
+ var clamp, now, secondsSince;
63
+
64
+ ConnectionMonitor.pollInterval = {
65
+ min: 3,
66
+ max: 30
67
+ };
68
+
69
+ ConnectionMonitor.staleThreshold = 6;
70
+
71
+ function ConnectionMonitor(connection) {
72
+ this.connection = connection;
73
+ this.visibilityDidChange = bind(this.visibilityDidChange, this);
74
+ this.reconnectAttempts = 0;
75
+ }
76
+
77
+ ConnectionMonitor.prototype.start = function() {
78
+ if (!this.isRunning()) {
79
+ this.startedAt = now();
80
+ delete this.stoppedAt;
81
+ this.startPolling();
82
+ document.addEventListener("visibilitychange", this.visibilityDidChange);
83
+ return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms");
84
+ }
85
+ };
86
+
87
+ ConnectionMonitor.prototype.stop = function() {
88
+ if (this.isRunning()) {
89
+ this.stoppedAt = now();
90
+ this.stopPolling();
91
+ document.removeEventListener("visibilitychange", this.visibilityDidChange);
92
+ return ActionCable.log("ConnectionMonitor stopped");
93
+ }
94
+ };
95
+
96
+ ConnectionMonitor.prototype.isRunning = function() {
97
+ return (this.startedAt != null) && (this.stoppedAt == null);
98
+ };
99
+
100
+ ConnectionMonitor.prototype.recordPing = function() {
101
+ return this.pingedAt = now();
102
+ };
103
+
104
+ ConnectionMonitor.prototype.recordConnect = function() {
105
+ this.reconnectAttempts = 0;
106
+ this.recordPing();
107
+ delete this.disconnectedAt;
108
+ return ActionCable.log("ConnectionMonitor recorded connect");
109
+ };
110
+
111
+ ConnectionMonitor.prototype.recordDisconnect = function() {
112
+ this.disconnectedAt = now();
113
+ return ActionCable.log("ConnectionMonitor recorded disconnect");
114
+ };
115
+
116
+ ConnectionMonitor.prototype.startPolling = function() {
117
+ this.stopPolling();
118
+ return this.poll();
119
+ };
120
+
121
+ ConnectionMonitor.prototype.stopPolling = function() {
122
+ return clearTimeout(this.pollTimeout);
123
+ };
124
+
125
+ ConnectionMonitor.prototype.poll = function() {
126
+ return this.pollTimeout = setTimeout((function(_this) {
127
+ return function() {
128
+ _this.reconnectIfStale();
129
+ return _this.poll();
130
+ };
131
+ })(this), this.getPollInterval());
132
+ };
133
+
134
+ ConnectionMonitor.prototype.getPollInterval = function() {
135
+ var interval, max, min, ref;
136
+ ref = this.constructor.pollInterval, min = ref.min, max = ref.max;
137
+ interval = 5 * Math.log(this.reconnectAttempts + 1);
138
+ return Math.round(clamp(interval, min, max) * 1000);
139
+ };
140
+
141
+ ConnectionMonitor.prototype.reconnectIfStale = function() {
142
+ if (this.connectionIsStale()) {
143
+ ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s");
144
+ this.reconnectAttempts++;
145
+ if (this.disconnectedRecently()) {
146
+ return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect");
147
+ } else {
148
+ ActionCable.log("ConnectionMonitor reopening");
149
+ return this.connection.reopen();
150
+ }
151
+ }
152
+ };
153
+
154
+ ConnectionMonitor.prototype.connectionIsStale = function() {
155
+ var ref;
156
+ return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold;
157
+ };
158
+
159
+ ConnectionMonitor.prototype.disconnectedRecently = function() {
160
+ return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;
161
+ };
162
+
163
+ ConnectionMonitor.prototype.visibilityDidChange = function() {
164
+ if (document.visibilityState === "visible") {
165
+ return setTimeout((function(_this) {
166
+ return function() {
167
+ if (_this.connectionIsStale() || !_this.connection.isOpen()) {
168
+ ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState);
169
+ return _this.connection.reopen();
170
+ }
171
+ };
172
+ })(this), 200);
173
+ }
174
+ };
175
+
176
+ now = function() {
177
+ return new Date().getTime();
178
+ };
179
+
180
+ secondsSince = function(time) {
181
+ return (now() - time) / 1000;
182
+ };
183
+
184
+ clamp = function(number, min, max) {
185
+ return Math.max(min, Math.min(max, number));
186
+ };
187
+
188
+ return ConnectionMonitor;
189
+
190
+ })();
191
+
192
+ }).call(this);
193
+ (function() {
194
+ var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol,
195
+ slice = [].slice,
196
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
197
+ indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
198
+
199
+ ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols;
200
+
201
+ supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++];
202
+
203
+ ActionCable.Connection = (function() {
204
+ Connection.reopenDelay = 500;
205
+
206
+ function Connection(consumer) {
207
+ this.consumer = consumer;
208
+ this.open = bind(this.open, this);
209
+ this.subscriptions = this.consumer.subscriptions;
210
+ this.monitor = new ActionCable.ConnectionMonitor(this);
211
+ this.disconnected = true;
212
+ }
213
+
214
+ Connection.prototype.send = function(data) {
215
+ if (this.isOpen()) {
216
+ this.webSocket.send(JSON.stringify(data));
217
+ return true;
218
+ } else {
219
+ return false;
220
+ }
221
+ };
222
+
223
+ Connection.prototype.open = function() {
224
+ if (this.isActive()) {
225
+ ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState()));
226
+ return false;
227
+ } else {
228
+ ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols);
229
+ if (this.webSocket != null) {
230
+ this.uninstallEventHandlers();
231
+ }
232
+ this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols);
233
+ this.installEventHandlers();
234
+ this.monitor.start();
235
+ return true;
236
+ }
237
+ };
238
+
239
+ Connection.prototype.close = function(arg) {
240
+ var allowReconnect, ref1;
241
+ allowReconnect = (arg != null ? arg : {
242
+ allowReconnect: true
243
+ }).allowReconnect;
244
+ if (!allowReconnect) {
245
+ this.monitor.stop();
246
+ }
247
+ if (this.isActive()) {
248
+ return (ref1 = this.webSocket) != null ? ref1.close() : void 0;
249
+ }
250
+ };
251
+
252
+ Connection.prototype.reopen = function() {
253
+ var error;
254
+ ActionCable.log("Reopening WebSocket, current state is " + (this.getState()));
255
+ if (this.isActive()) {
256
+ try {
257
+ return this.close();
258
+ } catch (error1) {
259
+ error = error1;
260
+ return ActionCable.log("Failed to reopen WebSocket", error);
261
+ } finally {
262
+ ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms");
263
+ setTimeout(this.open, this.constructor.reopenDelay);
264
+ }
265
+ } else {
266
+ return this.open();
267
+ }
268
+ };
269
+
270
+ Connection.prototype.getProtocol = function() {
271
+ var ref1;
272
+ return (ref1 = this.webSocket) != null ? ref1.protocol : void 0;
273
+ };
274
+
275
+ Connection.prototype.isOpen = function() {
276
+ return this.isState("open");
277
+ };
278
+
279
+ Connection.prototype.isActive = function() {
280
+ return this.isState("open", "connecting");
281
+ };
282
+
283
+ Connection.prototype.isProtocolSupported = function() {
284
+ var ref1;
285
+ return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0;
286
+ };
287
+
288
+ Connection.prototype.isState = function() {
289
+ var ref1, states;
290
+ states = 1 <= arguments.length ? slice.call(arguments, 0) : [];
291
+ return ref1 = this.getState(), indexOf.call(states, ref1) >= 0;
292
+ };
293
+
294
+ Connection.prototype.getState = function() {
295
+ var ref1, state, value;
296
+ for (state in WebSocket) {
297
+ value = WebSocket[state];
298
+ if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) {
299
+ return state.toLowerCase();
300
+ }
301
+ }
302
+ return null;
303
+ };
304
+
305
+ Connection.prototype.installEventHandlers = function() {
306
+ var eventName, handler;
307
+ for (eventName in this.events) {
308
+ handler = this.events[eventName].bind(this);
309
+ this.webSocket["on" + eventName] = handler;
310
+ }
311
+ };
312
+
313
+ Connection.prototype.uninstallEventHandlers = function() {
314
+ var eventName;
315
+ for (eventName in this.events) {
316
+ this.webSocket["on" + eventName] = function() {};
317
+ }
318
+ };
319
+
320
+ Connection.prototype.events = {
321
+ message: function(event) {
322
+ var identifier, message, ref1, type;
323
+ if (!this.isProtocolSupported()) {
324
+ return;
325
+ }
326
+ ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type;
327
+ switch (type) {
328
+ case message_types.welcome:
329
+ this.monitor.recordConnect();
330
+ return this.subscriptions.reload();
331
+ case message_types.ping:
332
+ return this.monitor.recordPing();
333
+ case message_types.confirmation:
334
+ return this.subscriptions.notify(identifier, "connected");
335
+ case message_types.rejection:
336
+ return this.subscriptions.reject(identifier);
337
+ default:
338
+ return this.subscriptions.notify(identifier, "received", message);
339
+ }
340
+ },
341
+ open: function() {
342
+ ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol");
343
+ this.disconnected = false;
344
+ if (!this.isProtocolSupported()) {
345
+ ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting.");
346
+ return this.close({
347
+ allowReconnect: false
348
+ });
349
+ }
350
+ },
351
+ close: function(event) {
352
+ ActionCable.log("WebSocket onclose event");
353
+ if (this.disconnected) {
354
+ return;
355
+ }
356
+ this.disconnected = true;
357
+ this.monitor.recordDisconnect();
358
+ return this.subscriptions.notifyAll("disconnected", {
359
+ willAttemptReconnect: this.monitor.isRunning()
360
+ });
361
+ },
362
+ error: function() {
363
+ return ActionCable.log("WebSocket onerror event");
364
+ }
365
+ };
366
+
367
+ return Connection;
368
+
369
+ })();
370
+
371
+ }).call(this);
372
+ (function() {
373
+ var slice = [].slice;
374
+
375
+ ActionCable.Subscriptions = (function() {
376
+ function Subscriptions(consumer) {
377
+ this.consumer = consumer;
378
+ this.subscriptions = [];
379
+ }
380
+
381
+ Subscriptions.prototype.create = function(channelName, mixin) {
382
+ var channel, params, subscription;
383
+ channel = channelName;
384
+ params = typeof channel === "object" ? channel : {
385
+ channel: channel
386
+ };
387
+ subscription = new ActionCable.Subscription(this.consumer, params, mixin);
388
+ return this.add(subscription);
389
+ };
390
+
391
+ Subscriptions.prototype.add = function(subscription) {
392
+ this.subscriptions.push(subscription);
393
+ this.consumer.ensureActiveConnection();
394
+ this.notify(subscription, "initialized");
395
+ this.sendCommand(subscription, "subscribe");
396
+ return subscription;
397
+ };
398
+
399
+ Subscriptions.prototype.remove = function(subscription) {
400
+ this.forget(subscription);
401
+ if (!this.findAll(subscription.identifier).length) {
402
+ this.sendCommand(subscription, "unsubscribe");
403
+ }
404
+ return subscription;
405
+ };
406
+
407
+ Subscriptions.prototype.reject = function(identifier) {
408
+ var i, len, ref, results, subscription;
409
+ ref = this.findAll(identifier);
410
+ results = [];
411
+ for (i = 0, len = ref.length; i < len; i++) {
412
+ subscription = ref[i];
413
+ this.forget(subscription);
414
+ this.notify(subscription, "rejected");
415
+ results.push(subscription);
416
+ }
417
+ return results;
418
+ };
419
+
420
+ Subscriptions.prototype.forget = function(subscription) {
421
+ var s;
422
+ this.subscriptions = (function() {
423
+ var i, len, ref, results;
424
+ ref = this.subscriptions;
425
+ results = [];
426
+ for (i = 0, len = ref.length; i < len; i++) {
427
+ s = ref[i];
428
+ if (s !== subscription) {
429
+ results.push(s);
430
+ }
431
+ }
432
+ return results;
433
+ }).call(this);
434
+ return subscription;
435
+ };
436
+
437
+ Subscriptions.prototype.findAll = function(identifier) {
438
+ var i, len, ref, results, s;
439
+ ref = this.subscriptions;
440
+ results = [];
441
+ for (i = 0, len = ref.length; i < len; i++) {
442
+ s = ref[i];
443
+ if (s.identifier === identifier) {
444
+ results.push(s);
445
+ }
446
+ }
447
+ return results;
448
+ };
449
+
450
+ Subscriptions.prototype.reload = function() {
451
+ var i, len, ref, results, subscription;
452
+ ref = this.subscriptions;
453
+ results = [];
454
+ for (i = 0, len = ref.length; i < len; i++) {
455
+ subscription = ref[i];
456
+ results.push(this.sendCommand(subscription, "subscribe"));
457
+ }
458
+ return results;
459
+ };
460
+
461
+ Subscriptions.prototype.notifyAll = function() {
462
+ var args, callbackName, i, len, ref, results, subscription;
463
+ callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
464
+ ref = this.subscriptions;
465
+ results = [];
466
+ for (i = 0, len = ref.length; i < len; i++) {
467
+ subscription = ref[i];
468
+ results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args))));
469
+ }
470
+ return results;
471
+ };
472
+
473
+ Subscriptions.prototype.notify = function() {
474
+ var args, callbackName, i, len, results, subscription, subscriptions;
475
+ subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
476
+ if (typeof subscription === "string") {
477
+ subscriptions = this.findAll(subscription);
478
+ } else {
479
+ subscriptions = [subscription];
480
+ }
481
+ results = [];
482
+ for (i = 0, len = subscriptions.length; i < len; i++) {
483
+ subscription = subscriptions[i];
484
+ results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0);
485
+ }
486
+ return results;
487
+ };
488
+
489
+ Subscriptions.prototype.sendCommand = function(subscription, command) {
490
+ var identifier;
491
+ identifier = subscription.identifier;
492
+ return this.consumer.send({
493
+ command: command,
494
+ identifier: identifier
495
+ });
496
+ };
497
+
498
+ return Subscriptions;
499
+
500
+ })();
501
+
502
+ }).call(this);
503
+ (function() {
504
+ ActionCable.Subscription = (function() {
505
+ var extend;
506
+
507
+ function Subscription(consumer, params, mixin) {
508
+ this.consumer = consumer;
509
+ if (params == null) {
510
+ params = {};
511
+ }
512
+ this.identifier = JSON.stringify(params);
513
+ extend(this, mixin);
514
+ }
515
+
516
+ Subscription.prototype.perform = function(action, data) {
517
+ if (data == null) {
518
+ data = {};
519
+ }
520
+ data.action = action;
521
+ return this.send(data);
522
+ };
523
+
524
+ Subscription.prototype.send = function(data) {
525
+ return this.consumer.send({
526
+ command: "message",
527
+ identifier: this.identifier,
528
+ data: JSON.stringify(data)
529
+ });
530
+ };
531
+
532
+ Subscription.prototype.unsubscribe = function() {
533
+ return this.consumer.subscriptions.remove(this);
534
+ };
535
+
536
+ extend = function(object, properties) {
537
+ var key, value;
538
+ if (properties != null) {
539
+ for (key in properties) {
540
+ value = properties[key];
541
+ object[key] = value;
542
+ }
543
+ }
544
+ return object;
545
+ };
546
+
547
+ return Subscription;
548
+
549
+ })();
550
+
551
+ }).call(this);
552
+ (function() {
553
+ ActionCable.Consumer = (function() {
554
+ function Consumer(url) {
555
+ this.url = url;
556
+ this.subscriptions = new ActionCable.Subscriptions(this);
557
+ this.connection = new ActionCable.Connection(this);
558
+ }
559
+
560
+ Consumer.prototype.send = function(data) {
561
+ return this.connection.send(data);
562
+ };
563
+
564
+ Consumer.prototype.connect = function() {
565
+ return this.connection.open();
566
+ };
567
+
568
+ Consumer.prototype.disconnect = function() {
569
+ return this.connection.close({
570
+ allowReconnect: false
571
+ });
572
+ };
573
+
574
+ Consumer.prototype.ensureActiveConnection = function() {
575
+ if (!this.connection.isActive()) {
576
+ return this.connection.open();
577
+ }
578
+ };
579
+
580
+ return Consumer;
581
+
582
+ })();
583
+
584
+ }).call(this);
585
+
586
+ var glowing = {}
587
+ function glow(cls) {
588
+ if (!glowing[cls]) {
589
+ var node = rubrowser.node.filter(function(d){
590
+ return d.id == cls;
591
+ });
592
+
593
+ if (node.size() > 0){
594
+ node.classed("running", true);
595
+ glowing[cls] = true;
596
+ setTimeout(function(){
597
+ glowing[cls] = false;
598
+ node.classed("running", false);
599
+ }, 2000)
600
+ }
601
+ }
602
+ }
603
+
604
+ var cable = ActionCable.createConsumer(server)
605
+ cable.ensureActiveConnection()
606
+ var channel = cable.subscriptions.create(
607
+ "classes",
608
+ {
609
+ received: function(data){
610
+ glow(data.message);
611
+ }
612
+ }
613
+ )