porcupine 0.1.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/.gitignore +18 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Jarfile +3 -0
- data/Jarfile.lock +29 -0
- data/LICENSE.txt +22 -0
- data/README.md +70 -0
- data/Rakefile +10 -0
- data/lib/porcupine/exceptions.rb +6 -0
- data/lib/porcupine/future.rb +12 -0
- data/lib/porcupine/observable.rb +27 -0
- data/lib/porcupine/porcupine.rb +61 -0
- data/lib/porcupine.rb +9 -0
- data/porcupine.gemspec +25 -0
- data/spec/future_spec.rb +24 -0
- data/spec/observable_spec.rb +75 -0
- data/spec/porcupine_spec.rb +138 -0
- data/spec/spec_helper.rb +1 -0
- metadata +134 -0
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
jruby
|
data/Gemfile
ADDED
data/Jarfile
ADDED
data/Jarfile.lock
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
---
|
2
|
+
version: 0.7.5
|
3
|
+
groups:
|
4
|
+
default:
|
5
|
+
dependencies:
|
6
|
+
- com.google.code.findbugs:jsr305:jar:2.0.0
|
7
|
+
- com.netflix.archaius:archaius-core:jar:0.4.1
|
8
|
+
- com.netflix.hystrix:hystrix-core:jar:1.3.2
|
9
|
+
- com.netflix.rxjava:rxjava-core:jar:0.10.1
|
10
|
+
- com.netflix.rxjava:rxjava-jruby:jar:0.10.1
|
11
|
+
- commons-configuration:commons-configuration:jar:1.8
|
12
|
+
- commons-lang:commons-lang:jar:2.6
|
13
|
+
- commons-logging:commons-logging:jar:1.1.1
|
14
|
+
- org.slf4j:slf4j-api:jar:1.7.5
|
15
|
+
- org.slf4j:slf4j-simple:jar:1.7.5
|
16
|
+
artifacts:
|
17
|
+
- jar:com.netflix.rxjava:rxjava-jruby:jar:0.10.1:
|
18
|
+
transitive:
|
19
|
+
com.netflix.rxjava:rxjava-core:jar:0.10.1: {}
|
20
|
+
- jar:com.netflix.hystrix:hystrix-core:jar:1.3.2:
|
21
|
+
transitive:
|
22
|
+
com.google.code.findbugs:jsr305:jar:2.0.0: {}
|
23
|
+
com.netflix.archaius:archaius-core:jar:0.4.1:
|
24
|
+
commons-configuration:commons-configuration:jar:1.8:
|
25
|
+
commons-logging:commons-logging:jar:1.1.1: {}
|
26
|
+
commons-lang:commons-lang:jar:2.6: {}
|
27
|
+
- jar:org.slf4j:slf4j-simple:jar:1.7.5:
|
28
|
+
transitive:
|
29
|
+
org.slf4j:slf4j-api:jar:1.7.5: {}
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Mike Ragalie
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Porcupine
|
2
|
+
|
3
|
+
Porcupine is a JRuby wrapper for Netflix's [Hystrix library](https://github.com/Netflix/Hystrix).
|
4
|
+
It simplifies instantiating HystrixCommands and throws Ruby exceptions for most things that can
|
5
|
+
go wrong (execution failures, timeouts, short circuits, no threads in the thread pool).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'porcupine'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install porcupine
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Instantiate a Porcupine object and give it a name, a group name (optional), a timeout (optional) and a block:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
porcupine = Porcupine.new("Sleeping Beauty", "Disney Characters", 10_000) { sleep(50) }
|
27
|
+
```
|
28
|
+
|
29
|
+
You can also provide a [Setter](https://github.com/Netflix/Hystrix/wiki/Configuration) directly:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
setter = com.netflix.hystrix.HystrixCommand::Setter.withGroupKey(com.netflix.hystrix.HystrixCommandGroupKey::Factory.asKey("Disney Characters"))
|
33
|
+
.andCommandKey(com.netflix.hystrix.HystrixCommandKey::Factory.asKey("Sleeping Beauty"))
|
34
|
+
porcupine = Porcupine.new(setter) { sleep(50) }
|
35
|
+
```
|
36
|
+
|
37
|
+
Then either you can request a result immediately:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
porcupine.execute
|
41
|
+
```
|
42
|
+
|
43
|
+
Or retrieve a Future and get the result later:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
future = porcupine.queue
|
47
|
+
future.get # Blocks on the result
|
48
|
+
```
|
49
|
+
|
50
|
+
Subscribing to an event is also supported:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
observer = porcupine.observe
|
54
|
+
observer.subscribe { puts "done!" } # Will puts "done!" when finished
|
55
|
+
```
|
56
|
+
|
57
|
+
If you provide an onError function, then the function will receive exceptions raised:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
observer = porcupine.observe
|
61
|
+
observer.subscribe("onNext" => lambda {}, "onError" => lambda {|exception| puts exception}) # Will puts any exception
|
62
|
+
```
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
1. Fork it
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
69
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
70
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "delegate"
|
2
|
+
|
3
|
+
class Porcupine
|
4
|
+
class Observable < SimpleDelegator
|
5
|
+
def subscribe(*args, &block)
|
6
|
+
raise ArgumentError unless block_given? || (args.first && args.first["onNext"])
|
7
|
+
|
8
|
+
on_next = if block_given?
|
9
|
+
block
|
10
|
+
else
|
11
|
+
args.first["onNext"]
|
12
|
+
end
|
13
|
+
|
14
|
+
on_error = args.first && args.first["onError"]
|
15
|
+
|
16
|
+
wrapped = lambda do |value_or_exception|
|
17
|
+
if value_or_exception.is_a?(Exception)
|
18
|
+
on_error && on_error.call(value_or_exception)
|
19
|
+
else
|
20
|
+
on_next.call(value_or_exception)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
__getobj__.subscribe("onNext" => wrapped, "onError" => on_error)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Porcupine < com.netflix.hystrix.HystrixCommand
|
2
|
+
java_import com.netflix.hystrix.HystrixCommand::Setter
|
3
|
+
java_import com.netflix.hystrix.HystrixCommandKey
|
4
|
+
java_import com.netflix.hystrix.HystrixCommandGroupKey
|
5
|
+
java_import com.netflix.hystrix.HystrixCommandProperties
|
6
|
+
|
7
|
+
DEFAULT_TIMEOUT = 10_000
|
8
|
+
DEFAULT_GROUP = "default"
|
9
|
+
|
10
|
+
attr_reader :block
|
11
|
+
|
12
|
+
def initialize(name_or_setter, group=DEFAULT_GROUP, timeout=DEFAULT_TIMEOUT, &block)
|
13
|
+
@block = block
|
14
|
+
|
15
|
+
setter = name_or_setter if name_or_setter.is_a?(com.netflix.hystrix.HystrixCommand::Setter)
|
16
|
+
setter ||= Setter.withGroupKey(HystrixCommandGroupKey::Factory.asKey(group))
|
17
|
+
.andCommandKey(HystrixCommandKey::Factory.asKey(name_or_setter))
|
18
|
+
.andCommandPropertiesDefaults(HystrixCommandProperties::Setter().withExecutionIsolationThreadTimeoutInMilliseconds(timeout))
|
19
|
+
|
20
|
+
super(setter)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Only catch Java exceptions since we already handle most exceptions in Observable#get
|
24
|
+
def execute
|
25
|
+
queue.get
|
26
|
+
rescue Java::JavaLang::Throwable => e
|
27
|
+
raise decomposeException(e)
|
28
|
+
end
|
29
|
+
|
30
|
+
def observe
|
31
|
+
Observable.new(super)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Only wrap the outer-most call; otherwise Java gets angry because the class of the
|
35
|
+
# returned object won't match the signature when the calls recurse
|
36
|
+
def toObservable(*args)
|
37
|
+
result = super
|
38
|
+
|
39
|
+
unless caller.first.match(/toObservable/) || caller.first.match(/observe/)
|
40
|
+
result = Observable.new(result)
|
41
|
+
end
|
42
|
+
|
43
|
+
result
|
44
|
+
end
|
45
|
+
|
46
|
+
def queue
|
47
|
+
Future.new(super)
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
block.call
|
52
|
+
end
|
53
|
+
|
54
|
+
def getFallback
|
55
|
+
return getFailedExecutionException.getException if isFailedExecution
|
56
|
+
return RejectedError.new if isResponseRejected
|
57
|
+
return ShortCircuitError.new if isResponseShortCircuited
|
58
|
+
return TimeoutError.new if isResponseTimedOut
|
59
|
+
RuntimeError.new
|
60
|
+
end
|
61
|
+
end
|
data/lib/porcupine.rb
ADDED
data/porcupine.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "porcupine"
|
7
|
+
spec.version = "0.1.0"
|
8
|
+
spec.authors = ["Mike Ragalie"]
|
9
|
+
spec.email = ["ragalie@gmail.com"]
|
10
|
+
spec.summary = "JRuby wrapper for Hystrix"
|
11
|
+
spec.homepage = "https://github.com/ragalie/porcupine"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files`.split($/)
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.extensions = ["Rakefile"]
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "lock_jar"
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.0"
|
25
|
+
end
|
data/spec/future_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Porcupine::Future do
|
4
|
+
let(:object) { double("future") }
|
5
|
+
subject(:future) { described_class.new(object) }
|
6
|
+
|
7
|
+
it "is a SimpleDelegator" do
|
8
|
+
future.should be_a(SimpleDelegator)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#get" do
|
12
|
+
before { object.stub(:get) { "banana" } }
|
13
|
+
|
14
|
+
it "returns the future value" do
|
15
|
+
future.get.should == "banana"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "raises if the value is an exception" do
|
19
|
+
exception = RuntimeError.new
|
20
|
+
object.stub(:get) { exception }
|
21
|
+
expect { future.get }.to raise_error(exception)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Porcupine::Observable do
|
4
|
+
let(:object) { double("observable", :subscribe => nil) }
|
5
|
+
subject(:observable) { described_class.new(object) }
|
6
|
+
|
7
|
+
it "is a SimpleDelegator" do
|
8
|
+
observable.should be_a(SimpleDelegator)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#subscribe" do
|
12
|
+
let(:on_next) { lambda {|v| "pumpkin" } }
|
13
|
+
let(:on_error) { lambda {|v| "apples" } }
|
14
|
+
let(:arguments) { observable.subscribe("onNext" => on_next, "onError" => on_error) }
|
15
|
+
|
16
|
+
describe "arguments" do
|
17
|
+
it "accepts a block" do
|
18
|
+
observable.subscribe {}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "accepts an onNext parameter" do
|
22
|
+
observable.subscribe("onNext" => lambda {})
|
23
|
+
end
|
24
|
+
|
25
|
+
it "raises otherwise" do
|
26
|
+
expect { observable.subscribe("cat!") }.to raise_error(ArgumentError)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "calls subscribe with a block" do
|
31
|
+
object.stub(:subscribe) {|arg| arg}
|
32
|
+
observable.subscribe(&on_next)
|
33
|
+
arguments["onNext"].call(1).should == "pumpkin"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "calls subscribe with the provided onNext method" do
|
37
|
+
object.stub(:subscribe) {|arg| arg}
|
38
|
+
arguments["onNext"].call(1).should == "pumpkin"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "calls subscribe with the provided onError method" do
|
42
|
+
object.stub(:subscribe) {|arg| arg}
|
43
|
+
arguments["onError"].should == on_error
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "onNext method" do
|
47
|
+
before { object.stub(:subscribe) {|arg| arg} }
|
48
|
+
|
49
|
+
it "calls the success method" do
|
50
|
+
wrapped = arguments["onNext"]
|
51
|
+
|
52
|
+
on_next.should_receive(:call).with("pony")
|
53
|
+
wrapped.call("pony")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "calls the error method if the value is an exception" do
|
57
|
+
wrapped = arguments["onNext"]
|
58
|
+
|
59
|
+
exception = RuntimeError.new
|
60
|
+
on_error.should_receive(:call).with(exception)
|
61
|
+
wrapped.call(exception)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "does nothing if there's no on_error" do
|
65
|
+
arguments = observable.subscribe(&on_next)
|
66
|
+
wrapped = arguments["onNext"]
|
67
|
+
|
68
|
+
exception = RuntimeError.new
|
69
|
+
on_error.should_not_receive(:call)
|
70
|
+
on_next.should_not_receive(:call)
|
71
|
+
wrapped.call(exception)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Porcupine do
|
4
|
+
let(:block) { lambda {} }
|
5
|
+
|
6
|
+
subject(:porcupine) do
|
7
|
+
described_class.new("test", &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
after do
|
11
|
+
com.netflix.hystrix.Hystrix.reset
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#initialize" do
|
15
|
+
it "handles a name, group, timeout and block" do
|
16
|
+
porcupine = described_class.new("blah", "blah_group", 1_000, &block)
|
17
|
+
porcupine.should be_a(com.netflix.hystrix.HystrixCommand)
|
18
|
+
porcupine.getCommandKey.name.should == "blah"
|
19
|
+
porcupine.getCommandGroup.name.should == "blah_group"
|
20
|
+
porcupine.getProperties.executionIsolationThreadTimeoutInMilliseconds.get.should == 1_000
|
21
|
+
porcupine.block.should == block
|
22
|
+
end
|
23
|
+
|
24
|
+
it "handles a setter" do
|
25
|
+
setter = com.netflix.hystrix.HystrixCommand::Setter.withGroupKey(com.netflix.hystrix.HystrixCommandGroupKey::Factory.asKey("blah2_group"))
|
26
|
+
.andCommandKey(com.netflix.hystrix.HystrixCommandKey::Factory.asKey("blah2"))
|
27
|
+
|
28
|
+
porcupine = described_class.new(setter, &block)
|
29
|
+
porcupine.should be_a(com.netflix.hystrix.HystrixCommand)
|
30
|
+
porcupine.getCommandKey.name.should == "blah2"
|
31
|
+
porcupine.getCommandGroup.name.should == "blah2_group"
|
32
|
+
porcupine.block.should == block
|
33
|
+
end
|
34
|
+
|
35
|
+
it "uses the defaults if none are provided" do
|
36
|
+
porcupine = described_class.new("blah3", &block)
|
37
|
+
porcupine.getCommandKey.name.should == "blah3"
|
38
|
+
porcupine.getCommandGroup.name.should == "default"
|
39
|
+
porcupine.getProperties.executionIsolationThreadTimeoutInMilliseconds.get.should == 10_000
|
40
|
+
porcupine.block.should == block
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#execute" do
|
45
|
+
let(:future) { double("future") }
|
46
|
+
|
47
|
+
before { porcupine.stub(:queue) { future } }
|
48
|
+
|
49
|
+
it "calls queue.get" do
|
50
|
+
porcupine.should_receive(:queue) { future }
|
51
|
+
future.should_receive(:get)
|
52
|
+
|
53
|
+
porcupine.execute
|
54
|
+
end
|
55
|
+
|
56
|
+
it "lets Ruby exceptions propogate" do
|
57
|
+
future.stub(:get).and_raise(RuntimeError)
|
58
|
+
porcupine.should_not_receive(:decomposeException)
|
59
|
+
|
60
|
+
expect { porcupine.execute }.to raise_error(RuntimeError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "catches Java exceptions and runs them through #decomposeException" do
|
64
|
+
exception = java.lang.Throwable.new
|
65
|
+
future.stub(:get).and_raise(exception)
|
66
|
+
porcupine.should_receive(:decomposeException).with(exception) { java.lang.Exception.new }
|
67
|
+
|
68
|
+
expect { porcupine.execute }.to raise_error(Java::JavaLang::Exception)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#observe" do
|
73
|
+
it "wraps the result in an Observable" do
|
74
|
+
observable = porcupine.observe
|
75
|
+
observable.should be_a(Porcupine::Observable)
|
76
|
+
observable.__getobj__.should be_a(Java::Rx::Observable)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#toObservable" do
|
81
|
+
it "wraps the result in an Observable with no args" do
|
82
|
+
observable = porcupine.toObservable
|
83
|
+
observable.should be_a(Porcupine::Observable)
|
84
|
+
observable.__getobj__.should be_a(Java::Rx::Observable)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "wraps the result in an Observable with one arg" do
|
88
|
+
observable = porcupine.toObservable(Java::RxConcurrency::Schedulers.threadPoolForComputation)
|
89
|
+
observable.should be_a(Porcupine::Observable)
|
90
|
+
observable.__getobj__.should be_a(Java::Rx::Observable)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#queue" do
|
95
|
+
it "wraps the result in a Future" do
|
96
|
+
future = porcupine.queue
|
97
|
+
future.should be_a(Porcupine::Future)
|
98
|
+
future.__getobj__.class.ancestors.should include(Java::JavaUtilConcurrent::Future)
|
99
|
+
future.cancel(true)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#run" do
|
104
|
+
it "calls the block" do
|
105
|
+
block.should_receive(:call)
|
106
|
+
porcupine.run
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#getFallback" do
|
111
|
+
it "returns the failure exception if the block failed" do
|
112
|
+
exception = Exception.new
|
113
|
+
|
114
|
+
porcupine.stub(:isFailedExecution) { true }
|
115
|
+
porcupine.stub_chain(:getFailedExecutionException, :getException) { exception }
|
116
|
+
porcupine.getFallback.should == exception
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns a RejectedError if the response was rejected" do
|
120
|
+
porcupine.stub(:isResponseRejected) { true }
|
121
|
+
porcupine.getFallback.should be_a(Porcupine::RejectedError)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "returns a ShortCircuitError if the response was short circuited" do
|
125
|
+
porcupine.stub(:isResponseShortCircuited) { true }
|
126
|
+
porcupine.getFallback.should be_a(Porcupine::ShortCircuitError)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "returns a TimeoutError if the response timed out" do
|
130
|
+
porcupine.stub(:isResponseTimedOut) { true }
|
131
|
+
porcupine.getFallback.should be_a(Porcupine::TimeoutError)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "returns a RuntimeError otherwise" do
|
135
|
+
porcupine.getFallback.should be_a(RuntimeError)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "porcupine"
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: porcupine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mike Ragalie
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: lock_jar
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
none: false
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
none: false
|
28
|
+
prerelease: false
|
29
|
+
type: :runtime
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ~>
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1.3'
|
37
|
+
none: false
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.3'
|
43
|
+
none: false
|
44
|
+
prerelease: false
|
45
|
+
type: :development
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
version_requirements: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
none: false
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
none: false
|
60
|
+
prerelease: false
|
61
|
+
type: :development
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.0'
|
69
|
+
none: false
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ~>
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '2.0'
|
75
|
+
none: false
|
76
|
+
prerelease: false
|
77
|
+
type: :development
|
78
|
+
description:
|
79
|
+
email:
|
80
|
+
- ragalie@gmail.com
|
81
|
+
executables: []
|
82
|
+
extensions:
|
83
|
+
- Rakefile
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- .ruby-version
|
88
|
+
- Gemfile
|
89
|
+
- Jarfile
|
90
|
+
- Jarfile.lock
|
91
|
+
- LICENSE.txt
|
92
|
+
- README.md
|
93
|
+
- Rakefile
|
94
|
+
- lib/porcupine.rb
|
95
|
+
- lib/porcupine/exceptions.rb
|
96
|
+
- lib/porcupine/future.rb
|
97
|
+
- lib/porcupine/observable.rb
|
98
|
+
- lib/porcupine/porcupine.rb
|
99
|
+
- porcupine.gemspec
|
100
|
+
- spec/future_spec.rb
|
101
|
+
- spec/observable_spec.rb
|
102
|
+
- spec/porcupine_spec.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
homepage: https://github.com/ragalie/porcupine
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
none: false
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
none: false
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: JRuby wrapper for Hystrix
|
129
|
+
test_files:
|
130
|
+
- spec/future_spec.rb
|
131
|
+
- spec/observable_spec.rb
|
132
|
+
- spec/porcupine_spec.rb
|
133
|
+
- spec/spec_helper.rb
|
134
|
+
has_rdoc:
|