actor 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 692bbec40fb07dccc05300db738a52d61779194d
4
+ data.tar.gz: fd21f5720cca18985abda493c3bdc55886b4ec71
5
+ SHA512:
6
+ metadata.gz: 27afa42688e8e9608dac5ecbffda7a677ef46d94ab192f5dbe8f9b10c88ab1f2a2ca5d0be40844e22fe603ecffa8806459602a8ad556053f5c8ec6282de07b59
7
+ data.tar.gz: 975d6e1f537467f2cd21c2efe9397c9dd0519337ed236b163ad6da55a6cf59a654b366bd4b4b59b4a08e0bfd28e4429a197fadff45c5a39572506f21ed681cf6
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+ /html/
23
+
24
+ ## Environment normalisation:
25
+ /.bundle/
26
+ /lib/bundler/man/
27
+
28
+ Gemfile.lock
29
+ .ruby-version
30
+ .ruby-gemset
31
+
32
+ .rvmrc
33
+
34
+ .idea/
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ cache: bundler
3
+
4
+ gemfile:
5
+ - gemfiles/Gemfile.travis
6
+ rvm:
7
+ - 2.0.0
8
+ - 1.9.3
9
+ - jruby-19mode
10
+ - rbx-2
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in actor.gemspec
4
+ gemspec path: File.expand_path('../', __FILE__)
5
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Max
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.
@@ -0,0 +1,114 @@
1
+ # Actor
2
+
3
+ [![Build Status](https://travis-ci.org/maxgale/actor.svg?branch=master)](https://travis-ci.org/maxgale/actor)
4
+
5
+ The actor gem provides a completely implicit implementation of the actor pattern. The goal of the library is to provide
6
+ an easy way to implement fast, concurrent code without having to worry about race conditions or unexpected side-effects.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'actor'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install actor
21
+
22
+ ## Usage
23
+
24
+ ### Actors
25
+
26
+ require 'actor/base'
27
+
28
+ class MyActor
29
+ include Actor::Base
30
+
31
+ def example_method
32
+ 'hi'
33
+ end
34
+ end
35
+
36
+ my_actor = MyActor.new
37
+
38
+ That's it! Now any interations with `my_actor` will be executed concurrently. It's also worth noting that there are no
39
+ return values. Instead, code is executed via message passing. Instead, there are callbacks.
40
+
41
+ ### Callbacks
42
+
43
+ my_actor.before_action :example_method do
44
+ # Code here is executed before :example_method is executed by the actor
45
+ puts 'before'
46
+ end
47
+
48
+ my_actor.after_action :example_method do |result|
49
+ # Code here is executed after :example_method is executed by the actor
50
+ puts 'after'
51
+ puts result
52
+ end
53
+
54
+ my_actor.example_method
55
+
56
+ => before
57
+ => after
58
+ => hi
59
+
60
+ ### Timers
61
+
62
+ Another useful feature is the timer. The timer is an object that periodically executes a block of code.
63
+
64
+ require 'actor/timer'
65
+
66
+ # Create a timer the executes every 1/30th of a second. Only executes twice.
67
+ Actor::Timer.new 0.033, 2 do
68
+ puts 'hi'
69
+ end
70
+
71
+ => hi
72
+ => hi
73
+
74
+ Passing in `0` as the number of iterations to the timer causes it to execute indefinitely. You can also pause, resume,
75
+ and wait for timers to finish execution.
76
+
77
+ my_timer = Timer.new 0.033, 0 do
78
+ # Do periodic work
79
+ end
80
+
81
+ my_timer.pause # Temporarily stop work
82
+
83
+ my_timer.resume # Resume the work
84
+
85
+ my_timer.wait # Since `iterations = 0`, this will block forever
86
+
87
+ ## Gotchas
88
+
89
+ Unfortunately, there are a few "gotchas" when using this gem.
90
+
91
+ 1. `Actor::Base` overrides the including class's `:new` method and renames it to `:__actor_new`. This sets up the
92
+ possibility of naming conflicts.
93
+ 1. `Actor::Base` overrides `:send`, making it impossible to use `:send` without concurrent execution and callbacks.
94
+ 1. All actors are wrapped in a proxy class. This proxy forwards all methods to the
95
+ instance to be executed in a concurrent way. This means it is impossible to execute code normally when handling the
96
+ proxy. You can access the underlying instance by calling `:__proxy_target` on the proxy. Note: No callbacks are not
97
+ triggered when accessing the instance directly (unless you use send).
98
+ 1. The timer period is counted from the end of the last block to the start of the next block. This means that the timer
99
+ firing is very approximate and definitely not designed for blocking code.
100
+
101
+ ## Todo
102
+
103
+ 1. Using a thread pool would be nice.
104
+ 2. Benchmarks comparing MRI 2.1.2 vs. Rubinisu 2.2.6.
105
+ 3. Benchmarks comparing of this gem vs. Celluloid
106
+ 5. Add a way of using actors over a network via RPC
107
+
108
+ ## Contributing
109
+
110
+ 1. Fork it ( https://github.com/maxgale/actor/fork )
111
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
112
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
113
+ 4. Push to the branch (`git push origin my-new-feature`)
114
+ 5. Create a new Pull Request
@@ -0,0 +1,14 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rdoc/task'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new :spec do |task|
6
+ task.rspec_opts = %w(--color --format nested)
7
+ end
8
+
9
+ RDoc::Task.new :rdoc do |rdoc|
10
+ rdoc.rdoc_files.include "lib/**/*.rb"
11
+ rdoc.options << "--all"
12
+ end
13
+
14
+ task default: [:spec, :rdoc]
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'actor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "actor"
8
+ spec.version = Actor::VERSION
9
+ spec.authors = ["Max Gale"]
10
+ spec.email = ["maxgale4@gmail.com"]
11
+ spec.summary = %q{A simple implementation of the actor pattern}
12
+ spec.homepage = "https://github.com/maxgale/actor"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_development_dependency "rake", "~> 10.3"
22
+ spec.add_development_dependency "rspec", "~> 2.14"
23
+ spec.add_development_dependency "rdoc", "~> 4.1"
24
+ end
@@ -0,0 +1,5 @@
1
+ platforms :rbx do
2
+ gem 'rubysl', '~> 2.0'
3
+ end
4
+
5
+ eval_gemfile File.expand_path('../../Gemfile', __FILE__)
@@ -0,0 +1,11 @@
1
+ require 'actor/base'
2
+ require 'actor/proxy'
3
+ require 'actor/timer'
4
+ require 'actor/version'
5
+
6
+ ##
7
+ # Module containing actor functionality. See Actor::Base, Actor::Proxy, and
8
+ # Actor::Timer for specific functionality.
9
+ module Actor
10
+
11
+ end
@@ -0,0 +1,89 @@
1
+ require 'set'
2
+ require 'actor/proxy'
3
+
4
+ module Actor
5
+ ##
6
+ # Module that actors should include
7
+ module Base
8
+ ##
9
+ # Adds a new message to the queue. Args and block are optional
10
+ #
11
+ # * *Args*:
12
+ # - +method_name+: symbol representation of the action (method) to preform
13
+ # - +args+: the arguments to pass to the action when it is executed
14
+ # - +block+: the block to pass to the action when it is executed
15
+ def send method_name, *args, &block
16
+ @mailbox << [method_name, args, block]
17
+ end
18
+
19
+ ##
20
+ # Adds a listener that is called before the including object performs
21
+ # the specified action.
22
+ #
23
+ # * *Args*:
24
+ # - +action+: the action (symbol) the hook into
25
+ # - +block+: the block to execute before the specified action
26
+ def before_action action, &block
27
+ @audience[:before][action] ||= Set.new
28
+ @audience[:before][action] << block
29
+ end
30
+
31
+ ##
32
+ # Adds a listener that is called after the including object performs
33
+ # the specified action.
34
+ #
35
+ # * *Args*:
36
+ # - +action+: the action the hook into
37
+ # - +block+: the block to execute after the specified action
38
+ # * *Yields*: the value returned by the action
39
+ def after_action action, &block
40
+ @audience[:after][action] ||= Set.new
41
+ @audience[:after][action] << block
42
+ end
43
+
44
+ ##
45
+ # Adds a hook before object initialization to automatically sets up the
46
+ # thread that executes actions and sets up the callback data structures.
47
+ #
48
+ # * *Args*:
49
+ # - +klass+: the class whose initialization is hooked into.
50
+ def self.included klass
51
+ class << klass
52
+ alias_method :__actor_new, :new
53
+
54
+ ##
55
+ # Hooks into the initialization of the object to initialize the
56
+ # mailbox. Also starts the thread executing async method calls
57
+ def new *args
58
+ instance = __actor_new *args
59
+ instance.instance_variable_set :@audience, {}
60
+ instance.instance_variable_set :@mailbox, Queue.new
61
+
62
+ audience = {}
63
+ audience[:before] = {}
64
+ audience[:after] = {}
65
+ instance.instance_variable_set :@audience, audience
66
+
67
+ Thread.new do
68
+ loop do
69
+ mailbox = instance.instance_variable_get :@mailbox
70
+ method_name, args, block = mailbox.pop
71
+
72
+ if audience[:before][method_name]
73
+ audience[:before][method_name].each { |callback| callback.call }
74
+ end
75
+
76
+ result = instance.method(method_name).call *args, &block
77
+
78
+ if audience[:after][method_name]
79
+ audience[:after][method_name].each { |callback| callback.yield result }
80
+ end
81
+ end
82
+ end
83
+
84
+ Proxy.new instance
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,46 @@
1
+ module Actor
2
+ ##
3
+ # The proxy class wraps an object and invokes all of its method using :send
4
+ class Proxy < BasicObject
5
+ ##
6
+ # Create a new proxy
7
+ #
8
+ # * *Args*:
9
+ # - +proxy_target+: the instance to proxy
10
+ def initialize proxy_target
11
+ @proxy_target = proxy_target
12
+ end
13
+
14
+ ##
15
+ # Proxies the method call to the proxy target using :send
16
+ def method_missing name, *args, &block
17
+ @proxy_target.send name, *args, &block
18
+ end
19
+
20
+ ##
21
+ # Get the proxy target of this proxy
22
+ #
23
+ # * *Returns*: the proxy target
24
+ def __proxy_target
25
+ @proxy_target
26
+ end
27
+
28
+ ##
29
+ # Overrides the proxy equals to pass the equality check to the proxy target
30
+ def == other
31
+ @proxy_target == other
32
+ end
33
+
34
+ ##
35
+ # Overrides the proxy equals to pass the equality check to the proxy target
36
+ def != other
37
+ @proxy_target != other
38
+ end
39
+
40
+ ##
41
+ # Overrides the proxy equals to pass the equality check to the proxy target
42
+ def equal? other
43
+ @proxy_target.equal? other
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ module Actor
2
+ ##
3
+ # Simple timer implementation
4
+ class Timer
5
+ ##
6
+ # Create a new timer that fires every <period> seconds. The number of
7
+ # iterations specifies how many times the timer should fire.
8
+ #
9
+ # * *Args*:
10
+ # - +period+: the time, in seconds, between firing the timer.
11
+ # - +iterations+: the number times the timer should fire. 0 iterations
12
+ # means fire infinitely
13
+ def initialize period, iterations, &block
14
+ @pause_queue = Queue.new
15
+
16
+ i = iterations == 0 ? 1.0 / 0.0 : iterations
17
+ @timer_thread = Thread.new do
18
+ (1..i).step do
19
+ sleep unless @pause_queue.empty?
20
+ block.call
21
+ sleep period
22
+ end
23
+ end
24
+ end
25
+
26
+ ##
27
+ # Pauses the timer. The currently executing iteration is finished before
28
+ # the time is paused
29
+ def pause
30
+ @pause_queue << :paused
31
+ end
32
+
33
+ ##
34
+ # Resumes the timer
35
+ def resume
36
+ @pause_queue.clear
37
+ @timer_thread.wakeup
38
+ end
39
+
40
+ ##
41
+ # Block the current thread until the timer has finished executing
42
+ def wait
43
+ @timer_thread.join
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ module Actor
2
+ ##
3
+ # Version number (semantic versioning)
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Actor::Base do
4
+ before :each do
5
+ @actor_class = Class.new do
6
+ include Actor::Base
7
+
8
+ def action
9
+ end
10
+ end
11
+ end
12
+
13
+ it 'initializes mailbox on creation' do
14
+ proxy = @actor_class.new
15
+ actor = proxy.__proxy_target
16
+
17
+ expect(actor.instance_variable_get :@mailbox).not_to be nil
18
+ end
19
+
20
+ it 'initializes mailbox on creation of subclass' do
21
+ child_actor = Class.new(@actor_class).new.__proxy_target
22
+ expect(child_actor.instance_variable_get :@mailbox).not_to be nil
23
+ end
24
+
25
+ it 'receives proxied messages' do
26
+ Thread.stub :new
27
+
28
+ proxy = @actor_class.new
29
+ actor = proxy.__proxy_target
30
+
31
+ proxy.message1
32
+ proxy.message2 :arg1, :arg2
33
+
34
+ messages = actor.instance_variable_get :@mailbox
35
+ expect(messages.size).to be 2
36
+ expect(messages.pop).to eq [:message1, [], nil]
37
+ expect(messages.pop).to eq [:message2, [:arg1, :arg2], nil]
38
+ end
39
+
40
+ it 'processes messages' do
41
+ proxy = @actor_class.new
42
+ actor = proxy.__proxy_target
43
+
44
+ actor.should_receive :message1
45
+ actor.should_receive(:message2).with :arg1
46
+ actor.should_receive(:message3).with :arg1, :arg2
47
+
48
+ proxy.message1
49
+ proxy.message2 :arg1
50
+ proxy.message3 :arg1, :arg2
51
+
52
+ # Sleep because threads are lame.
53
+ sleep 0.1
54
+
55
+ messages = actor.instance_variable_get :@mailbox
56
+ expect(messages.size).to be 0
57
+ end
58
+
59
+ it 'executes before/after callbacks' do
60
+ proxy = @actor_class.new
61
+ actor = proxy.__proxy_target
62
+
63
+ proxy.before_action :action do
64
+ actor.before_method
65
+ end
66
+
67
+ ret_value = nil
68
+ proxy.after_action :action do |result|
69
+ ret_value = result
70
+ actor.after_method
71
+ end
72
+
73
+ actor.should_receive(:before_method).ordered
74
+ actor.should_receive(:action).ordered.and_return('ret_value')
75
+ actor.should_receive(:after_method).ordered
76
+
77
+ proxy.action
78
+ sleep 0.1
79
+
80
+ expect(ret_value).to eq 'ret_value'
81
+ end
82
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Actor::Proxy do
4
+ before :each do
5
+ @target = Object.new
6
+ @proxy = Actor::Proxy.new @target
7
+ end
8
+
9
+ it 'sets the proxy target' do
10
+ expect(@proxy.instance_eval '@proxy_target').to be @target
11
+ end
12
+
13
+ it 'preserves equality' do
14
+ expect(@proxy).to eq @target
15
+ expect(@proxy != @target).to be false
16
+ expect(@proxy.equal? @target).to be true
17
+ end
18
+
19
+ it 'gets the proxy target' do
20
+ expect(@proxy.__proxy_target).to be @target
21
+ end
22
+
23
+ it 'forwards messages via send' do
24
+ @target.should_receive(:send).with :method, :to_s
25
+ @proxy.method :to_s
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ require 'actor'
2
+
3
+ Thread.abort_on_exception = true
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Actor::Timer do
4
+ it 'executes for the given number of iterations' do
5
+ iterations = 0
6
+ Actor::Timer.new 0.033, 30 do
7
+ iterations += 1
8
+ end.wait
9
+
10
+ expect(iterations).to be 30
11
+ end
12
+
13
+ it 'fires every period' do
14
+ deltas = []
15
+ last_time = Time.now - 0.033
16
+
17
+ Actor::Timer.new 0.033, 30 do
18
+ deltas << (Time.now - last_time).to_f
19
+ last_time = Time.now
20
+ end.wait
21
+
22
+ deltas.each { |delta| expect(delta).to be_within(0.01).of(0.033) }
23
+ end
24
+
25
+ it 'pauses and resumes' do
26
+ long_pointless_sum = 0
27
+ timer = Actor::Timer.new 0.033, 3000 do
28
+ long_pointless_sum += 1
29
+ end
30
+
31
+ timer.pause
32
+ timer.pause # Verify that two messages get queued
33
+ post_pause_sum = long_pointless_sum
34
+ sleep 1
35
+
36
+ pause_queue = timer.instance_variable_get(:@pause_queue)
37
+
38
+ expect(long_pointless_sum).to be post_pause_sum
39
+ expect(timer.instance_variable_get(:@timer_thread).status).to eq 'sleep'
40
+ expect(pause_queue.pop).to be :paused
41
+ expect(pause_queue.pop).to be :paused
42
+ expect(pause_queue).to be_empty
43
+
44
+ pause_queue.should_receive :clear
45
+ timer.resume
46
+ sleep 1
47
+
48
+ expect(long_pointless_sum).to be > post_pause_sum
49
+ end
50
+
51
+ it 'blocks the calling thread when waiting' do
52
+ side_effect = false
53
+ Actor::Timer.new 0.01, 1 do
54
+ sleep 1
55
+ side_effect = true
56
+ end.wait
57
+
58
+ expect(side_effect).to be true
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Max Gale
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2014-05-12 00:00:00 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ prerelease: false
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: "1.6"
22
+ type: :development
23
+ version_requirements: *id001
24
+ - !ruby/object:Gem::Dependency
25
+ name: rake
26
+ prerelease: false
27
+ requirement: &id002 !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ version: "10.3"
32
+ type: :development
33
+ version_requirements: *id002
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id003 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: "2.14"
42
+ type: :development
43
+ version_requirements: *id003
44
+ - !ruby/object:Gem::Dependency
45
+ name: rdoc
46
+ prerelease: false
47
+ requirement: &id004 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ~>
50
+ - !ruby/object:Gem::Version
51
+ version: "4.1"
52
+ type: :development
53
+ version_requirements: *id004
54
+ description:
55
+ email:
56
+ - maxgale4@gmail.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files: []
62
+
63
+ files:
64
+ - .gitignore
65
+ - .travis.yml
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - actor.gemspec
71
+ - gemfiles/Gemfile.travis
72
+ - lib/actor.rb
73
+ - lib/actor/base.rb
74
+ - lib/actor/proxy.rb
75
+ - lib/actor/timer.rb
76
+ - lib/actor/version.rb
77
+ - spec/base_spec.rb
78
+ - spec/proxy_spec.rb
79
+ - spec/spec_helper.rb
80
+ - spec/timer_spec.rb
81
+ homepage: https://github.com/maxgale/actor
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+
86
+ post_install_message:
87
+ rdoc_options: []
88
+
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - &id005
94
+ - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: "0"
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - *id005
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 2.2.2
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: A simple implementation of the actor pattern
107
+ test_files:
108
+ - spec/base_spec.rb
109
+ - spec/proxy_spec.rb
110
+ - spec/spec_helper.rb
111
+ - spec/timer_spec.rb