clearwater-hot_loader 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 62c2fa540fc31b83554e87857a0fa030fb28fd5f
4
+ data.tar.gz: 48acf0cb240586d81b00f681810731c149eaf75a
5
+ SHA512:
6
+ metadata.gz: 5eb6383c99d0897ba6f5dc9cd910c5657866d7bae1c9672b1e2d7b6091802b22eda30004d3fd22411e0da6b2c332c63bbf5c8f093fe311682c7946c5f25c088d
7
+ data.tar.gz: 549ef88113da09433a95cdc7b6a0cd0d2402550994dde6ab4d70ee39c14b3c18e26b6c4b139bbee7764755a6c93514ffe3134e751de2ea292ce85c612ae8cfaa
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.6
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in clearwater-hot_loader.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Clearwater::HotLoader
2
+
3
+ A complete solution for re-rendering a Clearwater app in development without a full-page reload.
4
+
5
+ ## Installation
6
+
7
+ In your `Gemfile`:
8
+
9
+ ```ruby
10
+ # This gem is only useful in the development environment
11
+ gem 'clearwater-hot_loader', group: :development
12
+ ```
13
+
14
+ Then run `bundle` to get it installed.
15
+
16
+ ## Usage
17
+
18
+ In order to get hot-loading working, we need to connect three parts:
19
+
20
+ 1. The filesystem monitor to trigger changes
21
+ 2. WebSocket server to notify the client about changes
22
+ 3. WebSocket client to receive the push from the server
23
+
24
+ The examples in this README will have examples for Rails, but we only rely on Rack.
25
+
26
+ ### Filesystem Monitor
27
+
28
+ You kick off the filesystem monitor by running `Clearwater::HotLoader.start`.
29
+
30
+ For a Rails app, simply add that command to the end of your `config/environments/development.rb` file to ensure it only gets run in development.
31
+
32
+ For Rack apps that aren't based on Rails, you can add this to your `config.ru` file (above the line beginning with `run`):
33
+
34
+ ```ruby
35
+ if ENV['RACK_ENV'] == 'development'
36
+ Clearwater::HotLoader.start
37
+ end
38
+ ```
39
+
40
+ ### WebSocket Server
41
+
42
+ The client needs to know what to connect to in order to listen for changes, so we need to add an endpoint to our web app to make this happen. How you do this depends entirely on which back-end framework you're using, but most Rack-based frameworks (including Rails) have a way to mount another Rack app as the handler for an endpoint.
43
+
44
+ _Note: You want to ensure you're only mounting it in development._
45
+
46
+ In Rails, add this to your `config/routes.rb` file:
47
+
48
+ ```ruby
49
+ mount Clearwater::HotLoader, at: '/clearwater_hot_loader' if Rails.env.development?
50
+ ```
51
+
52
+ The `Clearwater::HotLoader` module contains a Rack server which will handle a WebSocket connection. The filesystem monitor notifies the WebSocket server when files have changed.
53
+
54
+ ### WebSocket Client
55
+
56
+ The WebSocket client listens for updates from the server and executes them, updating the Ruby environment running inside the browser, and then re-renders your Clearwater app. If you have multiple Clearwater apps running on the page, it will re-render all of them.
57
+
58
+ To connect to the server, simply add this to the top of your Clearwater app:
59
+
60
+ ```ruby
61
+ require 'clearwater/hot_loader'
62
+ Clearwater::HotLoader.connect port
63
+ ```
64
+
65
+ Simply replace `port` with the port number on which your app is running. It will be the same port on which your web app is running. For example, if you usually open `localhost:3000` to load your web app in the browser, you'll want to connect to port 3000.
66
+
67
+ ## Caveats
68
+
69
+ - Hot loading involves patching classes and objects that are already loaded. If your code is executing as if being run for the first time, existing app state may be clobbered with fresh state.
70
+ - `require` statements are ignored for various reasons:
71
+ - Reloading all dependencies is nearly always unnecessary
72
+ - The Opal environment is not designed to be idempotent. Reloading it may clobber the one already loaded.
73
+ - Because of that, if you add an outside dependency, you will likely need to refresh the page.
74
+
75
+ ## Development
76
+
77
+ 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.
78
+
79
+ 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).
80
+
81
+ ## Contributing
82
+
83
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/clearwater-rb/clearwater-hot_loader).
84
+
85
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
data/Rakefile ADDED
@@ -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
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "clearwater/hot_loader"
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
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'clearwater/hot_loader/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "clearwater-hot_loader"
8
+ spec.version = Clearwater::HotLoader::VERSION
9
+ spec.authors = ["Jamie Gaskins"]
10
+ spec.email = ["jgaskins@gmail.com"]
11
+
12
+ spec.summary = %q{Reload your Clearwater app without refreshing the browser}
13
+ spec.homepage = "https://github.com/clearwater-rb/clearwater-hot_loader"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_runtime_dependency 'clearwater'
21
+ spec.add_runtime_dependency 'listen'
22
+ spec.add_runtime_dependency 'faye-websocket'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,29 @@
1
+ module Clearwater
2
+ module HotLoader
3
+ class Configuration
4
+ attr_reader :directories
5
+
6
+ def initialize attributes={}
7
+ candidate_directories = Dir[
8
+ *%w(
9
+ app/assets/javascripts
10
+ app/assets/javascripts/**/*
11
+ assets
12
+ assets/**/*
13
+ )
14
+ ]
15
+ self.directories = candidate_directories
16
+
17
+ attributes.each do |attr, value|
18
+ public_send "#{attr}=", value
19
+ end
20
+ end
21
+
22
+ def directories= directories
23
+ @directories = Array(directories).select { |f|
24
+ File.directory?(f)
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ require 'listen'
2
+
3
+ module Clearwater
4
+ module HotLoader
5
+ class FileListener
6
+ def initialize directory, &block
7
+ @directory = directory
8
+
9
+ @listener = Listen.to(directory) do |modified, added, removed|
10
+ (modified + added).each do |file|
11
+ block.call(file)
12
+ end
13
+ end
14
+ end
15
+
16
+ def start
17
+ @listener.start
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ require 'opal'
2
+ require 'faye/websocket'
3
+
4
+ module Clearwater
5
+ module HotLoader
6
+ class Server
7
+ include Faye
8
+
9
+ attr_reader :hot_loader
10
+
11
+ def initialize hot_loader=HotLoader
12
+ @hot_loader = hot_loader
13
+ end
14
+
15
+ def call env
16
+ if WebSocket.websocket? env
17
+ ws = WebSocket.new(env)
18
+
19
+ ws.on :close do
20
+ hot_loader.remove_socket ws
21
+ end
22
+
23
+ hot_loader.add_socket ws
24
+
25
+ ws.rack_response
26
+ else
27
+ [200, { 'Content-Type' => 'text/plain' }, ['Websockets only, please.']]
28
+ end
29
+ end
30
+
31
+ def compile_file filename
32
+ code = File.read(filename)
33
+
34
+ if filename.end_with? '.rb'
35
+ Opal.compile(code)
36
+ elsif filename.end_with? '.js'
37
+ code
38
+ else
39
+ ''
40
+ end
41
+ rescue => e
42
+ ''
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ module Clearwater
2
+ module HotLoader
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,64 @@
1
+ require 'opal'
2
+ require 'clearwater/hot_loader/server'
3
+ require 'clearwater/hot_loader/file_listener'
4
+ require 'clearwater/hot_loader/configuration'
5
+ require 'set'
6
+
7
+ module Clearwater
8
+ module HotLoader
9
+ module_function
10
+
11
+ def configure
12
+ yield configuration
13
+ end
14
+
15
+ def configuration
16
+ @configuration ||= Configuration.new
17
+ end
18
+
19
+ def call env
20
+ server.call env
21
+ end
22
+
23
+ def server
24
+ @server ||= Server.new
25
+ end
26
+
27
+ def start
28
+ @listeners = configuration.directories.map { |dir|
29
+ puts "[Clearwater::HotLoader] Monitoring #{dir}"
30
+ FileListener.new(dir) do |filename|
31
+ begin
32
+ puts "[Clearwater::HotLoader] Compiling #{filename}..."
33
+ code = server.compile_file(filename)
34
+ puts "[Clearwater::HotLoader] Hot-loading #{filename}..."
35
+
36
+ sockets.each do |ws|
37
+ ws.send code
38
+ end
39
+ rescue => e
40
+ puts "ONOES! #{e.class} - #{e.message}"
41
+ end
42
+ end
43
+ }
44
+ @listeners.each(&:start)
45
+ puts "[Clearwater::HotLoader] started."
46
+ end
47
+
48
+ def sockets
49
+ @sockets ||= Set.new
50
+ end
51
+
52
+ def add_socket socket
53
+ sockets << socket
54
+ self
55
+ end
56
+
57
+ def remove_socket socket
58
+ sockets.delete socket
59
+ self
60
+ end
61
+ end
62
+ end
63
+
64
+ Opal.append_path File.expand_path('../../../opal', __FILE__)
@@ -0,0 +1,35 @@
1
+ require 'bowser'
2
+ require 'bowser/websocket'
3
+ require 'clearwater'
4
+
5
+ module Clearwater
6
+ class HotLoader
7
+ attr_reader :port, :path
8
+
9
+ def self.connect port=3000, path='/clearwater_hot_loader'
10
+ new(port, path).connect
11
+ end
12
+
13
+ def initialize port, path='/clearwater_hot_loader'
14
+ @port = port
15
+ @path = path
16
+ end
17
+
18
+ def connect
19
+ @socket = Bowser::WebSocket.new("ws://localhost:#{port}#{path}")
20
+
21
+ @socket.on :message do |msg|
22
+ %x{ eval(msg.native.data) }
23
+ Clearwater::Application.render
24
+ end
25
+
26
+ @socket.on :close do
27
+ Bowser.window.delay 1 do
28
+ connect
29
+ end
30
+ end
31
+
32
+ self
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clearwater-hot_loader
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jamie Gaskins
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-05-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: clearwater
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: listen
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faye-websocket
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - jgaskins@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".travis.yml"
107
+ - CODE_OF_CONDUCT.md
108
+ - Gemfile
109
+ - README.md
110
+ - Rakefile
111
+ - bin/console
112
+ - bin/setup
113
+ - clearwater-hot_loader.gemspec
114
+ - lib/clearwater/hot_loader.rb
115
+ - lib/clearwater/hot_loader/configuration.rb
116
+ - lib/clearwater/hot_loader/file_listener.rb
117
+ - lib/clearwater/hot_loader/server.rb
118
+ - lib/clearwater/hot_loader/version.rb
119
+ - opal/clearwater/hot_loader.rb
120
+ homepage: https://github.com/clearwater-rb/clearwater-hot_loader
121
+ licenses: []
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.5.1
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Reload your Clearwater app without refreshing the browser
143
+ test_files: []