[DRE-commits] [ruby-aruba] 78/98: Re-integrate code of event-bus library
Hideki Yamane
henrich at moszumanska.debian.org
Tue Mar 22 12:20:42 UTC 2016
This is an automated email from the git hooks/post-receive script.
henrich pushed a commit to branch debian/sid
in repository ruby-aruba.
commit 7f26e7323ec5c2738f12fbbe2a214bac9cc48db0
Author: Dennis Günnewig <dg1 at ratiodata.de>
Date: Mon Jan 25 11:40:44 2016 +0100
Re-integrate code of event-bus library
---
History.md | 2 +-
aruba.gemspec | 1 -
lib/aruba/errors.rb | 6 ++
lib/aruba/event_bus.rb | 59 +++++++++++++
lib/aruba/event_bus/name_resolver.rb | 162 +++++++++++++++++++++++++++++++++++
lib/aruba/runtime.rb | 4 +-
spec/event_bus/name_resolver_spec.rb | 68 +++++++++++++++
spec/event_bus_spec.rb | 160 ++++++++++++++++++++++++++++++++++
8 files changed, 458 insertions(+), 4 deletions(-)
diff --git a/History.md b/History.md
index df84fc2..4d201dc 100644
--- a/History.md
+++ b/History.md
@@ -514,7 +514,7 @@
default value for io_wait_timeout can be set correctly.
* Make it possible to announce information on command error, using a new option
called `activate_announcer_on_command_failure` (PR #335, @njam)
-
+* Re-integrate `event-bus`-library into `aruba`-core (PR #342)
## [v1.0.0](https://github.com/cucumber/aruba/compare/v0.11.0...v1.0.0)
diff --git a/aruba.gemspec b/aruba.gemspec
index d5da5e6..e6af3a1 100644
--- a/aruba.gemspec
+++ b/aruba.gemspec
@@ -19,7 +19,6 @@ Gem::Specification.new do |s|
s.add_runtime_dependency 'rspec-expectations', '>= 2.99'
s.add_runtime_dependency 'contracts', '~> 0.9'
s.add_runtime_dependency 'thor', '~> 0.19'
- s.add_runtime_dependency 'event-bus', '~> 0.2'
s.add_development_dependency 'bundler', '~> 1.11'
diff --git a/lib/aruba/errors.rb b/lib/aruba/errors.rb
index 10d9cde..c0043e9 100644
--- a/lib/aruba/errors.rb
+++ b/lib/aruba/errors.rb
@@ -28,4 +28,10 @@ module Aruba
# Raised if command was already started, otherwise aruba forgets about the
# previous pid and you've got hidden commands run
class CommandAlreadyStartedError < Error; end
+
+ # Raised if an event name cannot be resolved
+ class EventNameResolveError < StandardError; end
+
+ # Raised if given object is not an event
+ class NoEventError < StandardError; end
end
diff --git a/lib/aruba/event_bus.rb b/lib/aruba/event_bus.rb
new file mode 100644
index 0000000..ef18fac
--- /dev/null
+++ b/lib/aruba/event_bus.rb
@@ -0,0 +1,59 @@
+require 'aruba/event_bus/name_resolver'
+require 'aruba/errors'
+
+module Aruba
+ # Event bus
+ #
+ # Implements and in-process pub-sub events broadcaster allowing multiple observers
+ # to subscribe to different events that fire as your tests are executed.
+ #
+ class EventBus
+ # Create EventBus
+ #
+ # @param [#transform] resolver
+ # A resolver which transforms Symbol, String, Class into an event Class.
+ def initialize(resolver)
+ @resolver = resolver
+ @handlers = Hash.new { |h, k| h[k] = [] }
+ end
+
+ # Register for an event
+ #
+ # @param [String, Symbol, Class, Array] event_ids
+ # If Array, register multiple events witht the same handler. If String,
+ # Symbol, Class register handler for given event.
+ #
+ # @param [#call] handler_object
+ # The handler object, needs to have method `#call`. Either
+ # `handler_object` or `block` can be defined. The handler object gets the
+ # event passed to `#call`.
+ #
+ # @yield
+ # Handler block which gets the event passed as parameter.
+ def register(event_ids, handler_object = nil, &handler_proc)
+ handler = handler_proc || handler_object
+
+ fail ArgumentError, 'Please pass either an object#call or a handler block' if handler.nil? || !handler.respond_to?(:call)
+
+ Array(event_ids).flatten.each do |id|
+ @handlers[
+ @resolver.transform(id).to_s
+ ] << handler
+ end
+
+ nil
+ end
+
+ # Broadcast an event
+ #
+ # @param [Object] event
+ # An object of registered event class. This object is passed to the event
+ # handler.
+ #
+ def notify(event)
+ fail NoEventError, 'Please pass an event object, not a class' if event.is_a?(Class)
+
+ @handlers[event.class.to_s].each { |handler| handler.call(event) }
+ end
+ end
+end
diff --git a/lib/aruba/event_bus/name_resolver.rb b/lib/aruba/event_bus/name_resolver.rb
new file mode 100644
index 0000000..4a035dd
--- /dev/null
+++ b/lib/aruba/event_bus/name_resolver.rb
@@ -0,0 +1,162 @@
+require 'aruba/errors'
+
+# Event notification library
+module Aruba
+ # EventBus
+ class EventBus
+ # Resolve name to Event name
+ class NameResolver
+ # @private
+ # Helpers for Resolvers
+ module ResolveHelpers
+ def camel_case(underscored_name)
+ if RUBY_VERSION < '1.9.3'
+ underscored_name.to_s.split('_').map { |word| word.upcase.chars.to_a[0] + word.chars.to_a[1..-1].join }.join
+ else
+ underscored_name.to_s.split('_').map { |word| word.upcase[0] + word[1..-1] }.join
+ end
+ end
+
+ # Thanks ActiveSupport
+ # (Only needed to support Ruby 1.9.3 and JRuby)
+ def constantize(camel_cased_word)
+ names = camel_cased_word.split('::')
+
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
+ Object.const_get(camel_cased_word) if names.empty?
+
+ # Remove the first blank element in case of '::ClassName' notation.
+ names.shift if names.size > 1 && names.first.empty?
+
+ names.inject(Object) do |constant, name|
+ if constant == Object
+ constant.const_get(name)
+ else
+ candidate = constant.const_get(name)
+
+ if RUBY_VERSION < '1.9.3'
+ next candidate if constant.const_defined?(name)
+ else
+ next candidate if constant.const_defined?(name, false)
+ end
+
+ next candidate unless Object.const_defined?(name)
+
+ # Go down the ancestors to check if it is owned directly. The check
+ # stops when we reach Object or the end of ancestors tree.
+ # rubocop:disable Style/EachWithObject
+ constant = constant.ancestors.inject do |const, ancestor|
+ break const if ancestor == Object
+ break ancestor if ancestor.const_defined?(name, false)
+ const
+ end
+ # rubocop:enable Style/EachWithObject
+
+ # owner is in Object, so raise
+ constant.const_get(name, false)
+ end
+ end
+ end
+ end
+
+ # @private
+ # Convert a class in to an event class
+ class ClassResolver
+ class << self
+ def match?(event_id)
+ event_id.is_a? Class
+ end
+
+ # Which types are supported
+ def supports
+ [Class]
+ end
+ end
+
+ def transform(_, event_id)
+ event_id
+ end
+ end
+
+ # @private
+ # Convert a string in to an event class
+ class StringResolver
+ include ResolveHelpers
+
+ class << self
+ def match?(event_id)
+ event_id.is_a? String
+ end
+
+ # Which types are supported
+ def supports
+ [String]
+ end
+ end
+
+ def transform(_, event_id)
+ constantize(event_id)
+ end
+ end
+
+ # @private
+ # Convert a symbol in to an event class
+ class SymbolResolver
+ include ResolveHelpers
+
+ class << self
+ def match?(event_id)
+ event_id.is_a? Symbol
+ end
+
+ # Which types are supported
+ def supports
+ [Symbol]
+ end
+ end
+
+ def transform(default_namespace, event_id)
+ constantize("#{default_namespace}::#{camel_case(event_id)}")
+ end
+ end
+
+ # @private
+ # Default failing resolver
+ #
+ # This comes into play if the user passes an invalid event type
+ class FailingResolver
+ class << self
+ def match?(event_id)
+ fail ArgumentError, %(Input type "#{event_id.class}" of event_id "#{event_id}" is invalid)
+ end
+
+ def supports
+ []
+ end
+ end
+ end
+
+ protected
+
+ attr_reader :resolvers, :default_namespace
+
+ public
+
+ def initialize(default_namespace)
+ @default_namespace = default_namespace
+
+ @resolvers = []
+ @resolvers << ClassResolver
+ @resolvers << StringResolver
+ @resolvers << SymbolResolver
+ @resolvers << FailingResolver
+ end
+
+ def transform(event_id)
+ resolvers.find { |r| r.match? event_id }.new.transform(default_namespace, event_id)
+ rescue => e
+ raise EventNameResolveError, %(Transforming "#{event_id}" into an event class failed. Supported types are: #{@resolvers.map(&:supports).flatten.join(', ')}. #{e.message}.\n\n#{e.backtrace.join("\n")})
+ end
+ end
+ end
+end
diff --git a/lib/aruba/runtime.rb b/lib/aruba/runtime.rb
index 0b0294f..0d6491d 100644
--- a/lib/aruba/runtime.rb
+++ b/lib/aruba/runtime.rb
@@ -2,7 +2,7 @@ require 'aruba/config'
require 'aruba/aruba_path'
require 'aruba/config_wrapper'
require 'aruba/events'
-require 'event/bus'
+require 'aruba/event_bus'
module Aruba
# Runtime of aruba
@@ -40,7 +40,7 @@ module Aruba
attr_accessor :config, :environment, :logger, :command_monitor, :announcer, :event_bus
def initialize(opts = {})
- @event_bus = ::Event::Bus.new(::Event::NameResolver.new(Aruba::Events))
+ @event_bus = EventBus.new(EventBus::NameResolver.new(Aruba::Events))
@announcer = opts.fetch(:announcer, Aruba.platform.announcer.new)
@config = opts.fetch(:config, ConfigWrapper.new(Aruba.config.make_copy, @event_bus))
@environment = opts.fetch(:environment, Aruba.platform.environment_variables.new)
diff --git a/spec/event_bus/name_resolver_spec.rb b/spec/event_bus/name_resolver_spec.rb
new file mode 100644
index 0000000..ca971cf
--- /dev/null
+++ b/spec/event_bus/name_resolver_spec.rb
@@ -0,0 +1,68 @@
+require 'aruba/event_bus/name_resolver'
+
+describe Aruba::EventBus::NameResolver do
+ subject(:resolver) { described_class.new(default_name_space) }
+ let(:default_name_space) { 'Events' }
+ let(:resolved_name) { resolver.transform(original_name) }
+
+ before :each do
+ stub_const('Events::MyEvent', Class.new)
+ stub_const('Events::MyEvent', Class.new)
+ end
+
+ describe '#transform' do
+ context 'when name is string' do
+ context 'when simple' do
+ let(:original_name) { 'Events::MyEvent' }
+ it { expect(resolved_name).to eq Events::MyEvent }
+ end
+
+ context 'when prefixed' do
+ let(:original_name) { '::Events::MyEvent' }
+ it { expect(resolved_name).to eq Events::MyEvent }
+ end
+ end
+
+ context 'when name is class' do
+ context 'when simple' do
+ let(:original_name) { Events::MyEvent }
+ it { expect(resolved_name).to eq Events::MyEvent }
+ end
+
+ context 'when prefixed' do
+ let(:original_name) { ::Events::MyEvent }
+ it { expect(resolved_name).to eq Events::MyEvent }
+ end
+ end
+
+ context 'when name is symbol' do
+ let(:original_name) { :my_event }
+ it { expect(resolved_name).to eq Events::MyEvent }
+ end
+
+ context 'when namespace ...' do
+ before :each do
+ stub_const('MyLib::Events::MyEvent', Class.new)
+ end
+
+ context 'when is string' do
+ let!(:default_name_space) { 'MyLib::Events' }
+ let!(:original_name) { :my_event }
+
+ it { expect(resolved_name).to eq MyLib::Events::MyEvent }
+ end
+
+ context 'when is module' do
+ let!(:default_name_space) { MyLib::Events }
+ let!(:original_name) { :my_event }
+
+ it { expect(resolved_name).to eq MyLib::Events::MyEvent }
+ end
+ end
+
+ context 'when invalid' do
+ let(:original_name) { 1 }
+ it { expect { resolved_name }.to raise_error Aruba::EventNameResolveError, /Transforming "1" into an event class failed. Supported types are: Class, String, Symbol. Input type "Fixnum" of event_id "1" is invalid./ }
+ end
+ end
+end
diff --git a/spec/event_bus_spec.rb b/spec/event_bus_spec.rb
new file mode 100644
index 0000000..64e174e
--- /dev/null
+++ b/spec/event_bus_spec.rb
@@ -0,0 +1,160 @@
+require 'aruba/event_bus'
+
+# rubocop:disable Style/Documentation
+module Events
+ class TestEvent; end
+ class AnotherTestEvent; end
+ module MalformedTestEvent; end
+end
+
+class MyHandler
+ def call(*); end
+end
+
+class MyMalformedHandler; end
+# rubocop:enable Style/Documentation
+
+describe Aruba::EventBus do
+ subject(:bus) { described_class.new(name_resolver) }
+
+ let(:name_resolver) { instance_double('Events::NameResolver') }
+
+ let!(:event_klass) { Events::TestEvent }
+ let!(:event_name) { event_klass }
+ let!(:event_instance) { Events::TestEvent.new }
+
+ let!(:another_event_klass) { Events::AnotherTestEvent }
+ let!(:another_event_name) { another_event_klass }
+ let!(:another_event_instance) { Events::AnotherTestEvent.new }
+
+ describe '#notify' do
+ before(:each) do
+ allow(name_resolver).to receive(:transform).with(event_name).and_return(event_klass)
+ end
+
+ context 'when subscriber to event, the block is called and get\'s an instance of the event passed as payload' do
+ before :each do
+ bus.register(event_klass) do |event|
+ @received_payload = event
+ end
+
+ bus.notify event_instance
+ end
+
+ it { expect(@received_payload).to eq(event_instance) }
+ end
+
+ context 'when not subscriber to event' do
+ before :each do
+ @received_payload = false
+ bus.register(event_klass) { @received_payload = true }
+ bus.notify another_event_instance
+ end
+
+ it { expect(@received_payload).to eq(false) }
+ end
+
+ context 'when event is not an instance of event class' do
+ let!(:event_name) { :test_event }
+ let(:received_payload) { [] }
+
+ before :each do
+ bus.register(event_name, proc {})
+ end
+
+ it { expect { bus.notify event_klass }.to raise_error Aruba::NoEventError }
+ end
+ end
+
+ describe '#register' do
+ before(:each) do
+ allow(name_resolver).to receive(:transform).with(event_name).and_return(event_klass)
+ end
+
+ context 'when valid subscriber' do
+ context 'when multiple instances are given' do
+ let(:received_events) { [] }
+
+ before :each do
+ bus.register(Events::TestEvent) do |event|
+ received_events << event
+ end
+ bus.register(Events::TestEvent) do |event|
+ received_events << event
+ end
+
+ bus.notify event_instance
+ end
+
+ it { expect(received_events.length).to eq 2 }
+ it { expect(received_events).to all eq event_instance }
+ end
+
+ context 'when is string' do
+ let!(:event_name) { event_klass.to_s }
+ let(:received_payload) { [] }
+
+ before :each do
+ bus.register(event_klass.to_s) do |event|
+ received_payload << event
+ end
+
+ bus.notify event_instance
+ end
+
+ it { expect(received_payload).to include event_instance }
+ end
+
+ context 'when is symbol and event is defined in the default namespace given to NameResolver.new' do
+ let!(:event_name) { :test_event }
+ let(:received_payload) { [] }
+
+ before :each do
+ bus.register(event_name) do |event|
+ received_payload << event
+ end
+
+ bus.notify event_instance
+ end
+
+ it { expect(received_payload).to include event_instance }
+ end
+ end
+
+ context 'when valid custom handler' do
+ context 'when single event class' do
+ before(:each) do
+ allow(name_resolver).to receive(:transform).with(event_name).and_return(event_klass)
+ end
+
+ before :each do
+ bus.register(event_klass, MyHandler.new)
+ end
+
+ it { expect { bus.notify event_instance }.not_to raise_error }
+ end
+
+ context 'when list of event classes' do
+ before(:each) do
+ allow(name_resolver).to receive(:transform).with(event_name).and_return(event_klass)
+ allow(name_resolver).to receive(:transform).with(another_event_name).and_return(another_event_klass)
+ end
+
+ before :each do
+ bus.register([event_klass, another_event_klass], MyHandler.new)
+ end
+
+ it { expect { bus.notify event_instance }.not_to raise_error }
+ it { expect { bus.notify another_event_instance }.not_to raise_error }
+ end
+ end
+
+ context 'when malformed custom handler' do
+ it { expect { bus.register(event_klass, MyMalformedHandler.new) }.to raise_error ArgumentError }
+ end
+
+ context 'when no handler is given' do
+ it { expect { bus.register(event_klass) }.to raise_error ArgumentError }
+ end
+ end
+end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-aruba.git
More information about the Pkg-ruby-extras-commits
mailing list