manana 0.0.2 → 0.1.0

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