clingfilm 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +156 -0
- data/Guardfile +30 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +6 -0
- data/build/tasks/cleanup.rake +5 -0
- data/build/tasks/coverage.rake +14 -0
- data/build/tasks/default.rake +14 -0
- data/build/tasks/rspec.rake +20 -0
- data/clingfilm.gemspec +23 -0
- data/lib/clingfilm.rb +3 -0
- data/lib/clingfilm/marshaller.rb +11 -0
- data/lib/clingfilm/messaging_wrapper.rb +53 -0
- data/lib/clingfilm/pulse.rb +26 -0
- data/spec/clingfilm/marshaller_spec.rb +57 -0
- data/spec/clingfilm/messaging_wrapper_spec.rb +113 -0
- data/spec/clingfilm/pulse_spec.rb +34 -0
- data/spec/support/actor_helper.rb +17 -0
- data/spec/support/celluloid_hooks.rb +13 -0
- data/spec/support/coverage_helper.rb +4 -0
- data/spec/support/logging_helper.rb +12 -0
- data/spec/support/messaging_helper.rb +28 -0
- data/spec/support/spec_helper.rb +20 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NjZjM2NjMDYzZjhlYjYxMjBmMGVkM2E4NzE3N2E3OWYwNjEyNTRhZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ODdkYTA5ZDRhNTcwMDBhNmIwNmRlYTkzODY3YjI5MWRmODEzNWU1Nw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MzJjNzYwOGRjNmVmZjc5NmM4MDQzMWU0OWZkNjg1MTI2MmU5OWJiZjgzOTdk
|
10
|
+
MzU5ZmMzZTQ5NzAyOTBiN2Y3M2VlZThhNGVkMDQxNjhjZDY1MGM0M2JhZTc4
|
11
|
+
NDVmM2RiZWYyN2RjOTY4YTE0YzQyYTk4NTVlODBiMjZmZTYxYmM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NGE5ZGQ2ZjYzOTk2NGRkZWFlMTAwMTliYWQ4ODllZjBlMjJiZmE1NmRmM2M1
|
14
|
+
NzU3ZTJmZjVlNjAzMWMwYzE0MTQ2NzM2ODc3NTRmYzg0M2QwMWY4ODMxNDc2
|
15
|
+
ZTA3YTk3ZDVkNmUwZWJmZDQ0YjliZGU2MGU1MjFkZWQ0OGM1YWY=
|
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use --create --install ruby-1.9.3-p429@hollywood
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem 'celluloid'
|
4
|
+
|
5
|
+
group :test, :development do
|
6
|
+
gem 'logging'
|
7
|
+
gem 'metric_fu'
|
8
|
+
gem 'rake'
|
9
|
+
gem 'rspec'
|
10
|
+
gem 'simplecov'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :development do
|
14
|
+
gem 'guard'
|
15
|
+
gem 'guard-bundler'
|
16
|
+
gem 'guard-rspec'
|
17
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (4.0.0)
|
5
|
+
i18n (~> 0.6, >= 0.6.4)
|
6
|
+
minitest (~> 4.2)
|
7
|
+
multi_json (~> 1.3)
|
8
|
+
thread_safe (~> 0.1)
|
9
|
+
tzinfo (~> 0.3.37)
|
10
|
+
arrayfields (4.9.0)
|
11
|
+
atomic (1.1.14)
|
12
|
+
awesome_print (1.2.0)
|
13
|
+
bluff (0.1.0)
|
14
|
+
cane (2.6.0)
|
15
|
+
parallel
|
16
|
+
celluloid (0.15.2)
|
17
|
+
timers (~> 1.1.0)
|
18
|
+
chronic (0.10.2)
|
19
|
+
churn (0.0.34)
|
20
|
+
chronic (>= 0.2.3)
|
21
|
+
hirb
|
22
|
+
json_pure
|
23
|
+
main
|
24
|
+
ruby_parser (~> 3.0)
|
25
|
+
sexp_processor (~> 4.1)
|
26
|
+
code_analyzer (0.4.3)
|
27
|
+
sexp_processor
|
28
|
+
code_metrics (0.1.1)
|
29
|
+
coderay (1.0.9)
|
30
|
+
colored (1.2)
|
31
|
+
diff-lcs (1.2.4)
|
32
|
+
erubis (2.7.0)
|
33
|
+
fattr (2.2.1)
|
34
|
+
ffi (1.9.0)
|
35
|
+
flay (2.4.0)
|
36
|
+
ruby_parser (~> 3.0)
|
37
|
+
sexp_processor (~> 4.0)
|
38
|
+
flog (4.1.2)
|
39
|
+
ruby_parser (~> 3.1, > 3.1.0)
|
40
|
+
sexp_processor (~> 4.0)
|
41
|
+
formatador (0.2.4)
|
42
|
+
guard (1.8.3)
|
43
|
+
formatador (>= 0.2.4)
|
44
|
+
listen (~> 1.3)
|
45
|
+
lumberjack (>= 1.0.2)
|
46
|
+
pry (>= 0.9.10)
|
47
|
+
thor (>= 0.14.6)
|
48
|
+
guard-bundler (1.0.0)
|
49
|
+
bundler (~> 1.0)
|
50
|
+
guard (~> 1.1)
|
51
|
+
guard-rspec (3.1.0)
|
52
|
+
guard (>= 1.8)
|
53
|
+
rspec (~> 2.13)
|
54
|
+
hirb (0.7.1)
|
55
|
+
i18n (0.6.5)
|
56
|
+
json_pure (1.8.0)
|
57
|
+
listen (1.3.1)
|
58
|
+
rb-fsevent (>= 0.9.3)
|
59
|
+
rb-inotify (>= 0.9)
|
60
|
+
rb-kqueue (>= 0.2)
|
61
|
+
little-plugger (1.1.3)
|
62
|
+
logging (1.8.1)
|
63
|
+
little-plugger (>= 1.1.3)
|
64
|
+
multi_json (>= 1.3.6)
|
65
|
+
lumberjack (1.0.4)
|
66
|
+
main (5.2.0)
|
67
|
+
arrayfields (>= 4.7.4)
|
68
|
+
chronic (>= 0.6.2)
|
69
|
+
fattr (>= 2.2.0)
|
70
|
+
map (>= 5.1.0)
|
71
|
+
map (6.5.1)
|
72
|
+
method_source (0.8.2)
|
73
|
+
metric_fu (4.4.4)
|
74
|
+
bluff
|
75
|
+
cane (~> 2.5, >= 2.5.2)
|
76
|
+
churn (~> 0.0.28)
|
77
|
+
code_metrics (~> 0.1)
|
78
|
+
coderay
|
79
|
+
flay (~> 2.1, >= 2.0.1)
|
80
|
+
flog (~> 4.1, >= 4.1.1)
|
81
|
+
metric_fu-Saikuro (>= 1.1.1.0)
|
82
|
+
multi_json
|
83
|
+
rails_best_practices (~> 1.14, >= 1.14.3)
|
84
|
+
redcard
|
85
|
+
reek (~> 1.3, >= 1.3.3)
|
86
|
+
roodi (~> 3.1)
|
87
|
+
metric_fu-Saikuro (1.1.1.0)
|
88
|
+
minitest (4.7.5)
|
89
|
+
multi_json (1.8.1)
|
90
|
+
parallel (0.8.4)
|
91
|
+
pry (0.9.12.2)
|
92
|
+
coderay (~> 1.0.5)
|
93
|
+
method_source (~> 0.8)
|
94
|
+
slop (~> 3.4)
|
95
|
+
rails_best_practices (1.14.4)
|
96
|
+
activesupport
|
97
|
+
awesome_print
|
98
|
+
code_analyzer (>= 0.4.3)
|
99
|
+
colored
|
100
|
+
erubis
|
101
|
+
i18n
|
102
|
+
require_all
|
103
|
+
ruby-progressbar
|
104
|
+
rake (10.1.0)
|
105
|
+
rb-fsevent (0.9.3)
|
106
|
+
rb-inotify (0.9.2)
|
107
|
+
ffi (>= 0.5.0)
|
108
|
+
rb-kqueue (0.2.0)
|
109
|
+
ffi (>= 0.5.0)
|
110
|
+
redcard (1.1.0)
|
111
|
+
reek (1.3.4)
|
112
|
+
ruby2ruby (~> 2.0.2)
|
113
|
+
ruby_parser (~> 3.2)
|
114
|
+
sexp_processor
|
115
|
+
require_all (1.3.1)
|
116
|
+
roodi (3.1.1)
|
117
|
+
ruby_parser (~> 3.2, >= 3.2.2)
|
118
|
+
rspec (2.14.1)
|
119
|
+
rspec-core (~> 2.14.0)
|
120
|
+
rspec-expectations (~> 2.14.0)
|
121
|
+
rspec-mocks (~> 2.14.0)
|
122
|
+
rspec-core (2.14.5)
|
123
|
+
rspec-expectations (2.14.3)
|
124
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
125
|
+
rspec-mocks (2.14.3)
|
126
|
+
ruby-progressbar (1.2.0)
|
127
|
+
ruby2ruby (2.0.6)
|
128
|
+
ruby_parser (~> 3.1)
|
129
|
+
sexp_processor (~> 4.0)
|
130
|
+
ruby_parser (3.2.2)
|
131
|
+
sexp_processor (~> 4.1)
|
132
|
+
sexp_processor (4.3.0)
|
133
|
+
simplecov (0.7.1)
|
134
|
+
multi_json (~> 1.0)
|
135
|
+
simplecov-html (~> 0.7.1)
|
136
|
+
simplecov-html (0.7.1)
|
137
|
+
slop (3.4.6)
|
138
|
+
thor (0.18.1)
|
139
|
+
thread_safe (0.1.3)
|
140
|
+
atomic
|
141
|
+
timers (1.1.0)
|
142
|
+
tzinfo (0.3.38)
|
143
|
+
|
144
|
+
PLATFORMS
|
145
|
+
ruby
|
146
|
+
|
147
|
+
DEPENDENCIES
|
148
|
+
celluloid
|
149
|
+
guard
|
150
|
+
guard-bundler
|
151
|
+
guard-rspec
|
152
|
+
logging
|
153
|
+
metric_fu
|
154
|
+
rake
|
155
|
+
rspec
|
156
|
+
simplecov
|
data/Guardfile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'bundler' do
|
5
|
+
watch('Gemfile')
|
6
|
+
# Uncomment next line if Gemfile contain `gemspec' command
|
7
|
+
# watch(/^.+\.gemspec/)
|
8
|
+
end
|
9
|
+
|
10
|
+
guard :rspec do
|
11
|
+
watch(%r{^spec/.+_spec\.rb$})
|
12
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
13
|
+
watch('spec/spec_helper.rb') { "spec" }
|
14
|
+
|
15
|
+
# Rails example
|
16
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
17
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
18
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
19
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
20
|
+
watch('config/routes.rb') { "spec/routing" }
|
21
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
22
|
+
|
23
|
+
# Capybara features specs
|
24
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
25
|
+
|
26
|
+
# Turnip features and steps
|
27
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
28
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
29
|
+
end
|
30
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Adam Whittingham
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
Clingfilm
|
2
|
+
=========
|
3
|
+
A nice place for your Ruby actors to live
|
4
|
+
-----------------------------------------
|
5
|
+
|
6
|
+
Clingfilm is light system for concurrency on top of the wonderful [Celluloid](http://celluloid.io/) project.
|
7
|
+
Its goal is to be a quick & simple way to make use of the actor pattern in Ruby.
|
8
|
+
|
9
|
+
Installation
|
10
|
+
------------
|
11
|
+
* Install the gem or add `gem "clingfilm"` to your Gemfile
|
12
|
+
|
13
|
+
Usage
|
14
|
+
-----
|
15
|
+
Clingfilm is made up of 3 main components: MessageWrappers, Pulses and Marshallers.
|
16
|
+
|
17
|
+
### Message Wrappers
|
18
|
+
These wrap any Ruby object which has an "update" method and turns it into an actor. They listen on one or more queues for :update messages, run the update method and announce on the outgoing queues when they are done.
|
19
|
+
|
20
|
+
### Pulses
|
21
|
+
These are very basic actors which 'pulse' update messages on a given interval. Useful (if slightly inaccurate) clocks for getting things going!
|
22
|
+
|
23
|
+
### Marshallers
|
24
|
+
These deal with the construction and wiring up of the other elements. They also recreate any actors which explode due to exceptions.
|
25
|
+
|
26
|
+
Logging
|
27
|
+
-------
|
28
|
+
Clingfilm publishes log messages about the sending and receiving of messages between actors at the debug level.
|
29
|
+
The logging is done using Celluloids logging mechanism, which is null unless set; for example, in Rails:
|
30
|
+
```
|
31
|
+
Celluloid.logger = Rails.logger
|
32
|
+
```
|
33
|
+
More details can be read in the [Celluloid logging docs](https://github.com/celluloid/celluloid/wiki/Logging).
|
34
|
+
|
35
|
+
ToDo
|
36
|
+
----
|
37
|
+
1. Allow sending data in messages instead of relying on store/retreive
|
38
|
+
2. Add an example implementation to the documentation
|
39
|
+
3. Add an more in-depth example implementation to the documentation
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
begin
|
2
|
+
require "simplecov"
|
3
|
+
|
4
|
+
namespace :coverage do
|
5
|
+
task :check_specs do
|
6
|
+
SimpleCov.coverage_dir 'log/coverage/rspec'
|
7
|
+
coverage = SimpleCov.result.covered_percent
|
8
|
+
fail "Spec coverage was only #{coverage}%" if coverage < 100.0
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
rescue LoadError
|
13
|
+
$stderr.puts 'Warning: SimpleCov not available.'
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "rake/clean"
|
2
|
+
|
3
|
+
task :default => [:spec, :'coverage:check_specs', :ok]
|
4
|
+
|
5
|
+
task :ok do
|
6
|
+
red = "\e[31m"
|
7
|
+
yellow = "\e[33m"
|
8
|
+
green = "\e[32m"
|
9
|
+
blue = "\e[34m"
|
10
|
+
purple = "\e[35m"
|
11
|
+
bold = "\e[1m"
|
12
|
+
normal = "\e[0m"
|
13
|
+
puts "", "#{bold}#{red}*#{yellow}*#{green}*#{blue}*#{purple}*#{green} ALL TESTS PASSED #{purple}*#{blue}*#{green}*#{yellow}*#{red}*#{normal}"
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
begin
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:'spec:unit') do |t|
|
7
|
+
t.pattern = "spec/unit/**/*_spec.rb"
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new(:'spec:int') do |t|
|
11
|
+
t.pattern = "spec/integration/**/*_spec.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec::Core::RakeTask.new(:rcov) do |t|
|
15
|
+
t.rcov = true
|
16
|
+
t.rcov_opts = %w{--exclude osx\/objc,gems\/,spec\/}
|
17
|
+
end
|
18
|
+
rescue LoadError
|
19
|
+
$stderr.puts 'Warning: RSpec not available.'
|
20
|
+
end
|
data/clingfilm.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "clingfilm"
|
7
|
+
spec.version = '0.4.0'
|
8
|
+
spec.authors = ["Adam Whittingham"]
|
9
|
+
spec.email = ["adam.whittingham@gmail.com"]
|
10
|
+
spec.description = %q{A light and easy way of working concurrently with Ruby, built on top of Celluloid}
|
11
|
+
spec.summary = %q{A light, thin wrapper made of Celluloid}
|
12
|
+
spec.homepage = "http://github.com/AdamWhittingham/clingfilm"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
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_runtime_dependency "celluloid", ">= 0.14.0"
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
data/lib/clingfilm.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
|
3
|
+
module Clingfilm
|
4
|
+
class MessagingWrapper
|
5
|
+
include Celluloid
|
6
|
+
include Celluloid::Notifications
|
7
|
+
include Celluloid::Logger
|
8
|
+
|
9
|
+
attr_reader :exception, :channel
|
10
|
+
|
11
|
+
def initialize content, input_channels, output_channel
|
12
|
+
bounce_if_invalid content
|
13
|
+
@content = content
|
14
|
+
Array(input_channels).each{|channel| depends_on channel}
|
15
|
+
updates output_channel
|
16
|
+
end
|
17
|
+
|
18
|
+
def wraps
|
19
|
+
@content
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_message(channel, message)
|
23
|
+
info "<- #{channel}"
|
24
|
+
debug "<< #{channel} = #{message}"
|
25
|
+
result = @content.update(message)
|
26
|
+
announce_updated(result) if result
|
27
|
+
end
|
28
|
+
|
29
|
+
def announce_updated message
|
30
|
+
publish(@channel, message)
|
31
|
+
info "-> #{@channel}"
|
32
|
+
debug ">> #{@channel} = #{message}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def depends_on channel
|
36
|
+
subscribe(channel, :handle_message)
|
37
|
+
end
|
38
|
+
|
39
|
+
def updates channel
|
40
|
+
@channel = channel
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
"#{self.class}[#{@content.class}]"
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def bounce_if_invalid content
|
50
|
+
raise "Cannot wrap an object which doesn't provide #update" unless content.respond_to? 'update'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
|
3
|
+
module Clingfilm
|
4
|
+
class Pulse
|
5
|
+
DEFAULT_INTERVAL = 600
|
6
|
+
include Celluloid
|
7
|
+
include Celluloid::Notifications
|
8
|
+
include Celluloid::Logger
|
9
|
+
|
10
|
+
attr_reader :channel
|
11
|
+
|
12
|
+
def initialize(channel, options = {})
|
13
|
+
@channel = channel
|
14
|
+
interval = options.fetch :interval, DEFAULT_INTERVAL
|
15
|
+
unless ENV["DISABLE_CLINGFILM_PULSES"]
|
16
|
+
every(interval) { pulse }
|
17
|
+
pulse
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def pulse
|
22
|
+
publish @channel, :update
|
23
|
+
debug "update -> #{@channel}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require production_code
|
3
|
+
|
4
|
+
class Foo; def update; end; end
|
5
|
+
|
6
|
+
describe Clingfilm::Marshaller, :celluloid do
|
7
|
+
|
8
|
+
subject{ Clingfilm::Marshaller.run! }
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@actors = ActorHelper.new
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when an actor is being supervised" do
|
15
|
+
before do
|
16
|
+
Clingfilm::Marshaller.supervise Clingfilm::MessagingWrapper,
|
17
|
+
as: :an_actor,
|
18
|
+
args: [Foo.new, 'test_channel_in', 'test_channel_out']
|
19
|
+
subject
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#stop' do
|
23
|
+
it 'terminates the actors' do
|
24
|
+
@actors[:an_actor].should be_alive
|
25
|
+
|
26
|
+
subject.stop
|
27
|
+
Timeout::timeout(10) do
|
28
|
+
sleep 0.01 while @actors[:an_actor] && @actors[:an_actor].alive?
|
29
|
+
end
|
30
|
+
|
31
|
+
actor = @actors[:an_actor]
|
32
|
+
if actor
|
33
|
+
expect(actor).to_not be_alive
|
34
|
+
else
|
35
|
+
expect(actor).to be_nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when an actor crashes' do
|
41
|
+
it 'restarts the actor' do
|
42
|
+
expect { @actors[:an_actor].crash_me }.to raise_error
|
43
|
+
loop do
|
44
|
+
sleep 0.1
|
45
|
+
break if @actors[:an_actor].class != NilClass
|
46
|
+
end
|
47
|
+
expect(@actors[:an_actor]).to be_alive
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'logs the crash' do
|
51
|
+
expect { @actors[:an_actor].crash_me }.to raise_error
|
52
|
+
expect(log_output).to include "MessagingWrapper crashed!"
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require production_code
|
2
|
+
require 'support/messaging_helper'
|
3
|
+
require 'support/celluloid_hooks'
|
4
|
+
|
5
|
+
describe Clingfilm::MessagingWrapper, :celluloid do
|
6
|
+
let(:wrapped) { double "wrapped", { :update => true } }
|
7
|
+
let(:input_channel) { "input_channel" }
|
8
|
+
let(:other_channel) { "other_channel" }
|
9
|
+
let(:output_channel) { "output_channel" }
|
10
|
+
let(:some_data) { double "some data" }
|
11
|
+
let!(:listener) { MessageHelper.new(output_channel) }
|
12
|
+
|
13
|
+
subject! { Clingfilm::MessagingWrapper.new(wrapped, input_channel, output_channel) }
|
14
|
+
|
15
|
+
describe '#new' do
|
16
|
+
it 'throws an exception if the wrapped object does not respond to #update' do
|
17
|
+
expect { Clingfilm::MessagingWrapper.new( double('un-updateable'), input_channel, output_channel)}.to raise_error "Cannot wrap an object which doesn't provide #update"
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can optionally be created with multiple input channels' do
|
21
|
+
Clingfilm::MessagingWrapper.new(wrapped, ['input_1', 'input_2'], output_channel)
|
22
|
+
MessageHelper.new.publish('input_1', :updated)
|
23
|
+
MessageHelper.new.publish('input_2', :updated)
|
24
|
+
expect(wrapped).to have_received(:update).twice
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#to_s' do
|
29
|
+
it 'mentions the wrapped class' do
|
30
|
+
expect(subject.to_s).to eq "Clingfilm::MessagingWrapper[#{wrapped.class}]"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#wraps" do
|
35
|
+
it 'wraps the given object' do
|
36
|
+
expect(subject.wraps).to eq wrapped
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "messaging" do
|
41
|
+
describe "incomming" do
|
42
|
+
it 'calls wrapped#update when receiving a message on a subscribed channel' do
|
43
|
+
MessageHelper.new.publish(input_channel, :update)
|
44
|
+
expect(wrapped).to have_received :update
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'does not update for messages on non-subscribed channels' do
|
48
|
+
MessageHelper.new.publish(other_channel, :update)
|
49
|
+
expect(wrapped).to_not have_received :update
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'can subscribe to multiple input channels' do
|
53
|
+
subject.depends_on 'foo'
|
54
|
+
MessageHelper.new.publish('input_channel', :updated)
|
55
|
+
MessageHelper.new.publish('foo', :updated)
|
56
|
+
expect(wrapped).to have_received(:update).twice
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "outgoing" do
|
62
|
+
it 'announces the return of wrapper#update on the output channel' do
|
63
|
+
wrapped.stub(update: some_data)
|
64
|
+
MessageHelper.new.publish(input_channel, :update)
|
65
|
+
expect(listener.messages).to include [output_channel, some_data]
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'does not announce if the wrapped object returns nil' do
|
69
|
+
wrapped.stub(update: nil)
|
70
|
+
MessageHelper.new.publish(input_channel, :update)
|
71
|
+
expect(listener).to_not be_updated
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'dies if the wrapped class exceptions' do
|
75
|
+
wrapped.stub(:update){raise 'some error'}
|
76
|
+
MessageHelper.new.publish(input_channel, :update)
|
77
|
+
expect(subject).to_not be_alive
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'logging' do
|
83
|
+
context "at the INFO level" do
|
84
|
+
it 'logs when it announces' do
|
85
|
+
wrapped.stub(update: :output)
|
86
|
+
MessageHelper.new.publish(input_channel, :update)
|
87
|
+
sleep 0.1
|
88
|
+
log_output.should include "INFO Celluloid : -> #{output_channel}"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'logs when a message is received' do
|
92
|
+
MessageHelper.new.publish(input_channel, :update)
|
93
|
+
sleep 0.1
|
94
|
+
log_output.should include "INFO Celluloid : <- #{input_channel}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "at the DEBUG level" do
|
99
|
+
it 'logs what it announces' do
|
100
|
+
MessageHelper.new.publish(input_channel, :update)
|
101
|
+
sleep 0.1
|
102
|
+
log_output.should include "DEBUG Celluloid : >> #{output_channel} = true"
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'logs the messages are received' do
|
106
|
+
MessageHelper.new.publish(input_channel,:update)
|
107
|
+
sleep 0.1
|
108
|
+
log_output.should include "DEBUG Celluloid : << #{input_channel} = update"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'support/messaging_helper'
|
2
|
+
require production_code
|
3
|
+
|
4
|
+
describe Clingfilm::Pulse, :celluloid do
|
5
|
+
let!(:receiver) {MessageHelper.new 'foo'}
|
6
|
+
|
7
|
+
before { ENV.delete "DISABLE_CLINGFILM_PULSES" }
|
8
|
+
after { receiver.reset }
|
9
|
+
|
10
|
+
it 'publishes an update message shortly after startup' do
|
11
|
+
Clingfilm::Pulse.new 'foo'
|
12
|
+
sleep 0.1
|
13
|
+
expect(receiver.message_count).to eq 1
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'publishes update messages for a given channel every x seconds' do
|
17
|
+
Clingfilm::Pulse.new 'foo', interval: 1
|
18
|
+
sleep 1.1
|
19
|
+
expect(receiver.message_count).to eq 2
|
20
|
+
end
|
21
|
+
|
22
|
+
it "does not pulse if ENV['DISABLE_CLINGFILM_PULSES'] is set" do
|
23
|
+
ENV["DISABLE_CLINGFILM_PULSES"] = "true"
|
24
|
+
Clingfilm::Pulse.new 'foo'
|
25
|
+
sleep 0.2
|
26
|
+
expect(receiver.message_count).to eq 0
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'logs when it sends a pulse' do
|
30
|
+
Clingfilm::Pulse.new 'foo'
|
31
|
+
sleep 0.1
|
32
|
+
expect(log_output).to include "update -> foo"
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "celluloid"
|
2
|
+
|
3
|
+
class ActorHelper
|
4
|
+
include Celluloid
|
5
|
+
|
6
|
+
def [](name)
|
7
|
+
Celluloid::Actor[name]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Clingfilm
|
12
|
+
class MessagingWrapper
|
13
|
+
def crash_me message= 'Crashed by tests!'
|
14
|
+
raise message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
require 'logging'
|
3
|
+
|
4
|
+
Celluloid.logger = Logging.logger.new(Celluloid.to_s)
|
5
|
+
Celluloid.shutdown_timeout = 1
|
6
|
+
|
7
|
+
# Reboot celluloid; ESSENTIAL in avoiding state overflowing between tests
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.before(:each, celluloid: true) do
|
10
|
+
Celluloid.shutdown
|
11
|
+
Celluloid.boot
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'logging'
|
2
|
+
require 'rspec/logging_helper'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
include RSpec::LoggingHelper
|
6
|
+
config.capture_log_messages
|
7
|
+
end
|
8
|
+
|
9
|
+
def log_output
|
10
|
+
fail "No log output found" unless @log_output
|
11
|
+
@log_output.readlines.map{|s|s.strip.squeeze(" ")}.join "\n"
|
12
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "celluloid"
|
2
|
+
|
3
|
+
class MessageHelper
|
4
|
+
include Celluloid
|
5
|
+
include Celluloid::Notifications
|
6
|
+
attr_reader :has_updated, :messages
|
7
|
+
|
8
|
+
def initialize channel='default'
|
9
|
+
@messages = []
|
10
|
+
subscribe(channel, :handle_message)
|
11
|
+
end
|
12
|
+
|
13
|
+
def message_count
|
14
|
+
@messages.size
|
15
|
+
end
|
16
|
+
|
17
|
+
def handle_message (channel, message)
|
18
|
+
@messages << [channel, message]
|
19
|
+
end
|
20
|
+
|
21
|
+
def updated?
|
22
|
+
message_count > 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset
|
26
|
+
@has_updated = false
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
$:.unshift 'lib'
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require "simplecov" # Needs to be done first
|
5
|
+
|
6
|
+
require_relative 'logging_helper'
|
7
|
+
require_relative 'actor_helper'
|
8
|
+
require_relative 'coverage_helper'
|
9
|
+
require_relative 'celluloid_hooks'
|
10
|
+
|
11
|
+
def production_code
|
12
|
+
spec = caller[0][/spec.+\.rb/]
|
13
|
+
'./' + spec.gsub('_spec','').gsub(/spec\//, 'lib/')
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.color_enabled = true
|
18
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
19
|
+
end
|
20
|
+
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: clingfilm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Whittingham
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: celluloid
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.14.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.14.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A light and easy way of working concurrently with Ruby, built on top
|
56
|
+
of Celluloid
|
57
|
+
email:
|
58
|
+
- adam.whittingham@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- .rspec
|
65
|
+
- .rvmrc
|
66
|
+
- Gemfile
|
67
|
+
- Gemfile.lock
|
68
|
+
- Guardfile
|
69
|
+
- LICENSE.txt
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- build/tasks/cleanup.rake
|
73
|
+
- build/tasks/coverage.rake
|
74
|
+
- build/tasks/default.rake
|
75
|
+
- build/tasks/rspec.rake
|
76
|
+
- clingfilm.gemspec
|
77
|
+
- lib/clingfilm.rb
|
78
|
+
- lib/clingfilm/marshaller.rb
|
79
|
+
- lib/clingfilm/messaging_wrapper.rb
|
80
|
+
- lib/clingfilm/pulse.rb
|
81
|
+
- spec/clingfilm/marshaller_spec.rb
|
82
|
+
- spec/clingfilm/messaging_wrapper_spec.rb
|
83
|
+
- spec/clingfilm/pulse_spec.rb
|
84
|
+
- spec/support/actor_helper.rb
|
85
|
+
- spec/support/celluloid_hooks.rb
|
86
|
+
- spec/support/coverage_helper.rb
|
87
|
+
- spec/support/logging_helper.rb
|
88
|
+
- spec/support/messaging_helper.rb
|
89
|
+
- spec/support/spec_helper.rb
|
90
|
+
homepage: http://github.com/AdamWhittingham/clingfilm
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.2.2
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: A light, thin wrapper made of Celluloid
|
114
|
+
test_files:
|
115
|
+
- spec/clingfilm/marshaller_spec.rb
|
116
|
+
- spec/clingfilm/messaging_wrapper_spec.rb
|
117
|
+
- spec/clingfilm/pulse_spec.rb
|
118
|
+
- spec/support/actor_helper.rb
|
119
|
+
- spec/support/celluloid_hooks.rb
|
120
|
+
- spec/support/coverage_helper.rb
|
121
|
+
- spec/support/logging_helper.rb
|
122
|
+
- spec/support/messaging_helper.rb
|
123
|
+
- spec/support/spec_helper.rb
|