You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by mc...@apache.org on 2015/06/03 22:30:44 UTC

[07/34] qpid-proton git commit: PROTON-799: Rearranged Ruby library.

PROTON-799: Rearranged Ruby library.

Moved files to match more closely with the new code layout for the
project.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/81a5449d
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/81a5449d
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/81a5449d

Branch: refs/heads/master
Commit: 81a5449d9b4b6a0c46d2bf2cd8e91d8d43fb2347
Parents: 78b4873
Author: Darryl L. Pierce <mc...@gmail.com>
Authored: Fri Feb 20 09:31:03 2015 -0500
Committer: Darryl L. Pierce <mc...@gmail.com>
Committed: Wed Jun 3 16:29:20 2015 -0400

----------------------------------------------------------------------
 proton-c/bindings/ruby/lib/codec/data.rb        | 788 +++++++++++++++++++
 proton-c/bindings/ruby/lib/codec/mapping.rb     | 170 ++++
 proton-c/bindings/ruby/lib/core/exceptions.rb   |  85 ++
 proton-c/bindings/ruby/lib/core/message.rb      | 621 +++++++++++++++
 proton-c/bindings/ruby/lib/messenger/filters.rb |  67 ++
 .../bindings/ruby/lib/messenger/messenger.rb    | 702 +++++++++++++++++
 .../bindings/ruby/lib/messenger/selectable.rb   | 126 +++
 .../bindings/ruby/lib/messenger/subscription.rb |  41 +
 proton-c/bindings/ruby/lib/messenger/tracker.rb |  42 +
 .../ruby/lib/messenger/tracker_status.rb        |  73 ++
 proton-c/bindings/ruby/lib/qpid_proton.rb       |  43 +-
 proton-c/bindings/ruby/lib/qpid_proton/array.rb | 173 ----
 proton-c/bindings/ruby/lib/qpid_proton/data.rb  | 788 -------------------
 .../bindings/ruby/lib/qpid_proton/described.rb  |  66 --
 .../ruby/lib/qpid_proton/exception_handling.rb  | 127 ---
 .../bindings/ruby/lib/qpid_proton/exceptions.rb |  85 --
 .../bindings/ruby/lib/qpid_proton/filters.rb    |  67 --
 proton-c/bindings/ruby/lib/qpid_proton/hash.rb  |  86 --
 .../bindings/ruby/lib/qpid_proton/mapping.rb    | 170 ----
 .../bindings/ruby/lib/qpid_proton/message.rb    | 621 ---------------
 .../bindings/ruby/lib/qpid_proton/messenger.rb  | 702 -----------------
 .../bindings/ruby/lib/qpid_proton/selectable.rb | 126 ---
 .../bindings/ruby/lib/qpid_proton/strings.rb    |  65 --
 .../ruby/lib/qpid_proton/subscription.rb        |  41 -
 .../bindings/ruby/lib/qpid_proton/tracker.rb    |  42 -
 .../ruby/lib/qpid_proton/tracker_status.rb      |  73 --
 .../bindings/ruby/lib/qpid_proton/version.rb    |  32 -
 proton-c/bindings/ruby/lib/types/array.rb       | 173 ++++
 proton-c/bindings/ruby/lib/types/described.rb   |  66 ++
 proton-c/bindings/ruby/lib/types/hash.rb        |  86 ++
 proton-c/bindings/ruby/lib/types/strings.rb     |  65 ++
 .../bindings/ruby/lib/util/error_handler.rb     | 127 +++
 proton-c/bindings/ruby/lib/util/version.rb      |  32 +
 33 files changed, 3291 insertions(+), 3280 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/codec/data.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/codec/data.rb b/proton-c/bindings/ruby/lib/codec/data.rb
