breakfast 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 68ce62fc8d2a9b3a03545936ed1841513872812d
4
+ data.tar.gz: 841d82099e64bc247ff815ae145845e6f203afca
5
+ SHA512:
6
+ metadata.gz: 1194e1f38671dab58baebae778721cb0235db9a751a08d2bfc0b87c3414a52df39aa1eeea565b88ab0678dce150c4e8173f90b875bbad9baed9da9a23c778bc1
7
+ data.tar.gz: dfdac97c7f8107e3d0d6884210edc8d164a49321da3c0078970848bacb9d8980d26050c950500053a02cf79e846dde2127641eeafeb02c4f73be963128a84815
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ node_package/node_modules/*
11
+ node_package/lib/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.3
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in breakfast.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Patrick Koperwas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,41 @@
1
+ # Breakfast
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/breakfast`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'breakfast'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install breakfast
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/breakfast.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "breakfast"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "breakfast/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "breakfast"
8
+ spec.version = Breakfast::VERSION
9
+ spec.authors = ["Patrick Koperwas"]
10
+ spec.email = ["patrick@devlocker.io"]
11
+
12
+ spec.summary = %q{Integrates Brunch into Rails}
13
+ spec.description = %q{Replace the asset pipeline with Brunch. Get CSS, JS and HTML live-reloading out of the box. Full ES6 support with require. No need to launch extra servers.}
14
+ spec.homepage = "https://github.com/devlocker/breakfast"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.12"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_dependency "rails", "5.0.0.rc2"
26
+ spec.add_dependency "actioncable"
27
+ spec.add_dependency "listen"
28
+ end
@@ -0,0 +1,8 @@
1
+ require "breakfast/version"
2
+ require "breakfast/live_reload_channel"
3
+ require "breakfast/view_helper"
4
+
5
+ module Breakfast
6
+ end
7
+
8
+ require "breakfast/railtie" if defined?(Rails)
@@ -0,0 +1,9 @@
1
+ require "rails"
2
+
3
+ module Breakfast
4
+ class LiveReloadChannel < ::ActionCable::Channel::Base
5
+ def subscribed
6
+ stream_from "breakfast_live_reload"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,46 @@
1
+ require "rails"
2
+
3
+ module BrunchRails
4
+ class Railtie < ::Rails::Railtie
5
+ config.breakfast = ActiveSupport::OrderedOptions.new
6
+
7
+ config.before_configuration do |app|
8
+ config.breakfast.live_reload = true
9
+
10
+ config.breakfast.output_folders = [Rails.root.join("public")]
11
+ config.breakfast.view_folders = [Rails.root.join("app", "views")]
12
+
13
+ config.breakfast.websocket_hostname = "localhost"
14
+ config.breakfast.websocket_port = 3000
15
+ end
16
+
17
+ initializer "breakfast.setup_view_helpers" do |app|
18
+ ActiveSupport.on_load(:action_view) do
19
+ include ::Breakfast::ViewHelper
20
+ end
21
+ end
22
+
23
+ config.after_initialize do |app|
24
+ if Rails.env.development? && defined?(Rails::Server)
25
+ Process.spawn("brunch watch")
26
+ end
27
+
28
+ listen_to_paths = Array.wrap(config.breakfast.output_folders) +
29
+ Array.wrap(config.breakfast.view_folders)
30
+
31
+ listener = ::Listen.to(*listen_to_paths) do |modified, added, removed|
32
+ files = modified + added + removed
33
+ extensions = ["css", "js", "html"].freeze
34
+
35
+ extensions.each do |extension|
36
+ if files.any? { |file| file.match(/\.#{extension}/) }
37
+ ActionCable.server.broadcast "breakfast_live_reload",
38
+ { extension: extension }
39
+ end
40
+ end
41
+ end
42
+
43
+ listener.start
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,3 @@
1
+ module Breakfast
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,13 @@
1
+ module Breakfast
2
+ module ViewHelper
3
+ def breakfast_autoreload_tag
4
+ content_tag :script do
5
+ <<-SCRIPT.html_safe
6
+ window.Breakfast = window.Breakfast || {};
7
+ window.Breakfast.liveReload = #{Rails.configuration.breakfast.live_reload};
8
+ require("breakfast-rails").init();
9
+ SCRIPT
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,78 @@
1
+ require "rails/generators"
2
+
3
+ module Breakfast
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ def install
9
+ if prerequisites_installed?
10
+ create_brunch_config
11
+ create_package_json
12
+ create_directory_structure
13
+ create_initialize_file
14
+ run_npm_install
15
+ add_node_modules_to_gitignore
16
+
17
+ puts <<-SUCCESS.strip_heredoc
18
+
19
+ ---> BREAKFAST INSTALLED SUCCESSFULLY
20
+ ---> See https://github.com/devlocker/breakfast for documentation and examples.
21
+
22
+ SUCCESS
23
+ else
24
+ puts <<-ERROR.strip_heredoc
25
+
26
+ ---> ERROR - MISSING NODE & NPM
27
+
28
+ ---> Node & npm are required to run Breakfast.
29
+ ---> Please install them before attempting to continue.
30
+ ---> https://nodejs.org
31
+ ---> https://npmjs.org
32
+
33
+ ERROR
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def prerequisites_installed?
40
+ `which node`.present? && `which npm`.present?
41
+ end
42
+
43
+ def create_brunch_config
44
+ copy_file "brunch-config.js", "brunch-config.js"
45
+ end
46
+
47
+ def create_package_json
48
+ copy_file "package.json", "package.json"
49
+ end
50
+
51
+ def create_directory_structure
52
+ empty_directory "assets/css"
53
+ empty_directory "assets/images"
54
+ empty_directory "assets/js"
55
+ empty_directory "assets/vendor"
56
+ end
57
+
58
+ def create_initialize_file
59
+ copy_file "initialize.js", "assets/js/initialize.js"
60
+ end
61
+
62
+ def run_npm_install
63
+ run "npm install"
64
+ end
65
+
66
+ def add_node_modules_to_gitignore
67
+ ignore = <<-IGNORE.strip_heredoc
68
+ # Added by Breakfast Gem
69
+ npm-debug.log
70
+ node_modules/*
71
+ public/assets/*
72
+ IGNORE
73
+
74
+ append_to_file(".gitignore", ignore)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,35 @@
1
+ module.exports = {
2
+ files: {
3
+ javascripts: {
4
+ joinTo: {
5
+ 'app.js': /^assets\/js\//,
6
+ 'vendor.js': /^(?!assets\/js)/
7
+ }
8
+ },
9
+ stylesheets: {
10
+ joinTo: 'app.css'
11
+ }
12
+ },
13
+
14
+ plugins: {
15
+ babel: {
16
+ presets: ['es2015']
17
+ },
18
+ },
19
+
20
+ paths: {
21
+ watched: [
22
+ "assets/",
23
+ ],
24
+
25
+ public: "public/assets"
26
+ },
27
+
28
+ conventions: {
29
+ assets: /^(assets\/images)/
30
+ },
31
+
32
+ npm: {
33
+ enabled: true
34
+ }
35
+ };
@@ -0,0 +1,4 @@
1
+ const App = {
2
+ }
3
+
4
+ module.exports = App;
@@ -0,0 +1,14 @@
1
+ {
2
+ "repository": {},
3
+ "dependencies": {
4
+ "babel-brunch": "~6.0.0",
5
+ "breakfast-rails": "0.0.1",
6
+ "brunch": "~2.1.3",
7
+ "clean-css-brunch": "~1.8.0",
8
+ "css-brunch": "~1.7.0",
9
+ "javascript-brunch": "~1.8.0",
10
+ "sass-brunch": "~2.6.3",
11
+ "uglify-js-brunch": "~1.7.0"
12
+ },
13
+ "devDependencies": {}
14
+ }
@@ -0,0 +1 @@
1
+ src/
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "breakfast-rails",
3
+ "version": "0.0.3",
4
+ "description": "Assets for the Breakfast Gem",
5
+ "main": "breakfast-rails.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "compile": "babel --presets es2015 -d lib/ src/",
9
+ "prepublish": "npm run compile"
10
+ },
11
+ "author": "Patrick Koperwas",
12
+ "license": "MIT",
13
+ "dependencies": {},
14
+ "devDependencies": {
15
+ "babel-cli": "^6.10.1",
16
+ "babel-preset-es2015": "^6.9.0"
17
+ }
18
+ }
@@ -0,0 +1,572 @@
1
+ // Copied from Rails source. Rails RC1.
2
+ var ActionCable = {
3
+ INTERNAL: {
4
+ "message_types": {
5
+ "welcome": "welcome",
6
+ "ping": "ping",
7
+ "confirmation": "confirm_subscription",
8
+ "rejection": "reject_subscription"
9
+ },
10
+ "default_mount_path": "/cable",
11
+ "protocols": ["actioncable-v1-json", "actioncable-unsupported"]
12
+ },
13
+ WebSocket: window.WebSocket,
14
+ logger: window.console,
15
+ createConsumer: function(url) {
16
+ var ref;
17
+ if (url == null) {
18
+ url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path;
19
+ }
20
+ return new ActionCable.Consumer(this.createWebSocketURL(url));
21
+ },
22
+ getConfig: function(name) {
23
+ var element;
24
+ element = document.head.querySelector("meta[name='action-cable-" + name + "']");
25
+ return element != null ? element.getAttribute("content") : void 0;
26
+ },
27
+ createWebSocketURL: function(url) {
28
+ var a;
29
+ if (url && !/^wss?:/i.test(url)) {
30
+ a = document.createElement("a");
31
+ a.href = url;
32
+ a.href = a.href;
33
+ a.protocol = a.protocol.replace("http", "ws");
34
+ return a.href;
35
+ } else {
36
+ return url;
37
+ }
38
+ },
39
+ startDebugging: function() {
40
+ return this.debugging = true;
41
+ },
42
+ stopDebugging: function() {
43
+ return this.debugging = null;
44
+ },
45
+ log: function() {
46
+ var messages, ref;
47
+ messages = 1 <= arguments.length ? slice.call(arguments, 0) : [];
48
+ if (this.debugging) {
49
+ messages.push(Date.now());
50
+ return (ref = this.logger).log.apply(ref, ["[ActionCable]"].concat(slice.call(messages)));
51
+ }
52
+ }
53
+ };
54
+
55
+ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
56
+
57
+ ActionCable.ConnectionMonitor = (function() {
58
+ var clamp, now, secondsSince;
59
+
60
+ ConnectionMonitor.pollInterval = {
61
+ min: 3,
62
+ max: 30
63
+ };
64
+
65
+ ConnectionMonitor.staleThreshold = 6;
66
+
67
+ function ConnectionMonitor(connection) {
68
+ this.connection = connection;
69
+ this.visibilityDidChange = bind(this.visibilityDidChange, this);
70
+ this.reconnectAttempts = 0;
71
+ }
72
+
73
+ ConnectionMonitor.prototype.start = function() {
74
+ if (!this.isRunning()) {
75
+ this.startedAt = now();
76
+ delete this.stoppedAt;
77
+ this.startPolling();
78
+ document.addEventListener("visibilitychange", this.visibilityDidChange);
79
+ return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms");
80
+ }
81
+ };
82
+
83
+ ConnectionMonitor.prototype.stop = function() {
84
+ if (this.isRunning()) {
85
+ this.stoppedAt = now();
86
+ this.stopPolling();
87
+ document.removeEventListener("visibilitychange", this.visibilityDidChange);
88
+ return ActionCable.log("ConnectionMonitor stopped");
89
+ }
90
+ };
91
+
92
+ ConnectionMonitor.prototype.isRunning = function() {
93
+ return (this.startedAt != null) && (this.stoppedAt == null);
94
+ };
95
+
96
+ ConnectionMonitor.prototype.recordPing = function() {
97
+ return this.pingedAt = now();
98
+ };
99
+
100
+ ConnectionMonitor.prototype.recordConnect = function() {
101
+ this.reconnectAttempts = 0;
102
+ this.recordPing();
103
+ delete this.disconnectedAt;
104
+ return ActionCable.log("ConnectionMonitor recorded connect");
105
+ };
106
+
107
+ ConnectionMonitor.prototype.recordDisconnect = function() {
108
+ this.disconnectedAt = now();
109
+ return ActionCable.log("ConnectionMonitor recorded disconnect");
110
+ };
111
+
112
+ ConnectionMonitor.prototype.startPolling = function() {
113
+ this.stopPolling();
114
+ return this.poll();
115
+ };
116
+
117
+ ConnectionMonitor.prototype.stopPolling = function() {
118
+ return clearTimeout(this.pollTimeout);
119
+ };
120
+
121
+ ConnectionMonitor.prototype.poll = function() {
122
+ return this.pollTimeout = setTimeout((function(_this) {
123
+ return function() {
124
+ _this.reconnectIfStale();
125
+ return _this.poll();
126
+ };
127
+ })(this), this.getPollInterval());
128
+ };
129
+
130
+ ConnectionMonitor.prototype.getPollInterval = function() {
131
+ var interval, max, min, ref;
132
+ ref = this.constructor.pollInterval, min = ref.min, max = ref.max;
133
+ interval = 5 * Math.log(this.reconnectAttempts + 1);
134
+ return Math.round(clamp(interval, min, max) * 1000);
135
+ };
136
+
137
+ ConnectionMonitor.prototype.reconnectIfStale = function() {
138
+ if (this.connectionIsStale()) {
139
+ 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");
140
+ this.reconnectAttempts++;
141
+ if (this.disconnectedRecently()) {
142
+ return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect");
143
+ } else {
144
+ ActionCable.log("ConnectionMonitor reopening");
145
+ return this.connection.reopen();
146
+ }
147
+ }
148
+ };
149
+
150
+ ConnectionMonitor.prototype.connectionIsStale = function() {
151
+ var ref;
152
+ return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold;
153
+ };
154
+
155
+ ConnectionMonitor.prototype.disconnectedRecently = function() {
156
+ return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;
157
+ };
158
+
159
+ ConnectionMonitor.prototype.visibilityDidChange = function() {
160
+ if (document.visibilityState === "visible") {
161
+ return setTimeout((function(_this) {
162
+ return function() {
163
+ if (_this.connectionIsStale() || !_this.connection.isOpen()) {
164
+ ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState);
165
+ return _this.connection.reopen();
166
+ }
167
+ };
168
+ })(this), 200);
169
+ }
170
+ };
171
+
172
+ now = function() {
173
+ return new Date().getTime();
174
+ };
175
+
176
+ secondsSince = function(time) {
177
+ return (now() - time) / 1000;
178
+ };
179
+
180
+ clamp = function(number, min, max) {
181
+ return Math.max(min, Math.min(max, number));
182
+ };
183
+
184
+ return ConnectionMonitor;
185
+
186
+ })();
187
+
188
+ var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol,
189
+ slice = [].slice,
190
+ bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
191
+ 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; };
192
+
193
+ ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols;
194
+
195
+ supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++];
196
+
197
+ ActionCable.Connection = (function() {
198
+ Connection.reopenDelay = 500;
199
+
200
+ function Connection(consumer) {
201
+ this.consumer = consumer;
202
+ this.open = bind(this.open, this);
203
+ this.subscriptions = this.consumer.subscriptions;
204
+ this.monitor = new ActionCable.ConnectionMonitor(this);
205
+ this.disconnected = true;
206
+ }
207
+
208
+ Connection.prototype.send = function(data) {
209
+ if (this.isOpen()) {
210
+ this.webSocket.send(JSON.stringify(data));
211
+ return true;
212
+ } else {
213
+ return false;
214
+ }
215
+ };
216
+
217
+ Connection.prototype.open = function() {
218
+ if (this.isActive()) {
219
+ ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState()));
220
+ throw new Error("Existing connection must be closed before opening");
221
+ } else {
222
+ ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols);
223
+ if (this.webSocket != null) {
224
+ this.uninstallEventHandlers();
225
+ }
226
+ this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols);
227
+ this.installEventHandlers();
228
+ this.monitor.start();
229
+ return true;
230
+ }
231
+ };
232
+
233
+ Connection.prototype.close = function(arg) {
234
+ var allowReconnect, ref1;
235
+ allowReconnect = (arg != null ? arg : {
236
+ allowReconnect: true
237
+ }).allowReconnect;
238
+ if (!allowReconnect) {
239
+ this.monitor.stop();
240
+ }
241
+ if (this.isActive()) {
242
+ return (ref1 = this.webSocket) != null ? ref1.close() : void 0;
243
+ }
244
+ };
245
+
246
+ Connection.prototype.reopen = function() {
247
+ var error, error1;
248
+ ActionCable.log("Reopening WebSocket, current state is " + (this.getState()));
249
+ if (this.isActive()) {
250
+ try {
251
+ return this.close();
252
+ } catch (error1) {
253
+ error = error1;
254
+ return ActionCable.log("Failed to reopen WebSocket", error);
255
+ } finally {
256
+ ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms");
257
+ setTimeout(this.open, this.constructor.reopenDelay);
258
+ }
259
+ } else {
260
+ return this.open();
261
+ }
262
+ };
263
+
264
+ Connection.prototype.getProtocol = function() {
265
+ var ref1;
266
+ return (ref1 = this.webSocket) != null ? ref1.protocol : void 0;
267
+ };
268
+
269
+ Connection.prototype.isOpen = function() {
270
+ return this.isState("open");
271
+ };
272
+
273
+ Connection.prototype.isActive = function() {
274
+ return this.isState("open", "connecting");
275
+ };
276
+
277
+ Connection.prototype.isProtocolSupported = function() {
278
+ var ref1;
279
+ return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0;
280
+ };
281
+
282
+ Connection.prototype.isState = function() {
283
+ var ref1, states;
284
+ states = 1 <= arguments.length ? slice.call(arguments, 0) : [];
285
+ return ref1 = this.getState(), indexOf.call(states, ref1) >= 0;
286
+ };
287
+
288
+ Connection.prototype.getState = function() {
289
+ var ref1, state, value;
290
+ for (state in WebSocket) {
291
+ value = WebSocket[state];
292
+ if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) {
293
+ return state.toLowerCase();
294
+ }
295
+ }
296
+ return null;
297
+ };
298
+
299
+ Connection.prototype.installEventHandlers = function() {
300
+ var eventName, handler;
301
+ for (eventName in this.events) {
302
+ handler = this.events[eventName].bind(this);
303
+ this.webSocket["on" + eventName] = handler;
304
+ }
305
+ };
306
+
307
+ Connection.prototype.uninstallEventHandlers = function() {
308
+ var eventName;
309
+ for (eventName in this.events) {
310
+ this.webSocket["on" + eventName] = function() {};
311
+ }
312
+ };
313
+
314
+ Connection.prototype.events = {
315
+ message: function(event) {
316
+ var identifier, message, ref1, type;
317
+ if (!this.isProtocolSupported()) {
318
+ return;
319
+ }
320
+ ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type;
321
+ switch (type) {
322
+ case message_types.welcome:
323
+ this.monitor.recordConnect();
324
+ return this.subscriptions.reload();
325
+ case message_types.ping:
326
+ return this.monitor.recordPing();
327
+ case message_types.confirmation:
328
+ return this.subscriptions.notify(identifier, "connected");
329
+ case message_types.rejection:
330
+ return this.subscriptions.reject(identifier);
331
+ default:
332
+ return this.subscriptions.notify(identifier, "received", message);
333
+ }
334
+ },
335
+ open: function() {
336
+ ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol");
337
+ this.disconnected = false;
338
+ if (!this.isProtocolSupported()) {
339
+ ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting.");
340
+ return this.close({
341
+ allowReconnect: false
342
+ });
343
+ }
344
+ },
345
+ close: function(event) {
346
+ ActionCable.log("WebSocket onclose event");
347
+ if (this.disconnected) {
348
+ return;
349
+ }
350
+ this.disconnected = true;
351
+ this.monitor.recordDisconnect();
352
+ return this.subscriptions.notifyAll("disconnected", {
353
+ willAttemptReconnect: this.monitor.isRunning()
354
+ });
355
+ },
356
+ error: function() {
357
+ return ActionCable.log("WebSocket onerror event");
358
+ }
359
+ };
360
+
361
+ return Connection;
362
+
363
+ })();
364
+
365
+ var slice = [].slice;
366
+
367
+ ActionCable.Subscriptions = (function() {
368
+ function Subscriptions(consumer) {
369
+ this.consumer = consumer;
370
+ this.subscriptions = [];
371
+ }
372
+
373
+ Subscriptions.prototype.create = function(channelName, mixin) {
374
+ var channel, params, subscription;
375
+ channel = channelName;
376
+ params = typeof channel === "object" ? channel : {
377
+ channel: channel
378
+ };
379
+ subscription = new ActionCable.Subscription(this.consumer, params, mixin);
380
+ return this.add(subscription);
381
+ };
382
+
383
+ Subscriptions.prototype.add = function(subscription) {
384
+ this.subscriptions.push(subscription);
385
+ this.consumer.ensureActiveConnection();
386
+ this.notify(subscription, "initialized");
387
+ this.sendCommand(subscription, "subscribe");
388
+ return subscription;
389
+ };
390
+
391
+ Subscriptions.prototype.remove = function(subscription) {
392
+ this.forget(subscription);
393
+ if (!this.findAll(subscription.identifier).length) {
394
+ this.sendCommand(subscription, "unsubscribe");
395
+ }
396
+ return subscription;
397
+ };
398
+
399
+ Subscriptions.prototype.reject = function(identifier) {
400
+ var i, len, ref, results, subscription;
401
+ ref = this.findAll(identifier);
402
+ results = [];
403
+ for (i = 0, len = ref.length; i < len; i++) {
404
+ subscription = ref[i];
405
+ this.forget(subscription);
406
+ this.notify(subscription, "rejected");
407
+ results.push(subscription);
408
+ }
409
+ return results;
410
+ };
411
+
412
+ Subscriptions.prototype.forget = function(subscription) {
413
+ var s;
414
+ this.subscriptions = (function() {
415
+ var i, len, ref, results;
416
+ ref = this.subscriptions;
417
+ results = [];
418
+ for (i = 0, len = ref.length; i < len; i++) {
419
+ s = ref[i];
420
+ if (s !== subscription) {
421
+ results.push(s);
422
+ }
423
+ }
424
+ return results;
425
+ }).call(this);
426
+ return subscription;
427
+ };
428
+
429
+ Subscriptions.prototype.findAll = function(identifier) {
430
+ var i, len, ref, results, s;
431
+ ref = this.subscriptions;
432
+ results = [];
433
+ for (i = 0, len = ref.length; i < len; i++) {
434
+ s = ref[i];
435
+ if (s.identifier === identifier) {
436
+ results.push(s);
437
+ }
438
+ }
439
+ return results;
440
+ };
441
+
442
+ Subscriptions.prototype.reload = function() {
443
+ var i, len, ref, results, subscription;
444
+ ref = this.subscriptions;
445
+ results = [];
446
+ for (i = 0, len = ref.length; i < len; i++) {
447
+ subscription = ref[i];
448
+ results.push(this.sendCommand(subscription, "subscribe"));
449
+ }
450
+ return results;
451
+ };
452
+
453
+ Subscriptions.prototype.notifyAll = function() {
454
+ var args, callbackName, i, len, ref, results, subscription;
455
+ callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
456
+ ref = this.subscriptions;
457
+ results = [];
458
+ for (i = 0, len = ref.length; i < len; i++) {
459
+ subscription = ref[i];
460
+ results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args))));
461
+ }
462
+ return results;
463
+ };
464
+
465
+ Subscriptions.prototype.notify = function() {
466
+ var args, callbackName, i, len, results, subscription, subscriptions;
467
+ subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : [];
468
+ if (typeof subscription === "string") {
469
+ subscriptions = this.findAll(subscription);
470
+ } else {
471
+ subscriptions = [subscription];
472
+ }
473
+ results = [];
474
+ for (i = 0, len = subscriptions.length; i < len; i++) {
475
+ subscription = subscriptions[i];
476
+ results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0);
477
+ }
478
+ return results;
479
+ };
480
+
481
+ Subscriptions.prototype.sendCommand = function(subscription, command) {
482
+ var identifier;
483
+ identifier = subscription.identifier;
484
+ return this.consumer.send({
485
+ command: command,
486
+ identifier: identifier
487
+ });
488
+ };
489
+
490
+ return Subscriptions;
491
+
492
+ })();
493
+
494
+ ActionCable.Subscription = (function() {
495
+ var extend;
496
+
497
+ function Subscription(consumer, params, mixin) {
498
+ this.consumer = consumer;
499
+ if (params == null) {
500
+ params = {};
501
+ }
502
+ this.identifier = JSON.stringify(params);
503
+ extend(this, mixin);
504
+ }
505
+
506
+ Subscription.prototype.perform = function(action, data) {
507
+ if (data == null) {
508
+ data = {};
509
+ }
510
+ data.action = action;
511
+ return this.send(data);
512
+ };
513
+
514
+ Subscription.prototype.send = function(data) {
515
+ return this.consumer.send({
516
+ command: "message",
517
+ identifier: this.identifier,
518
+ data: JSON.stringify(data)
519
+ });
520
+ };
521
+
522
+ Subscription.prototype.unsubscribe = function() {
523
+ return this.consumer.subscriptions.remove(this);
524
+ };
525
+
526
+ extend = function(object, properties) {
527
+ var key, value;
528
+ if (properties != null) {
529
+ for (key in properties) {
530
+ value = properties[key];
531
+ object[key] = value;
532
+ }
533
+ }
534
+ return object;
535
+ };
536
+
537
+ return Subscription;
538
+
539
+ })();
540
+
541
+ ActionCable.Consumer = (function() {
542
+ function Consumer(url) {
543
+ this.url = url;
544
+ this.subscriptions = new ActionCable.Subscriptions(this);
545
+ this.connection = new ActionCable.Connection(this);
546
+ }
547
+
548
+ Consumer.prototype.send = function(data) {
549
+ return this.connection.send(data);
550
+ };
551
+
552
+ Consumer.prototype.connect = function() {
553
+ return this.connection.open();
554
+ };
555
+
556
+ Consumer.prototype.disconnect = function() {
557
+ return this.connection.close({
558
+ allowReconnect: false
559
+ });
560
+ };
561
+
562
+ Consumer.prototype.ensureActiveConnection = function() {
563
+ if (!this.connection.isActive()) {
564
+ return this.connection.open();
565
+ }
566
+ };
567
+
568
+ return Consumer;
569
+
570
+ })();
571
+
572
+ module.exports = ActionCable
@@ -0,0 +1,11 @@
1
+ let LiveReloader = require("./live-reload")
2
+
3
+ let BreakfastRails = {
4
+ init() {
5
+ let liveReloader = new LiveReloader
6
+ liveReloader.init()
7
+ }
8
+ }
9
+
10
+ // The plugin has to be the module’s default export
11
+ module.exports = BreakfastRails;
@@ -0,0 +1,54 @@
1
+ const ActionCable = require('./action-cable');
2
+
3
+ class LiveReloader {
4
+ buildFreshUrl(url) {
5
+ let date = Math.round(Date.now() / 1000).toString();
6
+ url = url.replace(/(\&|\\?)version=\d*/, '');
7
+
8
+ return(`${url}${(url.indexOf('?') >= 0 ? '&' : '?')}version=${date}`);
9
+ }
10
+
11
+ cssReload() {
12
+ var reloadableLinkElements = window.top.document.querySelectorAll(
13
+ 'link[rel=stylesheet]:not([data-no-reload]):not([data-pending-removal])'
14
+ );
15
+
16
+ [].slice
17
+ .call(reloadableLinkElements)
18
+ .filter(link => link.href)
19
+ .forEach(link => link.href = this.buildFreshUrl(link.href))
20
+
21
+ // Repaint
22
+ setTimeout(function(){ document.body.offsetHeight; }, 25);
23
+ }
24
+
25
+ pageReload() {
26
+ window.top.location.reload();
27
+ }
28
+
29
+ init(host = "localhost", port = 3000) {
30
+ const reloaders = {
31
+ js: this.pageReload.bind(this),
32
+ css: this.cssReload.bind(this),
33
+ html: this.pageReload.bind(this)
34
+ }
35
+
36
+ document.addEventListener('DOMContentLoaded', () => {
37
+ let Breakfast = window.Breakfast || {};
38
+
39
+ if(Breakfast.liveReload) {
40
+ let reloadChannel = 'Breakfast::LiveReloadChannel'
41
+
42
+ Breakfast.cable = ActionCable.createConsumer(`ws://${host}:${port}/cable`);
43
+ Breakfast.channel = Breakfast.cable.subscriptions.create(reloadChannel, {
44
+ received: (data) => {
45
+ let reloader = reloaders[data.extension]
46
+ reloader();
47
+ }
48
+ })
49
+ }
50
+ });
51
+ }
52
+ }
53
+
54
+ module.exports = LiveReloader;
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: breakfast
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Patrick Koperwas
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 5.0.0.rc2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 5.0.0.rc2
69
+ - !ruby/object:Gem::Dependency
70
+ name: actioncable
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: listen
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Replace the asset pipeline with Brunch. Get CSS, JS and HTML live-reloading
98
+ out of the box. Full ES6 support with require. No need to launch extra servers.
99
+ email:
100
+ - patrick@devlocker.io
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - breakfast.gemspec
115
+ - lib/breakfast.rb
116
+ - lib/breakfast/live_reload_channel.rb
117
+ - lib/breakfast/railtie.rb
118
+ - lib/breakfast/version.rb
119
+ - lib/breakfast/view_helper.rb
120
+ - lib/generators/breakfast/install_generator.rb
121
+ - lib/generators/breakfast/templates/brunch-config.js
122
+ - lib/generators/breakfast/templates/initialize.js
123
+ - lib/generators/breakfast/templates/package.json
124
+ - node_package/.npmignore
125
+ - node_package/package.json
126
+ - node_package/src/action-cable.js
127
+ - node_package/src/breakfast-rails.js
128
+ - node_package/src/live-reload.js
129
+ homepage: https://github.com/devlocker/breakfast
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.5.1
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Integrates Brunch into Rails
153
+ test_files: []