clingfilm 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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=
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.swo
3
+ *.swp
4
+ log
5
+ tags
6
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require support/spec_helper
2
+ --colour
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
@@ -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
@@ -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
+
@@ -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.
@@ -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
@@ -0,0 +1,6 @@
1
+ $:.unshift "lib"
2
+ require 'rubygems'
3
+ require 'rake/clean'
4
+ require 'bundler/setup'
5
+
6
+ Dir.glob('build/tasks/*.rake').each { |r| import r }
@@ -0,0 +1,5 @@
1
+ namespace :logs do
2
+ task :cleanup do
3
+ FileUtils.rm_rf('log/raw_data')
4
+ end
5
+ end
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ require_relative 'clingfilm/messaging_wrapper'
2
+ require_relative 'clingfilm/marshaller'
3
+ require_relative 'clingfilm/pulse'
@@ -0,0 +1,11 @@
1
+ require 'celluloid'
2
+ require 'celluloid/autostart'
3
+
4
+ require_relative 'messaging_wrapper'
5
+ require_relative 'pulse'
6
+
7
+ module Clingfilm
8
+ class Marshaller < Celluloid::SupervisionGroup
9
+ alias_method :stop, :finalize
10
+ end
11
+ end
@@ -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,4 @@
1
+ SimpleCov.coverage_dir 'log/coverage/rspec'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ 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