new file mode 100644
index 0000000..b6b3002
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/codec/data.rb
@@ -0,0 +1,788 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # +DataError+ is raised when an error occurs while encoding
+    # or decoding data.
+    class DataError < Exception; end
+
+    # The +Data+ class provides an interface for decoding, extracting,
+    # creating, and encoding arbitrary AMQP data. A +Data+ object
+    # contains a tree of AMQP values. Leaf nodes in this tree correspond
+    # to scalars in the AMQP type system such as INT or STRING. Interior
+    # nodes in this tree correspond to compound values in the AMQP type
+    # system such as *LIST*,*MAP*, *ARRAY*, or *DESCRIBED*. The root node
+    # of the tree is the +Data+ object itself and can have an arbitrary
+    # number of children.
+    #
+    # A +Data+ object maintains the notion of the current sibling node
+    # and a current parent node. Siblings are ordered within their parent.
+    # Values are accessed and/or added by using the #next, #prev,
+    # #enter, and #exit methods to navigate to the desired location in
+    # the tree and using the supplied variety of mutator and accessor
+    # methods to access or add a value of the desired type.
+    #
+    # The mutator methods will always add a value _after_ the current node
+    # in the tree. If the current node has a next sibling the mutator method
+    # will overwrite the value on this node. If there is no current node
+    # or the current node has no next sibling then one will be added. The
+    # accessor methods always set the added/modified node to the current
+    # node. The accessor methods read the value of the current node and do
+    # not change which node is current.
+    #
+    # The following types of scalar values are supported:
+    #
+    # * *NULL*
+    # * *BOOL*
+    # * *UBYTE*
+    # * *BYTE*
+    # * *USHORT*
+    # * *SHORT*
+    # * *UINT*
+    # * *INT*
+    # * *CHAR*
+    # * *ULONG*
+    # * *LONG*
+    # * *TIMESTAMP*
+    # * *FLOAT*
+    # * *DOUBLE*
+    # * *DECIMAL32*
+    # * *DECIMAL64*
+    # * *DECIMAL128*
+    # * *UUID*
+    # * *BINARY*
+    # * *STRING*
+    # * *SYMBOL*
+    #
+    # The following types of compound values are supported:
+    #
+    # * *DESCRIBED*
+    # * *ARRAY*
+    # * *LIST*
+    # * *MAP*
+    #
+    class Data
+
+      # Creates a new instance with the specified capacity.
+      #
+      # ==== Options
+      #
+      # * capacity - the capacity
+      #
+      def initialize(capacity = 16)
+        if (!capacity.nil?) &&
+            (capacity.is_a?(Fixnum) ||
+             capacity.is_a?(Bignum))
+          @data = Cproton.pn_data(capacity)
+          @free = true
+        else
+          @data = capacity
+          @free = false
+        end
+
+        # destructor
+        ObjectSpace.define_finalizer(self, self.class.finalize!(@data))
+      end
+
+      def self.finalize!(data) # :nodoc:
+        proc {
+          Cproton.pn_data_free(data) if @free
+        }
+      end
+
+      def to_s
+        tmp = Cproton.pn_string("")
+        Cproton.pn_inspect(@data, tmp)
+        result = Cproton.pn_string_get(tmp)
+        Cproton.pn_free(tmp)
+        return result
+      end
+
+      # Clears the object.
+      def clear
+        Cproton.pn_data_clear(@data)
+      end
+
+      # Clears the current node and sets the parent to the root node.
+      #
+      # Clearing the current node sets it _before_ the first node, calling
+      # #next will advance to the first node.
+      def rewind
+        Cproton.pn_data_rewind(@data)
+      end
+
+      # Advances the current node to its next sibling and returns its types.
+      #
+      # If there is no next sibling the current node remains unchanged
+      # and nil is returned.
+      def next(print = false)
+        Cproton.pn_data_next(@data)
+      end
+
+      # Advances the current node to its previous sibling and returns its type.
+      #
+      # If there is no previous sibling then the current node remains unchanged
+      # and nil is return.
+      def prev
+        return Cproton.pn_data_prev(@data) ? type : nil
+      end
+
+      # Sets the parent node to the current node and clears the current node.
+      #
+      # Clearing the current node sets it _before_ the first child.
+      def enter
+        Cproton.pn_data_enter(@data)
+      end
+
+      # Sets the current node to the parent node and the parent node to its own
+      # parent.
+      def exit
+        Cproton.pn_data_exit(@data)
+      end
+
+      # Returns the numeric type code of the current node.
+      def type_code
+        dtype = Cproton.pn_data_type(@data)
+        return (dtype == -1) ? nil : dtype
+      end
+
+      # Return the Type object for the current node
+      def type
+        Mapping.for_code(type_code)
+      end
+
+      # Returns a representation of the data encoded in AMQP format.
+      def encode
+        buffer = "\0"*1024
+        loop do
+          cd = Cproton.pn_data_encode(@data, buffer, buffer.length)
+          if cd == Cproton::PN_OVERFLOW
+            buffer *= 2
+          elsif cd >= 0
+            return buffer[0...cd]
+          else
+            check(cd)
+          end
+        end
+      end
+
+      # Decodes the first value from supplied AMQP data and returns the number
+      # of bytes consumed.
+      #
+      # ==== Options
+      #
+      # * encoded - the encoded data
+      #
+      def decode(encoded)
+        check(Cproton.pn_data_decode(@data, encoded, encoded.length))
+      end
+
+      # Puts a list value.
+      #
+      # Elements may be filled by entering the list node and putting element
+      # values.
+      #
+      # ==== Examples
+      #
+      #   data = Qpid::Proton::Data.new
+      #   data.put_list
+      #   data.enter
+      #   data.int = 1
+      #   data.int = 2
+      #   data.int = 3
+      #   data.exit
+      #
+      def put_list
+        check(Cproton.pn_data_put_list(@data))
+      end
+
+      # If the current node is a list, this returns the number of elements.
+      # Otherwise, it returns zero.
+      #
+      # List elements can be accessed by entering the list.
+      #
+      # ==== Examples
+      #
+      #   count = @data.list
+      #   @data.enter
+      #   (0...count).each
+      #     type = @data.next
+      #     puts "Value: #{@data.string}" if type == STRING
+      #     # ... process other node types
+      #   end
+      def list
+        Cproton.pn_data_get_list(@data)
+      end
+
+      # Puts a map value.
+      #
+      # Elements may be filled by entering the map node and putting alternating
+      # key/value pairs.
+      #
+      # ==== Examples
+      #
+      #   data = Qpid::Proton::Data.new
+      #   data.put_map
+      #   data.enter
+      #   data.string = "key"
+      #   data.string = "value"
+      #   data.exit
+      #
+      def put_map
+        check(Cproton.pn_data_put_map(@data))
+      end
+
+      # If the  current node is a map, this returns the number of child
+      # elements. Otherwise, it returns zero.
+      #
+      # Key/value pairs can be accessed by entering the map.
+      #
+      # ==== Examples
+      #
+      #   count = @data.map
+      #   @data.enter
+      #   (0...count).each do
+      #     type = @data.next
+      #     puts "Key=#{@data.string}" if type == STRING
+      #     # ... process other key types
+      #     type = @data.next
+      #     puts "Value=#{@data.string}" if type == STRING
+      #     # ... process other value types
+      #   end
+      #   @data.exit
+      def map
+        Cproton.pn_data_get_map(@data)
+      end
+
+      def get_map # :nodoc:
+        ::Hash.proton_data_get(self)
+      end
+
+      # Puts an array value.
+      #
+      # Elements may be filled by entering the array node and putting the
+      # element values. The values must all be of the specified array element
+      # type.
+      #
+      # If an array is *described* then the first child value of the array
+      # is the descriptor and may be of any type.
+      #
+      # ==== Options
+      #
+      # * described - specifies whether the array is described
+      # * element_type - the type of the array elements
+      #
+      # ==== Examples
+      #
+      #   # create an array of integer values
+      #   data = Qpid::Proton::Data.new
+      #   data.put_array(false, INT)
+      #   data.enter
+      #   data.int = 1
+      #   data.int = 2
+      #   data.int = 3
+      #   data.exit
+      #
+      #   # create an array of double values
+      #   data.put_array(true, DOUBLE)
+      #   data.enter
+      #   data.symbol = "array-descriptor"
+      #   data.double = 1.1
+      #   data.double = 1.2
+      #   data.double = 1.3
+      #   data.exit
+      #
+      def put_array(described, element_type)
+        check(Cproton.pn_data_put_array(@data, described, element_type.code))
+      end
+
+      # If the current node is an array, returns a tuple of the element count, a
+      # boolean indicating whether the array is described, and the type of each
+      # element. Otherwise it returns +(0, false, nil).
+      #
+      # Array data can be accessed by entering the array.
+      #
+      # ==== Examples
+      #
+      #   # get the details of thecurrent array
+      #   count, described, array_type = @data.array
+      #
+      #   # enter the node
+      #   data.enter
+      #
+      #   # get the next node
+      #   data.next
+      #   puts "Descriptor: #{data.symbol}" if described
+      #   (0...count).each do
+      #     @data.next
+      #     puts "Element: #{@data.string}"
+      #   end
+      def array
+        count = Cproton.pn_data_get_array(@data)
+        described = Cproton.pn_data_is_array_described(@data)
+        array_type = Cproton.pn_data_get_array_type(@data)
+        return nil if array_type == -1
+        [count, described, Mapping.for_code(array_type) ]
+      end
+
+      def get_array # :nodoc:
+        ::Array.proton_get(self)
+      end
+
+      # Puts a described value.
+      #
+      # A described node has two children, the descriptor and the value.
+      # These are specified by entering the node and putting the
+      # desired values.
+      #
+      # ==== Examples
+      #
+      #   data = Qpid::Proton::Data.new
+      #   data.put_described
+      #   data.enter
+      #   data.symbol = "value-descriptor"
+      #   data.string = "the value"
+      #   data.exit
+      #
+      def put_described
+        check(Cproton.pn_data_put_described(@data))
+      end
+
+      def get_described # :nodoc:
+        raise TypeError, "not a described type" unless self.described?
+        self.enter
+        self.next
+        type = self.type
+        descriptor = type.get(self)
+        self.next
+        type = self.type
+        value = type.get(self)
+        self.exit
+        Described.new(descriptor, value)
+      end
+
+      # Checks if the current node is a described value.
+      #
+      # The described and value may be accessed by entering the described value.
+      #
+      # ==== Examples
+      #
+      #   if @data.described?
+      #     @data.enter
+      #     puts "The symbol is #{@data.symbol}"
+      #     puts "The value is #{@data.string}"
+      #   end
+      def described?
+        Cproton.pn_data_is_described(@data)
+      end
+
+      # Puts a null value.
+      def null
+        check(Cproton.pn_data_put_null(@data))
+      end
+
+      # Utility method for Qpid::Proton::Mapping
+      def null=(value) # :nodoc:
+        null
+      end
+
+      # Checks if the current node is null.
+      def null?
+        Cproton.pn_data_is_null(@data)
+      end
+
+      # Puts a boolean value.
+      #
+      # ==== Options
+      #
+      # * value - the boolean value
+      def bool=(value)
+        check(Cproton.pn_data_put_bool(@data, value))
+      end
+
+      # If the current node is a boolean, then it returns the value. Otherwise,
+      # it returns false.
+      def bool
+        Cproton.pn_data_get_bool(@data)
+      end
+
+      # Puts an unsigned byte value.
+      #
+      # ==== Options
+      #
+      # * value - the unsigned byte value
+      def ubyte=(value)
+        check(Cproton.pn_data_put_ubyte(@data, value))
+      end
+
+      # If the current node is an unsigned byte, returns its value. Otherwise,
+      # it reutrns 0.
+      def ubyte
+        Cproton.pn_data_get_ubyte(@data)
+      end
+
+      # Puts a byte value.
+      #
+      # ==== Options
+      #
+      # * value - the byte value
+      def byte=(value)
+        check(Cproton.pn_data_put_byte(@data, value))
+      end
+
+      # If the current node is an byte, returns its value. Otherwise,
+      # it returns 0.
+      def byte
+        Cproton.pn_data_get_byte(@data)
+      end
+
+      # Puts an unsigned short value.
+      #
+      # ==== Options
+      #
+      # * value - the unsigned short value
+      def ushort=(value)
+        check(Cproton.pn_data_put_ushort(@data, value))
+      end
+
+      # If the current node is an unsigned short, returns its value. Otherwise,
+      # it returns 0.
+      def ushort
+        Cproton.pn_data_get_ushort(@data)
+      end
+
+      # Puts a short value.
+      #
+      # ==== Options
+      #
+      # * value - the short value
+      def short=(value)
+        check(Cproton.pn_data_put_short(@data, value))
+      end
+
+      # If the current node is a short, returns its value. Otherwise,
+      # returns a 0.
+      def short
+        Cproton.pn_data_get_short(@data)
+      end
+
+      # Puts an unsigned integer value.
+      #
+      # ==== Options
+      #
+      # * value - the unsigned integer value
+      def uint=(value)
+        raise TypeError if value.nil?
+        raise RangeError, "invalid uint: #{value}" if value < 0
+        check(Cproton.pn_data_put_uint(@data, value))
+      end
+
+      # If the current node is an unsigned int, returns its value. Otherwise,
+      # returns 0.
+      def uint
+        Cproton.pn_data_get_uint(@data)
+      end
+
+      # Puts an integer value.
+      #
+      # ==== Options
+      #
+      # * value - the integer value
+      def int=(value)
+        check(Cproton.pn_data_put_int(@data, value))
+      end
+
+      # If the current node is an integer, returns its value. Otherwise,
+      # returns 0.
+      def int
+        Cproton.pn_data_get_int(@data)
+      end
+
+      # Puts a character value.
+      #
+      # ==== Options
+      #
+      # * value - the character value
+      def char=(value)
+        check(Cproton.pn_data_put_char(@data, value))
+      end
+
+      # If the current node is a character, returns its value. Otherwise,
+      # returns 0.
+      def char
+        Cproton.pn_data_get_char(@data)
+      end
+
+      # Puts an unsigned long value.
+      #
+      # ==== Options
+      #
+      # * value - the unsigned long value
+      def ulong=(value)
+        raise TypeError if value.nil?
+        raise RangeError, "invalid ulong: #{value}" if value < 0
+        check(Cproton.pn_data_put_ulong(@data, value))
+      end
+
+      # If the current node is an unsigned long, returns its value. Otherwise,
+      # returns 0.
+      def ulong
+        Cproton.pn_data_get_ulong(@data)
+      end
+
+      # Puts a long value.
+      #
+      # ==== Options
+      #
+      # * value - the long value
+      def long=(value)
+        check(Cproton.pn_data_put_long(@data, value))
+      end
+
+      # If the current node is a long, returns its value. Otherwise, returns 0.
+      def long
+        Cproton.pn_data_get_long(@data)
+      end
+
+      # Puts a timestamp value.
+      #
+      # ==== Options
+      #
+      # * value - the timestamp value
+      def timestamp=(value)
+        value = value.to_i if (!value.nil? && value.is_a?(Time))
+        check(Cproton.pn_data_put_timestamp(@data, value))
+      end
+
+      # If the current node is a timestamp, returns its value. Otherwise,
+      # returns 0.
+      def timestamp
+        Cproton.pn_data_get_timestamp(@data)
+      end
+
+      # Puts a float value.
+      #
+      # ==== Options
+      #
+      # * value - the float value
+      def float=(value)
+        check(Cproton.pn_data_put_float(@data, value))
+      end
+
+      # If the current node is a float, returns its value. Otherwise,
+      # returns 0.
+      def float
+        Cproton.pn_data_get_float(@data)
+      end
+
+      # Puts a double value.
+      #
+      # ==== Options
+      #
+      # * value - the double value
+      def double=(value)
+        check(Cproton.pn_data_put_double(@data, value))
+      end
+
+      # If the current node is a double, returns its value. Otherwise,
+      # returns 0.
+      def double
+        Cproton.pn_data_get_double(@data)
+      end
+
+      # Puts a decimal32 value.
+      #
+      # ==== Options
+      #
+      # * value - the decimal32 value
+      def decimal32=(value)
+        check(Cproton.pn_data_put_decimal32(@data, value))
+      end
+
+      # If the current node is a decimal32, returns its value. Otherwise,
+      # returns 0.
+      def decimal32
+        Cproton.pn_data_get_decimal32(@data)
+      end
+
+      # Puts a decimal64 value.
+      #
+      # ==== Options
+      #
+      # * value - the decimal64 value
+      def decimal64=(value)
+        check(Cproton.pn_data_put_decimal64(@data, value))
+      end
+
+      # If the current node is a decimal64, returns its value. Otherwise,
+      # it returns 0.
+      def decimal64
+        Cproton.pn_data_get_decimal64(@data)
+      end
+
+      # Puts a decimal128 value.
+      #
+      # ==== Options
+      #
+      # * value - the decimal128 value
+      def decimal128=(value)
+        raise TypeError, "invalid decimal128 value: #{value}" if value.nil?
+        value = value.to_s(16).rjust(32, "0")
+        bytes = []
+        value.scan(/(..)/) {|v| bytes << v[0].to_i(16)}
+        check(Cproton.pn_data_put_decimal128(@data, bytes))
+      end
+
+      # If the current node is a decimal128, returns its value. Otherwise,
+      # returns 0.
+      def decimal128
+        value = ""
+        Cproton.pn_data_get_decimal128(@data).each{|val| value += ("%02x" % val)}
+        value.to_i(16)
+      end
+
+      # Puts a +UUID+ value.
+      #
+      # The UUID is expected to be in the format of a string or else a 128-bit
+      # integer value.
+      #
+      # ==== Options
+      #
+      # * value - the +UUID+
+      #
+      # ==== Examples
+      #
+      #   # set a uuid value from a string value
+      #   require 'securerandom'
+      #   @data.uuid = SecureRandom.uuid
+      #
+      #   # or
+      #   @data.uuid = "fd0289a5-8eec-4a08-9283-81d02c9d2fff"
+      #
+      #   # set a uuid value from a 128-bit value
+      #   @data.uuid = 0 # sets to 00000000-0000-0000-0000-000000000000
+      #
+      def uuid=(value)
+        raise ArgumentError, "invalid uuid: #{value}" if value.nil?
+
+        # if the uuid that was submitted was numeric value, then translated
+        # it into a hex string, otherwise assume it was a string represtation
+        # and attempt to decode it
+        if value.is_a? Numeric
+          value = "%032x" % value
+        else
+          raise ArgumentError, "invalid uuid: #{value}" if !valid_uuid?(value)
+
+          value = (value[0, 8]  +
+                   value[9, 4]  +
+                   value[14, 4] +
+                   value[19, 4] +
+                   value[24, 12])
+        end
+        bytes = []
+        value.scan(/(..)/) {|v| bytes << v[0].to_i(16)}
+        check(Cproton.pn_data_put_uuid(@data, bytes))
+      end
+
+      # If the current value is a +UUID+, returns its value. Otherwise,
+      # it returns nil.
+      def uuid
+        value = ""
+        Cproton.pn_data_get_uuid(@data).each{|val| value += ("%02x" % val)}
+        value.insert(8, "-").insert(13, "-").insert(18, "-").insert(23, "-")
+      end
+
+      # Puts a binary value.
+      #
+      # ==== Options
+      #
+      # * value - the binary value
+      def binary=(value)
+        check(Cproton.pn_data_put_binary(@data, value))
+      end
+
+      # If the current node is binary, returns its value. Otherwise, it returns
+      # an empty string ("").
+      def binary
+        Qpid::Proton::BinaryString.new(Cproton.pn_data_get_binary(@data))
+      end
+
+      # Puts a unicode string value.
+      #
+      # *NOTE:* A nil value is stored as an empty string rather than as a nil.
+      #
+      # ==== Options
+      #
+      # * value - the unicode string value
+      def string=(value)
+        check(Cproton.pn_data_put_string(@data, value))
+      end
+
+      # If the current node is a string, returns its value. Otherwise, it
+      # returns an empty string ("").
+      def string
+        Qpid::Proton::UTFString.new(Cproton.pn_data_get_string(@data))
+      end
+
+      # Puts a symbolic value.
+      #
+      # ==== Options
+      #
+      # * value - the symbol name
+      def symbol=(value)
+        check(Cproton.pn_data_put_symbol(@data, value))
+      end
+
+      # If the current node is a symbol, returns its value. Otherwise, it
+      # returns an empty string ("").
+      def symbol
+        Cproton.pn_data_get_symbol(@data)
+      end
+
+      # Get the current value as a single object.
+      def get
+        type.get(self);
+      end
+
+      # Put value as an object of type type_
+      def put(value, type_);
+        type_.put(self, value);
+      end
+
+      private
+
+      def valid_uuid?(value)
+        # ensure that the UUID is in the right format
+        # xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
+        value =~ /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/
+      end
+
+      def check(err) # :nodoc:
+        if err < 0
+          raise DataError, "[#{err}]: #{Cproton.pn_data_error(@data)}"
+        else
+          return err
+        end
+      end
+    end
+  end
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/codec/mapping.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/codec/mapping.rb b/proton-c/bindings/ruby/lib/codec/mapping.rb
new file mode 100644
index 0000000..9189cbc
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/codec/mapping.rb
@@ -0,0 +1,170 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # Maps between Proton types and their Ruby native language counterparts.
+    #
+    class Mapping
+
+      attr_reader :code
+      attr_reader :put_method
+      attr_reader :get_method
+
+      # Creates a new mapping.
+      #
+      # ==== Arguments
+      #
+      # * code    - the AMQP code for this type
+      # * name    - the AMQP name for this type
+      # * klasses - the Ruby classes for this type
+      # * getter  - overrides the get method for the type
+      def initialize(code, name, klasses = nil, getter = nil)
+
+        @debug = (name == "bool")
+
+        @code = code
+        @name = name
+
+        @@by_preferred ||= {}
+        @@by_code ||= {}
+        @@by_code["#{code}"] = self
+        @@by_name ||= {}
+        @@by_name[name] = self
+        @@by_class ||= {}
+
+        unless klasses.nil?
+          klasses.each do |klass|
+            raise "entry exists for #{klass}" if @@by_class.keys.include? klass
+            @@by_class[klass] = self unless klass.nil?
+          end
+        end
+
+        @put_method = (name + "=").intern
+
+        if getter.nil?
+          @get_method = name.intern
+        else
+          @get_method = getter.intern
+        end
+      end
+
+      def to_s; @name; end
+
+      def put(data, value)
+        data.__send__(@put_method, value)
+      end
+
+      def get(data)
+        data.__send__(@get_method)
+      end
+
+      def self.for_class(klass) # :nodoc:
+        @@by_class[klass]
+      end
+
+      def self.for_code(code)
+        @@by_code["#{code}"]
+      end
+
+    end
+
+    NULL       = Mapping.new(Cproton::PN_NULL, "null", [NilClass], "nil?")
+    BOOL       = Mapping.new(Cproton::PN_BOOL, "bool", [TrueClass, FalseClass], "bool")
+    UBYTE      = Mapping.new(Cproton::PN_UBYTE, "ubyte")
+    BYTE       = Mapping.new(Cproton::PN_BYTE, "byte")
+    USHORT     = Mapping.new(Cproton::PN_USHORT, "ushort")
+    SHORT      = Mapping.new(Cproton::PN_SHORT, "short")
+    UINT       = Mapping.new(Cproton::PN_UINT, "uint")
+    INT        = Mapping.new(Cproton::PN_INT, "int")
+    CHAR       = Mapping.new(Cproton::PN_CHAR, "char")
+    ULONG      = Mapping.new(Cproton::PN_ULONG, "ulong")
+    LONG       = Mapping.new(Cproton::PN_LONG, "long", [Fixnum, Bignum])
+    TIMESTAMP  = Mapping.new(Cproton::PN_TIMESTAMP, "timestamp", [Date, Time])
+    FLOAT      = Mapping.new(Cproton::PN_FLOAT, "float")
+    DOUBLE     = Mapping.new(Cproton::PN_DOUBLE, "double", [Float])
+    DECIMAL32  = Mapping.new(Cproton::PN_DECIMAL32, "decimal32")
+    DECIMAL64  = Mapping.new(Cproton::PN_DECIMAL64, "decimal64")
+    DECIMAL128 = Mapping.new(Cproton::PN_DECIMAL128, "decimal128")
+    UUID       = Mapping.new(Cproton::PN_UUID, "uuid")
+    BINARY     = Mapping.new(Cproton::PN_BINARY, "binary")
+    STRING     = Mapping.new(Cproton::PN_STRING, "string", [String, Symbol,
+                                                           UTFString,
+                                                           BinaryString])
+
+    class << STRING # :nodoc:
+      def put(data, value)
+        # if we have a symbol then convert it to a string
+        value = value.to_s if value.is_a?(Symbol)
+
+        isutf = false
+
+        if value.is_a?(Qpid::Proton::UTFString)
+          isutf = true
+        else
+          # For Ruby 1.8 we will just treat all strings as binary.
+          # For Ruby 1.9+ we can check the encoding first to see what it is
+          if RUBY_VERSION >= "1.9"
+            # If the string is ASCII-8BIT then treat is as binary. Otherwise,
+            # try to convert it to UTF-8 and, if successful, send as that.
+            if value.encoding != Encoding::ASCII_8BIT &&
+                value.encode(Encoding::UTF_8).valid_encoding?
+              isutf = true
+            end
+          end
+        end
+
+        data.string = value if isutf
+        data.binary = value if !isutf
+
+      end
+    end
+
+    SYMBOL     = Mapping.new(Cproton::PN_SYMBOL, "symbol")
+    DESCRIBED  = Mapping.new(Cproton::PN_DESCRIBED, "described", [Qpid::Proton::Described], "get_described")
+    ARRAY      = Mapping.new(Cproton::PN_ARRAY, "array", nil, "get_array")
+    LIST       = Mapping.new(Cproton::PN_LIST, "list", [::Array], "get_array")
+    MAP        = Mapping.new(Cproton::PN_MAP, "map", [::Hash], "get_map")
+
+    class << MAP # :nodoc:
+      def put(data, map, options = {})
+        data.put_map
+        data.enter
+        map.each_pair do |key, value|
+          if options[:keys] == :SYMBOL
+            SYMBOL.put(data, key)
+          else
+            Mapping.for_class(key.class).put(data, key)
+          end
+
+          if value.nil?
+            data.null
+          else
+            Mapping.for_class(value.class).put(data, value)
+          end
+        end
+        data.exit
+      end
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/core/exceptions.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/core/exceptions.rb b/proton-c/bindings/ruby/lib/core/exceptions.rb
new file mode 100644
index 0000000..189f574
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/core/exceptions.rb
@@ -0,0 +1,85 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    module Error
+
+      NONE = 0
+      EOS = Cproton::PN_EOS
+      ERROR = Cproton::PN_ERR
+      OVERFLOW = Cproton::PN_OVERFLOW
+      UNDERFLOW = Cproton::PN_UNDERFLOW
+      STATE = Cproton::PN_STATE_ERR
+      ARGUMENT = Cproton::PN_ARG_ERR
+      TIMEOUT = Cproton::PN_TIMEOUT
+      INTERRUPTED = Cproton::PN_INTR
+      INPROGRESS = Cproton::PN_INPROGRESS
+
+    end
+
+    # Represents a generic error at the messaging level.
+    #
+    class ProtonError < RuntimeError
+    end
+
+    # Represents an end-of-stream error while messaging.
+    #
+    class EOSError < ProtonError
+    end
+
+    # Represents a data overflow exception while messaging.
+    #
+    class OverflowError < ProtonError
+    end
+
+    # Represents a data underflow exception while messaging.
+    #
+    class UnderflowError < ProtonError
+    end
+
+    # Represents an invalid, missing or illegal argument while messaging.
+    #
+    class ArgumentError < ProtonError
+    end
+
+    # Represents that the client has got into an unexpected state during
+    # messaging.
+    #
+    class StateError < ProtonError
+    end
+
+    # Represents a timeout during messaging.
+    #
+    class TimeoutError < ProtonError
+    end
+
+    # Represents an interrupting during a blocking I/O operation.
+    #
+    class InterruptedError < ProtonError
+    end
+
+    class InProgressError < ProtonError
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/core/message.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/core/message.rb b/proton-c/bindings/ruby/lib/core/message.rb
new file mode 100644
index 0000000..144990b
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/core/message.rb
@@ -0,0 +1,621 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # A Message represents an addressable quantity of data.
+    #
+    # ==== Message Body
+    #
+    # The message body can be set using the #body= method. The message will
+    # then attempt to determine how exactly to encode the content.
+    #
+    # ==== Examples
+    #
+    # To create a message for sending:
+    #
+    #   # send a simple text message
+    #   msg = Qpid::Proton::Message.new
+    #   msg.body = "STATE: update"
+    #
+    #   # send a binary chunk of data
+    #   data = File.binread("/home/qpid/binfile.tar.gz")
+    #   msg = Qpid::Proton::Message.new
+    #   msg.body = Qpid::Proton::BinaryString.new(data)
+    #
+    class Message
+
+      # Decodes a message from supplied AMQP data and returns the number
+      # of bytes consumed.
+      #
+      # ==== Options
+      #
+      # * encoded - the encoded data
+      #
+      def decode(encoded)
+        check(Cproton.pn_message_decode(@impl, encoded, encoded.length))
+
+        post_decode
+      end
+
+      def post_decode # :nodoc:
+        # decode elements from the message
+        @properties = {}
+        props = Qpid::Proton::Data.new(Cproton::pn_message_properties(@impl))
+        if props.next
+          @properties = props.type.get(props)
+        end
+        @instructions = nil
+        insts = Qpid::Proton::Data.new(Cproton::pn_message_instructions(@impl))
+        if insts.next
+          @instructions = insts.type.get(insts)
+        end
+        @annotations = nil
+        annts = Qpid::Proton::Data.new(Cproton::pn_message_annotations(@impl))
+        if annts.next
+          @annotations = annts.type.get(annts)
+        end
+        @body = nil
+        body = Qpid::Proton::Data.new(Cproton::pn_message_body(@impl))
+        if body.next
+          @body = body.type.get(body)
+        end
+      end
+
+      # Encodes the message.
+      def encode
+        pre_encode
+        size = 16
+        loop do
+          error, data = Cproton::pn_message_encode(@impl, size)
+          if error == Qpid::Proton::Error::OVERFLOW
+            size *= 2
+          else
+            check(error)
+            return data
+          end
+        end
+      end
+
+      def pre_encode # :nodoc:
+        # encode elements from the message
+        props = Qpid::Proton::Data.new(Cproton::pn_message_properties(@impl))
+        props.clear
+        Qpid::Proton::Mapping.for_class(@properties.class).put(props, @properties) unless @properties.empty?
+        insts = Qpid::Proton::Data.new(Cproton::pn_message_instructions(@impl))
+        insts.clear
+        if !@instructions.nil?
+          mapping = Qpid::Proton::Mapping.for_class(@instructions.class)
+          mapping.put(insts, @instructions)
+        end
+        annts = Qpid::Proton::Data.new(Cproton::pn_message_annotations(@impl))
+        annts.clear
+        if !@annotations.nil?
+          mapping = Qpid::Proton::Mapping.for_class(@annotations.class)
+          mapping.put(annts, @annotations, :keys => :SYMBOL)
+        end
+        body = Qpid::Proton::Data.new(Cproton::pn_message_body(@impl))
+        body.clear
+        if !@body.nil?
+          mapping = Qpid::Proton::Mapping.for_class(@body.class)
+          mapping.put(body, @body)
+        end
+      end
+
+      # Creates a new +Message+ instance.
+      def initialize
+        @impl = Cproton.pn_message
+        ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
+        @properties = {}
+        @instructions = {}
+        @annotations = {}
+        @body = nil
+      end
+
+      def to_s
+        tmp = Cproton.pn_string("")
+        Cproton.pn_inspect(@impl, tmp)
+        result = Cproton.pn_string_get(tmp)
+        Cproton.pn_free(tmp)
+        return result
+      end
+
+      # Invoked by garbage collection to clean up resources used
+      # by the underlying message implementation.
+      def self.finalize!(impl) # :nodoc:
+        proc {
+          Cproton.pn_message_free(impl)
+        }
+      end
+
+      # Returns the underlying message implementation.
+      def impl # :nodoc:
+        @impl
+      end
+
+      # Clears the state of the +Message+. This allows a single instance of
+      # +Message+ to be reused.
+      #
+      def clear
+        Cproton.pn_message_clear(@impl)
+        @properties.clear unless @properties.nil?
+        @instructions.clear unless @instructions.nil?
+        @annotations.clear unless @annotations.nil?
+        @body = nil
+      end
+
+      # Returns the most recent error number.
+      #
+      def errno
+        Cproton.pn_message_errno(@impl)
+      end
+
+      # Returns the most recent error message.
+      #
+      def error
+        Cproton.pn_error_text(Cproton.pn_message_error(@impl))
+      end
+
+      # Returns whether there is currently an error reported.
+      #
+      def error?
+        !Cproton.pn_message_errno(@impl).zero?
+      end
+
+      # Sets the durable flag.
+      #
+      # See ::durable for more details on message durability.
+      #
+      # ==== Options
+      #
+      # * state - the durable state
+      #
+      def durable=(state)
+        raise TypeError.new("state cannot be nil") if state.nil?
+        Cproton.pn_message_set_durable(@impl, state)
+      end
+
+      # Returns the durable property.
+      #
+      # The durable property indicates that the emessage should be held durably
+      # by any intermediaries taking responsibility for the message.
+      #
+      # ==== Examples
+      #
+      #  msg = Qpid::Proton::Message.new
+      #  msg.durable = true
+      #
+      def durable
+        Cproton.pn_message_is_durable(@impl)
+      end
+
+      # Sets the priority.
+      #
+      # +NOTE:+ Priority values are limited to the range [0,255].
+      #
+      # ==== Options
+      #
+      # * priority - the priority value
+      #
+      def priority=(priority)
+        raise TypeError.new("invalid priority: #{priority}") if priority.nil? || !([Float, Fixnum].include?(priority.class))
+        raise RangeError.new("priority out of range: #{priority}") if ((priority > 255) || (priority < 0))
+        Cproton.pn_message_set_priority(@impl, priority.floor)
+      end
+
+      # Returns the priority.
+      #
+      def priority
+        Cproton.pn_message_get_priority(@impl)
+      end
+
+      # Sets the time-to-live for the message.
+      #
+      # ==== Options
+      #
+      # * time - the time in milliseconds
+      #
+      def ttl=(time)
+        raise TypeError.new("invalid ttl: #{time}") if time.nil? || !([Float, Fixnum].include?(time.class))
+        raise RangeError.new("time out of range: #{time}") if ((time < 0))
+        Cproton.pn_message_set_ttl(@impl, time.floor)
+      end
+
+      # Returns the time-to-live, in milliseconds.
+      #
+      def ttl
+        Cproton.pn_message_get_ttl(@impl)
+      end
+
+      # Sets whether this is the first time the message was acquired.
+      #
+      # See ::first_acquirer? for more details.
+      #
+      # ==== Options
+      #
+      # * state - true if claiming the message
+      #
+      def first_acquirer=(state)
+        raise TypeError.new("invalid state: #{state}") if state.nil? || !([TrueClass, FalseClass].include?(state.class))
+        Cproton.pn_message_set_first_acquirer(@impl, state)
+      end
+
+      # Sets the delivery count for the message.
+      #
+      # See ::delivery_count for more details.
+      #
+      # ==== Options
+      #
+      # * count - the delivery count
+      #
+      def delivery_count=(count)
+        raise ArgumentError.new("invalid count: #{count}") if count.nil? || !([Float, Fixnum].include?(count.class))
+        raise RangeError.new("count out of range: #{count}") if count < 0
+
+        Cproton.pn_message_set_delivery_count(@impl, count.floor)
+      end
+
+      # Returns the delivery count for the message.
+      #
+      # This is the number of delivery attempts for the given message.
+      #
+      def delivery_count
+        Cproton.pn_message_get_delivery_count(@impl)
+      end
+
+      # Returns whether this is the first acquirer.
+      #
+      #
+      def first_acquirer?
+        Cproton.pn_message_is_first_acquirer(@impl)
+      end
+
+      # Sets the message id.
+      #
+      # ==== Options
+      #
+      # * id = the id
+      #
+      def id=(id)
+        Cproton.pn_message_set_id(@impl, id)
+      end
+
+      # Returns the message id.
+      #
+      def id
+        Cproton.pn_message_get_id(@impl)
+      end
+
+      # Sets the user id.
+      #
+      # ==== Options
+      #
+      # * id - the user id
+      #
+      def user_id=(id)
+        Cproton.pn_message_set_user_id(@impl, id)
+      end
+
+      # Returns the user id.
+      #
+      def user_id
+        Cproton.pn_message_get_user_id(@impl)
+      end
+
+      # Sets the destination address.
+      #
+      # ==== Options
+      #
+      # * address - the address
+      #
+      def address=(address)
+        Cproton.pn_message_set_address(@impl, address)
+      end
+
+      # Returns the destination address.
+      #
+      def address
+        Cproton.pn_message_get_address(@impl)
+      end
+
+      # Sets the subject.
+      #
+      # ==== Options
+      #
+      # * subject - the subject
+      #
+      def subject=(subject)
+        Cproton.pn_message_set_subject(@impl, subject)
+      end
+
+      # Returns the subject
+      #
+      def subject
+        Cproton.pn_message_get_subject(@impl)
+      end
+
+      # Sets the reply-to address.
+      #
+      # ==== Options
+      #
+      # * address - the reply-to address
+      #
+      def reply_to=(address)
+        Cproton.pn_message_set_reply_to(@impl, address)
+      end
+
+      # Returns the reply-to address
+      #
+      def reply_to
+        Cproton.pn_message_get_reply_to(@impl)
+      end
+
+      # Sets the correlation id.
+      #
+      # ==== Options
+      #
+      # * id - the correlation id
+      #
+      def correlation_id=(id)
+        Cproton.pn_message_set_correlation_id(@impl, id)
+      end
+
+      # Returns the correlation id.
+      #
+      def correlation_id
+        Cproton.pn_message_get_correlation_id(@impl)
+      end
+
+      # Sets the message format.
+      #
+      # See MessageFormat for more details on formats.
+      #
+      # *Warning:* This method has been deprecated.
+      #
+      # ==== Options
+      #
+      # * format - the format
+      #
+      def format=(format)
+        raise TypeError.new("invalid message format: #{format}") if (format.nil? || !format.kind_of?(Qpid::Proton::MessageFormat))
+        Cproton.pn_message_set_format(@impl, format.value)
+      end
+
+      # Returns the message format
+      #
+      # *Warning:* This method has been deprecated.
+      #
+      # ==== Note
+      #
+      # This method is now deprecated.
+      #
+      def format
+        Qpid::Proton::MessageFormat.by_value(Cproton.pn_message_get_format(@impl))
+      end
+
+      # Sets the content type.
+      #
+      # ==== Options
+      #
+      # * content_type - the content type
+      #
+      def content_type=(content_type)
+        Cproton.pn_message_set_content_type(@impl, content_type)
+      end
+
+      # Returns the content type
+      #
+      def content_type
+        Cproton.pn_message_get_content_type(@impl)
+      end
+
+      # Sets the content encoding type.
+      #
+      # ==== Options
+      #
+      # * encoding - the content encoding
+      #
+      def content_encoding=(encoding)
+        Cproton.pn_message_set_content_encoding(@impl, encoding)
+      end
+
+      # Returns the content encoding type.
+      #
+      def content_encoding
+        Cproton.pn_message_get_content_encoding(@impl)
+      end
+
+      # Sets the expiration time.
+      #
+      # ==== Options
+      #
+      # * time - the expiry time
+      #
+      def expires=(time)
+        raise TypeError.new("invalid expiry time: #{time}") if time.nil?
+        raise ArgumentError.new("expiry time cannot be negative: #{time}") if time < 0
+        Cproton.pn_message_set_expiry_time(@impl, time)
+      end
+
+      # Returns the expiration time.
+      #
+      def expires
+        Cproton.pn_message_get_expiry_time(@impl)
+      end
+
+      # Sets the creation time.
+      #
+      # ==== Options
+      #
+      # * time - the creation time
+      #
+      def creation_time=(time)
+        raise TypeError.new("invalid time: #{time}") if time.nil?
+        raise ArgumentError.new("time cannot be negative") if time < 0
+        Cproton.pn_message_set_creation_time(@impl, time)
+      end
+
+      # Returns the creation time.
+      #
+      def creation_time
+        Cproton.pn_message_get_creation_time(@impl)
+      end
+
+      # Sets the group id.
+      #
+      # ==== Options
+      #
+      # * id - the group id
+      #
+      def group_id=(id)
+        Cproton.pn_message_set_group_id(@impl, id)
+      end
+
+      # Returns the group id.
+      #
+      def group_id
+        Cproton.pn_message_get_group_id(@impl)
+      end
+
+      # Sets the group sequence number.
+      #
+      # ==== Options
+      #
+      # * seq - the sequence number
+      #
+      def group_sequence=(seq)
+        raise TypeError.new("invalid seq: #{seq}") if seq.nil?
+        Cproton.pn_message_set_group_sequence(@impl, seq)
+      end
+
+      # Returns the group sequence number.
+      #
+      def group_sequence
+        Cproton.pn_message_get_group_sequence(@impl)
+      end
+
+      # Sets the reply-to group id.
+      #
+      # ==== Options
+      #
+      # * id - the id
+      #
+      def reply_to_group_id=(id)
+        Cproton.pn_message_set_reply_to_group_id(@impl, id)
+      end
+
+      # Returns the reply-to group id.
+      #
+      def reply_to_group_id
+        Cproton.pn_message_get_reply_to_group_id(@impl)
+      end
+
+      # Returns the list of property names for associated with this message.
+      #
+      # ==== Examples
+      #
+      #   msg.properties.each do |name|
+      #   end
+      #
+      def properties
+        @properties
+      end
+
+      # Replaces the entire set of properties with the specified hash.
+      #
+      def properties=(properties)
+        @properties = properties
+      end
+
+      # Assigns the value given to the named property.
+      #
+      # ==== Arguments
+      #
+      # * name - the property name
+      # * value - the property value
+      #
+      def []=(name, value)
+        @properties[name] = value
+      end
+
+      # Retrieves the value for the specified property name. If not found, then
+      # it returns nil.
+      #
+      def [](name)
+        @properties[name]
+      end
+
+      # Deletes the named property.
+      #
+      def delete_property(name)
+        @properties.delete(name)
+      end
+
+      # Returns the instructions for this message.
+      #
+      def instructions
+        @instructions
+      end
+
+      # Assigns instructions to this message.
+      #
+      def instructions=(instr)
+        @instructions = instr
+      end
+
+      # Returns the annotations for this message.
+      #
+      def annotations
+        @annotations
+      end
+
+      # Assigns annotations to this message.
+      #
+      def annotations=(annotations)
+        @annotations = annotations
+      end
+
+      # Returns the body property of the message.
+      #
+      def body
+        @body
+      end
+
+      # Assigns a new value to the body of the message.
+      #
+      def body=(body)
+        @body = body
+      end
+
+      private
+
+      def check(err) # :nodoc:
+        if err < 0
+          raise DataError, "[#{err}]: #{Cproton.pn_message_error(@impl)}"
+        else
+          return err
+        end
+      end
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/messenger/filters.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/messenger/filters.rb b/proton-c/bindings/ruby/lib/messenger/filters.rb
new file mode 100644
index 0000000..370d017
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/messenger/filters.rb
@@ -0,0 +1,67 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    module Filters
+
+      def self.included(base)
+        base.class_eval do
+          extend ClassMethods
+        end
+      end
+
+      module ClassMethods
+
+        def method_added(method_name)
+          @@hooked_methods ||= []
+          return if @@hooked_methods.include?(method_name)
+          @@hooked_methods << method_name
+          hooks = @@before_hooks[method_name]
+          return if hooks.nil?
+          orig_method = instance_method(method_name)
+          define_method(method_name) do |*args, &block|
+            hooks = @@before_hooks[method_name]
+            hooks.each do |hook|
+              method(hook).call
+            end
+
+            orig_method.bind(self).call(*args, &block)
+          end
+        end
+
+        def call_before(before_method, *methods)
+          @@before_hooks ||= {}
+          methods.each do |method|
+            hooks = @@before_hooks[method] || []
+            raise "Repeat filter: #{before_method}" if hooks.include? before_method
+            hooks << before_method
+            @@before_hooks[method] = hooks
+          end
+        end
+
+      end
+
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/messenger/messenger.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/messenger/messenger.rb b/proton-c/bindings/ruby/lib/messenger/messenger.rb
new file mode 100644
index 0000000..5a16c50
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/messenger/messenger.rb
@@ -0,0 +1,702 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # The +Messenger+ class defines a high level interface for
+    # sending and receiving Messages. Every Messenger contains
+    # a single logical queue of incoming messages and a single
+    # logical queue of outgoing messages. These messages in these
+    # queues may be destined for, or originate from, a variety of
+    # addresses.
+    #
+    # The messenger interface is single-threaded.  All methods
+    # except one ( #interrupt ) are intended to be used from within
+    # the messenger thread.
+    #
+    # === Sending & Receiving Messages
+    #
+    # The Messenger class works in conjuction with the Message class. The
+    # Message class is a mutable holder of message content.
+    #
+    # The put method copies its Message to the outgoing queue, and may
+    # send queued messages if it can do so without blocking.  The send
+    # method blocks until it has sent the requested number of messages,
+    # or until a timeout interrupts the attempt.
+    #
+    # Similarly, the recv method receives messages into the incoming
+    # queue, and may block as it attempts to receive the requested number
+    # of messages,  or until timeout is reached. It may receive fewer
+    # than the requested number.  The get method pops the
+    # eldest Message off the incoming queue and copies it into the Message
+    # object that you supply.  It will not block.
+    #
+    # The blocking attribute allows you to turn off blocking behavior entirely,
+    # in which case send and recv will do whatever they can without
+    # blocking, and then return.  You can then look at the number
+    # of incoming and outgoing messages to see how much outstanding work
+    # still remains.
+    #
+    class Messenger
+
+      include Qpid::Proton::ExceptionHandling
+
+      can_raise_exception [:send, :receive, :password=, :start, :stop,
+                           :perform_put, :perform_get, :interrupt,
+                           :route, :rewrite, :accept, :reject,
+                           :incoming_window=, :outgoing_window=]
+
+      # Creates a new +Messenger+.
+      #
+      # The +name+ parameter is optional. If one is not provided then
+      # a unique name is generated.
+      #
+      # ==== Options
+      #
+      # * name - the name (def. nil)
+      #
+      def initialize(name = nil)
+        @impl = Cproton.pn_messenger(name)
+        @selectables = {}
+        ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
+      end
+
+      def self.finalize!(impl) # :nodoc:
+        proc {
+          Cproton.pn_messenger_free(impl)
+        }
+      end
+
+      # Returns the name.
+      #
+      def name
+        Cproton.pn_messenger_name(@impl)
+      end
+
+      # This property contains the password for the Messenger.private_key
+      # file, or +nil+ if the file is not encrypted.
+      #
+      # ==== Arguments
+      #
+      # * password - the password
+      #
+      def password=(password)
+        Cproton.pn_messenger_set_password(@impl, password)
+      end
+
+      # Returns the password property for the Messenger.private_key file.
+      #
+      def password
+        Cproton.pn_messenger_get_password(@impl)
+      end
+
+      # Sets the timeout period, in milliseconds.
+      #
+      # A negative timeout period implies an infinite timeout.
+      #
+      # ==== Options
+      #
+      # * timeout - the timeout period
+      #
+      def timeout=(timeout)
+        raise TypeError.new("invalid timeout: #{timeout}") if timeout.nil?
+        Cproton.pn_messenger_set_timeout(@impl, timeout)
+      end
+
+      # Returns the timeout period
+      #
+      def timeout
+        Cproton.pn_messenger_get_timeout(@impl)
+      end
+
+      # Returns true if blocking mode is enabled.
+      #
+      # Enable or disable blocking behavior during message sending
+      # and receiving.  This affects every blocking call, with the
+      # exception of work().  Currently, the affected calls are
+      # send, recv, and stop.
+      def blocking?
+        Cproton.pn_messenger_is_blocking(@impl)
+      end
+
+      # Sets the blocking mode.
+      def blocking=(blocking)
+        Cproton.pn_messenger_set_blocking(@impl, blocking)
+      end
+
+      # Returns true if passive mode is enabled.
+      #
+      def passive?
+        Cproton.pn_messenger_is_passive(@impl)
+      end
+
+      # Turns passive mode on or off.
+      #
+      # When set to passive mode, Messenger will not attempt to perform I/O
+      # operations internally. In this mode it is necesssary to use the
+      # Selectable type to drive any I/O needed to perform requestioned
+      # actions.
+      #
+      # In this mode Messenger will never block.
+      #
+      def passive=(mode)
+        Cproton.pn_messenger_set_passive(@impl, mode)
+      end
+
+      def deadline
+        tstamp = Cproton.pn_messenger_deadline(@impl)
+        return tstamp / 1000.0 unless tstamp.nil?
+      end
+
+      # Reports whether an error occurred.
+      #
+      def error?
+        !Cproton.pn_messenger_errno(@impl).zero?
+      end
+
+      # Returns the most recent error number.
+      #
+      def errno
+        Cproton.pn_messenger_errno(@impl)
+      end
+
+      # Returns the most recent error message.
+      #
+      def error
+        Cproton.pn_error_text(Cproton.pn_messenger_error(@impl))
+      end
+
+      # Clears the current error state.
+      #
+      def clear_error
+        error = Cproton.pn_messenger_error(@impl)
+        unless error.nil?
+          Cproton.pn_error_clear(error)
+        end
+      end
+
+      # Currently a no-op placeholder.
+      # For future compatibility, do not send or recv messages
+      # before starting the +Messenger+.
+      #
+      def start
+        Cproton.pn_messenger_start(@impl)
+      end
+
+      # Stops the +Messenger+, preventing it from sending or receiving
+      # any more messages.
+      #
+      def stop
+        Cproton.pn_messenger_stop(@impl)
+      end
+
+      # Returns true if a Messenger is in the stopped state.
+      # This function does not block.
+      #
+      def stopped?
+        Cproton.pn_messenger_stopped(@impl)
+      end
+
+      # Subscribes the Messenger to messages originating from the
+      # specified source. The source is an address as specified in the
+      # Messenger introduction with the following addition. If the
+      # domain portion of the address begins with the '~' character, the
+      # Messenger will interpret the domain as host/port, bind to it,
+      # and listen for incoming messages. For example "~0.0.0.0",
+      # "amqp://~0.0.0.0" will all bind to any local interface and
+      # listen for incoming messages.  An address of "amqps://~0.0.0.0"
+      # will only permit incoming SSL connections.
+      #
+      # ==== Options
+      #
+      # * address - the source address to be subscribe
+      # * timeout - an optional time-to-live value, in seconds, for the
+      #             subscription
+      #
+      def subscribe(address, timeout=0)
+        raise TypeError.new("invalid address: #{address}") if address.nil?
+        subscription = Cproton.pn_messenger_subscribe_ttl(@impl, address, timeout)
+        raise Qpid::Proton::ProtonError.new("Subscribe failed") if subscription.nil?
+        Qpid::Proton::Subscription.new(subscription)
+      end
+
+      # Path to a certificate file for the +Messenger+.
+      #
+      # This certificate is used when the +Messenger+ accepts or establishes
+      # SSL/TLS connections.  This property must be specified for the
+      # Messenger to accept incoming SSL/TLS connections and to establish
+      # client authenticated outgoing SSL/TLS connection.  Non client authenticated
+      # outgoing SSL/TLS connections do not require this property.
+      #
+      # ==== Options
+      #
+      # * certificate - the certificate
+      #
+      def certificate=(certificate)
+        Cproton.pn_messenger_set_certificate(@impl, certificate)
+      end
+
+      # Returns the path to a certificate file.
+      #
+      def certificate
+        Cproton.pn_messenger_get_certificate(@impl)
+      end
+
+      # Path to a private key file for the +Messenger+.
+      #
+      # The property must be specified for the +Messenger+ to accept incoming
+      # SSL/TLS connections and to establish client authenticated outgoing
+      # SSL/TLS connections.  Non client authenticated SSL/TLS connections
+      # do not require this property.
+      #
+      # ==== Options
+      #
+      # * key - the key file
+      #
+      def private_key=(key)
+        Cproton.pn_messenger_set_private_key(@impl, key)
+      end
+
+      # Returns the path to a private key file.
+      #
+      def private_key
+        Cproton.pn_messenger_get_private_key(@impl)
+      end
+
+      # A path to a database of trusted certificates for use in verifying the
+      # peer on an SSL/TLS connection. If this property is +nil+, then the
+      # peer will not be verified.
+      #
+      # ==== Options
+      #
+      # * certificates - the certificates path
+      #
+      def trusted_certificates=(certificates)
+        Cproton.pn_messenger_set_trusted_certificates(@impl,certificates)
+      end
+
+      # The path to the databse of trusted certificates.
+      #
+      def trusted_certificates
+        Cproton.pn_messenger_get_trusted_certificates(@impl)
+      end
+
+      # Places the content contained in the message onto the outgoing
+      # queue of the Messenger.
+      #
+      # This method will never block, however it will send any unblocked
+      # Messages in the outgoing queue immediately and leave any blocked
+      # Messages remaining in the outgoing queue.
+      # The send call may then be used to block until the outgoing queue
+      # is empty.  The outgoing attribute may be used to check the depth
+      # of the outgoing queue.
+      #
+      # ==== Options
+      #
+      # * message - the message
+      #
+      def put(message)
+        raise TypeError.new("invalid message: #{message}") if message.nil?
+        raise ArgumentError.new("invalid message type: #{message.class}") unless message.kind_of?(Message)
+        # encode the message first
+        message.pre_encode
+        perform_put(message)
+        return outgoing_tracker
+      end
+
+      private
+
+      def perform_put(message) # :nodoc:
+        Cproton.pn_messenger_put(@impl, message.impl)
+      end
+
+      public
+
+
+      # This call will block until the indicated number of messages
+      # have been sent, or until the operation times out.
+      # If n is -1 this call will block until all outgoing messages
+      # have been sent. If n is 0 then this call will send whatever
+      # it can without blocking.
+      #
+      def send(n = -1)
+        Cproton.pn_messenger_send(@impl, n)
+      end
+
+      # Moves the message from the head of the incoming message queue into
+      # the supplied message object. Any content in the supplied message
+      # will be overwritten.
+      # A tracker for the incoming Message is returned.  The tracker can
+      # later be used to communicate your acceptance or rejection of the
+      # Message.
+      #
+      # If no message is provided in the argument, then one is created. In
+      # either case, the one returned will be the fetched message.
+      #
+      # ==== Options
+      #
+      # * msg - the (optional) +Message+ instance to be used
+      #
+      def get(msg = nil)
+        msg_impl = nil
+        if msg.nil? then
+          msg_impl = nil
+        else
+          msg_impl = msg.impl
+        end
+        perform_get(msg_impl)
+        msg.post_decode unless msg.nil?
+        return incoming_tracker
+      end
+
+      private
+
+      def perform_get(msg) # :nodoc:
+        Cproton.pn_messenger_get(@impl, msg)
+      end
+
+      public
+
+      # Receives up to limit messages into the incoming queue.  If no value
+      # for limit is supplied, this call will receive as many messages as it
+      # can buffer internally.  If the Messenger is in blocking mode, this
+      # call will block until at least one Message is available in the
+      # incoming queue.
+      #
+      # Options ====
+      #
+      # * limit - the maximum number of messages to receive
+      #
+      def receive(limit = -1)
+        Cproton.pn_messenger_recv(@impl, limit)
+      end
+
+      # Returns true if the messenger is currently receiving data.
+      def receiving?
+        Cproton.pn_messenger_receiving(@impl)
+      end
+
+      # Attempts interrupting of the messenger thread.
+      #
+      # The Messenger interface is single-threaded, and this is the only
+      # function intended to be called from outside of is thread.
+      #
+      # Call this from a non-Messenger thread to interrupt it while it
+      # is blocking. This will cause a ::InterruptError to be raised.
+      #
+      # If there is no currently blocking call, then the next blocking
+      # call will be affected, even if it is within the same thread that
+      # originated the interrupt.
+      #
+      def interrupt
+        Cproton.pn_messenger_interrupt(@impl)
+      end
+
+      # Sends or receives any outstanding messages queued for a Messenger.
+      #
+      # This will block for the indicated timeout.  This method may also do I/O
+      # other than sending and receiving messages.  For example, closing
+      # connections after stop() has been called.
+      #
+      def work(timeout=-1)
+        err = Cproton.pn_messenger_work(@impl, timeout)
+        if (err == Cproton::PN_TIMEOUT) then
+          return false
+        else
+          check_for_error(err)
+          return true
+        end
+      end
+
+      # Returns the number messages in the outgoing queue that have not been
+      # transmitted.
+      #
+      def outgoing
+        Cproton.pn_messenger_outgoing(@impl)
+      end
+
+      # Returns the number of messages in the incoming queue that have not
+      # been retrieved.
+      #
+      def incoming
+        Cproton.pn_messenger_incoming(@impl)
+      end
+
+      # Adds a routing rule to the Messenger's internal routing table.
+      #
+      # The route procedure may be used to influence how a Messenger will
+      # internally treat a given address or class of addresses. Every call
+      # to the route procedure will result in Messenger appending a routing
+      # rule to its internal routing table.
+      #
+      # Whenever a Message is presented to a Messenger for delivery, it
+      # will match the address of this message against the set of routing
+      # rules in order. The first rule to match will be triggered, and
+      # instead of routing based on the address presented in the message,
+      # the Messenger will route based on the address supplied in the rule.
+      #
+      # The pattern matching syntax supports two types of matches, a '%'
+      # will match any character except a '/', and a '*' will match any
+      # character including a '/'.
+      #
+      # A routing address is specified as a normal AMQP address, however it
+      # may additionally use substitution variables from the pattern match
+      # that triggered the rule.
+      #
+      # ==== Arguments
+      #
+      # * pattern - the address pattern
+      # * address - the target address
+      #
+      # ==== Examples
+      #
+      #   # route messages sent to foo to the destionaty amqp://foo.com
+      #   messenger.route("foo", "amqp://foo.com")
+      #
+      #   # any message to foobar will be routed to amqp://foo.com/bar
+      #   messenger.route("foobar", "amqp://foo.com/bar")
+      #
+      #   # any message to bar/<path> will be routed to the same path within
+      #   # the amqp://bar.com domain
+      #   messenger.route("bar/*", "amqp://bar.com/$1")
+      #
+      #   # route all Message objects over TLS
+      #   messenger.route("amqp:*", "amqps:$1")
+      #
+      #   # supply credentials for foo
+      #   messenger.route("amqp://foo.com/*", "amqp://user:password@foo.com/$1")
+      #
+      #   # supply credentials for all domains
+      #   messenger.route("amqp://*", "amqp://user:password@$1")
+      #
+      #   # route all addresses through a single proxy while preserving the
+      #   # original destination
+      #   messenger.route("amqp://%$/*", "amqp://user:password@proxy/$1/$2")
+      #
+      #   # route any address through a single broker
+      #   messenger.route("*", "amqp://user:password@broker/$1")
+      #
+      def route(pattern, address)
+        Cproton.pn_messenger_route(@impl, pattern, address)
+      end
+
+      # Similar to #route, except that the destination of
+      # the Message is determined before the message address is rewritten.
+      #
+      # The outgoing address is only rewritten after routing has been
+      # finalized.  If a message has an outgoing address of
+      # "amqp://0.0.0.0:5678", and a rewriting rule that changes its
+      # outgoing address to "foo", it will still arrive at the peer that
+      # is listening on "amqp://0.0.0.0:5678", but when it arrives there,
+      # the receiver will see its outgoing address as "foo".
+      #
+      # The default rewrite rule removes username and password from addresses
+      # before they are transmitted.
+      #
+      # ==== Arguments
+      #
+      # * pattern - the outgoing address
+      # * address - the target address
+      #
+      def rewrite(pattern, address)
+        Cproton.pn_messenger_rewrite(@impl, pattern, address)
+      end
+
+      def selectable
+        impl = Cproton.pn_messenger_selectable(@impl)
+
+        # if we don't have any selectables, then return
+        return nil if impl.nil?
+
+        fd = Cproton.pn_selectable_fd(impl)
+
+        selectable = @selectables[fd]
+        if selectable.nil?
+          selectable = Selectable.new(self, impl)
+          @selectables[fd] = selectable
+        end
+        return selectable
+      end
+
+      # Returns a +Tracker+ for the message most recently sent via the put
+      # method.
+      #
+      def outgoing_tracker
+        impl = Cproton.pn_messenger_outgoing_tracker(@impl)
+        return nil if impl == -1
+        Qpid::Proton::Tracker.new(impl)
+      end
+
+      # Returns a +Tracker+ for the most recently received message.
+      #
+      def incoming_tracker
+        impl = Cproton.pn_messenger_incoming_tracker(@impl)
+        return nil if impl == -1
+        Qpid::Proton::Tracker.new(impl)
+      end
+
+      # Signal the sender that you have acted on the Message
+      # pointed to by the tracker.  If no tracker is supplied,
+      # then all messages that have been returned by the get
+      # method are accepted, except those that have already been
+      # auto-settled by passing beyond your incoming window size.
+      #
+      # ==== Options
+      #
+      # * tracker - the tracker
+      #
+      def accept(tracker = nil)
+        raise TypeError.new("invalid tracker: #{tracker}") unless tracker.nil? or valid_tracker?(tracker)
+        if tracker.nil? then
+          tracker = self.incoming_tracker
+          flag = Cproton::PN_CUMULATIVE
+        else
+          flag = 0
+        end
+        Cproton.pn_messenger_accept(@impl, tracker.impl, flag)
+      end
+
+      # Rejects the incoming message identified by the tracker.
+      # If no tracker is supplied, all messages that have been returned
+      # by the get method are rejected, except those that have already
+      # been auto-settled by passing beyond your outgoing window size.
+      #
+      # ==== Options
+      #
+      # * tracker - the tracker
+      #
+      def reject(tracker)
+        raise TypeError.new("invalid tracker: #{tracker}") unless tracker.nil? or valid_tracker?(tracker)
+        if tracker.nil? then
+          tracker = self.incoming_tracker
+          flag = Cproton::PN_CUMULATIVE
+        else
+          flag = 0
+        end
+        Cproton.pn_messenger_reject(@impl, tracker.impl, flag)
+      end
+
+      # Gets the last known remote state of the delivery associated with
+      # the given tracker, as long as the Message is still within your
+      # outgoing window. (Also works on incoming messages that are still
+      # within your incoming queue. See TrackerStatus for details on the
+      # values returned.
+      #
+      # ==== Options
+      #
+      # * tracker - the tracker
+      #
+      def status(tracker)
+        raise TypeError.new("invalid tracker: #{tracker}") unless valid_tracker?(tracker)
+        Qpid::Proton::TrackerStatus.by_value(Cproton.pn_messenger_status(@impl, tracker.impl))
+      end
+
+      # Frees a Messenger from tracking the status associated
+      # with a given tracker. If you don't supply a tracker, all
+      # outgoing messages up to the most recent will be settled.
+      #
+      # ==== Options
+      #
+      # * tracker - the tracker
+      #
+      # ==== Examples
+      #
+      def settle(tracker)
+        raise TypeError.new("invalid tracker: #{tracker}") unless valid_tracker?(tracker)
+        if tracker.nil? then
+          tracker = self.incoming_tracker
+          flag = Cproton::PN_CUMULATIVE
+        else
+          flag = 0
+        end
+        Cproton.pn_messenger_settle(@impl, tracker.impl, flag)
+      end
+
+      # Sets the incoming window.
+      #
+      # The Messenger will track the remote status of this many incoming
+      # deliveries after they have been accepted or rejected.
+      #
+      # Messages enter this window only when you take them into your application
+      # using get().  If your incoming window size is n, and you get n+1 messages
+      # without explicitly accepting or rejecting the oldest message, then the
+      # message that passes beyond the edge of the incoming window will be
+      # assigned the default disposition of its link.
+      #
+      # ==== Options
+      #
+      # * window - the window size
+      #
+      def incoming_window=(window)
+        raise TypeError.new("invalid window: #{window}") unless valid_window?(window)
+        Cproton.pn_messenger_set_incoming_window(@impl, window)
+      end
+
+      # Returns the incoming window.
+      #
+      def incoming_window
+        Cproton.pn_messenger_get_incoming_window(@impl)
+      end
+
+      # Sets the outgoing window.
+      #
+      # The Messenger will track the remote status of this many outgoing
+      # deliveries after calling send.
+      # A Message enters this window when you call the put() method with the
+      # message.  If your outgoing window size is n, and you call put n+1
+      # times, status information will no longer be available for the
+      # first message.
+      #
+      # ==== Options
+      #
+      # * window - the window size
+      #
+      def outgoing_window=(window)
+        raise TypeError.new("invalid window: #{window}") unless valid_window?(window)
+        Cproton.pn_messenger_set_outgoing_window(@impl, window)
+      end
+
+      # Returns the outgoing window.
+      #
+      def outgoing_window
+        Cproton.pn_messenger_get_outgoing_window(@impl)
+      end
+
+      # Unregisters a selectable object.
+      def unregister_selectable(fileno) # :nodoc:
+        @selectables.delete(fileno)
+      end
+
+      private
+
+      def valid_tracker?(tracker)
+        !tracker.nil? && tracker.is_a?(Qpid::Proton::Tracker)
+      end
+
+      def valid_window?(window)
+        !window.nil? && [Float, Fixnum].include?(window.class)
+      end
+
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/messenger/selectable.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/messenger/selectable.rb b/proton-c/bindings/ruby/lib/messenger/selectable.rb
new file mode 100644
index 0000000..33554cd
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/messenger/selectable.rb
@@ -0,0 +1,126 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # Selectable enables accessing the underlying file descriptors
+    # for Messenger.
+    class Selectable
+
+      include Qpid::Proton::Filters
+
+      call_before :check_is_initialized,
+      :fileno, :capacity, :pending, :deadline,
+      :readable, :writable, :expired,
+      :registered=, :registered?
+
+      def initialize(messenger, impl) # :nodoc:
+        @messenger = messenger
+        @impl = impl
+        @io = nil
+        @freed = false
+      end
+
+      # Returns the underlying file descriptor.
+      #
+      # This can be used in conjunction with the IO class.
+      #
+      def fileno
+        Cproton.pn_selectable_fd(@impl)
+      end
+
+      def to_io
+        @io ||= IO.new(fileno)
+      end
+
+      # The number of bytes the selectable is capable of consuming.
+      #
+      def capacity
+        Cproton.pn_selectable_capacity(@impl)
+      end
+
+      # The number of bytes waiting to be written to the file descriptor.
+      #
+      def pending
+        Cproton.pn_selectable_pending(@impl)
+      end
+
+      # The future expiry time at which control will be returned to the
+      # selectable.
+      #
+      def deadline
+        tstamp = Cproton.pn_selectable_deadline(@impl)
+        tstamp.nil? ? nil : tstamp / 1000
+      end
+
+      def readable
+        Cproton.pn_selectable_readable(@impl)
+      end
+
+      def writable
+        Cproton.pn_selectable_writable(@impl)
+      end
+
+      def expired?
+        Cproton.pn_selectable_expired(@impl)
+      end
+
+      def registered=(registered)
+        Cproton.pn_selectable_set_registered(@impl, registered)
+      end
+
+      def registered?
+        Cproton.pn_selectable_is_registered(@impl)
+      end
+
+      def terminal?
+        return true if @impl.nil?
+        Cproton.pn_selectable_is_terminal(@impl)
+      end
+
+      def to_s
+        "fileno=#{self.fileno} registered=#{self.registered?} terminal=#{self.terminal?}"
+      end
+
+      def free
+        return if @freed
+        @freed = true
+        @messenger.unregister_selectable(fileno)
+        @io.close unless @io.nil?
+        Cproton.pn_selectable_free(@impl)
+        @impl = nil
+      end
+
+      def freed? # :nodoc:
+        @freed
+      end
+
+      private
+
+      def check_is_initialized
+        raise RuntimeError.new("selectable freed") if @impl.nil?
+      end
+
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/messenger/subscription.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/messenger/subscription.rb b/proton-c/bindings/ruby/lib/messenger/subscription.rb
new file mode 100644
index 0000000..21d9281
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/messenger/subscription.rb
@@ -0,0 +1,41 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # A +Subscription+ is an opaque object for working with a +Messenger+'s
+    # subscriptions.
+    #
+    class Subscription
+
+      def initialize(impl) # :nodoc:
+          @impl = impl
+      end
+
+      def impl # :nodoc:
+          @impl
+      end
+
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/messenger/tracker.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/messenger/tracker.rb b/proton-c/bindings/ruby/lib/messenger/tracker.rb
new file mode 100644
index 0000000..7de271a
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/messenger/tracker.rb
@@ -0,0 +1,42 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # A +Tracker+ is used to track the disposition of a +Message+.
+    #
+    class Tracker
+
+      CUMULATIVE = Cproton::PN_CUMULATIVE
+
+      def initialize(impl) # :nodoc:
+        @impl = impl
+      end
+
+      def impl # :nodoc:
+        @impl
+      end
+
+    end
+
+  end
+
+end

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/81a5449d/proton-c/bindings/ruby/lib/messenger/tracker_status.rb
----------------------------------------------------------------------
diff --git a/proton-c/bindings/ruby/lib/messenger/tracker_status.rb b/proton-c/bindings/ruby/lib/messenger/tracker_status.rb
new file mode 100644
index 0000000..81c9ea3
--- /dev/null
+++ b/proton-c/bindings/ruby/lib/messenger/tracker_status.rb
@@ -0,0 +1,73 @@
+#--
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#++
+
+module Qpid # :nodoc:
+
+  module Proton # :nodoc:
+
+    # TrackerStatus contains symbols that represent the status value for a
+    # Tracker.
+    #
+    class TrackerStatus
+
+        def initialize value, name # :nodoc:
+          @value = value
+          @name = name
+        end
+
+        def value # :nodoc:
+          @value
+        end
+
+        def to_s # :nodoc:
+          @name.to_s
+        end
+
+       def self.by_name(name) # :nodoc:
+          @by_name[name.to_sym] unless name.nil?
+        end
+
+        def self.by_value(value) # :nodoc:
+          @by_value[value] unless value.nil?
+        end
+
+        private
+
+        def self.add_item(key, value) # :nodoc:
+          @by_name ||= {}
+          @by_name[key] = TrackerStatus.new value, key
+          @by_value ||= {}
+          @by_value[value] = @by_name[key]
+        end
+
+        def self.const_missing(key) # :nodoc:
+          @by_name[key]
+        end
+
+        self.add_item :UNKNOWN,  Cproton::PN_STATUS_UNKNOWN
+        self.add_item :PENDING,  Cproton::PN_STATUS_PENDING
+        self.add_item :ACCEPTED, Cproton::PN_STATUS_ACCEPTED
+        self.add_item :REJECTED, Cproton::PN_STATUS_REJECTED
+        self.add_item :SETTLED,  Cproton::PN_STATUS_SETTLED
+
+    end
+
+  end
+
+end


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org