manana 0.0.2 → 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 CHANGED
File without changes
data/.travis.yml CHANGED
File without changes
data/.yardopts CHANGED
File without changes
data/Gemfile CHANGED
File without changes
data/LICENSE.txt CHANGED
File without changes
data/README.md CHANGED
@@ -54,7 +54,24 @@ Or install it yourself as:
54
54
 
55
55
  ## Usage
56
56
 
57
- See the [samples](https://github.com/coldnebo/manana/blob/master/samples) for examples of use.
57
+ ```ruby
58
+ require 'manana'
59
+
60
+ # initialization...
61
+ client = Manana.deferred_init {
62
+ Weather.setup # web service adapter setup
63
+ Weather # return the class instance
64
+ }
65
+
66
+ runtime_loop {
67
+ # wait for next interval
68
+ weather = client.city_weather("02201") # deferred initialization happens here once
69
+ puts "At %s the temperature is currently %s F and the humidity is %s." % [weather.city, weather.temperature, weather.relative_humidity]
70
+ }
71
+ ```
72
+
73
+
74
+ See the [samples](https://github.com/coldnebo/manana/blob/master/samples) for more detailed examples of use.
58
75
 
59
76
  ## Contributing
60
77
 
data/Rakefile CHANGED
File without changes
@@ -1,3 +1,3 @@
1
1
  class Manana
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/manana.rb CHANGED
@@ -4,7 +4,7 @@ require "manana/version"
4
4
  # *Manana* lets you defer the initialization of an object until its methods are called.
5
5
  # @example basic usage - see {https://github.com/coldnebo/manana/blob/master/samples/self_healing.rb samples/self_healing.rb}
6
6
  # # initialization...
7
- # client = Manana.wrap {
7
+ # client = Manana.deferred_init {
8
8
  # Weather.setup
9
9
  # Weather
10
10
  # }
@@ -16,17 +16,17 @@ require "manana/version"
16
16
  # }
17
17
  #
18
18
  class Manana
19
-
20
- # wraps an object initialization block so that it can be deferred to a later time when object methods are called.
19
+
20
+ # wraps an initialization block so that it can be deferred to a later time when object methods are called.
21
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 {
22
+ # client = Manana.deferred_init {
23
23
  # Weather.setup # initialize the class
24
24
  # Weather # return the Weather class
25
25
  # }
26
26
  #
27
27
  # @param initialization_block [Proc] object initialization. the block must return the object to be wrapped.
28
28
  # @return [Manana] a wrapped version of the object.
29
- def self.wrap(&initialization_block)
29
+ def self.deferred_init(&initialization_block)
30
30
  Manana.new(&initialization_block)
31
31
  end
32
32
 
@@ -38,16 +38,23 @@ class Manana
38
38
  # weather = client.city_weather("02201")
39
39
  #
40
40
  def method_missing(method, *args, &block)
41
- instance = get_instance
41
+ instance = safe_get_instance
42
42
  instance.send(method, *args, &block);
43
43
  end
44
44
 
45
45
  private
46
46
 
47
47
  def initialize(&initialization_block)
48
+ @mutex = Mutex.new
48
49
  @deferred_initialization = initialization_block
49
50
  end
50
51
 
52
+ def safe_get_instance
53
+ @mutex.synchronize do
54
+ get_instance
55
+ end
56
+ end
57
+
51
58
  def get_instance
52
59
  if @instance.nil?
53
60
  @instance = @deferred_initialization.call
@@ -55,5 +62,4 @@ class Manana
55
62
  @instance
56
63
  end
57
64
 
58
-
59
65
  end
data/manana.gemspec CHANGED
File without changes
File without changes
File without changes
File without changes
@@ -31,7 +31,7 @@ end
31
31
 
32
32
  # ------------ initialization code
33
33
 
34
- client = Manana.wrap {
34
+ client = Manana.deferred_init {
35
35
  # exponential backkoff logic in the initialization block
36
36
  retries = 0
37
37
  obj = nil
@@ -44,7 +44,7 @@ mini_death_star = nil
44
44
  puts "[Vader]: requsition a new DeathStar and make it snappy!"
45
45
  # boss said requisitions have to be faster*! Manana to the rescue!
46
46
  puts Benchmark.measure {
47
- mini_death_star = Manana.wrap {
47
+ mini_death_star = Manana.deferred_init {
48
48
  DeathStar.new
49
49
  }
50
50
  }
@@ -47,7 +47,7 @@ end
47
47
 
48
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
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 {
50
+ client = Manana.deferred_init {
51
51
  Weather.setup
52
52
  Weather
53
53
  }
data/test/klass.rb ADDED
@@ -0,0 +1,32 @@
1
+ class Klass
2
+ INITIALIZE_MESSAGE = "initialized!"
3
+ DO_SOMETHING_MESSAGE = "I did something!"
4
+ RAISE_MESSAGE = "kablooey!"
5
+
6
+ def self.incr
7
+ @count ||= 0
8
+ @count += 1
9
+ @count
10
+ end
11
+
12
+ def self.count
13
+ @count ||= 0
14
+ @count
15
+ end
16
+
17
+ def self.reset
18
+ @count = 0
19
+ end
20
+
21
+ def initialize
22
+ puts INITIALIZE_MESSAGE
23
+ end
24
+
25
+ def do_something
26
+ DO_SOMETHING_MESSAGE
27
+ end
28
+
29
+ def raise_something
30
+ raise RAISE_MESSAGE
31
+ end
32
+ end
@@ -1,7 +1,9 @@
1
1
  unless ENV["TRAVIS"] == "1"
2
2
  require 'simplecov'
3
3
  require 'pry'
4
- SimpleCov.start
4
+ SimpleCov.start do
5
+ add_filter "/test/"
6
+ end
5
7
  end
6
8
 
7
9
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
data/test/test_manana.rb CHANGED
@@ -1,41 +1,26 @@
1
1
  require 'minitest_helper'
2
+ require 'klass'
2
3
 
3
- class TestManana < MiniTest::Unit::TestCase
4
+ class TestManana < Minitest::Test
4
5
  def test_that_it_has_a_version_number
5
6
  refute_nil ::Manana::VERSION
6
7
  end
7
8
 
8
- # initialize a very generic example object that does some stuff in initialization and has some instance methods you can call.
9
+ # initialize a very generic example object that does some stuff in initialization
10
+ # and has some instance methods you can call.
9
11
  def setup
10
- @klass = Class.new
11
- @klass.class_eval {
12
- def initialize
13
- puts "class initialized!"
14
- end
15
-
16
- def do_something
17
- "I did something!" # simulate an arbitrary method
18
- end
19
-
20
- def add_something(x,y)
21
- x+y # simulate a method with params
22
- end
23
-
24
- def raise_something
25
- raise "kablooey!" # simulate a call that raises an exception
26
- end
27
- }
28
12
  end
29
13
 
30
14
  # sanity check
31
15
  def test_that_things_work_without_manana
32
16
  obj = nil
17
+
33
18
  out, err = capture_io do
34
- obj = @klass.new
19
+ obj = Klass.new
35
20
  end
36
- assert_match(%r%class initialized!%, out)
21
+ assert_match(/#{Klass::INITIALIZE_MESSAGE}/, out)
37
22
  assert_instance_of(String, obj.do_something)
38
- assert_equal(5, obj.add_something(2,3))
23
+ assert_match(/#{Klass::DO_SOMETHING_MESSAGE}/, obj.do_something)
39
24
  assert_raises RuntimeError do
40
25
  obj.raise_something
41
26
  end
@@ -44,42 +29,60 @@ class TestManana < MiniTest::Unit::TestCase
44
29
  obj.raise_something
45
30
  rescue Exception => e
46
31
  # 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)
32
+ assert_match(/.*klass.rb:\d+:in .raise_something./, e.backtrace.first)
48
33
  end
49
-
50
34
  end
51
35
 
52
36
  def test_deferred_init
53
- handle = nil
37
+ obj = nil
54
38
  out, err = capture_io do
55
- # the idea here is that we use the 'Strategy' pattern to store the method of initialization.
56
- # in this case, it's really simple, but in a network service, it might be a config + some class method calls
57
- # to fully setup a service instance.
58
- handle = Manana.wrap {
59
- obj = @klass.new
39
+ obj = Manana.deferred_init {
40
+ Klass.new
60
41
  }
61
42
  end
62
43
  # make sure the init isn't executed until we call...
63
- refute_match(%r%class initialized!%, out)
64
-
44
+ refute_match(/#{Klass::INITIALIZE_MESSAGE}/, out)
45
+
46
+ # now call a method on the object...
65
47
  result = nil
66
48
  out, err = capture_io do
67
- result = handle.do_something
49
+ result = obj.do_something
68
50
  end
69
- # now it should have been inited
70
- assert_match(%r%class initialized!%, out)
71
- # and the method we called used
51
+ # and make sure the init was called
52
+ assert_match(/#{Klass::INITIALIZE_MESSAGE}/, out)
53
+ # and that we got the desired result
72
54
  assert_instance_of(String, result)
73
-
55
+ assert_match(/#{Klass::DO_SOMETHING_MESSAGE}/, result)
56
+ assert_raises RuntimeError do
57
+ obj.raise_something
58
+ end
74
59
 
75
60
  begin
76
- handle.raise_something
61
+ obj.raise_something
77
62
  rescue Exception => e
78
63
  # 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)
64
+ assert_match(/.*klass.rb:\d+:in .raise_something./, e.backtrace.first)
80
65
  end
66
+ end
67
+
68
+ # https://github.com/coldnebo/manana/issues/1
69
+ def test_that_init_is_threadsafe
70
+ Klass.reset
71
+
72
+ klass = Manana.deferred_init {
73
+ sleep(1)
74
+ Klass.incr
75
+ Klass
76
+ }
81
77
 
78
+ t1 = Thread.new{klass.count}
79
+ t2 = Thread.new{klass.count}
80
+ t3 = Thread.new{klass.count}
81
+ t1.join
82
+ t2.join
83
+ t3.join
82
84
 
85
+ assert_equal(1,klass.count)
83
86
  end
84
87
 
85
88
 
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.2
4
+ version: 0.1.0
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-15 00:00:00.000000000 Z
12
+ date: 2013-12-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -83,6 +83,7 @@ files:
83
83
  - samples/exponential_backoff.rb
84
84
  - samples/fast_startup.rb
85
85
  - samples/self_healing.rb
86
+ - test/klass.rb
86
87
  - test/minitest_helper.rb
87
88
  - test/test_manana.rb
88
89
  homepage: https://github.com/coldnebo/manana
@@ -100,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
100
101
  version: '0'
101
102
  segments:
102
103
  - 0
103
- hash: -1234298163661349463
104
+ hash: -3306959934859244204
104
105
  required_rubygems_version: !ruby/object:Gem::Requirement
105
106
  none: false
106
107
  requirements:
@@ -109,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
110
  version: '0'
110
111
  segments:
111
112
  - 0
112
- hash: -1234298163661349463
113
+ hash: -3306959934859244204
113
114
  requirements: []
114
115
  rubyforge_project:
115
116
  rubygems_version: 1.8.25
@@ -118,6 +119,7 @@ specification_version: 3
118
119
  summary: provides a simple way to defer initialization of an object until its methods
119
120
  are called
120
121
  test_files:
122
+ - test/klass.rb
121
123
  - test/minitest_helper.rb
122
124
  - test/test_manana.rb
123
125
  has_rdoc: