cistern 0.2.3 → 0.3.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/lib/cistern.rb +7 -9
- data/lib/cistern/collection.rb +25 -24
- data/lib/cistern/formatter.rb +9 -0
- data/lib/cistern/model.rb +10 -14
- data/lib/cistern/service.rb +13 -11
- data/lib/cistern/timeout.rb +23 -0
- data/lib/cistern/version.rb +1 -1
- data/lib/cistern/wait_for.rb +26 -10
- data/spec/wait_for_spec.rb +78 -0
- metadata +5 -2
data/lib/cistern.rb
CHANGED
@@ -2,7 +2,9 @@ require 'cistern/version'
|
|
2
2
|
require 'time'
|
3
3
|
|
4
4
|
module Cistern
|
5
|
-
|
5
|
+
|
6
|
+
Error = Class.new(StandardError)
|
7
|
+
Timeout = Class.new(Error)
|
6
8
|
|
7
9
|
require 'cistern/hash'
|
8
10
|
require 'cistern/mock'
|
@@ -12,18 +14,14 @@ module Cistern
|
|
12
14
|
require 'cistern/model'
|
13
15
|
require 'cistern/service'
|
14
16
|
|
17
|
+
extend WaitFor
|
18
|
+
timeout_error = Timeout
|
19
|
+
|
15
20
|
autoload :Formatter, 'cistern/formatter'
|
16
21
|
|
17
|
-
def self.timeout=(timeout); @timeout= timeout; end
|
18
|
-
def self.timeout; @timeout || 0; end
|
19
22
|
def self.formatter=(formatter); @formatter = formatter; end
|
20
23
|
|
21
24
|
def self.formatter
|
22
|
-
@formatter ||=
|
23
|
-
Cistern::Formatter::AwesomePrint
|
24
|
-
elsif defined?(Formatador)
|
25
|
-
Cistern::Formatter::Formatador
|
26
|
-
else Cistern::Formatter::Default
|
27
|
-
end
|
25
|
+
@formatter ||= Cistern::Formatter.default
|
28
26
|
end
|
29
27
|
end
|
data/lib/cistern/collection.rb
CHANGED
@@ -25,11 +25,20 @@ class Cistern::Collection < Array
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
attr_accessor :connection
|
29
|
+
|
30
|
+
alias build initialize
|
31
|
+
|
28
32
|
def initialize(attributes = {})
|
29
33
|
@loaded = false
|
30
34
|
merge_attributes(attributes)
|
31
35
|
end
|
32
36
|
|
37
|
+
def clear
|
38
|
+
@loaded = true
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
33
42
|
def create(attributes={})
|
34
43
|
self.new(attributes).save
|
35
44
|
end
|
@@ -38,17 +47,28 @@ class Cistern::Collection < Array
|
|
38
47
|
raise NotImplementedError
|
39
48
|
end
|
40
49
|
|
41
|
-
def
|
42
|
-
@loaded
|
43
|
-
|
50
|
+
def inspect
|
51
|
+
lazy_load unless @loaded
|
52
|
+
Cistern.formatter.call(self)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
def lazy_load
|
57
|
+
self.all
|
58
|
+
end
|
59
|
+
|
60
|
+
def load(objects)
|
61
|
+
clear
|
62
|
+
for object in objects
|
63
|
+
self << new(object)
|
64
|
+
end
|
65
|
+
self
|
44
66
|
end
|
45
67
|
|
46
68
|
def model
|
47
69
|
self.class.instance_variable_get('@model')
|
48
70
|
end
|
49
71
|
|
50
|
-
attr_accessor :connection
|
51
|
-
|
52
72
|
def new(attributes = {})
|
53
73
|
unless attributes.is_a?(::Hash)
|
54
74
|
raise(ArgumentError.new("Initialization parameters must be an attributes hash, got #{attributes.class} #{attributes.inspect}"))
|
@@ -61,28 +81,9 @@ class Cistern::Collection < Array
|
|
61
81
|
)
|
62
82
|
end
|
63
83
|
|
64
|
-
def load(objects)
|
65
|
-
clear
|
66
|
-
for object in objects
|
67
|
-
self << new(object)
|
68
|
-
end
|
69
|
-
self
|
70
|
-
end
|
71
|
-
|
72
84
|
def reload
|
73
85
|
clear
|
74
86
|
lazy_load
|
75
87
|
self
|
76
88
|
end
|
77
|
-
|
78
|
-
def inspect
|
79
|
-
lazy_load unless @loaded
|
80
|
-
Cistern.formatter.call(self)
|
81
|
-
end
|
82
|
-
|
83
|
-
private
|
84
|
-
|
85
|
-
def lazy_load
|
86
|
-
self.all
|
87
|
-
end
|
88
89
|
end
|
data/lib/cistern/formatter.rb
CHANGED
@@ -2,4 +2,13 @@ module Cistern::Formatter
|
|
2
2
|
autoload :AwesomePrint, 'cistern/formatter/awesome_print'
|
3
3
|
autoload :Default, 'cistern/formatter/default'
|
4
4
|
autoload :Formatador, 'cistern/formatter/formatador'
|
5
|
+
|
6
|
+
def self.default
|
7
|
+
if defined?(AwesomePrint)
|
8
|
+
Cistern::Formatter::AwesomePrint
|
9
|
+
elsif defined?(Formatador)
|
10
|
+
Cistern::Formatter::Formatador
|
11
|
+
else Cistern::Formatter::Default
|
12
|
+
end
|
13
|
+
end
|
5
14
|
end
|
data/lib/cistern/model.rb
CHANGED
@@ -33,19 +33,15 @@ class Cistern::Model
|
|
33
33
|
!comparison_object.new_record?)
|
34
34
|
end
|
35
35
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
raise Cistern::Error.new("Reload failed, #{self.class} #{self.identity} went away.") # FIXME: pretty much assumes you are calling #ready?
|
47
|
-
end
|
48
|
-
instance_eval(&block)
|
49
|
-
end
|
36
|
+
def service
|
37
|
+
self.connection ? self.connection.class : Cistern
|
38
|
+
end
|
39
|
+
|
40
|
+
def wait_for(timeout = self.service.timeout, interval = self.service.poll_interval, &block)
|
41
|
+
service.wait_for(timeout, interval) { reload && block.call(self) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def wait_for!(timeout = self.service.timeout, interval = self.service.poll_interval, &block)
|
45
|
+
service.wait_for!(timeout, interval) { reload && block.call(self) }
|
50
46
|
end
|
51
47
|
end
|
data/lib/cistern/service.rb
CHANGED
@@ -28,10 +28,13 @@ class Cistern::Service
|
|
28
28
|
#{klass.name}
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
31
32
|
def self.service
|
32
33
|
#{klass.name}
|
33
34
|
end
|
34
35
|
EOS
|
36
|
+
|
37
|
+
klass.send(:const_set, :Timeout, Class.new(Cistern::Error))
|
35
38
|
end
|
36
39
|
|
37
40
|
def model_path(model_path)
|
@@ -82,8 +85,8 @@ class Cistern::Service
|
|
82
85
|
requests << request_name
|
83
86
|
end
|
84
87
|
|
85
|
-
def collection(collection_name)
|
86
|
-
collections << collection_name
|
88
|
+
def collection(collection_name, options={})
|
89
|
+
collections << [collection_name, options]
|
87
90
|
end
|
88
91
|
|
89
92
|
def validate_options(options={})
|
@@ -123,8 +126,8 @@ class Cistern::Service
|
|
123
126
|
EOS
|
124
127
|
end
|
125
128
|
end
|
126
|
-
collections.each do |collection|
|
127
|
-
require File.join(@model_path, collection.to_s)
|
129
|
+
collections.each do |collection, options|
|
130
|
+
require File.join(@model_path, collection.to_s) unless options[:require] == false
|
128
131
|
class_name = collection.to_s.split("_").map(&:capitalize).join
|
129
132
|
self.const_get(:Collections).module_eval <<-EOS, __FILE__, __LINE__
|
130
133
|
def #{collection}(attributes={})
|
@@ -140,13 +143,12 @@ class Cistern::Service
|
|
140
143
|
validate_options(options)
|
141
144
|
setup_requirements
|
142
145
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
end
|
146
|
+
klass = self.const_get(self.mocking? ? :Mock : :Real)
|
147
|
+
|
148
|
+
klass.send(:include, service::Collections)
|
149
|
+
klass.send(:extend, Cistern::WaitFor)
|
150
|
+
klass.timeout_error = service::Timeout
|
151
|
+
klass.new(options)
|
150
152
|
end
|
151
153
|
|
152
154
|
def reset!
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Cistern
|
2
|
+
module WaitFor
|
3
|
+
def self.wait_for(timeout = Cistern.timeout, interval = Cistern.poll_interval, &block)
|
4
|
+
duration = 0
|
5
|
+
start = Time.now
|
6
|
+
|
7
|
+
until yield || duration > timeout
|
8
|
+
sleep(interval.to_f)
|
9
|
+
duration = Time.now - start
|
10
|
+
end
|
11
|
+
|
12
|
+
if duration > timeout
|
13
|
+
false
|
14
|
+
else
|
15
|
+
{ :duration => duration }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.wait_for!(*arg)
|
20
|
+
wait_for
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/cistern/version.rb
CHANGED
data/lib/cistern/wait_for.rb
CHANGED
@@ -1,15 +1,31 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
1
3
|
module Cistern
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
module WaitFor
|
5
|
+
DEFAULT_TIMEOUT = 3 * 60 # 3 minutes
|
6
|
+
DEFAULT_POLL_INTERVAL = 10 # seconds
|
7
|
+
|
8
|
+
def timeout; @timeout || DEFAULT_TIMEOUT; end
|
9
|
+
def timeout=(timeout); @timeout = timeout; end
|
10
|
+
def poll_interval; @poll_interval || DEFAULT_POLL_INTERVAL; end
|
11
|
+
def poll_interval=(poll_interval); @poll_interval = poll_interval; end
|
12
|
+
def timeout_error=(timeout_error); @timeout_error = timeout_error; end
|
13
|
+
def timeout_error; @timeout_error || self.const_defined?(:Timeout) && self.const_get(:Timeout) || ::Timeout::Error; end
|
14
|
+
|
15
|
+
def wait_for(timeout = self.timeout, interval = self.poll_interval, &block)
|
16
|
+
duration = 0
|
17
|
+
start = Time.now
|
18
|
+
|
19
|
+
until yield || duration > timeout
|
20
|
+
sleep(interval.to_f)
|
21
|
+
duration = Time.now - start
|
22
|
+
end
|
23
|
+
|
24
|
+
duration > timeout ? false : duration
|
8
25
|
end
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
{ :duration => duration }
|
26
|
+
|
27
|
+
def wait_for!(timeout = self.timeout, interval = self.poll_interval, &block)
|
28
|
+
wait_for(timeout, interval, &block) || raise(timeout_error, "wait_for(#{timeout}) exceeded")
|
13
29
|
end
|
14
30
|
end
|
15
31
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class WaitForService < Cistern::Service
|
4
|
+
model :wait_for_model, require: false
|
5
|
+
collection :wait_for_models, require: false
|
6
|
+
|
7
|
+
class Real
|
8
|
+
def initialize(*args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class WaitForService::WaitForModel < Cistern::Model
|
14
|
+
identity :id
|
15
|
+
|
16
|
+
attribute :name
|
17
|
+
end
|
18
|
+
|
19
|
+
class WaitForService::WaitForModels < Cistern::Collection
|
20
|
+
model WaitForService::WaitForModel
|
21
|
+
|
22
|
+
def get(identity)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'Cistern#wait_for' do
|
28
|
+
it "should return false if timeout exceeded" do
|
29
|
+
Cistern.wait_for(0, 0) { false }.should be_false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'Cistern#wait_for!' do
|
34
|
+
it "should raise if timeout exceeded" do
|
35
|
+
lambda { Cistern.wait_for!(0, 0) { false } }.should raise_exception(Cistern::Timeout)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'Cistern::Model#wait_for!' do
|
40
|
+
let(:service) { WaitForService.new }
|
41
|
+
let(:model) { service.wait_for_models.new(identity: 1) }
|
42
|
+
|
43
|
+
it "should raise if timeout exceeded" do
|
44
|
+
lambda { model.wait_for!(0, 0) { false } }.should raise_exception(WaitForService::Timeout)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
describe "WaitForModel#timeout" do
|
50
|
+
let(:service) { WaitForService.new }
|
51
|
+
let(:model) { service.wait_for_models.new(identity: 1) }
|
52
|
+
|
53
|
+
it "should use service-specific timeout in #wait_for" do
|
54
|
+
service.class.timeout = 0.1
|
55
|
+
service.class.poll_interval = 0
|
56
|
+
|
57
|
+
elapsed = 0
|
58
|
+
|
59
|
+
timeout(2) do
|
60
|
+
lambda do
|
61
|
+
model.wait_for! { sleep(0.2); elapsed += 0.2; elapsed > 0.2 }
|
62
|
+
end.should raise_exception(WaitForService::Timeout)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should favor explicit timeout" do
|
67
|
+
service.class.timeout = 1
|
68
|
+
service.class.poll_interval = 0
|
69
|
+
|
70
|
+
elapsed = 0
|
71
|
+
|
72
|
+
timeout(2) do
|
73
|
+
lambda do
|
74
|
+
model.wait_for!(0.1) { sleep(0.2); elapsed += 0.2; elapsed > 0.2 }
|
75
|
+
end.should raise_exception(WaitForService::Timeout)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: cistern
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.3.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Josh Lane
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-29 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: API client framework extracted from Fog
|
15
15
|
email:
|
@@ -37,12 +37,14 @@ files:
|
|
37
37
|
- lib/cistern/mock.rb
|
38
38
|
- lib/cistern/model.rb
|
39
39
|
- lib/cistern/service.rb
|
40
|
+
- lib/cistern/timeout.rb
|
40
41
|
- lib/cistern/version.rb
|
41
42
|
- lib/cistern/wait_for.rb
|
42
43
|
- spec/cistern_spec.rb
|
43
44
|
- spec/collection_spec.rb
|
44
45
|
- spec/model_spec.rb
|
45
46
|
- spec/spec_helper.rb
|
47
|
+
- spec/wait_for_spec.rb
|
46
48
|
homepage: http://joshualane.com/cistern
|
47
49
|
licenses: []
|
48
50
|
post_install_message:
|
@@ -72,4 +74,5 @@ test_files:
|
|
72
74
|
- spec/collection_spec.rb
|
73
75
|
- spec/model_spec.rb
|
74
76
|
- spec/spec_helper.rb
|
77
|
+
- spec/wait_for_spec.rb
|
75
78
|
has_rdoc:
|