slinky 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|