roadrunner-live-reload 0.3.1 → 0.3.2

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.
@@ -1,126 +1,126 @@
1
- ;(function(global){
2
-
3
- /**
4
- * @class RoadRunner
5
- * @static
6
- */
7
- var RoadRunner = {};
8
-
9
- var host = location.hostname || "localhost";
10
- var port = 9876;
11
-
12
- /**
13
- * Creates a WebSocket client and listen to the RoadRunner server
14
- * @method listen
15
- * @static
16
- */
17
- RoadRunner.listen = function(){
18
- var socket = new WebSocket("ws://" + host + ":" + port);
19
- var rr = this;
20
- socket.onmessage = function(msg){
21
- var msgJSON = JSON.parse(msg["data"]);
22
- rr.resolveChange(msgJSON)
23
- }
24
- }
25
-
26
- /**
27
- * Split a file path in path, file and extension
28
- * @method _getPathParts
29
- * @param url {String} URL to split
30
- * @return {Object} the Hash containing the URL parts
31
- * @private
32
- */
33
- var _getPathParts = function(url) {
34
- if(!url.match(/[\/\\]/)) url = "/" + url;
35
-
36
- var m = url.match(/(.*)[\/\\]([^\/\\]+)\.(\w+)$/);
37
-
38
- return {
39
- fullPath: url,
40
- path: m[1],
41
- file: m[2],
42
- ext: m[3]
43
- };
44
- };
45
-
46
- /**
47
- * Shows a warning in console
48
- * @method _warn
49
- * @param url {String} Message to be shown
50
- * @private
51
- */
52
- var _warn = function(msg){
53
- console.warn("RoadRunner:", msg);
54
- }
55
-
56
- /**
57
- * Resolve changes depending on file type
58
- * @method resolveChange
59
- * @param msg {Object} The JSON message with info about the change
60
- * @static
61
- */
62
- RoadRunner.resolveChange = function(msg){
63
- var URLparts = _getPathParts(msg.filepath);
64
- var resolver;
65
- switch(URLparts.ext.toLowerCase()){
66
- case "css":
67
- resolver = CSSResolver;
68
- break;
69
-
70
- case "js":
71
- resolver = GenericResolver;
72
- break;
73
-
74
- case "png":
75
- case "gif":
76
- case "svg":
77
- case "jpg":
78
- case "jpeg":
79
- //ToDo: Create a resolver for images to update img tags and backgrounds without reloading the page
80
- resolver = GenericResolver;
81
- break;
82
-
83
- case "html":
84
- case "htm":
85
- resolver = GenericResolver;
86
-
87
- default:
88
- resolver = GenericResolver;
89
- }
90
- resolver.resolve(URLparts);
91
- _warn("The file \"" + URLparts.fullPath + "\" has changed at " + msg.modified_at + ".");
92
- }
93
-
94
- /**
95
- * Generic strategy to resolve static files changes,
96
- * its behaviour is to refresh the page forcing to not use the local cache
97
- * @class GenericResolver
98
- * @static
99
- */
100
- var GenericResolver = {};
101
- GenericResolver.resolve = function(URLparts){
102
- location.reload(true);
103
- }
104
-
105
- /**
106
- * Strategy to resolve CSS files changes,
107
- * its behaviour is update link tags' href references and force the browser to not using the cache
108
- * @class CSSResolver
109
- * @static
110
- */
111
- var CSSResolver = {};
112
- CSSResolver.resolve = function(URLparts){
113
- var path = URLparts.fullPath;
114
- var stylesheets = global.document.querySelectorAll("link[href*=\"" + path + "\"]");
115
-
116
- if(stylesheets.length > 0){
117
- for(var i = 0; i < stylesheets.length; i++){
118
- var stylesheet = stylesheets[i];
119
- stylesheet.setAttribute("href", path + "?rand=" + Math.floor(Math.random() * 9999));
120
-
121
- }
122
- }
123
- }
124
-
125
- RoadRunner.listen();
1
+ ;(function(global){
2
+
3
+ /**
4
+ * @class RoadRunner
5
+ * @static
6
+ */
7
+ var RoadRunner = {};
8
+
9
+ var host = location.hostname || "localhost";
10
+ var port = 9876;
11
+
12
+ /**
13
+ * Creates a WebSocket client and listen to the RoadRunner server
14
+ * @method listen
15
+ * @static
16
+ */
17
+ RoadRunner.listen = function(){
18
+ var socket = new WebSocket("ws://" + host + ":" + port);
19
+ var rr = this;
20
+ socket.onmessage = function(msg){
21
+ var msgJSON = JSON.parse(msg["data"]);
22
+ rr.resolveChange(msgJSON)
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Split a file path in path, file and extension
28
+ * @method _getPathParts
29
+ * @param url {String} URL to split
30
+ * @return {Object} the Hash containing the URL parts
31
+ * @private
32
+ */
33
+ var _getPathParts = function(url) {
34
+ if(!url.match(/[\/\\]/)) url = "/" + url;
35
+
36
+ var m = url.match(/(.*)[\/\\]([^\/\\]+)\.(\w+)$/);
37
+
38
+ return {
39
+ fullPath: url,
40
+ path: m[1],
41
+ file: m[2],
42
+ ext: m[3]
43
+ };
44
+ };
45
+
46
+ /**
47
+ * Shows a warning in console
48
+ * @method _warn
49
+ * @param url {String} Message to be shown
50
+ * @private
51
+ */
52
+ var _warn = function(msg){
53
+ console.warn("RoadRunner:", msg);
54
+ }
55
+
56
+ /**
57
+ * Resolve changes depending on file type
58
+ * @method resolveChange
59
+ * @param msg {Object} The JSON message with info about the change
60
+ * @static
61
+ */
62
+ RoadRunner.resolveChange = function(msg){
63
+ var URLparts = _getPathParts(msg.filepath);
64
+ var resolver;
65
+ switch(URLparts.ext.toLowerCase()){
66
+ case "css":
67
+ resolver = CSSResolver;
68
+ break;
69
+
70
+ case "js":
71
+ resolver = GenericResolver;
72
+ break;
73
+
74
+ case "png":
75
+ case "gif":
76
+ case "svg":
77
+ case "jpg":
78
+ case "jpeg":
79
+ //ToDo: Create a resolver for images to update img tags and backgrounds without reloading the page
80
+ resolver = GenericResolver;
81
+ break;
82
+
83
+ case "html":
84
+ case "htm":
85
+ resolver = GenericResolver;
86
+
87
+ default:
88
+ resolver = GenericResolver;
89
+ }
90
+ resolver.resolve(URLparts);
91
+ _warn("The file \"" + URLparts.fullPath + "\" has changed at " + msg.modified_at + ".");
92
+ }
93
+
94
+ /**
95
+ * Generic strategy to resolve static files changes,
96
+ * its behaviour is to refresh the page forcing to not use the local cache
97
+ * @class GenericResolver
98
+ * @static
99
+ */
100
+ var GenericResolver = {};
101
+ GenericResolver.resolve = function(URLparts){
102
+ location.reload(true);
103
+ }
104
+
105
+ /**
106
+ * Strategy to resolve CSS files changes,
107
+ * its behaviour is update link tags' href references and force the browser to not using the cache
108
+ * @class CSSResolver
109
+ * @static
110
+ */
111
+ var CSSResolver = {};
112
+ CSSResolver.resolve = function(URLparts){
113
+ var path = URLparts.fullPath;
114
+ var stylesheets = global.document.querySelectorAll("link[href*=\"" + path + "\"]");
115
+
116
+ if(stylesheets.length > 0){
117
+ for(var i = 0; i < stylesheets.length; i++){
118
+ var stylesheet = stylesheets[i];
119
+ stylesheet.setAttribute("href", path + "?rand=" + Math.floor(Math.random() * 9999));
120
+
121
+ }
122
+ }
123
+ }
124
+
125
+ RoadRunner.listen();
126
126
  })(window);
@@ -1,31 +1,31 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "roadrunner-live-reload"
7
- s.version = RoadRunner::VERSION.dup
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["Alcides Queiroz Aguiar"]
10
- s.email = ["alcidesqueiroz@gmail.com"]
11
- s.homepage = "http://rubygems.org/gems/roadrunner"
12
- s.extra_rdoc_files = ["README.md"]
13
- s.summary = "A live reload command line tool written in ruby."
14
- s.description = s.summary
15
- s.extensions = ["Rakefile"]
16
-
17
- #s.files = `git ls-files`.split($\)
18
- s.files = [ ".gitignore", ".rspec",
19
- "Gemfile", "Gemfile.lock",
20
- "LICENSE", "README.md", "Rakefile",
21
- "lib/version.rb", "lib/websocket.rb", "src/webserver.rb",
22
- "lib/tasks/register.rake", "lib/os.rb",
23
- "roadrunner-0.3.1.debug.js", "roadrunner-live-reload.gemspec",
24
- "roadrunner.sample.yml", "spec/comingsoon.gitkeep",
25
- "src/roadrunner.rb", "distr/roadrunner", "distr/roadrunner.bat"]
26
-
27
- s.require_paths = ["lib"]
28
-
29
- s.add_development_dependency "bundler", ">= 1.0.0"
30
- s.add_development_dependency "rake", "~> 0.9.2"
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "roadrunner-live-reload"
7
+ s.version = RoadRunner::VERSION.dup
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Alcides Queiroz Aguiar"]
10
+ s.email = ["alcidesqueiroz@gmail.com"]
11
+ s.homepage = "http://rubygems.org/gems/roadrunner"
12
+ s.extra_rdoc_files = ["README.md"]
13
+ s.summary = "A live reload command line tool written in ruby."
14
+ s.description = s.summary
15
+ s.extensions = ["Rakefile"]
16
+
17
+ #s.files = `git ls-files`.split($\)
18
+ s.files = [ ".gitignore", ".rspec",
19
+ "Gemfile", "Gemfile.lock",
20
+ "LICENSE", "README.md", "Rakefile",
21
+ "lib/version.rb", "lib/websocket.rb", "src/webserver.rb",
22
+ "lib/tasks/register.rake", "lib/os.rb",
23
+ "roadrunner-0.3.2.debug.js", "roadrunner-live-reload.gemspec",
24
+ "roadrunner.sample.yml", "spec/comingsoon.gitkeep",
25
+ "src/roadrunner.rb", "distr/roadrunner", "distr/roadrunner.bat"]
26
+
27
+ s.require_paths = ["lib"]
28
+
29
+ s.add_development_dependency "bundler", ">= 1.0.0"
30
+ s.add_development_dependency "rake", "~> 0.9.2"
31
31
  end
@@ -1,9 +1,9 @@
1
- config:
2
- polling_interval: 0.1
3
- change_check_strategy: modification_time #You also can use 'checksum'
4
- live_reload_port: 9876
5
- web_server_port: 9875
6
- files: [
7
- ["/relative/path/to/some/css-file.css", "/relative/path/in/your/web-server.css"],
8
- "/equivalent/path.css"
9
- ]
1
+ config:
2
+ polling_interval: 0.1
3
+ change_check_strategy: modification_time #You also can use 'checksum'
4
+ live_reload_port: 9876
5
+ web_server_port: 9875
6
+ files: [
7
+ ["/relative/path/to/some/css-file.css", "/relative/path/in/your/web-server.css"],
8
+ "/equivalent/path.css"
9
+ ]
@@ -1,13 +1,13 @@
1
- APOLOGY
2
- =======
3
-
4
- Roadrunner is being succesfully used for a few months, since its very first version there have been almost no changes.
5
- Recently (since I'm completely outta time) I made an effort to transform the existing code in a gem, to make it easier to use.
6
- I confess, once I didn't wrote tests in the very beginning of the development process for this tool (totally my fault), it became harder and harder to have enough time to retroactively cover the code with tests (I know there's not so much code to test, but it doesn't make any difference, due to time availability).
7
-
8
- Last, but not least: I really promise, when I have enough time I'll do my homework and cover this tool with tests.
9
-
10
- I Hope Roadrunner is useful for you.
11
-
12
- Sincerely yours
1
+ APOLOGY
2
+ =======
3
+
4
+ Roadrunner is being succesfully used for a few months, since its very first version there have been almost no changes.
5
+ Recently (since I'm completely outta time) I made an effort to transform the existing code in a gem, to make it easier to use.
6
+ I confess, once I didn't wrote tests in the very beginning of the development process for this tool (totally my fault), it became harder and harder to have enough time to retroactively cover the code with tests (I know there's not so much code to test, but it doesn't make any difference, due to time availability).
7
+
8
+ Last, but not least: I really promise, when I have enough time I'll do my homework and cover this tool with tests.
9
+
10
+ I Hope Roadrunner is useful for you.
11
+
12
+ Sincerely yours
13
13
  Alcides Queiroz - alcidesqueiroz (at) gmail (dot) com
data/src/roadrunner.rb CHANGED
@@ -1,162 +1,162 @@
1
- require 'socket'
2
- require 'yaml'
3
- require_relative '../lib/websocket'
4
- require_relative '../lib/version'
5
- require_relative 'webserver'
6
-
7
- module RoadRunner
8
- def self.root_dir
9
- Dir.pwd
10
- end
11
-
12
- def self.config_file
13
- File.join(root_dir, "roadrunner.yml")
14
- end
15
-
16
- def self.config key=nil
17
- unless defined? @@config
18
- begin
19
- @@config = YAML.load_file(config_file)["config"]
20
- parse_config_key key
21
- rescue
22
- puts "Could not found the roadrunner.yml configuration file."
23
- puts "To create a new configuration file run 'roadrunner setup', then edit the generated file."
24
- puts "Finishing a little early =("
25
- abort
26
- end
27
- end
28
- @@config
29
- end
30
-
31
- def self.parse_config_key key
32
- return @@config if key.nil?
33
- key_parts = key.split(/[\.,>]/)
34
-
35
- ret = @@config
36
- key_parts.each do |part|
37
- ret = ret[part];
38
- end
39
-
40
- ret
41
- end
42
-
43
- def self.load_files_to_monitor
44
- files = config("files")
45
- @@files_to_monitor = []
46
- files.each do |path|
47
- if path.is_a? Array
48
- relative_path = path[0]
49
- url_relative_path = path[1]
50
- else
51
- relative_path = path
52
- url_relative_path = path
53
- end
54
-
55
- absolute_path = File.join(root_dir, relative_path)
56
- file = File.open(absolute_path)
57
- @@files_to_monitor << {
58
- :relative_path => relative_path,
59
- :absolute_path => absolute_path,
60
- :url_relative_path => url_relative_path,
61
- :mtime => file.mtime,
62
- :checksum => calculate_checksum(file)
63
- }
64
- file.close
65
- end
66
- end
67
-
68
- def self.monitor_files
69
- load_files_to_monitor
70
- polling_interval = config("polling_interval")
71
-
72
- strategy = config("change_check_strategy")
73
- checksum_checker = Proc.new do |file, file_hash|
74
- checksum = calculate_checksum(file)
75
-
76
- if checksum != file_hash[:checksum]
77
- file_hash[:mtime] = Time.now
78
- file_hash[:checksum] = checksum
79
- notify_change file, file_hash[:relative_path], file_hash[:url_relative_path]
80
- end
81
- end
82
-
83
- mtime_checker = Proc.new do |file, file_hash|
84
- if file.mtime != file_hash[:mtime]
85
- file_hash[:mtime] = file.mtime
86
- notify_change file, file_hash[:relative_path], file_hash[:url_relative_path]
87
- end
88
- end
89
-
90
- if strategy == "checksum"
91
- checker = checksum_checker
92
- elsif strategy == "modification_time"
93
- checker = mtime_checker
94
- else
95
- raise "Invalid change_check_strategy"
96
- end
97
-
98
- loop do
99
- sleep polling_interval
100
- @@files_to_monitor.each do |file_hash|
101
- begin
102
- file = File.open(file_hash[:absolute_path])
103
- checker.call file, file_hash
104
- file.close
105
- rescue
106
- puts "/!\\ Could not found the file #{file_hash[:absolute_path]} "
107
- end
108
- end
109
- end
110
- end
111
-
112
- def self.notify_change file, relative_path, url_relative_path
113
- puts "!!! File '#{file.path}' changed at #{file.mtime}. \nNotification sent to listeners."
114
- lost_connection = []
115
- @@sockets.each do |socket|
116
- begin
117
- socket.send "{ \"filepath\": \"#{url_relative_path.gsub("\\", "/")}\", \"modified_at\": \"#{file.mtime}\" }"
118
- rescue
119
- lost_connection << socket
120
- end
121
- end
122
-
123
- lost_connection.each do |socket|
124
- @@sockets.delete socket
125
- end
126
- end
127
-
128
- def self.init_server
129
- initialization_message
130
- @@sockets = []
131
- Thread.new { RoadRunner::WebServer.init_server }
132
- Thread.new { monitor_files }
133
- Thread.abort_on_exception = true
134
-
135
- server = WebSocketServer.new(
136
- :accepted_domains => ["*"],
137
- :port => config("live_reload_port"))
138
- loop do
139
- server.run do |ws|
140
- @@sockets << ws
141
- puts "New connection at #{Time.now.to_s}"
142
- ws.handshake()
143
- while data = ws.receive()
144
- sleep 0.1
145
- end
146
- end
147
- end
148
- end
149
-
150
- def self.initialization_message
151
- puts "Starting Roadrunner #{RoadRunner::VERSION} (ctrl-c to exit)"
152
- puts "RoadRunner Live Reload Server is running on port #{config("live_reload_port")}"
153
- puts "RoadRunner Simple Web Server is running on port #{config("web_server_port")}"
154
- puts "Polling for changes..."
155
- end
156
-
157
- private
158
-
159
- def self.calculate_checksum file
160
- Digest::SHA2.file(file).hexdigest
161
- end
1
+ require 'socket'
2
+ require 'yaml'
3
+ require_relative '../lib/websocket'
4
+ require_relative '../lib/version'
5
+ require_relative 'webserver'
6
+
7
+ module RoadRunner
8
+ def self.root_dir
9
+ Dir.pwd
10
+ end
11
+
12
+ def self.config_file
13
+ File.join(root_dir, "roadrunner.yml")
14
+ end
15
+
16
+ def self.config key=nil
17
+ unless defined? @@config
18
+ begin
19
+ @@config = YAML.load_file(config_file)["config"]
20
+ parse_config_key key
21
+ rescue
22
+ puts "Could not found the roadrunner.yml configuration file."
23
+ puts "To create a new configuration file run 'roadrunner setup', then edit the generated file."
24
+ puts "Finishing a little early =("
25
+ abort
26
+ end
27
+ end
28
+ @@config
29
+ end
30
+
31
+ def self.parse_config_key key
32
+ return @@config if key.nil?
33
+ key_parts = key.split(/[\.,>]/)
34
+
35
+ ret = @@config
36
+ key_parts.each do |part|
37
+ ret = ret[part];
38
+ end
39
+
40
+ ret
41
+ end
42
+
43
+ def self.load_files_to_monitor
44
+ files = config("files")
45
+ @@files_to_monitor = []
46
+ files.each do |path|
47
+ if path.is_a? Array
48
+ relative_path = path[0]
49
+ url_relative_path = path[1]
50
+ else
51
+ relative_path = path
52
+ url_relative_path = path
53
+ end
54
+
55
+ absolute_path = File.join(root_dir, relative_path)
56
+ file = File.open(absolute_path)
57
+ @@files_to_monitor << {
58
+ :relative_path => relative_path,
59
+ :absolute_path => absolute_path,
60
+ :url_relative_path => url_relative_path,
61
+ :mtime => file.mtime,
62
+ :checksum => calculate_checksum(file)
63
+ }
64
+ file.close
65
+ end
66
+ end
67
+
68
+ def self.monitor_files
69
+ load_files_to_monitor
70
+ polling_interval = config("polling_interval")
71
+
72
+ strategy = config("change_check_strategy")
73
+ checksum_checker = Proc.new do |file, file_hash|
74
+ checksum = calculate_checksum(file)
75
+
76
+ if checksum != file_hash[:checksum]
77
+ file_hash[:mtime] = Time.now
78
+ file_hash[:checksum] = checksum
79
+ notify_change file, file_hash[:relative_path], file_hash[:url_relative_path]
80
+ end
81
+ end
82
+
83
+ mtime_checker = Proc.new do |file, file_hash|
84
+ if file.mtime != file_hash[:mtime]
85
+ file_hash[:mtime] = file.mtime
86
+ notify_change file, file_hash[:relative_path], file_hash[:url_relative_path]
87
+ end
88
+ end
89
+
90
+ if strategy == "checksum"
91
+ checker = checksum_checker
92
+ elsif strategy == "modification_time"
93
+ checker = mtime_checker
94
+ else
95
+ raise "Invalid change_check_strategy"
96
+ end
97
+
98
+ loop do
99
+ sleep polling_interval
100
+ @@files_to_monitor.each do |file_hash|
101
+ begin
102
+ file = File.open(file_hash[:absolute_path])
103
+ checker.call file, file_hash
104
+ file.close
105
+ rescue
106
+ puts "/!\\ Could not found the file #{file_hash[:absolute_path]} "
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def self.notify_change file, relative_path, url_relative_path
113
+ puts "!!! File '#{file.path}' changed at #{file.mtime}. \nNotification sent to listeners."
114
+ lost_connection = []
115
+ @@sockets.each do |socket|
116
+ begin
117
+ socket.send "{ \"filepath\": \"#{url_relative_path.gsub("\\", "/")}\", \"modified_at\": \"#{file.mtime}\" }"
118
+ rescue
119
+ lost_connection << socket
120
+ end
121
+ end
122
+
123
+ lost_connection.each do |socket|
124
+ @@sockets.delete socket
125
+ end
126
+ end
127
+
128
+ def self.init_server
129
+ initialization_message
130
+ @@sockets = []
131
+ Thread.new { RoadRunner::WebServer.init_server }
132
+ Thread.new { monitor_files }
133
+ Thread.abort_on_exception = true
134
+
135
+ server = WebSocketServer.new(
136
+ :accepted_domains => ["*"],
137
+ :port => config("live_reload_port"))
138
+ loop do
139
+ server.run do |ws|
140
+ @@sockets << ws
141
+ puts "New connection at #{Time.now.to_s}"
142
+ ws.handshake()
143
+ while data = ws.receive()
144
+ sleep 0.1
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ def self.initialization_message
151
+ puts "Starting Roadrunner #{RoadRunner::VERSION} (ctrl-c to exit)"
152
+ puts "RoadRunner Live Reload Server is running on port #{config("live_reload_port")}"
153
+ puts "RoadRunner Simple Web Server is running on port #{config("web_server_port")}"
154
+ puts "Polling for changes..."
155
+ end
156
+
157
+ private
158
+
159
+ def self.calculate_checksum file
160
+ Digest::SHA2.file(file).hexdigest
161
+ end
162
162
  end