New Upstream Release - ruby-ami

Ready changes

Summary

Merged new upstream version: 3.0.0 (was: 2.4.0).

Resulting package

Built on 2022-03-17T20:56 (took 6m14s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases ruby-ami

Lintian Result

Diff

diff --git a/.travis.yml b/.travis.yml
index 332471a..31ff307 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,12 @@
 language: ruby
 sudo: false
 rvm:
-  - 1.9.3
-  - 2.0.0
-  - 2.1.0
-  - jruby
-  - rbx-2.1.1
+  - 2.2.5
+  - 2.3.1
+  - jruby-9.1.2.0
   - ruby-head
 matrix:
   allow_failures:
     - rvm: ruby-head
-    - rvm: rbx-2.1.1
 notifications:
   irc: "irc.freenode.org#adhearsion"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9dfe162..016a5a6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # [develop](https://github.com/adhearsion/ruby_ami)
 
+# [3.0.0](https://github.com/adhearsion/ruby_ami/compare/v2.4.0...v3.0.0) - [2016-07-25](https://rubygems.org/gems/ruby_ami/versions/3.0.0)
+  * Breaking change: Ruby 1.9 is no longer supported. Minimum supported versions are Ruby 2.2.0 and JRuby 9.0.0.0
+  * Breaking change: Removed the deprecated `RubyAMI::Client` because it is no longer relevant.
+  * Breaking change: Start the connection when the `RubyAMI::Stream` starts, permitting supervised restart of the stream on connection failure. To support this, the event callback now passes a second parameter which is the stream itself.
+  * Feature: Optimisation of the protocol lexer
+
 # [2.4.0](https://github.com/adhearsion/ruby_ami/compare/v2.3.0...v2.4.0) - [2015-12-07](https://rubygems.org/gems/ruby_ami/versions/2.4.0)
   # Feature: Reveal the AMI version for a `Stream` via `Stream#version`
 
diff --git a/LICENSE.txt b/LICENSE.txt
index cd0d514..9cbcb02 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2011 Ben Langfeld, Jay Phillips
+Copyright (c) 2011-2016 Ben Langfeld, Jay Phillips
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/README.md b/README.md
index 54708f5..15d6c3a 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 [![Coverage Status](https://coveralls.io/repos/adhearsion/ruby_ami/badge.png?branch=develop)](https://coveralls.io/r/adhearsion/ruby_ami)
 [![Inline docs](http://inch-ci.org/github/adhearsion/ruby_ami.png?branch=develop)](http://inch-ci.org/github/adhearsion/ruby_ami)
 
-RubyAMI is an AMI client library in Ruby and based on EventMachine with the sole purpose of providing a connection to the Asterisk Manager Interface. RubyAMI does not provide any features beyond connection management and protocol parsing. Actions are sent over the wire, and responses are returned. Events are passed to a callback you define. It's up to you to match these up into something useful. In this regard, RubyAMI is very similar to [Blather](https://github.com/sprsquish/blather) for XMPP or [Punchblock](https://github.com/adhearsion/punchblock), the Ruby 3PCC library. In fact, Punchblock uses RubyAMI under the covers for its Asterisk implementation, including an implementation of AsyncAGI.
+RubyAMI is an AMI client library in Ruby based on Celluloid with the sole purpose of providing a connection to the Asterisk Manager Interface. RubyAMI does not provide any features beyond connection management and protocol parsing. Actions are sent over the wire, and responses are returned. Events are passed to a callback you define. It's up to you to match these up into something useful. In this regard, RubyAMI is very similar to [Blather](https://github.com/sprsquish/blather) for XMPP or [Punchblock](https://github.com/adhearsion/punchblock), the Ruby 3PCC library. In fact, Punchblock uses RubyAMI under the covers for its Asterisk implementation, including an implementation of AsyncAGI.
 
 NB: If you're looking to develop an application on Asterisk, you should take a look at the [Adhearsion](http://adhearsion.com) framework first. This library is much lower level.
 
@@ -21,10 +21,6 @@ In order to setup a connection to listen for AMI events, one can do:
 ```ruby
 require 'ruby_ami'
 
-stream = RubyAMI::Stream.new '127.0.0.1', 5038, 'manager', 'password',
-                              ->(e) { handle_event e },
-                              Logger.new(STDOUT), 10
-
 def handle_event(event)
   case event.name
   when 'FullyBooted'
@@ -34,7 +30,19 @@ def handle_event(event)
   end
 end
 
-$stream.run # This will block until the actor is terminated elsewhere. $stream.async.run is also available if you need to do other things in the main thread.
+stream = RubyAMI::Stream.new '127.0.0.1', 5038, 'manager', 'password',
+                              ->(e, stream) { handle_event e },
+                              Logger.new(STDOUT), 10
+
+Celluloid::Actor.join(stream) # This will block until the actor is terminated elsewhere. Otherwise, the actor will run in its own thread allowing other work to be done here.
+```
+
+Note that using `Stream.new`, the actor will shut down when the connection is lost (and in this case the program will exit). If it is necessary to restart the actor on failure, you can start it in a Celluloid supervisor:
+
+```ruby
+RubyAMI::Stream.supervise_as :ami_connection, '127.0.0.1', 5038, 'manager', 'password',
+                              ->(e, stream) { handle_event e },
+                              Logger.new(STDOUT), 10
 ```
 
 It is also possible to execute actions in response to events:
@@ -42,26 +50,24 @@ It is also possible to execute actions in response to events:
 ```ruby
 require 'ruby_ami'
 
-$stream = RubyAMI::Stream.new '127.0.0.1', 5038, 'manager', 'password',
-                              ->(e) { handle_event e },
-                              Logger.new(STDOUT), 10
-
-def handle_event(event)
+def handle_event(event, stream)
   case event.name
   when 'FullyBooted'
     puts "The connection was successful. Originating a call."
-    response = $stream.send_action 'Originate', 'Channel' => 'SIP/foo'
+    response = stream.send_action 'Originate', 'Channel' => 'SIP/foo'
     puts "The call origination resulted in #{response.inspect}"
   end
 end
 
-$stream.run
+stream = RubyAMI::Stream.new '127.0.0.1', 5038, 'manager', 'password',
+                              ->(e, stream) { handle_event e, stream },
+                              Logger.new(STDOUT), 10
+
+Celluloid::Actor.join(stream) # This will block until the actor is terminated elsewhere. Otherwise, the actor will run in its own thread allowing other work to be done here.
 ```
 
 Executing actions does not strictly have to be done within the event handler, but it is not valid to send AMI events before receiving a `FullyBooted` event. If you attempt to execute an action prior to this, it may fail, and `RubyAMI::Stream` will not help you recover or queue the action until the connection is `FullyBooted`; you must manage this timing yourself. That said, assuming you take care of this, you may invoke `RubyAMI::Stream#send_action` from anywhere in your code and it will return the response of the action.
 
-RubyAMI also has a class called `RubyAMI::Client` which used to be the main usage method. The purpose of this class was to tie together two AMI connections and separate events and action execution between the two in order to avoid some issues present in Asterisk < 1.8 with regards to separating overlapping events and executing multiple actions simultaneously. These issues are no longer present, and so **`RubyAMI::Client` is now deprecated and will be removed in RubyAMI 3.0**.
-
 ## Links:
 * [Source](https://github.com/adhearsion/ruby_ami)
 * [Documentation](http://rdoc.info/github/adhearsion/ruby_ami/master/frames)
@@ -78,4 +84,4 @@ RubyAMI also has a class called `RubyAMI::Client` which used to be the main usag
 
 ## Copyright
 
-Copyright (c) 2013 Ben Langfeld, Jay Phillips. MIT licence (see LICENSE for details).
+Copyright (c) 2011-2016 Ben Langfeld, Jay Phillips. MIT licence (see LICENSE for details).
diff --git a/debian/changelog b/debian/changelog
index 2288c92..15267b1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-ruby-ami (2.4.0-2) UNRELEASED; urgency=medium
+ruby-ami (3.0.0-1) UNRELEASED; urgency=medium
 
   [ Utkarsh Gupta ]
   * Add salsa-ci.yml
@@ -14,8 +14,9 @@ ruby-ami (2.4.0-2) UNRELEASED; urgency=medium
   * Update Vcs-* headers to use salsa repository.
   * Update watch file format version to 4.
   * Bump debhelper from old 12 to 13.
+  * New upstream release.
 
- -- Utkarsh Gupta <guptautkarsh2102@gmail.com>  Tue, 13 Aug 2019 03:26:41 +0530
+ -- Utkarsh Gupta <guptautkarsh2102@gmail.com>  Thu, 17 Mar 2022 20:50:45 -0000
 
 ruby-ami (2.4.0-1) unstable; urgency=medium
 
diff --git a/lib/ruby_ami.rb b/lib/ruby_ami.rb
index f402055..661cc57 100644
--- a/lib/ruby_ami.rb
+++ b/lib/ruby_ami.rb
@@ -17,7 +17,6 @@ end
   action
   agi_result_parser
   async_agi_environment_parser
-  client
   error
   event
   lexer
diff --git a/lib/ruby_ami/client.rb b/lib/ruby_ami/client.rb
deleted file mode 100644
index 7aab0f0..0000000
--- a/lib/ruby_ami/client.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-# encoding: utf-8
-module RubyAMI
-  class Client
-    include Celluloid
-
-    trap_exit :stream_died
-
-    attr_reader :events_stream, :actions_stream
-
-    def initialize(options)
-      @options        = options
-      @event_handler  = @options[:event_handler]
-      @state          = :stopped
-      client          = current_actor
-      @events_stream  = new_stream ->(event) { client.async.handle_event event }
-      @actions_stream = new_stream ->(message) { client.async.handle_message message }
-    end
-
-    [:started, :stopped, :ready].each do |state|
-      define_method("#{state}?") { @state == state }
-    end
-
-    def start
-      @events_stream.async.run
-      @actions_stream.async.run
-      @state = :started
-    end
-
-    def send_action(*args)
-      actions_stream.send_action *args
-    end
-
-    def handle_message(message)
-      logger.trace "[RECV-ACTIONS]: #{message.inspect}"
-      case message
-      when Stream::Connected
-        send_action 'Events', 'EventMask' => 'Off'
-      when Stream::Disconnected
-      when Event
-        pass_event message
-      end
-    end
-
-    def handle_event(event)
-      logger.trace "[RECV-EVENTS]: #{event.inspect}"
-      case event
-      when Stream::Connected, Stream::Disconnected
-      else
-        pass_event event
-      end
-    end
-
-    private
-
-    def pass_event(event)
-      @event_handler.call event if @event_handler.respond_to? :call
-    end
-
-    def new_stream(callback)
-      Stream.new_link @options[:host], @options[:port], @options[:username], @options[:password], callback, logger, @options[:timeout]
-    end
-
-    def stream_died(stream, reason = nil)
-      terminate
-    end
-
-    def logger
-      super
-    rescue
-      @logger ||= begin
-        logger = Logger
-        logger.define_singleton_method :trace, logger.method(:debug)
-        logger
-      end
-    end
-  end
-end
diff --git a/lib/ruby_ami/error.rb b/lib/ruby_ami/error.rb
index c5fce4d..6390c61 100644
--- a/lib/ruby_ami/error.rb
+++ b/lib/ruby_ami/error.rb
@@ -16,6 +16,11 @@ module RubyAMI
       @headers[key] = value
     end
 
+    def merge_headers!(hash)
+      self.message = hash['Message'] if hash.has_key?('Message')
+      @headers.merge!(hash)
+    end
+
     def action_id
       @headers['ActionID']
     end
diff --git a/lib/ruby_ami/lexer.rb b/lib/ruby_ami/lexer.rb
index 1d2ca2a..631edbc 100644
--- a/lib/ruby_ami/lexer.rb
+++ b/lib/ruby_ami/lexer.rb
@@ -88,9 +88,9 @@ module RubyAMI
 
       # Strip off the header line
       raw.slice! HEADER_SLICE
-      populate_message_body msg, raw
+      raw_index = populate_message_body msg, raw
 
-      return msg if response_follows && !handle_response_follows(msg, raw)
+      return msg if response_follows && !handle_response_follows(msg, raw[raw_index..-1])
 
       case msg
       when Error
@@ -129,11 +129,15 @@ module RubyAMI
       @delegate.syntax_error_encountered ignored_chunk
     end
 
+    # returns first char index after last match
     def populate_message_body(obj, raw)
-      while raw.slice! KEYVALUEPAIR
-        obj[$1] = $2
+      headers = raw.scan(KEYVALUEPAIR)
+      if match = $~
+        obj.merge_headers!(Hash[headers])
+        match.end(match.size - 1) + 2
+      else
+        0
       end
-      obj
     end
 
     def handle_response_follows(obj, raw)
diff --git a/lib/ruby_ami/response.rb b/lib/ruby_ami/response.rb
index ebccad9..3cda072 100644
--- a/lib/ruby_ami/response.rb
+++ b/lib/ruby_ami/response.rb
@@ -28,6 +28,10 @@ module RubyAMI
       @headers.clone
     end
 
+    def merge_headers!(hash)
+      @headers.merge!(hash)
+    end
+
     def [](arg)
       @headers[arg.to_s]
     end
diff --git a/lib/ruby_ami/stream.rb b/lib/ruby_ami/stream.rb
index 6a2ff56..44635d5 100644
--- a/lib/ruby_ami/stream.rb
+++ b/lib/ruby_ami/stream.rb
@@ -29,6 +29,7 @@ module RubyAMI
       @lexer = Lexer.new self
       @sent_actions   = {}
       @causal_actions = {}
+      async.run
     end
 
     [:started, :stopped, :ready].each do |state|
@@ -125,7 +126,7 @@ module RubyAMI
     end
 
     def fire_event(event)
-      @event_callback.call event
+      @event_callback.call event, current_actor
     end
 
     def register_sent_action(action)
diff --git a/lib/ruby_ami/version.rb b/lib/ruby_ami/version.rb
index 9c97f7a..064bf18 100644
--- a/lib/ruby_ami/version.rb
+++ b/lib/ruby_ami/version.rb
@@ -1,4 +1,4 @@
 # encoding: utf-8
 module RubyAMI
-  VERSION = "2.4.0"
+  VERSION = "3.0.0"
 end
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index c779b20..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,258 +0,0 @@
---- !ruby/object:Gem::Specification
-name: ruby_ami
-version: !ruby/object:Gem::Version
-  version: 2.4.0
-platform: ruby
-authors:
-- Ben Langfeld
-- Ben Klang
-autorequire: 
-bindir: bin
-cert_chain: []
-date: 2015-12-07 00:00:00.000000000 Z
-dependencies:
-- !ruby/object:Gem::Dependency
-  name: celluloid-io
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '0.13'
-  type: :runtime
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '0.13'
-- !ruby/object:Gem::Dependency
-  name: bundler
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '1.0'
-- !ruby/object:Gem::Dependency
-  name: rspec
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.5'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '2.5'
-- !ruby/object:Gem::Dependency
-  name: cucumber
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: yard
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '0.6'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - "~>"
-      - !ruby/object:Gem::Version
-        version: '0.6'
-- !ruby/object:Gem::Dependency
-  name: rake
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: guard-rspec
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: guard-shell
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: guard-cucumber
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: guard-rake
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-- !ruby/object:Gem::Dependency
-  name: benchmark_suite
-  requirement: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: !ruby/object:Gem::Requirement
-    requirements:
-    - - ">="
-      - !ruby/object:Gem::Version
-        version: '0'
-description: A Ruby client library for the Asterisk Management Interface built on
-  Celluloid IO.
-email:
-- ben@langfeld.me
-- bklang@mojolingo.com
-executables: []
-extensions: []
-extra_rdoc_files: []
-files:
-- ".gitignore"
-- ".rspec"
-- ".travis.yml"
-- CHANGELOG.md
-- Gemfile
-- Guardfile
-- LICENSE.txt
-- README.md
-- Rakefile
-- benchmarks/agi_env_parse.rb
-- benchmarks/lexer.rb
-- cucumber.yml
-- features/lexer.feature
-- features/step_definitions/lexer_steps.rb
-- features/support/ami_fixtures.yml
-- features/support/env.rb
-- features/support/introspective_lexer.rb
-- features/support/lexer_helper.rb
-- lib/ruby_ami.rb
-- lib/ruby_ami/action.rb
-- lib/ruby_ami/agi_result_parser.rb
-- lib/ruby_ami/async_agi_environment_parser.rb
-- lib/ruby_ami/client.rb
-- lib/ruby_ami/core_ext/celluloid.rb
-- lib/ruby_ami/error.rb
-- lib/ruby_ami/event.rb
-- lib/ruby_ami/lexer.rb
-- lib/ruby_ami/response.rb
-- lib/ruby_ami/stream.rb
-- lib/ruby_ami/version.rb
-- ruby_ami.gemspec
-- spec/ruby_ami/action_spec.rb
-- spec/ruby_ami/agi_result_parser_spec.rb
-- spec/ruby_ami/async_agi_environment_parser_spec.rb
-- spec/ruby_ami/client_spec.rb
-- spec/ruby_ami/error_spec.rb
-- spec/ruby_ami/event_spec.rb
-- spec/ruby_ami/response_spec.rb
-- spec/ruby_ami/stream_spec.rb
-- spec/spec_helper.rb
-- spec/support/mock_server.rb
-homepage: ''
-licenses: []
-metadata: {}
-post_install_message: 
-rdoc_options: []
-require_paths:
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - ">="
-    - !ruby/object:Gem::Version
-      version: '0'
-required_rubygems_version: !ruby/object:Gem::Requirement
-  requirements:
-  - - ">="
-    - !ruby/object:Gem::Version
-      version: '0'
-requirements: []
-rubyforge_project: ruby_ami
-rubygems_version: 2.4.5
-signing_key: 
-specification_version: 4
-summary: Futzing with AMI so you don't have to
-test_files:
-- features/lexer.feature
-- features/step_definitions/lexer_steps.rb
-- features/support/ami_fixtures.yml
-- features/support/env.rb
-- features/support/introspective_lexer.rb
-- features/support/lexer_helper.rb
-- spec/ruby_ami/action_spec.rb
-- spec/ruby_ami/agi_result_parser_spec.rb
-- spec/ruby_ami/async_agi_environment_parser_spec.rb
-- spec/ruby_ami/client_spec.rb
-- spec/ruby_ami/error_spec.rb
-- spec/ruby_ami/event_spec.rb
-- spec/ruby_ami/response_spec.rb
-- spec/ruby_ami/stream_spec.rb
-- spec/spec_helper.rb
-- spec/support/mock_server.rb
-has_rdoc: 
diff --git a/ruby_ami.gemspec b/ruby_ami.gemspec
index a8c3339..64d8452 100644
--- a/ruby_ami.gemspec
+++ b/ruby_ami.gemspec
@@ -13,12 +13,15 @@ Gem::Specification.new do |s|
 
   s.rubyforge_project = "ruby_ami"
 
+  s.required_ruby_version = '>= 2.2.0'
+
   s.files         = `git ls-files`.split("\n") << 'lib/ruby_ami/lexer.rb'
   s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
   s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
   s.require_paths = ["lib"]
 
   s.add_runtime_dependency %q<celluloid-io>, ["~> 0.13"]
+  s.add_runtime_dependency %q<celluloid>, ["~> 0.16.0"]
 
   s.add_development_dependency %q<bundler>, ["~> 1.0"]
   s.add_development_dependency %q<rspec>, ["~> 2.5"]
diff --git a/spec/ruby_ami/action_spec.rb b/spec/ruby_ami/action_spec.rb
index 2089126..278d4e5 100644
--- a/spec/ruby_ami/action_spec.rb
+++ b/spec/ruby_ami/action_spec.rb
@@ -15,13 +15,15 @@ module RubyAMI
     it { should_not be_complete }
 
     describe "SIPPeers actions" do
-      subject { Action.new('SIPPeers') }
-      its(:has_causal_events?) { should be true }
+      it "has causal events" do
+        Action.new('SIPPeers').has_causal_events?.should be true
+      end
     end
 
     describe "the ParkedCalls terminator event" do
-      subject { Action.new('ParkedCalls') }
-      its(:causal_event_terminator_name) { should == "parkedcallscomplete" }
+      it "knows its causal event terminator name" do
+        Action.new('ParkedCalls').causal_event_terminator_name.should == "parkedcallscomplete"
+      end
     end
 
     it "should properly convert itself into a String when additional headers are given" do
@@ -108,7 +110,7 @@ module RubyAMI
 
           it { should be_complete }
 
-          its(:response) { should be response }
+          it { subject.response.should be response }
         end
       end
     end
diff --git a/spec/ruby_ami/agi_result_parser_spec.rb b/spec/ruby_ami/agi_result_parser_spec.rb
index 54991ab..8359e27 100644
--- a/spec/ruby_ami/agi_result_parser_spec.rb
+++ b/spec/ruby_ami/agi_result_parser_spec.rb
@@ -16,46 +16,46 @@ module RubyAMI
     context 'with a simple result with no data' do
       let(:result_string) { "200%20result=123%0A" }
 
-      its(:code)      { should == 200 }
-      its(:result)    { should == 123 }
-      its(:data)      { should == '' }
-      its(:data_hash) { should == nil }
+      it { subject.code.should == 200 }
+      it { subject.result.should == 123 }
+      it { subject.data.should == '' }
+      it { subject.data_hash.should == nil }
     end
 
     context 'with a simple unescaped result with no data' do
       let(:result_string) { "200 result=123" }
 
-      its(:code)      { should == 200 }
-      its(:result)    { should == 123 }
-      its(:data)      { should == '' }
-      its(:data_hash) { should == nil }
+      it { subject.code.should == 200 }
+      it { subject.result.should == 123 }
+      it { subject.data.should == '' }
+      it { subject.data_hash.should == nil }
     end
 
     context 'with a result and data in parens' do
       let(:result_string) { "200%20result=-123%20(timeout)%0A" }
 
-      its(:code)      { should == 200 }
-      its(:result)    { should == -123 }
-      its(:data)      { should == 'timeout' }
-      its(:data_hash) { should == nil }
+      it { subject.code.should == 200 }
+      it { subject.result.should == -123 }
+      it { subject.data.should == 'timeout' }
+      it { subject.data_hash.should == nil }
     end
 
     context 'with a result and key-value data' do
       let(:result_string) { "200%20result=123%20foo=bar%0A" }
 
-      its(:code)      { should == 200 }
-      its(:result)    { should == 123 }
-      its(:data)      { should == 'foo=bar' }
-      its(:data_hash) { should == {'foo' => 'bar'} }
+      it { subject.code.should == 200 }
+      it { subject.result.should == 123 }
+      it { subject.data.should == 'foo=bar' }
+      it { subject.data_hash.should == {'foo' => 'bar'} }
     end
 
     context 'with a 5xx error' do
       let(:result_string) { "510%20Invalid%20or%20unknown%20command%0A" }
 
-      its(:code)      { should == 510 }
-      its(:result)    { should be_nil }
-      its(:data)      { should == 'Invalid or unknown command' }
-      its(:data_hash) { should be_nil }
+      it { subject.code.should == 510 }
+      it { subject.result.should be_nil }
+      it { subject.data.should == 'Invalid or unknown command' }
+      it { subject.data_hash.should be_nil }
     end
   end
 end
diff --git a/spec/ruby_ami/async_agi_environment_parser_spec.rb b/spec/ruby_ami/async_agi_environment_parser_spec.rb
index 87d84a8..f7e6593 100644
--- a/spec/ruby_ami/async_agi_environment_parser_spec.rb
+++ b/spec/ruby_ami/async_agi_environment_parser_spec.rb
@@ -9,12 +9,12 @@ module RubyAMI
 
     subject { described_class.new environment_string }
 
-    its(:to_s) { should == environment_string }
-    its(:to_s) { should_not be environment_string }
+    it { subject.to_s.should == environment_string }
+    it { subject.to_s.should_not be environment_string }
 
     describe 'retrieving a hash representation' do
-      its(:to_hash) do
-        should == {
+      it "should return a hash of attributes" do
+        subject.to_hash.should == {
           :agi_request      => 'async',
           :agi_channel      => 'SIP/1234-00000000',
           :agi_language     => 'en',
diff --git a/spec/ruby_ami/client_spec.rb b/spec/ruby_ami/client_spec.rb
deleted file mode 100644
index e698971..0000000
--- a/spec/ruby_ami/client_spec.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-# encoding: utf-8
-require 'spec_helper'
-
-module RubyAMI
-  describe Client do
-    let(:event_handler) { [] }
-
-    let(:options) do
-      {
-        :host     => '127.0.0.1',
-        :port     => 50000 - rand(1000),
-        :username => 'username',
-        :password => 'password',
-        :event_handler => lambda { |event| event_handler << event }
-      }
-    end
-
-    subject { Client.new options }
-
-    it { should be_stopped }
-
-    its(:events_stream)   { should be_a Stream }
-    its(:actions_stream)  { should be_a Stream }
-
-    it 'should return when the timeout option is specified and reached' do
-      pending
-      options[:timeout] = 2
-      options[:host] = '192.0.2.1' # unreachable IP that will generally cause a timeout (RFC 5737)
-
-      start_time = Time.now
-      subject.start
-      duration = Time.now - start_time
-
-      duration.should be_between(options[:timeout], options[:timeout] + 1)
-    end
-
-    describe 'starting up' do
-      before do
-        ms = MockServer.new
-        ms.should_receive(:receive_data).at_least :once
-        s = ServerMock.new options[:host], options[:port], ms
-        subject.async.start
-        sleep 0.2
-      end
-
-      it { should be_started }
-    end
-
-    describe 'logging in streams' do
-      context 'when the actions stream connects' do
-        let(:mock_actions_stream) { mock 'Actions Stream' }
-
-        before do
-          subject.wrapped_object.stub(:actions_stream).and_return mock_actions_stream
-        end
-
-        it 'should disable events' do
-          mock_actions_stream.should_receive(:send_action).with 'Events', 'EventMask' => 'Off'
-
-          subject.handle_message Stream::Connected.new
-        end
-      end
-    end
-
-    describe 'when the events stream disconnects' do
-      it 'should shut down the client' do
-        subject.events_stream.terminate
-        sleep 0.2
-        subject.alive?.should be_false
-      end
-    end
-
-    describe 'when the actions stream disconnects' do
-      it 'should shut down the client' do
-        subject.actions_stream.terminate
-        sleep 0.2
-        subject.alive?.should be_false
-      end
-    end
-
-    describe 'when an event is received' do
-      let(:event) { Event.new 'foobar' }
-
-      it 'should call the event handler' do
-        subject.handle_event event
-        event_handler.should == [event]
-      end
-    end
-  end
-end
diff --git a/spec/ruby_ami/error_spec.rb b/spec/ruby_ami/error_spec.rb
index dbc2563..53eb997 100644
--- a/spec/ruby_ami/error_spec.rb
+++ b/spec/ruby_ami/error_spec.rb
@@ -3,6 +3,6 @@ require 'spec_helper'
 
 module RubyAMI
   describe Error do
-    pending
+    skip
   end # Error
 end # RubyAMI
diff --git a/spec/ruby_ami/stream_spec.rb b/spec/ruby_ami/stream_spec.rb
index e687bb8..1c1c8e5 100644
--- a/spec/ruby_ami/stream_spec.rb
+++ b/spec/ruby_ami/stream_spec.rb
@@ -6,13 +6,13 @@ module RubyAMI
     let(:server_port) { 50000 - rand(1000) }
 
     def client
-      @client ||= mock('Client')
+      @client ||= double('Client')
     end
 
     before do
-      def client.message_received(message)
+      def client.message_received(message, stream)
         @messages ||= Queue.new
-        @messages << message
+        @messages << [message, stream]
       end
 
       def client.messages
@@ -31,37 +31,29 @@ module RubyAMI
 
     def mocked_server(times = nil, fake_client = nil, &block)
       mock_target = MockServer.new
-      mock_target.should_receive(:receive_data).send(*(times ? [:exactly, times] : [:at_least, 1])).with &block
+      mock_target.should_receive(:receive_data).send(*(times ? [:exactly, times] : [:at_least, 1]), &block)
       s = ServerMock.new '127.0.0.1', server_port, mock_target
-      @stream = Stream.new '127.0.0.1', server_port, username, password, lambda { |m| client.message_received m }
-      @stream.async.run
+      @stream = Stream.new '127.0.0.1', server_port, username, password, lambda { |m, stream| client.message_received m, stream }
       fake_client.call if fake_client.respond_to? :call
-      Celluloid::Actor.join s
       Timeout.timeout 5 do
+        Celluloid::Actor.join s
         Celluloid::Actor.join @stream
       end
-    end
-
-    def expect_connected_event
-      client.should_receive(:message_received).with Stream::Connected.new
-    end
-
-    def expect_disconnected_event
-      client.should_receive(:message_received).with Stream::Disconnected.new
+    rescue Timeout::Error
     end
 
     before { @sequence = 1 }
 
     describe "after connection" do
       it "should be started" do
-        expect_connected_event
-        expect_disconnected_event
-        mocked_server 0, -> { @stream.started?.should be_true }
+        mocked_server 0, -> { @stream.started?.should be true }
+        client_messages.should be == [
+          [Stream::Connected.new, @stream],
+          [Stream::Disconnected.new, @stream],
+        ]
       end
 
       it "stores the reported AMI version" do
-        expect_connected_event
-        expect_disconnected_event
         mocked_server(1, lambda {
           @stream.send_action('Command') # Just to get the server kicked in to replying using the below block
           expect(@stream.version).to eq('2.8.0')
@@ -79,8 +71,6 @@ Message: Recording started
       end
 
       it "can send an action" do
-        expect_connected_event
-        expect_disconnected_event
         mocked_server(1, lambda { @stream.send_action('Command') }) do |val, server|
           val.should == <<-ACTION
 Action: command\r
@@ -98,8 +88,6 @@ Message: Recording started
       end
 
       it "can send an action with headers" do
-        expect_connected_event
-        expect_disconnected_event
         mocked_server(1, lambda { @stream.send_action('Command', 'Command' => 'RECORD FILE evil') }) do |val, server|
           val.should == <<-ACTION
 Action: command\r
@@ -148,8 +136,6 @@ Extension '1,1,AGI(agi:async)' added into 'adhearsion-redirect' context
         let(:password) { 'jones' }
 
         it "should log itself in" do
-          expect_connected_event
-          expect_disconnected_event
           mocked_server(1, lambda { }) do |val, server|
             val.should == <<-ACTION
 Action: login\r
@@ -183,18 +169,13 @@ Cause: 0
       end
 
       client_messages.should be == [
-        Stream::Connected.new,
-        Event.new('Hangup', 'Channel' => 'SIP/101-3f3f', 'Uniqueid' => '1094154427.10', 'Cause' => '0'),
-        Stream::Disconnected.new
+        [Stream::Connected.new, @stream],
+        [Event.new('Hangup', 'Channel' => 'SIP/101-3f3f', 'Uniqueid' => '1094154427.10', 'Cause' => '0'), @stream],
+        [Stream::Disconnected.new, @stream],
       ]
     end
 
     describe 'when a response is received' do
-      before do
-        expect_connected_event
-        expect_disconnected_event
-      end
-
       it 'should be returned from #send_action' do
         response = nil
         mocked_server(1, lambda { response = @stream.send_action 'Command', 'Command' => 'RECORD FILE evil' }) do |val, server|
@@ -219,7 +200,7 @@ Message: Thanks for all the fish.
 
           EVENT
         end
-  
+
         response.should == Response.new('ActionID' => RubyAMI.new_uuid, 'Message' => 'Thanks for all the fish.')
       end
 
@@ -304,20 +285,26 @@ ActionID: #{RubyAMI.new_uuid}
     end
 
     it 'puts itself in the stopped state and fires a disconnected event when unbound' do
-      expect_connected_event
-      expect_disconnected_event
       mocked_server(1, lambda { @stream.send_data 'Foo' }) do |val, server|
         @stream.stopped?.should be false
       end
       @stream.alive?.should be false
+      client_messages.should be == [
+        [Stream::Connected.new, @stream],
+        [Stream::Disconnected.new, @stream],
+      ]
     end
   end
 
   describe Stream::Connected do
-    its(:name) { should == 'RubyAMI::Stream::Connected' }
+    it "has a name matching the class" do
+      subject.name.should == 'RubyAMI::Stream::Connected'
+    end
   end
 
   describe Stream::Disconnected do
-    its(:name) { should == 'RubyAMI::Stream::Disconnected' }
+    it "has a name matching the class" do
+      subject.name.should == 'RubyAMI::Stream::Disconnected'
+    end
   end
 end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index a623668..97744f5 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -10,6 +10,7 @@ RSpec.configure do |config|
   config.mock_with :rspec
   config.filter_run :focus => true
   config.run_all_when_everything_filtered = true
+  config.raise_errors_for_deprecations!
 
   config.before :each do
     uuid = RubyAMI.new_uuid

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/ruby_ami-3.0.0.gemspec

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/ruby/vendor_ruby/ruby_ami/client.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/ruby_ami-2.4.0.gemspec

No differences were encountered in the control files

More details

Full run details