slinky 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -6
- data/README.md +137 -48
- data/VERSION +1 -1
- data/bin/slinky +0 -3
- data/lib/slinky/builder.rb +7 -2
- data/lib/slinky/compiled_file.rb +1 -1
- data/lib/slinky/compilers/clojurescript-compiler.rb +18 -0
- data/lib/slinky/compilers/coffee-compiler.rb +2 -3
- data/lib/slinky/compilers/haml-compiler.rb +3 -4
- data/lib/slinky/compilers/less-compiler.rb +14 -0
- data/lib/slinky/compilers/sass-compiler.rb +2 -3
- data/lib/slinky/compilers.rb +34 -2
- data/lib/slinky/config_reader.rb +49 -0
- data/lib/slinky/listener.rb +27 -6
- data/lib/slinky/live_reload.rb +51 -0
- data/lib/slinky/manifest.rb +37 -18
- data/lib/slinky/proxy_server.rb +3 -4
- data/lib/slinky/runner.rb +30 -13
- data/lib/slinky/server.rb +39 -30
- data/lib/slinky.rb +15 -12
- data/slinky.gemspec +21 -19
- data/spec/slinky_spec.rb +90 -11
- data/spec/spec_helper.rb +21 -0
- metadata +145 -58
- data/lib/slinky/compilers/coffee-helper +0 -3
data/Gemfile
CHANGED
@@ -1,23 +1,25 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
+
# main gems
|
3
4
|
gem "eventmachine", ">= 0.12.0"
|
4
5
|
gem "eventmachine_httpserver", ">= 0.2.0"
|
6
|
+
gem "em-websocket", "~> 0.3.8"
|
5
7
|
gem "em-proxy", ">= 0.1.6"
|
6
8
|
gem "rainbow", ">= 1.1.3"
|
7
|
-
gem "haml", ">= 3.0.0"
|
8
|
-
gem "sass", ">= 3.1.1"
|
9
|
-
gem "coffee-script", ">= 2.2.0"
|
10
9
|
gem "mime-types", ">= 1.16"
|
11
10
|
gem "yui-compressor", ">= 0.9.6"
|
12
11
|
gem "listen", ">= 0.4.5"
|
13
12
|
|
13
|
+
# compilation support gems
|
14
|
+
gem "haml", ">= 3.0.0"
|
15
|
+
gem "sass", ">= 3.1.1"
|
16
|
+
gem "coffee-script", ">= 2.2.0"
|
17
|
+
|
14
18
|
group :development do
|
15
19
|
gem "rspec", "~> 2.10.0"
|
16
20
|
gem "yard", "~> 0.6.0"
|
17
|
-
gem "bundler", "
|
21
|
+
gem "bundler", ">= 1.1.0"
|
18
22
|
gem "jeweler", "~> 1.8.0"
|
19
|
-
gem 'cover_me', '>= 1.0.0.rc6'
|
20
23
|
gem "fakefs", '~> 0.4.0'
|
21
24
|
gem "em-http-request", '~> 1.0.0'
|
22
|
-
# gem "em-synchrony", ">= 0"
|
23
25
|
end
|
data/README.md
CHANGED
@@ -1,42 +1,79 @@
|
|
1
|
-
#Slinky
|
1
|
+
# Slinky
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
Once you're ready for production the slinky builder will compile all of
|
11
|
-
your sources and concatenate and minify your javascript and css,
|
12
|
-
leaving you a directory that's ready to be pushed to your servers.
|
3
|
+
If you write single-page rich client apps, Slinky is here to
|
4
|
+
make your life easier. For development, it provides a static file
|
5
|
+
server that transparently handles compiled languages like CoffeeScript
|
6
|
+
and SASS while supporting advanced features like dependency management,
|
7
|
+
proxying and automatic browser reloads. And once you're ready to
|
8
|
+
deploy, Slinky will compile, concatenate, and minify your sources,
|
9
|
+
leaving you ready to push to production.
|
13
10
|
|
14
11
|
[![Build Status](https://secure.travis-ci.org/mwylde/slinky.png)](http://travis-ci.org/mwylde/slinky)
|
15
12
|
|
16
|
-
|
13
|
+
What can slinky do for you?
|
14
|
+
|
15
|
+
#### Slinky Server
|
16
|
+
|
17
|
+
* Transparently compiles sources for a variety of languages (currently
|
18
|
+
supported: CoffeeScript, ClojureScript, SASS/SCSS, LESS, HAML)
|
19
|
+
* Supports the [LiveReload](http://livereload.com) protocol, for
|
20
|
+
instant browser updates
|
21
|
+
* Allows proxying to backend servers, so you can develop your client
|
22
|
+
and server code separately
|
23
|
+
* Includes support for HTML5 [pushState](https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history) based apps
|
24
|
+
|
25
|
+
#### Slinky Builder
|
26
|
+
|
27
|
+
* Keeps track of the proper include order of your scripts and styles
|
28
|
+
* Compiles, minifies and concatenates JavaScript and CSS
|
29
|
+
|
30
|
+
Slinky is not a framework, and it does not want to control your source
|
31
|
+
code. Its goal is to help you when you want it—and get out of the way
|
32
|
+
when you don't. It endeavors to be sufficiently flexible to support a
|
33
|
+
wide variety of development styles.
|
34
|
+
|
35
|
+
## Quick start
|
17
36
|
|
18
37
|
```
|
19
38
|
$ gem install slinky
|
20
|
-
$ cd ~/my/awesome/project
|
39
|
+
$ cd ~/my/awesome/project/src
|
21
40
|
$ slinky start
|
22
41
|
[hardcore web development action]
|
23
|
-
$ slinky build
|
24
|
-
$ scp -r
|
42
|
+
$ slinky build -o ../pub
|
43
|
+
$ scp -r ../pub/ myserver.com:/var/www/project
|
25
44
|
````
|
26
|
-
## But tell me more!
|
27
45
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
46
|
+
## The details
|
47
|
+
|
48
|
+
1. [LiveReload/Guard support](#livereloadguard-support)
|
49
|
+
2. [Script & style management](#script--style-management)
|
50
|
+
3. [Specifying order](#specifying-order)
|
51
|
+
4. [Dependencies](#dependencies)
|
52
|
+
5. [Configuration](#configuration)
|
53
|
+
6. [PushState](#pushstate)
|
54
|
+
7. [Proxies](#proxies)
|
55
|
+
8. [Ignores](#ignores)
|
56
|
+
|
57
|
+
### LiveReload/Guard support
|
58
|
+
|
59
|
+
The typical edit-save-reload cycle of web development can be tedious,
|
60
|
+
especially when trying to get your CSS *just* right. What if you could
|
61
|
+
reduce that to just edit-save? [LiveReload](http://livereload.com/)
|
62
|
+
allows just that. Slinky includes built-in support for LiveReload
|
63
|
+
service. All you need to do is run a browser extension (available
|
64
|
+
[here](http://go.livereload.com/extensions) for Safari, Chrome and
|
65
|
+
Firefox) or include a little script (http://go.livereload.com/mobile).
|
66
|
+
In addition to reloading your app whenever a source file changes,
|
67
|
+
LiveReload supports hot reloading of CSS, letting you tweak your
|
68
|
+
styles with ease. If don't want the LiveReload server running,
|
69
|
+
disabling it is a simple `--no-livereload` away.
|
33
70
|
|
34
71
|
### Script & style management
|
35
72
|
|
36
73
|
Slinky can manage all of your javascript and css files if you want it
|
37
74
|
to, serving them up individually during development and concatenating
|
38
75
|
and minifying them for production. To support this, Slinky recognizes
|
39
|
-
`slinky_scripts` in your HTML/
|
76
|
+
`slinky_scripts` in your HTML/HAML files. For example, when Slinky
|
40
77
|
sees this:
|
41
78
|
|
42
79
|
```haml
|
@@ -50,18 +87,19 @@ sees this:
|
|
50
87
|
```
|
51
88
|
|
52
89
|
it will compile the HAML to HTML and replace slinky_styles with the
|
53
|
-
appropriate HTML.
|
90
|
+
appropriate HTML. You can also disable minification with the
|
91
|
+
`--dont-minify` option or the `dont_minify: true` configuration
|
92
|
+
option.
|
54
93
|
|
55
94
|
### Specifying order
|
56
95
|
|
57
|
-
|
58
|
-
|
96
|
+
Often scripts and styles depend on being included in the page
|
97
|
+
in a particular order. For this, we need the `slinky_require`
|
59
98
|
directive.
|
60
99
|
|
61
100
|
For example, consider the case of two coffeescript files, A.coffee and
|
62
101
|
B.coffee. A includes a class definition that B depends upon, so we
|
63
|
-
want to make sure that A comes before B in the concatenation order.
|
64
|
-
can solve this simply using `slinky_require(script)`
|
102
|
+
want to make sure that A comes before B in the concatenation order.
|
65
103
|
|
66
104
|
File A.coffee:
|
67
105
|
|
@@ -76,7 +114,7 @@ File B.coffee:
|
|
76
114
|
slinky_require("A.coffee")
|
77
115
|
alert (new A).hello("world")
|
78
116
|
```
|
79
|
-
We can also do this in CSS/SASS/
|
117
|
+
We can also do this in CSS/SASS/SC SS:
|
80
118
|
|
81
119
|
```sass
|
82
120
|
/* slinky_require("reset.css")
|
@@ -84,15 +122,15 @@ a
|
|
84
122
|
color: red
|
85
123
|
```
|
86
124
|
|
87
|
-
###
|
125
|
+
### Dependencies
|
88
126
|
|
89
127
|
As HAML and SASS scripts can include external content as part of their
|
90
|
-
build process,
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
128
|
+
build process, you may want certain files to be recompiled whenever
|
129
|
+
other files change. For example, you may use mustache templates
|
130
|
+
defined each in their own file, but have set up your HAML file to
|
131
|
+
include them all into the HTML. Thus when one of the mustache files
|
132
|
+
changes, you would like the HAML file to be recompiled so that the
|
133
|
+
templates will also be updated.
|
96
134
|
|
97
135
|
These relationships are specified as "dependencies," and like requirements
|
98
136
|
they are incdicated through a special `slinky_depends("file")` directive in
|
@@ -120,13 +158,70 @@ Slinky can optionally be configured using a yaml file. By default, it
|
|
120
158
|
looks for a file called `slinky.yaml` in the source directory, but you
|
121
159
|
can also supply a file name on the command line using `-c`.
|
122
160
|
|
123
|
-
|
161
|
+
Most of what can be specified on the command line is also available in
|
162
|
+
the configuration file. Here's a fully-decked out config:
|
163
|
+
|
164
|
+
```yaml
|
165
|
+
pushstate:
|
166
|
+
"/app1": "/index.html"
|
167
|
+
"/app2": "/index2.html"
|
168
|
+
proxy:
|
169
|
+
"/test1": "http://127.0.0.1:8000"
|
170
|
+
"/test2": "http://127.0.0.1:7000"
|
171
|
+
ignore:
|
172
|
+
- script/vendor
|
173
|
+
- script/jquery.js
|
174
|
+
port: 5555
|
175
|
+
src_dir: "src/"
|
176
|
+
build_dir: "build/"
|
177
|
+
no_proxy: true
|
178
|
+
no_livereload: true
|
179
|
+
livereload_port: 5556
|
180
|
+
dont_minify: true
|
181
|
+
```
|
182
|
+
|
183
|
+
Most are self explanatory, but a few of the options merit further
|
184
|
+
attention:
|
185
|
+
|
186
|
+
### PushState
|
187
|
+
|
188
|
+
[PushState](https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history)
|
189
|
+
is a new Javascript API that gives web apps more control over the
|
190
|
+
browser's history, making possible single-page javascript applications
|
191
|
+
that retain the advantages of their multi-page peers without resorting
|
192
|
+
to hacks like hash urls. The essential idea is this: when a user
|
193
|
+
navigates to a conceptually different "page" in the app, the URL
|
194
|
+
should be updated to reflect that so that behaviors such as
|
195
|
+
deep-linking and history navigation work properly.
|
196
|
+
|
197
|
+
For this to work, however, the server must be able to return the
|
198
|
+
content of your main HTML page for arbitrary paths, as otherwise when
|
199
|
+
a user tries to reload a pushstate-enabled web app they would receive
|
200
|
+
a 404. Slinky supports multiple pushState paths using the pushstate
|
201
|
+
configuration option:
|
202
|
+
|
203
|
+
```yaml
|
204
|
+
pushstate:
|
205
|
+
"/": "/index.html"
|
206
|
+
"/app1": "/app1/index.haml"
|
207
|
+
"/app2": "/app2.haml"
|
208
|
+
```
|
209
|
+
|
210
|
+
Here, the key of the hash is a URL prefix, while the value is the file
|
211
|
+
that should actually be displayed for non-existent requests that begin
|
212
|
+
with the key. In the case of conflicting rules, the more specific one
|
213
|
+
wins. For this config, instead of returning a 404 for a path like
|
214
|
+
`/this/file/does/not/exist`, Slinky will send the content of
|
215
|
+
`/index.html`, leaving your JavaScript free to render the proper view for
|
216
|
+
that content. Similarly, a request for `/app1/photo/1/edit`, assuming
|
217
|
+
such file does not exist, will return `/app1/index.haml`.
|
124
218
|
|
125
219
|
### Proxies
|
126
220
|
|
127
221
|
Slinky has a built-in proxy server which lets you test ajax requests
|
128
|
-
with your actual backend servers
|
129
|
-
will look something like
|
222
|
+
with your actual backend servers without violating the same-origin
|
223
|
+
policy. To set it up, your slinky.yaml file will look something like
|
224
|
+
this:
|
130
225
|
|
131
226
|
```yaml
|
132
227
|
proxy:
|
@@ -147,18 +242,12 @@ the request by the specified number of milliseconds in order to
|
|
147
242
|
simulate the latency associated with remote servers.
|
148
243
|
|
149
244
|
An example: we have some javascript code which makes an AJAX GET
|
150
|
-
request to `/search/widgets?q=foo`. When
|
151
|
-
will see that it has a matching proxy rule,
|
152
|
-
appropriately (changing paths and hosts) and
|
245
|
+
request to `/search/widgets?q=foo`. When Slinky gets the request it
|
246
|
+
will see that it has a matching proxy rule, rewrites the request
|
247
|
+
appropriately (changing paths and hosts) and sends it on to the backend
|
153
248
|
server (in this case, 127.0.0.1:4567). Once it gets a response it will
|
154
249
|
wait until 2 seconds has elapsed since slinky itself received the
|
155
|
-
request and
|
156
|
-
|
157
|
-
This is very convenient for developing rich web clients locally. For
|
158
|
-
example, you may have some code that shows a loading indicator while
|
159
|
-
an AJAX request is outstanding. However, when run locally the request
|
160
|
-
returns so quickly that you can't even see the loading indicator. By
|
161
|
-
adding in a lag this problem is remedied.
|
250
|
+
request and finally returns the response back to the browser.
|
162
251
|
|
163
252
|
### Ignores
|
164
253
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/bin/slinky
CHANGED
data/lib/slinky/builder.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
module Slinky
|
2
2
|
class Builder
|
3
|
-
def self.build
|
4
|
-
|
3
|
+
def self.build options, config
|
4
|
+
dir = options[:src_dir] || config.src_dir
|
5
|
+
build_dir = options[:build_dir] || config.build_dir
|
6
|
+
manifest = Manifest.new(dir, config,
|
7
|
+
:build_to => build_dir,
|
8
|
+
:devel => false,
|
9
|
+
:no_minify => config.dont_minify || options[:no_minify])
|
5
10
|
begin
|
6
11
|
manifest.build
|
7
12
|
rescue BuildFailedError
|
data/lib/slinky/compiled_file.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Slinky
|
2
|
+
module ClojureScriptCompiler
|
3
|
+
Compilers.register_compiler self,
|
4
|
+
:inputs => ["cljs"],
|
5
|
+
:outputs => ["js"],
|
6
|
+
:dependencies => [["clementine", "~> 0.0.3"]]
|
7
|
+
|
8
|
+
def ClojureScriptCompiler::compile s, file
|
9
|
+
# Clementine.options[:pretty_print] = true
|
10
|
+
# Clementine.options[:optimizations] = :none
|
11
|
+
@engine ||= Clementine::ClojureScriptEngine.new(file,
|
12
|
+
:pretty_print => true,
|
13
|
+
:optimizations => :none,
|
14
|
+
:output_dir => Dir.tmpdir)
|
15
|
+
@engine.compile
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'coffee-script'
|
2
|
-
|
3
1
|
module Slinky
|
4
2
|
module CoffeeCompiler
|
5
3
|
Compilers.register_compiler self,
|
6
4
|
:inputs => ["coffee"],
|
7
|
-
:outputs => ["js"]
|
5
|
+
:outputs => ["js"],
|
6
|
+
:dependencies => [["coffee-script", ">= 2.2.0"]]
|
8
7
|
|
9
8
|
def CoffeeCompiler::compile s, file
|
10
9
|
CoffeeScript::compile(s)
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'haml'
|
2
|
-
|
3
1
|
module Slinky
|
4
2
|
module HamlCompiler
|
5
3
|
Compilers.register_compiler self,
|
6
|
-
|
7
|
-
|
4
|
+
:inputs => ["haml"],
|
5
|
+
:outputs => ["html"],
|
6
|
+
:dependencies => [["haml", "~> 3.1.0"]]
|
8
7
|
|
9
8
|
def HamlCompiler::compile s, file
|
10
9
|
haml_engine = Haml::Engine.new(s)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Slinky
|
2
|
+
module LessCompiler
|
3
|
+
Compilers.register_compiler self,
|
4
|
+
:inputs => ["less"],
|
5
|
+
:outputs => ["css"],
|
6
|
+
:dependencies => [["less", ">= 2.2.0"]]
|
7
|
+
|
8
|
+
def LessCompiler::compile s, file
|
9
|
+
parser = Less::Parser.new
|
10
|
+
tree = parser.parse(s)
|
11
|
+
tree.to_css
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'sass'
|
2
|
-
|
3
1
|
module Slinky
|
4
2
|
module SassCompiler
|
5
3
|
Compilers.register_compiler self,
|
6
4
|
:inputs => ["sass", "scss"],
|
7
|
-
:outputs => ["css"]
|
5
|
+
:outputs => ["css"],
|
6
|
+
:dependencies => [["sass", ">= 3.1.1"]]
|
8
7
|
|
9
8
|
def SassCompiler::compile s, file
|
10
9
|
sass_engine = Sass::Engine.new(s, :load_paths => [File.dirname(file)])
|
data/lib/slinky/compilers.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module Slinky
|
2
4
|
EXTENSION_REGEX = /(.+)\.(\w+)/
|
3
5
|
|
@@ -5,6 +7,12 @@ module Slinky
|
|
5
7
|
@compilers = []
|
6
8
|
@compilers_by_ext = {}
|
7
9
|
@compilers_by_input = {}
|
10
|
+
@checked_dependencies = Set.new
|
11
|
+
|
12
|
+
DEPENDENCY_NOT_MET = "Missing dependency %s (version %s), which is\n" +
|
13
|
+
"necessary to compile %s files\n\n" +
|
14
|
+
"Running the following should rectify this problem:\n" +
|
15
|
+
" $ gem install --version '%s' %s"
|
8
16
|
|
9
17
|
class << self
|
10
18
|
def register_compiler klass, options
|
@@ -19,6 +27,30 @@ module Slinky
|
|
19
27
|
end
|
20
28
|
end
|
21
29
|
|
30
|
+
def get_cfile source, compiler, input_ext, output_ext
|
31
|
+
if has_dependencies compiler, input_ext
|
32
|
+
CompiledFile.new source, compiler[:klass], output_ext
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_dependencies compiler, ext
|
37
|
+
(compiler[:dependencies] || []).all? {|d|
|
38
|
+
if @checked_dependencies.include?(d)
|
39
|
+
true
|
40
|
+
else
|
41
|
+
begin
|
42
|
+
gem(d[0], d[1])
|
43
|
+
require d[0]
|
44
|
+
@checked_dependencies.add(d)
|
45
|
+
true
|
46
|
+
rescue Gem::LoadError
|
47
|
+
$stderr.puts((DEPENDENCY_NOT_MET % [d[0], d[1], ext, d[1], d[0]]).foreground(:red))
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
22
54
|
# Produces a CompiledFile for an input file if the file needs to
|
23
55
|
# be compiled, or nil otherwise. Note that path is the path of
|
24
56
|
# the compiled file, so script.js not script.coffee.
|
@@ -44,7 +76,7 @@ module Slinky
|
|
44
76
|
compilers[extension].each do |c|
|
45
77
|
c[:inputs].each do |i|
|
46
78
|
if files_by_ext[i]
|
47
|
-
cfile =
|
79
|
+
cfile = get_cfile(files_by_ext[i], c, ext, extension)
|
48
80
|
break
|
49
81
|
end
|
50
82
|
end
|
@@ -62,7 +94,7 @@ module Slinky
|
|
62
94
|
_, file, ext = path.match(EXTENSION_REGEX).to_a
|
63
95
|
|
64
96
|
if ext && ext != "" && compiler = @compilers_by_input[ext]
|
65
|
-
|
97
|
+
get_cfile(path, compiler, ext, compiler[:outputs].first)
|
66
98
|
else
|
67
99
|
nil
|
68
100
|
end
|
data/lib/slinky/config_reader.rb
CHANGED
@@ -19,5 +19,54 @@ module Slinky
|
|
19
19
|
def ignores
|
20
20
|
@config["ignore"] || []
|
21
21
|
end
|
22
|
+
|
23
|
+
def port
|
24
|
+
@config["port"] || 5323
|
25
|
+
end
|
26
|
+
|
27
|
+
def src_dir
|
28
|
+
@config["src_dir"] || "."
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_dir
|
32
|
+
@config["build_dir"] || "build"
|
33
|
+
end
|
34
|
+
|
35
|
+
def no_proxy
|
36
|
+
@config["no_proxy"] || false
|
37
|
+
end
|
38
|
+
|
39
|
+
def no_livereload
|
40
|
+
@config["no_livereload"] || false
|
41
|
+
end
|
42
|
+
|
43
|
+
def livereload_port
|
44
|
+
@config["livereload_port"] || 35729
|
45
|
+
end
|
46
|
+
|
47
|
+
def dont_minify
|
48
|
+
@config["dont_minify"] || false
|
49
|
+
end
|
50
|
+
|
51
|
+
def pushstates
|
52
|
+
@config["pushstate"]
|
53
|
+
end
|
54
|
+
|
55
|
+
def pushstate_for_path path
|
56
|
+
if pushstates && pushstates.is_a?(Hash)
|
57
|
+
p = pushstates.sort_by{|from, to| -from.count("/")}.find{|a|
|
58
|
+
path.start_with? a[0]
|
59
|
+
}
|
60
|
+
p[1] if p
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def [](x)
|
65
|
+
@config[x]
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
@config.to_s
|
70
|
+
end
|
22
71
|
end
|
23
72
|
end
|
data/lib/slinky/listener.rb
CHANGED
@@ -2,17 +2,32 @@ Thread.abort_on_exception = true
|
|
2
2
|
|
3
3
|
module Slinky
|
4
4
|
class Listener
|
5
|
-
def initialize manifest
|
5
|
+
def initialize manifest, livereload
|
6
6
|
@manifest = manifest
|
7
|
+
@livereload = livereload
|
7
8
|
end
|
8
9
|
|
9
10
|
def run
|
10
|
-
|
11
11
|
listener = Listen.to(@manifest.dir)
|
12
12
|
listener.change do |mod, add, rem|
|
13
13
|
handle_mod(mod) if mod.size > 0
|
14
14
|
handle_add(add) if add.size > 0
|
15
|
-
|
15
|
+
|
16
|
+
EM.next_tick {
|
17
|
+
files = (mod + add + rem).map{|path|
|
18
|
+
mpath = Pathname.new(path)\
|
19
|
+
.relative_path_from(Pathname.new(@manifest.dir).expand_path).to_s
|
20
|
+
mf = @manifest.find_by_path(mpath, false).first
|
21
|
+
if mf
|
22
|
+
mf.output_path
|
23
|
+
else
|
24
|
+
path
|
25
|
+
end
|
26
|
+
}
|
27
|
+
@livereload.reload_browser(files)
|
28
|
+
} if @livereload
|
29
|
+
|
30
|
+
handle_rem(rem) if rem.size > 0
|
16
31
|
end
|
17
32
|
listener.start(false)
|
18
33
|
end
|
@@ -22,13 +37,19 @@ module Slinky
|
|
22
37
|
|
23
38
|
def handle_add files
|
24
39
|
EM.next_tick {
|
25
|
-
|
40
|
+
begin
|
41
|
+
@manifest.add_all_by_path files
|
42
|
+
rescue
|
43
|
+
end
|
26
44
|
}
|
27
45
|
end
|
28
|
-
|
46
|
+
|
29
47
|
def handle_rem files
|
30
48
|
EM.next_tick {
|
31
|
-
|
49
|
+
begin
|
50
|
+
@manifest.remove_all_by_path files
|
51
|
+
rescue
|
52
|
+
end
|
32
53
|
}
|
33
54
|
end
|
34
55
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Slinky
|
2
|
+
# Code to interface with the LiveReload set of browser plugins and
|
3
|
+
# javascript clients. Adapted from the guard-livereload project at
|
4
|
+
# github.com/guard/guard-livereload.
|
5
|
+
class LiveReload
|
6
|
+
def initialize host, port
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
@websockets = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
EventMachine.run do
|
14
|
+
begin
|
15
|
+
EventMachine.start_server(@host,
|
16
|
+
@port,
|
17
|
+
EventMachine::WebSocket::Connection, {}) do |ws|
|
18
|
+
ws.onopen do
|
19
|
+
begin
|
20
|
+
$stdout.puts "Browser connected to livereload server"
|
21
|
+
ws.send "!!ver:1.6"
|
22
|
+
@websockets << ws
|
23
|
+
rescue
|
24
|
+
$stderr.puts $!.to_s.foreground(:red)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ws.onclose do
|
29
|
+
@websockets.delete ws
|
30
|
+
$stdout.puts "Browser disconnected"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
$stdout.puts "Started live-reload server on port #{@port}"
|
34
|
+
rescue
|
35
|
+
puts "Unable to start livereload server on port #{@port}".foreground(:red)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def reload_browser(paths = [])
|
41
|
+
paths.each do |path|
|
42
|
+
data = MultiJson.encode(['refresh', {
|
43
|
+
:path => "#{path}",
|
44
|
+
:apply_js_live => false,
|
45
|
+
:apply_css_live => true
|
46
|
+
}])
|
47
|
+
@websockets.each { |ws| ws.send(data) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|