slinky 0.7.3 → 0.8.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.
- checksums.yaml +13 -5
- data/.travis.yml +1 -1
- data/Gemfile +2 -0
- data/README.md +119 -8
- data/VERSION +1 -1
- data/lib/slinky.rb +2 -0
- data/lib/slinky/builder.rb +4 -2
- data/lib/slinky/compiled_file.rb +1 -1
- data/lib/slinky/compilers.rb +5 -2
- data/lib/slinky/compilers/clojurescript-compiler.rb +4 -4
- data/lib/slinky/compilers/coffee-compiler.rb +4 -3
- data/lib/slinky/compilers/haml-compiler.rb +4 -3
- data/lib/slinky/compilers/jsx-compiler.rb +13 -0
- data/lib/slinky/compilers/less-compiler.rb +4 -3
- data/lib/slinky/compilers/sass-compiler.rb +4 -3
- data/lib/slinky/config_reader.rb +18 -2
- data/lib/slinky/errors.rb +91 -0
- data/lib/slinky/graph.rb +113 -0
- data/lib/slinky/manifest.rb +290 -123
- data/lib/slinky/proxy_server.rb +1 -1
- data/lib/slinky/runner.rb +1 -1
- data/lib/slinky/server.rb +41 -5
- data/lib/slinky/templates/error.css +32 -0
- data/lib/slinky/templates/error.haml +13 -0
- data/lib/slinky/templates/error.js +26 -0
- data/lib/slinky/templates/inject.css +27 -0
- data/slinky.gemspec +17 -3
- data/spec/compilers_spec.rb +15 -0
- data/spec/manifest_spec.rb +750 -0
- data/spec/slinky_spec.rb +9 -421
- data/spec/spec_helper.rb +22 -7
- metadata +83 -47
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTAyMTk5MzgwNzNkMTA0MzhhZjc0ODBmNjFiM2JlMTM4NDE2ZjNhYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjdjMDMwZGIzZWU4YjE2MmIwOGU0ZTIyMzc2ZDYyZDg2M2I2NWRmMg==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Nzc5Y2M4YjUzNGI1MDMyNTgxMzQwY2FkNWRkMDkwZGZjYWI3ODNmOWI0Mzk1
|
10
|
+
Nzk1ZjNlMzcxMDVjYjFiNWFhODNhZGUyMzcyYzM1YzBkMjI3MzljNGFhYzEw
|
11
|
+
ODFiNGFjZmM5MDYyNzAyMzc4ZjExNjQ3NDkyOWNmNzAxZTYyYzU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzQ1ZmIzMDY5NjdlYjMyYzg4MzZkMjczMzk5MGRlNjBiZGEyNWM1YmNhMzFj
|
14
|
+
Nzc1ZTQ1Yzc3OTdmZTk2YTc1NmE4ZDI3YjM3YTRkYWE0YzA2MmU1OThiODMy
|
15
|
+
Y2NjZDExZDY1ZGQ0YTg0NDBmMTg0MGFmNTM3ZjMwMzgzN2M5NzI=
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
3
|
# main gems
|
4
|
+
gem 'multi_json', '~> 1.9.2'
|
4
5
|
gem "eventmachine", "~> 1.0"
|
5
6
|
gem "eventmachine_httpserver", "~> 0.2"
|
6
7
|
gem "em-websocket", "~> 0.3"
|
@@ -26,4 +27,5 @@ group :development do
|
|
26
27
|
# optional compilation gems
|
27
28
|
gem "less", ">= 2.2.0"
|
28
29
|
gem "therubyracer" # for less
|
30
|
+
gem "react-jsx", '~> 0.8.0'
|
29
31
|
end
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Slinky
|
1
|
+
# Slinky
|
2
2
|
|
3
3
|
If you write single-page rich client apps, Slinky is here to
|
4
4
|
make your life easier. For development, it provides a static file
|
@@ -52,6 +52,8 @@ $ scp -r ../pub/ myserver.com:/var/www/project
|
|
52
52
|
7. [PushState](#pushstate)
|
53
53
|
8. [Proxies](#proxies)
|
54
54
|
9. [Ignores](#ignores)
|
55
|
+
10. [Products](#products)
|
56
|
+
11. [Path matching](#path-matching)
|
55
57
|
|
56
58
|
### Transparent compilation
|
57
59
|
|
@@ -69,6 +71,7 @@ Currently supported languages include:
|
|
69
71
|
* HAML
|
70
72
|
* SASS/SCSS
|
71
73
|
* LESS
|
74
|
+
* JSX (react templates)
|
72
75
|
* ClojureScript (experimental)
|
73
76
|
|
74
77
|
Adding support for new languages is simple, and pull requests are welcome.
|
@@ -109,7 +112,8 @@ sees this:
|
|
109
112
|
it will compile the HAML to HTML and replace slinky_styles with the
|
110
113
|
appropriate HTML. You can also disable minification with the
|
111
114
|
`--dont-minify` option or the `dont_minify: true` configuration
|
112
|
-
option.
|
115
|
+
option. `slinky_scripts` and `slinky_styles` are conveniences built on
|
116
|
+
top of the [full product system](#products).
|
113
117
|
|
114
118
|
### Specifying order
|
115
119
|
|
@@ -153,8 +157,8 @@ changes, you would like the HAML file to be recompiled so that the
|
|
153
157
|
templates will also be updated.
|
154
158
|
|
155
159
|
These relationships are specified as "dependencies," and like requirements
|
156
|
-
they are incdicated through a special `slinky_depends("file")` directive in
|
157
|
-
your source files. For our template example, the index.haml files might look
|
160
|
+
they are incdicated through a special `slinky_depends("file")` directive in
|
161
|
+
your source files. For our template example, the index.haml files might look
|
158
162
|
like this:
|
159
163
|
|
160
164
|
```haml
|
@@ -188,9 +192,16 @@ pushstate:
|
|
188
192
|
proxy:
|
189
193
|
"/test1": "http://127.0.0.1:8000"
|
190
194
|
"/test2": "http://127.0.0.1:7000"
|
191
|
-
|
192
|
-
|
193
|
-
|
195
|
+
produce:
|
196
|
+
"/scripts.js":
|
197
|
+
include:
|
198
|
+
- "*.js"
|
199
|
+
exclude:
|
200
|
+
- "/script/vendor/"
|
201
|
+
- "/script/jquery.js"
|
202
|
+
"/styles.css":
|
203
|
+
include:
|
204
|
+
- "*.css"
|
194
205
|
port: 5555
|
195
206
|
src_dir: "src/"
|
196
207
|
build_dir: "build/"
|
@@ -198,6 +209,8 @@ no_proxy: true
|
|
198
209
|
no_livereload: true
|
199
210
|
livereload_port: 5556
|
200
211
|
dont_minify: true
|
212
|
+
# enable browser error injection (experimental)
|
213
|
+
enable_browser_errors: true
|
201
214
|
```
|
202
215
|
|
203
216
|
Most are self explanatory, but a few of the options merit further
|
@@ -212,7 +225,7 @@ that retain the advantages of their multi-page peers without resorting
|
|
212
225
|
to hacks like hash urls. The essential idea is this: when a user
|
213
226
|
navigates to a conceptually different "page" in the app, the URL
|
214
227
|
should be updated to reflect that so that behaviors such as
|
215
|
-
deep-linking and history navigation work properly.
|
228
|
+
deep-linking and history navigation work properly.
|
216
229
|
|
217
230
|
For this to work, however, the server must be able to return the
|
218
231
|
content of your main HTML page for arbitrary paths, as otherwise when
|
@@ -271,6 +284,9 @@ request and finally returns the response back to the browser.
|
|
271
284
|
|
272
285
|
### Ignores
|
273
286
|
|
287
|
+
_Ignores are deprecated and will be removed in the next major release.
|
288
|
+
Use the new product system instead._
|
289
|
+
|
274
290
|
By default slinky will include every javascript and css file it finds
|
275
291
|
into the combined scripts.js and styles.css files. However, it may be
|
276
292
|
that for some reason you want to keep some files separate and handle
|
@@ -285,3 +301,98 @@ ignore:
|
|
285
301
|
|
286
302
|
This will causes everything in the script/vendor directory to be
|
287
303
|
ignored by slinky, as well as the reset.css file.
|
304
|
+
|
305
|
+
### Products
|
306
|
+
|
307
|
+
_New in 0.8: use master to get them now_
|
308
|
+
|
309
|
+
Products are the outputs of the build system. Most files are just
|
310
|
+
copied to the build directory, but you may want some to undergo
|
311
|
+
further processing. For simplicity, Slinky defines two default
|
312
|
+
products which you have seen above: `/scripts.js` and `/styles.css`.
|
313
|
+
These are defined like this:
|
314
|
+
|
315
|
+
```yaml
|
316
|
+
produce:
|
317
|
+
"/scripts.js":
|
318
|
+
include:
|
319
|
+
- "*.js"
|
320
|
+
"/styles.css":
|
321
|
+
include:
|
322
|
+
- "*.css"
|
323
|
+
```
|
324
|
+
|
325
|
+
Products are defined by an output path (in this case `/scripts.js` and
|
326
|
+
`/styles.css`), a set of paths to include, and a set of paths to
|
327
|
+
exclude (with gitignore-style glob patterns supported; see
|
328
|
+
[here](#path-matching) for the match rules). In development mode, all
|
329
|
+
of the files included in a product will be included in your html
|
330
|
+
separately. When built in production mode, they will all be minified
|
331
|
+
and concatenated into a single output file. We can also create our own
|
332
|
+
products:
|
333
|
+
|
334
|
+
```yaml
|
335
|
+
produce:
|
336
|
+
"/test/test.js":
|
337
|
+
include:
|
338
|
+
- "*_test.js"
|
339
|
+
"/main.js":
|
340
|
+
include:
|
341
|
+
- "*.js"
|
342
|
+
exclude:
|
343
|
+
- "vendor/jquery*.js"
|
344
|
+
- "*_test.js"
|
345
|
+
"/main.css":
|
346
|
+
include:
|
347
|
+
- "*.css"
|
348
|
+
exclude:
|
349
|
+
- "vendor/boostrap.css"
|
350
|
+
```
|
351
|
+
|
352
|
+
This config will produce three products in the build directory:
|
353
|
+
`test/test.js`, which will include all files ending in `_test.js`,
|
354
|
+
`main.js` which includes all .js files except jquery and test files,
|
355
|
+
and `main.css` which includes all css files except for boostrap.css in
|
356
|
+
the vendor directory. Custom products can be included in your HTML
|
357
|
+
like this:
|
358
|
+
|
359
|
+
```html
|
360
|
+
<html>
|
361
|
+
<head>
|
362
|
+
slinky_product("/main.js")
|
363
|
+
slinky_product("/main.css")
|
364
|
+
</head>
|
365
|
+
...
|
366
|
+
```
|
367
|
+
|
368
|
+
The default product directives (`slinky_scripts` and `slinky_styles`)
|
369
|
+
are merely sugar for `slinky_product("/scripts.js")` and
|
370
|
+
`slinky_product("/styles.css")`.
|
371
|
+
|
372
|
+
# Path matching
|
373
|
+
|
374
|
+
Several slinky config features involve specifying paths, with support
|
375
|
+
for globbing. These are interpreted similarly to .gitignore rules. The full
|
376
|
+
specification is:
|
377
|
+
|
378
|
+
1. If the pattern ends with a slash, it will only match directories;
|
379
|
+
e.g. `foo/` would match a directory `foo/` but not a file `foo`. In
|
380
|
+
a file context, matching a directory is equivalent to matching all
|
381
|
+
files under that directory, recursively.
|
382
|
+
2. If the pattern does not contain a slash, slinky treats it as a
|
383
|
+
relative pathname which can match files in any directory. For
|
384
|
+
example, the rule `test.js` will matching `/test.js` and
|
385
|
+
`/component/test.js`.
|
386
|
+
3. If the pattern begins with a slash, it will be treated as an
|
387
|
+
absolute path starting at the root of the source directory.
|
388
|
+
4. If the pattern does not begin with a slash, but does contain one or
|
389
|
+
more slashes, it will be treated as a path relative to any
|
390
|
+
directory. For example, `test/*.js` will match `/test/main.js`, and
|
391
|
+
`/component/test/component.js`, but not `main.js`.
|
392
|
+
5. A single star `*` in a pattern will match any number of characters within a
|
393
|
+
single path component. For example, `/test/*.js` will match
|
394
|
+
`/test/main_test.js` but not `/test/component/test.js`.
|
395
|
+
6. A double star `**` will match any number of characters including
|
396
|
+
path separators. For example `/scripts/**/main.js` will match any
|
397
|
+
file named `main.js` under the `/scripts` directory, including
|
398
|
+
`/scripts/main.js` and `/scripts/component/main.js`.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
data/lib/slinky.rb
CHANGED
@@ -14,8 +14,10 @@ require 'listen'
|
|
14
14
|
require 'multi_json'
|
15
15
|
|
16
16
|
require "slinky/em-popen3"
|
17
|
+
require "slinky/errors"
|
17
18
|
require "slinky/compilers"
|
18
19
|
require "slinky/config_reader"
|
20
|
+
require "slinky/graph"
|
19
21
|
require "slinky/manifest"
|
20
22
|
require "slinky/compiled_file"
|
21
23
|
require "slinky/proxy_server"
|
data/lib/slinky/builder.rb
CHANGED
@@ -9,8 +9,10 @@ module Slinky
|
|
9
9
|
:no_minify => config.dont_minify || options[:no_minify])
|
10
10
|
begin
|
11
11
|
manifest.build
|
12
|
-
rescue
|
13
|
-
|
12
|
+
rescue SlinkyError => e
|
13
|
+
e.messages.each{|m|
|
14
|
+
$stderr.puts(m.foreground(:red))
|
15
|
+
}
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
data/lib/slinky/compiled_file.rb
CHANGED
@@ -74,7 +74,7 @@ module Slinky
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def compile_failed e
|
77
|
-
|
77
|
+
SlinkyError.raise BuildFailedError, "Compilation failed on #{name}: #{e}"
|
78
78
|
end
|
79
79
|
|
80
80
|
# Calls the supplied callback with the path of the compiled file,
|
data/lib/slinky/compilers.rb
CHANGED
@@ -34,13 +34,12 @@ module Slinky
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def has_dependencies compiler, ext
|
37
|
-
(compiler[:dependencies] || []).all? {|d|
|
37
|
+
ds = (compiler[:dependencies] || []).all? {|d|
|
38
38
|
if @checked_dependencies.include?(d)
|
39
39
|
true
|
40
40
|
else
|
41
41
|
begin
|
42
42
|
gem(d[0], d[1])
|
43
|
-
require d[0]
|
44
43
|
@checked_dependencies.add(d)
|
45
44
|
true
|
46
45
|
rescue Gem::LoadError
|
@@ -49,6 +48,10 @@ module Slinky
|
|
49
48
|
end
|
50
49
|
end
|
51
50
|
}
|
51
|
+
(compiler[:requires] || []).each {|d|
|
52
|
+
require d
|
53
|
+
}
|
54
|
+
ds
|
52
55
|
end
|
53
56
|
|
54
57
|
# Produces a CompiledFile for an input file if the file needs to
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Slinky
|
2
2
|
module ClojureScriptCompiler
|
3
3
|
Compilers.register_compiler self,
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
:inputs => ["cljs"],
|
5
|
+
:outputs => ["js"],
|
6
|
+
:dependencies => [["clementine", "~> 0.0.3"]],
|
7
|
+
:requires => ["clementine"]
|
8
8
|
def ClojureScriptCompiler::compile s, file
|
9
9
|
# Clementine.options[:pretty_print] = true
|
10
10
|
# Clementine.options[:optimizations] = :none
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Slinky
|
2
2
|
module CoffeeCompiler
|
3
3
|
Compilers.register_compiler self,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
:inputs => ["coffee"],
|
5
|
+
:outputs => ["js"],
|
6
|
+
:dependencies => [["coffee-script", ">= 2.2.0"]],
|
7
|
+
:requires => ["coffee-script"]
|
7
8
|
|
8
9
|
def CoffeeCompiler::compile s, file
|
9
10
|
CoffeeScript::compile(s)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Slinky
|
2
2
|
module HamlCompiler
|
3
3
|
Compilers.register_compiler self,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
:inputs => ["haml"],
|
5
|
+
:outputs => ["html"],
|
6
|
+
:dependencies => [["haml", "~> 3.1.0"]],
|
7
|
+
:requires => ["haml"]
|
7
8
|
|
8
9
|
def HamlCompiler::compile s, file
|
9
10
|
haml_engine = Haml::Engine.new(s)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Slinky
|
2
|
+
module JSXCompiler
|
3
|
+
Compilers.register_compiler self,
|
4
|
+
:inputs => ["jsx"],
|
5
|
+
:outputs => ["js"],
|
6
|
+
:dependencies => [["react-jsx", "~> 0.8.0"]],
|
7
|
+
:requires => ["react/jsx"]
|
8
|
+
|
9
|
+
def JSXCompiler::compile s, file
|
10
|
+
React::JSX.compile(s)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Slinky
|
2
2
|
module LessCompiler
|
3
3
|
Compilers.register_compiler self,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
:inputs => ["less"],
|
5
|
+
:outputs => ["css"],
|
6
|
+
:dependencies => [["less", ">= 2.2.0"]],
|
7
|
+
:requires => ["less"]
|
7
8
|
|
8
9
|
def LessCompiler::compile s, file
|
9
10
|
parser = Less::Parser.new
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module Slinky
|
2
2
|
module SassCompiler
|
3
3
|
Compilers.register_compiler self,
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
:inputs => ["sass", "scss"],
|
5
|
+
:outputs => ["css"],
|
6
|
+
:dependencies => [["sass", ">= 3.1.1"]],
|
7
|
+
:requires => ["sass"]
|
7
8
|
|
8
9
|
def SassCompiler::compile s, file
|
9
10
|
syntax = file.end_with?(".sass") ? :sass : :scss
|
data/lib/slinky/config_reader.rb
CHANGED
@@ -10,6 +10,9 @@ module Slinky
|
|
10
10
|
BOOL_TYPE = "bool"
|
11
11
|
ANY_TYPE = "any"
|
12
12
|
|
13
|
+
DEFAULT_SCRIPT_PRODUCT = "/scripts.js"
|
14
|
+
DEFAULT_STYLE_PRODUCT = "/styles.css"
|
15
|
+
|
13
16
|
class ConfigEntry
|
14
17
|
attr_reader :type, :name, :default
|
15
18
|
def initialize(name, type, default)
|
@@ -30,6 +33,12 @@ module Slinky
|
|
30
33
|
ConfigEntry.new("livereload_port", NUMBER_TYPE, 35729),
|
31
34
|
ConfigEntry.new("dont_minify", BOOL_TYPE, false),
|
32
35
|
ConfigEntry.new("pushstate", ANY_TYPE, []),
|
36
|
+
ConfigEntry.new("dependencies", HASH_TYPE, {}),
|
37
|
+
ConfigEntry.new("produce", HASH_TYPE, {
|
38
|
+
DEFAULT_SCRIPT_PRODUCT => {"include" => ["*.js"]},
|
39
|
+
DEFAULT_STYLE_PRODUCT => {"include" => ["*.css"]}
|
40
|
+
}),
|
41
|
+
ConfigEntry.new("enable_browser_errors", BOOL_TYPE, false)
|
33
42
|
]
|
34
43
|
|
35
44
|
@entries.each{|e|
|
@@ -64,8 +73,15 @@ module Slinky
|
|
64
73
|
end
|
65
74
|
end
|
66
75
|
|
67
|
-
def initialize
|
68
|
-
|
76
|
+
def initialize string_or_hash
|
77
|
+
case string_or_hash
|
78
|
+
when String
|
79
|
+
@config = YAML::load(string_or_hash)
|
80
|
+
when Hash
|
81
|
+
@config = string_or_hash
|
82
|
+
else
|
83
|
+
raise TypeError.new("Config must be either a string or a hash")
|
84
|
+
end
|
69
85
|
ConfigReader.validate(@config)
|
70
86
|
end
|
71
87
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'continuation'
|
2
|
+
|
3
|
+
module Slinky
|
4
|
+
# Common base class for all Slinky errors
|
5
|
+
class SlinkyError < StandardError
|
6
|
+
class NoContinuationError < StandardError; end
|
7
|
+
|
8
|
+
attr_accessor :continuation
|
9
|
+
|
10
|
+
# Continue where we left off
|
11
|
+
def continue
|
12
|
+
raise NoContinuationError unless continuation.respond_to?(:call)
|
13
|
+
continuation.call
|
14
|
+
end
|
15
|
+
|
16
|
+
def messages
|
17
|
+
[message]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Raises an error with a continuation that allows us to continue
|
21
|
+
# with processing as if no error had been thrown
|
22
|
+
def self.raise(exception = SlinkyError, string = nil, array = caller)
|
23
|
+
if exception.is_a?(String)
|
24
|
+
string = exception
|
25
|
+
exception = SlinkyError
|
26
|
+
end
|
27
|
+
|
28
|
+
callcc do |cc|
|
29
|
+
obj = string.nil? ? exception : exception.exception(string)
|
30
|
+
obj.set_backtrace(array)
|
31
|
+
obj.continuation = cc
|
32
|
+
super obj
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# batches all SlinkyErrors thrown in the supplied block and
|
37
|
+
# re-raises them at the end of processing wrapped in a MultiError.
|
38
|
+
def self.batch_errors
|
39
|
+
errors = []
|
40
|
+
result = nil
|
41
|
+
begin
|
42
|
+
result = yield
|
43
|
+
rescue SlinkyError => e
|
44
|
+
errors << e
|
45
|
+
if e.continuation.respond_to?(:call)
|
46
|
+
e.continue
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if !errors.empty?
|
51
|
+
if errors.size == 1
|
52
|
+
raise errors.first
|
53
|
+
else
|
54
|
+
raise MultiError, errors
|
55
|
+
end
|
56
|
+
end
|
57
|
+
result
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Raised when a compilation fails for any reason
|
62
|
+
class BuildFailedError < SlinkyError; end
|
63
|
+
# Raised when a required file is not found.
|
64
|
+
class FileNotFoundError < SlinkyError; end
|
65
|
+
# Raised when there is a cycle in the dependency graph (i.e., file A
|
66
|
+
# requires file B which requires C which requires A)
|
67
|
+
class DependencyError < SlinkyError; end
|
68
|
+
# Raise when there is a request for a product that doesn't exist
|
69
|
+
class NoSuchProductError < SlinkyError; end
|
70
|
+
# Raise when there are multiple errors
|
71
|
+
class MultiError < SlinkyError
|
72
|
+
attr_reader :errors
|
73
|
+
|
74
|
+
def initialize errors
|
75
|
+
@errors = errors.map{|e|
|
76
|
+
case e
|
77
|
+
when MultiError then e.errors
|
78
|
+
else e
|
79
|
+
end
|
80
|
+
}.flatten
|
81
|
+
end
|
82
|
+
|
83
|
+
def message
|
84
|
+
@errors.map{|e| e.message}.join(", ")
|
85
|
+
end
|
86
|
+
|
87
|
+
def messages
|
88
|
+
@errors.map{|e| e.message}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|