manana 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -1
- data/Gemfile +20 -4
- data/LICENSE.txt +1 -1
- data/README.md +37 -7
- data/Rakefile +7 -0
- data/lib/manana/version.rb +1 -1
- data/lib/manana.rb +35 -5
- data/manana.gemspec +3 -3
- data/samples/common/samples.gemfile +10 -0
- data/samples/common/samples.gemfile.lock +42 -0
- data/samples/common/samples_helper.rb +7 -0
- data/samples/exponential_backoff.rb +65 -0
- data/samples/fast_startup.rb +83 -0
- data/samples/self_healing.rb +104 -0
- data/test/test_manana.rb +17 -5
- metadata +15 -8
data/.yardopts
CHANGED
data/Gemfile
CHANGED
@@ -5,10 +5,26 @@ gemspec
|
|
5
5
|
|
6
6
|
# these aren't strictly needed for development but are nice to have
|
7
7
|
unless ENV["TRAVIS"] == "1"
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem 'yard'
|
11
|
+
gem 'redcarpet'
|
12
|
+
|
13
|
+
gem 'pry'
|
14
|
+
gem 'pry-debugger'
|
15
|
+
gem 'pry-rescue'
|
16
|
+
gem 'pry-stack_explorer'
|
17
|
+
end
|
18
|
+
|
19
|
+
group :samples do
|
20
|
+
gem 'savon', '~> 2.3'
|
21
|
+
gem 'webmock'
|
22
|
+
end
|
23
|
+
|
24
|
+
group :test do
|
25
|
+
gem 'simplecov'
|
26
|
+
end
|
27
|
+
|
12
28
|
end
|
13
29
|
|
14
30
|
# for travis.cl
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,42 @@
|
|
1
1
|
# Manana
|
2
2
|
|
3
|
-
*Manana* lets you defer the initialization of
|
3
|
+
*Manana* lets you defer the initialization of an object until its methods are called.
|
4
4
|
|
5
|
-
This can be useful in cases where
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
This can be useful in cases where initialization may take a long time or fail due to errors. For example, in rails, if
|
6
|
+
the database specified in `database.yml` doesn't exist at start time, the rails application will fail initialization. Likewise
|
7
|
+
if you tie configuration of SOAP services (e.g. using [Savon](http://savonrb.com/version2/)) to your application initialization,
|
8
|
+
and the service wsdl isn't up, your application will fail to start.
|
9
|
+
|
10
|
+
Instead, it is an established best practice in service-oriented architectures to make your application or service *startup order independent*:
|
11
|
+
i.e. your app starts fast and initializes other dependencies afterwards, providing fault detection and *self-healing* properties for the app.
|
12
|
+
|
13
|
+
*Manana* is a simple approach that allows you to keep your configuration and initialization code in the same place, while deferring it to method calls.
|
14
|
+
|
15
|
+
### Pros
|
16
|
+
|
17
|
+
* Reduces the startup time for your app. (i.e. moves the startup cost from initialization to first use)
|
18
|
+
|
19
|
+
* Once initialization is succesful, it stores the object instance for reuse.
|
20
|
+
|
21
|
+
* Until the initialization is successful, it will retry every time a method is called.
|
22
|
+
|
23
|
+
* You can layer more complex retry semantics such as [exponential backoff](http://en.wikipedia.org/wiki/Exponential_backoff) using this wrapper. See [samples/exponential_backoff.rb](https://github.com/coldnebo/manana/blob/master/samples/exponential_backoff.rb)
|
24
|
+
|
25
|
+
### Cons
|
26
|
+
|
27
|
+
* If your initialization takes a very long time, (i.e. a cache) you may want to pre-warm it instead of taking the hit on the first use of the object.
|
28
|
+
|
29
|
+
* Very simple approach. You may want more complex retry semantics, or pooling.
|
30
|
+
|
31
|
+
### Similar ideas:
|
32
|
+
|
33
|
+
* [Connection pool](http://en.wikipedia.org/wiki/Connection_pool) of one?
|
34
|
+
|
35
|
+
* [Avoid Start Order Dependencies](http://wiki.osgi.org/wiki/Avoid_Start_Order_Dependencies)
|
36
|
+
|
37
|
+
* [Data Centers need shutdown/startup order](http://www.boche.net/blog/index.php/2009/01/01/datacenters-need-shutdownstartup-order/)
|
38
|
+
|
39
|
+
* 'self-healing' initialization faults from the practice of [Autonomic computing](http://en.wikipedia.org/wiki/Autonomic_computing)
|
10
40
|
|
11
41
|
## Installation
|
12
42
|
|
@@ -24,7 +54,7 @@ Or install it yourself as:
|
|
24
54
|
|
25
55
|
## Usage
|
26
56
|
|
27
|
-
|
57
|
+
See the [samples](https://github.com/coldnebo/manana/blob/master/samples) for examples of use.
|
28
58
|
|
29
59
|
## Contributing
|
30
60
|
|
data/Rakefile
CHANGED
data/lib/manana/version.rb
CHANGED
data/lib/manana.rb
CHANGED
@@ -1,12 +1,42 @@
|
|
1
1
|
require "manana/version"
|
2
2
|
|
3
|
+
|
4
|
+
# *Manana* lets you defer the initialization of an object until its methods are called.
|
5
|
+
# @example basic usage - see {https://github.com/coldnebo/manana/blob/master/samples/self_healing.rb samples/self_healing.rb}
|
6
|
+
# # initialization...
|
7
|
+
# client = Manana.wrap {
|
8
|
+
# Weather.setup
|
9
|
+
# Weather
|
10
|
+
# }
|
11
|
+
#
|
12
|
+
# runtime_loop {
|
13
|
+
# # wait for next interval
|
14
|
+
# weather = client.city_weather("02201") # deferred initialization happens here once
|
15
|
+
# puts "At %s the temperature is currently %s F and the humidity is %s." % [weather.city, weather.temperature, weather.relative_humidity]
|
16
|
+
# }
|
17
|
+
#
|
3
18
|
class Manana
|
4
|
-
attr_reader :deferred_initialization, :instance
|
5
19
|
|
6
|
-
|
7
|
-
|
20
|
+
# wraps an object initialization block so that it can be deferred to a later time when object methods are called.
|
21
|
+
# @example wrap an object - see {https://github.com/coldnebo/manana/blob/master/samples/self_healing.rb samples/self_healing.rb}
|
22
|
+
# client = Manana.wrap {
|
23
|
+
# Weather.setup # initialize the class
|
24
|
+
# Weather # return the Weather class
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# @param initialization_block [Proc] object initialization. the block must return the object to be wrapped.
|
28
|
+
# @return [Manana] a wrapped version of the object.
|
29
|
+
def self.wrap(&initialization_block)
|
30
|
+
Manana.new(&initialization_block)
|
8
31
|
end
|
9
32
|
|
33
|
+
# passes any method call through to the wrapped object after ensuring that the initialization block has
|
34
|
+
# successfully completed once (setting a valid instance of the object).
|
35
|
+
# @note Once the initialization block succeeds, it keeps the resulting object instance for subsequent method calls.
|
36
|
+
#
|
37
|
+
# @example calling a wrapped object - see {https://github.com/coldnebo/manana/blob/master/samples/self_healing.rb samples/self_healing.rb}
|
38
|
+
# weather = client.city_weather("02201")
|
39
|
+
#
|
10
40
|
def method_missing(method, *args, &block)
|
11
41
|
instance = get_instance
|
12
42
|
instance.send(method, *args, &block);
|
@@ -14,8 +44,8 @@ class Manana
|
|
14
44
|
|
15
45
|
private
|
16
46
|
|
17
|
-
def initialize(&
|
18
|
-
@deferred_initialization =
|
47
|
+
def initialize(&initialization_block)
|
48
|
+
@deferred_initialization = initialization_block
|
19
49
|
end
|
20
50
|
|
21
51
|
def get_instance
|
data/manana.gemspec
CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Manana::VERSION
|
9
9
|
spec.authors = ["coldnebo"]
|
10
10
|
spec.email = ["larry.kyrala@gmail.com"]
|
11
|
-
spec.description = %q{provides a simple way to defer initialization of an object
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.homepage = ""
|
11
|
+
spec.description = %q{provides a simple way to defer initialization of an object until its methods are called}
|
12
|
+
spec.summary = %q{provides a simple way to defer initialization of an object until its methods are called}
|
13
|
+
spec.homepage = "https://github.com/coldnebo/manana"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
@@ -0,0 +1,42 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.3.5)
|
5
|
+
akami (1.2.0)
|
6
|
+
gyoku (>= 0.4.0)
|
7
|
+
nokogiri (>= 1.4.0)
|
8
|
+
builder (3.2.2)
|
9
|
+
crack (0.4.1)
|
10
|
+
safe_yaml (~> 0.9.0)
|
11
|
+
gyoku (1.1.0)
|
12
|
+
builder (>= 2.1.2)
|
13
|
+
httpi (2.1.0)
|
14
|
+
rack
|
15
|
+
rubyntlm (~> 0.3.2)
|
16
|
+
nokogiri (1.5.10)
|
17
|
+
nori (2.3.0)
|
18
|
+
rack (1.5.2)
|
19
|
+
rubyntlm (0.3.4)
|
20
|
+
safe_yaml (0.9.7)
|
21
|
+
savon (2.3.0)
|
22
|
+
akami (~> 1.2.0)
|
23
|
+
builder (>= 2.1.2)
|
24
|
+
gyoku (~> 1.1.0)
|
25
|
+
httpi (~> 2.1.0)
|
26
|
+
nokogiri (>= 1.4.0, < 1.6)
|
27
|
+
nori (~> 2.3.0)
|
28
|
+
wasabi (~> 3.2.0)
|
29
|
+
wasabi (3.2.0)
|
30
|
+
httpi (~> 2.0)
|
31
|
+
nokogiri (>= 1.4.0, < 1.6)
|
32
|
+
webmock (1.15.2)
|
33
|
+
addressable (>= 2.2.7)
|
34
|
+
crack (>= 0.3.2)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
rack
|
41
|
+
savon (~> 2.3)
|
42
|
+
webmock
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# sample helper takes care of loading the gem from source without requiring it to be rebuilt and installed.
|
2
|
+
# this is useful in allowing the samples in this directory to evolve the behavior of the actual gem.
|
3
|
+
|
4
|
+
lp = File.expand_path(File.join(*%w[.. .. lib]), File.dirname(__FILE__))
|
5
|
+
unless $LOAD_PATH.include?(lp)
|
6
|
+
$LOAD_PATH.unshift(lp)
|
7
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# This sample demonstrates how exponential backoff can be layered on top of Manana
|
2
|
+
#
|
3
|
+
# run from the gem dir with:
|
4
|
+
# $ rake samples
|
5
|
+
# $ ruby samples/exponential_backoff.rb
|
6
|
+
|
7
|
+
require_relative 'common/samples_helper.rb'
|
8
|
+
|
9
|
+
# ------------------------- sample code starts here -------------------------
|
10
|
+
|
11
|
+
require 'manana'
|
12
|
+
require 'benchmark'
|
13
|
+
|
14
|
+
|
15
|
+
class PoorService
|
16
|
+
@@instance = 0
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@@instance += 1
|
20
|
+
if @@instance <= 3
|
21
|
+
raise "failed to init"
|
22
|
+
end
|
23
|
+
puts "successfully inited service."
|
24
|
+
end
|
25
|
+
|
26
|
+
def process
|
27
|
+
puts "successfully called service!"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# ------------ initialization code
|
33
|
+
|
34
|
+
client = Manana.wrap {
|
35
|
+
# exponential backkoff logic in the initialization block
|
36
|
+
retries = 0
|
37
|
+
obj = nil
|
38
|
+
|
39
|
+
puts "trying to create service object..."
|
40
|
+
begin
|
41
|
+
obj = PoorService.new
|
42
|
+
rescue RuntimeError => e
|
43
|
+
puts "couldn't create object, sleeping for #{2**retries} seconds before next try..."
|
44
|
+
sleep(2**retries)
|
45
|
+
retries += 1
|
46
|
+
|
47
|
+
if retries <= 3
|
48
|
+
retry
|
49
|
+
else
|
50
|
+
puts "giving up."
|
51
|
+
raise e
|
52
|
+
end
|
53
|
+
end
|
54
|
+
obj
|
55
|
+
}
|
56
|
+
|
57
|
+
|
58
|
+
# ------------ runtime code
|
59
|
+
|
60
|
+
client.process
|
61
|
+
client.process
|
62
|
+
client.process
|
63
|
+
client.process
|
64
|
+
|
65
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# This sample demonstrates how Manana may be used to defer a long initialization
|
2
|
+
# to the first method call.
|
3
|
+
#
|
4
|
+
# run from the gem dir with:
|
5
|
+
# $ rake samples
|
6
|
+
# $ ruby samples/fast_startup.rb
|
7
|
+
|
8
|
+
require_relative 'common/samples_helper.rb'
|
9
|
+
|
10
|
+
# ------------------------- sample code starts here -------------------------
|
11
|
+
|
12
|
+
require 'manana'
|
13
|
+
require 'benchmark'
|
14
|
+
|
15
|
+
|
16
|
+
class DeathStar
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
puts " DeathStar initialization sequence commencing..."
|
20
|
+
super_complex_startup_sequence
|
21
|
+
puts " ...sequence complete."
|
22
|
+
end
|
23
|
+
|
24
|
+
def navigate_to(planet)
|
25
|
+
puts "setting course for the planet '#{planet}'"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def super_complex_startup_sequence
|
31
|
+
puts " 1. press the 'start' button."
|
32
|
+
puts " 2. snooze while Vader isn't looking."
|
33
|
+
sleep(5)
|
34
|
+
puts " 3. ???"
|
35
|
+
puts " 4. profit!"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# ------------ initialization code
|
41
|
+
|
42
|
+
mini_death_star = nil
|
43
|
+
|
44
|
+
puts "[Vader]: requsition a new DeathStar and make it snappy!"
|
45
|
+
# boss said requisitions have to be faster*! Manana to the rescue!
|
46
|
+
puts Benchmark.measure {
|
47
|
+
mini_death_star = Manana.wrap {
|
48
|
+
DeathStar.new
|
49
|
+
}
|
50
|
+
}
|
51
|
+
puts "[Expendable Commander]: completed, sir!"
|
52
|
+
|
53
|
+
|
54
|
+
puts "-------------------------------------------"
|
55
|
+
|
56
|
+
|
57
|
+
# ------------ runtime code
|
58
|
+
|
59
|
+
puts "[Vader]: ok, send it towards some rebels..."
|
60
|
+
|
61
|
+
# * this first method eats the hidden startup cost...
|
62
|
+
puts Benchmark.measure {
|
63
|
+
mini_death_star.navigate_to("Yavin")
|
64
|
+
}
|
65
|
+
puts "[Vader raises an eyebrow and starts to reach towards the commander] \n# first method call was long, but subsequent calls are faster..."
|
66
|
+
|
67
|
+
# * subsequent method calls are fast though... maybe tradeoff is good enough for Vader?
|
68
|
+
puts Benchmark.measure {
|
69
|
+
mini_death_star.navigate_to("Bespin")
|
70
|
+
}
|
71
|
+
|
72
|
+
puts Benchmark.measure {
|
73
|
+
mini_death_star.navigate_to("Tatooine")
|
74
|
+
}
|
75
|
+
|
76
|
+
puts "[Vader shrugs]: Well done Expendable Commander!"
|
77
|
+
puts "[Expendable Commander sweatly profusely]: Thank you Lord Vader!"
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# This sample demonstrates how Manana may be used to create a self-healing soap adapter
|
2
|
+
# by wrapping an existing Savon::Model client.
|
3
|
+
#
|
4
|
+
# run from the gem dir with:
|
5
|
+
# $ rake samples
|
6
|
+
# $ ruby samples/self_healing.rb
|
7
|
+
|
8
|
+
require_relative 'common/samples_helper.rb'
|
9
|
+
|
10
|
+
# ------------------------- sample code starts here -------------------------
|
11
|
+
|
12
|
+
require 'manana'
|
13
|
+
require 'savon'
|
14
|
+
require 'ostruct'
|
15
|
+
|
16
|
+
# used to simulate conn up/down
|
17
|
+
require 'webmock'
|
18
|
+
include WebMock::API
|
19
|
+
# fake a failure to get the wsdl (service down temporarily)
|
20
|
+
stub_request(:any, /wsf.cdyne.com\/.*/).
|
21
|
+
to_return(:status => 500, :body => "Internal Server Error", :headers => {})
|
22
|
+
|
23
|
+
|
24
|
+
LOGGING_ENABLED = false
|
25
|
+
HTTPI.log = false unless LOGGING_ENABLED
|
26
|
+
|
27
|
+
class Weather < OpenStruct
|
28
|
+
extend Savon::Model
|
29
|
+
|
30
|
+
client wsdl: "http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL", convert_request_keys_to: :none, log: LOGGING_ENABLED
|
31
|
+
|
32
|
+
def self.setup
|
33
|
+
# if this were outside of setup() the class would fail to load if the service was down.
|
34
|
+
# instead we dynamically initialize the available operations from withing a class method to be used by the Manana wrapper.
|
35
|
+
operations *client.operations
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.city_weather(zip)
|
39
|
+
resp = get_city_weather_by_zip(message: {"ZIP" => zip})
|
40
|
+
weather = resp.body[:get_city_weather_by_zip_response][:get_city_weather_by_zip_result]
|
41
|
+
Weather.new(weather)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# ------------ initialization code
|
47
|
+
|
48
|
+
# Before we start, we use Manana to wrap the client setup so that method calls on the client can be self-healing in case of failure.
|
49
|
+
# NOTE: that the caller doesn't have to deal with whether or not this initialization succeeded, they can just call the client methods repeatedly.
|
50
|
+
client = Manana.wrap {
|
51
|
+
Weather.setup
|
52
|
+
Weather
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
# ------------ runtime code
|
57
|
+
|
58
|
+
# first call fails...
|
59
|
+
# a) Weather.setup() called, but raises because the server is 500.
|
60
|
+
begin
|
61
|
+
weather = client.city_weather("02201")
|
62
|
+
rescue Wasabi::Resolver::HTTPError => e
|
63
|
+
puts "# 1. first call failed as expected, because Weather.setup() couldn't connect to provide the operations for the client."
|
64
|
+
end
|
65
|
+
|
66
|
+
# server restored
|
67
|
+
WebMock.disable!
|
68
|
+
|
69
|
+
# second call ok...
|
70
|
+
# a) Weather.setup() succeeds, caches instance for future use.
|
71
|
+
# b) city_weather() succeeds.
|
72
|
+
weather = client.city_weather("02201")
|
73
|
+
|
74
|
+
puts "# 2. second call should succeed; Weather.setup() runs successfully and returns a successfully intialized Weather class."
|
75
|
+
puts " > At %s the temperature is currently %s F and the humidity is %s." % [weather.city, weather.temperature, weather.relative_humidity]
|
76
|
+
|
77
|
+
# server down again
|
78
|
+
WebMock.enable!
|
79
|
+
|
80
|
+
# third call; service down again...
|
81
|
+
# remember, we already have a valid instance, so Weather.setup() is not called this time.
|
82
|
+
# a) city_weather() fails because the server is 500.
|
83
|
+
begin
|
84
|
+
weather = client.city_weather("02201")
|
85
|
+
rescue Savon::HTTPError => e
|
86
|
+
puts "# 3. third call fails; the connection is down again, but this time the failure is in the API call since Weather has successfully intialized opertaions from call #2."
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
# server restored
|
91
|
+
WebMock.disable!
|
92
|
+
|
93
|
+
# fourth call ok...
|
94
|
+
# a) city_weather() succeeds.
|
95
|
+
weather = client.city_weather("02201")
|
96
|
+
|
97
|
+
puts "# 4. fourth call should succeed; connection is up again, still using cached operations from the first time service was up (call #2)."
|
98
|
+
puts " > At %s the temperature is currently %s F and the humidity is %s." % [weather.city, weather.temperature, weather.relative_humidity]
|
99
|
+
|
100
|
+
|
101
|
+
puts "\nThis concludes the demonstration of how Manana provides self-healing capability to a web-service adapter."
|
102
|
+
|
103
|
+
|
104
|
+
|
data/test/test_manana.rb
CHANGED
@@ -22,11 +22,7 @@ class TestManana < MiniTest::Unit::TestCase
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def raise_something
|
25
|
-
raise "
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.do_another_thing
|
29
|
-
"I did something else" # simulate a class method call
|
25
|
+
raise "kablooey!" # simulate a call that raises an exception
|
30
26
|
end
|
31
27
|
}
|
32
28
|
end
|
@@ -43,6 +39,14 @@ class TestManana < MiniTest::Unit::TestCase
|
|
43
39
|
assert_raises RuntimeError do
|
44
40
|
obj.raise_something
|
45
41
|
end
|
42
|
+
|
43
|
+
begin
|
44
|
+
obj.raise_something
|
45
|
+
rescue Exception => e
|
46
|
+
# make sure we get an appropriate stack trace at the point of raise.
|
47
|
+
assert_match(/test_manana.rb:25:in .raise_something./, e.backtrace.first)
|
48
|
+
end
|
49
|
+
|
46
50
|
end
|
47
51
|
|
48
52
|
def test_deferred_init
|
@@ -68,6 +72,14 @@ class TestManana < MiniTest::Unit::TestCase
|
|
68
72
|
assert_instance_of(String, result)
|
69
73
|
|
70
74
|
|
75
|
+
begin
|
76
|
+
handle.raise_something
|
77
|
+
rescue Exception => e
|
78
|
+
# make sure we get an appropriate stack trace at the point of raise.
|
79
|
+
assert_match(/test_manana.rb:25:in .raise_something./, e.backtrace.first)
|
80
|
+
end
|
81
|
+
|
82
|
+
|
71
83
|
end
|
72
84
|
|
73
85
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: manana
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-11-
|
12
|
+
date: 2013-11-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -59,8 +59,8 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
-
description: provides a simple way to defer initialization of an object
|
63
|
-
|
62
|
+
description: provides a simple way to defer initialization of an object until its
|
63
|
+
methods are called
|
64
64
|
email:
|
65
65
|
- larry.kyrala@gmail.com
|
66
66
|
executables: []
|
@@ -77,9 +77,15 @@ files:
|
|
77
77
|
- lib/manana.rb
|
78
78
|
- lib/manana/version.rb
|
79
79
|
- manana.gemspec
|
80
|
+
- samples/common/samples.gemfile
|
81
|
+
- samples/common/samples.gemfile.lock
|
82
|
+
- samples/common/samples_helper.rb
|
83
|
+
- samples/exponential_backoff.rb
|
84
|
+
- samples/fast_startup.rb
|
85
|
+
- samples/self_healing.rb
|
80
86
|
- test/minitest_helper.rb
|
81
87
|
- test/test_manana.rb
|
82
|
-
homepage:
|
88
|
+
homepage: https://github.com/coldnebo/manana
|
83
89
|
licenses:
|
84
90
|
- MIT
|
85
91
|
post_install_message:
|
@@ -94,7 +100,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
100
|
version: '0'
|
95
101
|
segments:
|
96
102
|
- 0
|
97
|
-
hash: -
|
103
|
+
hash: -1234298163661349463
|
98
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
105
|
none: false
|
100
106
|
requirements:
|
@@ -103,13 +109,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
109
|
version: '0'
|
104
110
|
segments:
|
105
111
|
- 0
|
106
|
-
hash: -
|
112
|
+
hash: -1234298163661349463
|
107
113
|
requirements: []
|
108
114
|
rubyforge_project:
|
109
115
|
rubygems_version: 1.8.25
|
110
116
|
signing_key:
|
111
117
|
specification_version: 3
|
112
|
-
summary:
|
118
|
+
summary: provides a simple way to defer initialization of an object until its methods
|
119
|
+
are called
|
113
120
|
test_files:
|
114
121
|
- test/minitest_helper.rb
|
115
122
|
- test/test_manana.rb
|