slinky 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
[](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
|