PROTON-1537: [ruby] Fixed encoding problems, simplified Codec::Data. Code::Data decodes/encodes all specific AMQP types with methods named type/type= General encoding of any ruby object with Data#object=, Data#<< General decoding with Data#object, decodes as ruby object for the type.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/c172383d Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/c172383d Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/c172383d Branch: refs/heads/go1 Commit: c172383d4439f0c47a094e403134a7d226b85fa7 Parents: 889c0c6 Author: Alan Conway <[email protected]> Authored: Thu Dec 7 14:26:05 2017 -0500 Committer: Alan Conway <[email protected]> Committed: Wed Dec 13 13:16:48 2017 -0500 ---------------------------------------------------------------------- proton-c/bindings/ruby/lib/codec/data.rb | 465 ++++++--------------- proton-c/bindings/ruby/lib/codec/mapping.rb | 273 ++++++------ proton-c/bindings/ruby/lib/core/container.rb | 2 +- proton-c/bindings/ruby/lib/core/event.rb | 1 - proton-c/bindings/ruby/lib/core/exceptions.rb | 3 +- proton-c/bindings/ruby/lib/core/message.rb | 139 ++---- proton-c/bindings/ruby/lib/qpid_proton.rb | 1 + proton-c/bindings/ruby/lib/types/array.rb | 188 +++------ proton-c/bindings/ruby/lib/types/described.rb | 43 +- proton-c/bindings/ruby/lib/types/hash.rb | 63 +-- proton-c/bindings/ruby/lib/types/type.rb | 68 +++ proton-c/bindings/ruby/lib/util/wrapper.rb | 1 + proton-c/bindings/ruby/spec/array_spec.rb | 17 +- proton-c/bindings/ruby/spec/data_spec.rb | 22 +- proton-c/bindings/ruby/spec/hash_spec.rb | 12 - proton-c/bindings/ruby/tests/test_data.rb | 66 +++ proton-c/bindings/ruby/tests/test_interop.rb | 76 ++-- 17 files changed, 541 insertions(+), 899 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/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 index 9814836..86af3a1 100644 --- a/proton-c/bindings/ruby/lib/codec/data.rb +++ b/proton-c/bindings/ruby/lib/codec/data.rb @@ -15,80 +15,40 @@ # specific language governing permissions and limitations # under the License. +module Qpid::Proton + # @private + module Codec -module Qpid::Proton module Codec - - # +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 - # + DataError = ::TypeError + + # @private wrapper for pn_data_t* + # Raises TypeError for invalid conversions class Data # @private - PROTON_METHOD_PREFIX = "pn_disposition" + PROTON_METHOD_PREFIX = "pn_data" # @private include Util::Wrapper - # Rewind and convert a pn_data_t* containing a single value to a ruby object. - def self.to_object(impl) Data.new(impl).rewind.object; end + # @private + # Convert a pn_data_t* containing a single value to a ruby object. + # @return [Object, nil] The ruby value extracted from +impl+ or nil if impl is empty + def self.to_object(impl) + if (Cproton.pn_data_size(impl) > 0) + d = Data.new(impl) + d.rewind + d.next_object + end + end - # Clear a pn_data_t* and convert a ruby object into it. - def self.from_object(impl, x) Data.new(impl).clear.object = x; end + # @private + # Clear a pn_data_t* and convert a ruby object into it. If x==nil leave it empty. + def self.from_object(impl, x) + d = Data.new(impl) + d.clear + d.object = x if x + nil + end # @overload initialize(capacity) # @param capacity [Integer] capacity for the new data instance. @@ -115,86 +75,20 @@ module Qpid::Proton module Codec } end - # Clears the object. - # - def clear - Cproton.pn_data_clear(@impl) - self - 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. - # - # @return self - def rewind - Cproton.pn_data_rewind(@impl) - self - end + proton_caller :clear, :rewind, :next, :prev, :enter, :exit, :type - # 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 - Cproton.pn_data_next(@impl) + def enter_exit() + enter + yield self + ensure + exit 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(@impl) ? 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(@impl) - end - - # Sets the current node to the parent node and the parent node to its own - # parent. - # - def exit - Cproton.pn_data_exit(@impl) - end - - # Returns the numeric type code of the current node. - # - # @return [Integer] The current node type. - # @return [nil] If there is no current node. - # - def type_code - dtype = Cproton.pn_data_type(@impl) - return (dtype == -1) ? nil : dtype - end + def code() Cproton.pn_data_type(@impl); end - # @return [Integer] The type object for the current node. - # @see #type_code - # - def type - Mapping.for_code(type_code) - end + def type() Mapping.for_code(Cproton.pn_data_type(@impl)); end # Returns a representation of the data encoded in AMQP format. - # - # @return [String] The context of the Data as an AMQP data string. - # - # @example - # - # @impl.string = "This is a test." - # @encoded = @impl.encode - # - # # @encoded now contains the text "This is a test." encoded for - # # AMQP transport. - # def encode buffer = "\0"*1024 loop do @@ -213,233 +107,101 @@ module Qpid::Proton module Codec # of bytes consumed. # # @param encoded [String] The encoded data. - # - # @example - # - # # SCENARIO: A string of encoded data, @encoded, contains the text - # # of "This is a test." and is passed to an instance of Data - # # for decoding. - # - # @impl.decode(@encoded) - # @impl.string #=> "This is a test." - # def decode(encoded) check(Cproton.pn_data_decode(@impl, encoded, encoded.length)) end - # Puts a list value. - # - # Elements may be filled by entering the list node and putting element - # values. - # - # @example - # - # data = Qpid::Proton::Codec::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(@impl)) - end + proton_is :described, :array_described + proton_caller :put_described + proton_caller :put_list, :get_list, :put_map, :get_map + proton_get :array_type + proton_caller :put_array + def get_array() [Cproton.pn_data_get_array(@impl), array_described?, array_type]; 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. - # - # @example - # - # count = @impl.list - # @impl.enter - # (0...count).each - # type = @impl.next - # puts "Value: #{@impl.string}" if type == STRING - # # ... process other node types - # end - def list - Cproton.pn_data_get_list(@impl) + def expect(code) + unless code == self.code + raise TypeError, "expected #{Cproton.pn_type_name(code)}, got #{Cproton.pn_type_name(code)}" + end end - # Puts a map value. - # - # Elements may be filled by entering the map node and putting alternating - # key/value pairs. - # - # @example - # - # data = Qpid::Proton::Codec::Data.new - # data.put_map - # data.enter - # data.string = "key" - # data.string = "value" - # data.exit - # - def put_map - check(Cproton.pn_data_put_map(@impl)) + def described + expect Cproton::PN_DESCRIBED + enter_exit { Types::Described.new(self.next_object, self.next_object) } 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. - # - # @example - # - # count = @impl.map - # @impl.enter - # (0...count).each do - # type = @impl.next - # puts "Key=#{@impl.string}" if type == STRING - # # ... process other key types - # type = @impl.next - # puts "Value=#{@impl.string}" if type == STRING - # # ... process other value types - # end - # @impl.exit - def map - Cproton.pn_data_get_map(@impl) + def described= d + put_described + enter_exit { self << d.descriptor << d.value } end - # @private - def get_map - ::Hash.proton_data_get(self) + def fill(a, count, what) + a << self.object while self.next + raise TypeError, "#{what} expected #{count} elements, got #{a.size}" unless a.size == count + a 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. - # - # @param described [Boolean] True if the array is described. - # @param element_type [Integer] The AMQP type for each element of the array. - # - # @example - # - # # create an array of integer values - # data = Qpid::Proton::Codec::Data.new - # data.put_array(false, INT) - # data.enter - # data.int = 1 - # data.int = 2 - # data.int = 3 - # data.exit - # - # # create a described 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(@impl, described, element_type.code)) + def list + return array if code == Cproton::PN_ARRAY + expect Cproton::PN_LIST + count = get_list + a = [] + enter_exit { fill(a, count, __method__) } 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. - # - # @example - # - # # get the details of thecurrent array - # count, described, array_type = @impl.array - # - # # enter the node - # data.enter - # - # # get the next node - # data.next - # puts "Descriptor: #{data.symbol}" if described - # (0...count).each do - # @impl.next - # puts "Element: #{@impl.string}" - # end - def array - count = Cproton.pn_data_get_array(@impl) - described = Cproton.pn_data_is_array_described(@impl) - array_type = Cproton.pn_data_get_array_type(@impl) - return nil if array_type == -1 - [count, described, Mapping.for_code(array_type) ] + def list=(a) + put_list + enter_exit { a.each { |x| self << x } } end - # @private - def get_array - ::Array.proton_get(self) + def array + return list if code == Cproton::PN_LIST + expect Cproton::PN_ARRAY + count, d, t = get_array + enter_exit do + desc = next_object if d + a = Types::UniformArray.new(t, nil, desc) + fill(a, count, "array") + end 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. - # - # @example - # - # data = Qpid::Proton::Codec::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(@impl)) + def array=(a) + t = a.type if a.respond_to? :type + d = a.descriptor if a.respond_to? :descriptor + if (h = a.instance_variable_get(:@proton_array_header)) + t ||= h.type + d ||= h.descriptor + end + raise TypeError, "no type when converting #{a.class} to an array" unless t + put_array(!d.nil?, t.code) + m = Mapping[t] + enter_exit do + self << d unless d.nil? + a.each { |e| m.put(self, e); } + end end - # @private - def get_described - 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 - Qpid::Proton::Types::Described.new(descriptor, value) + def map + expect Cproton::PN_MAP + count = self.get_map + raise TypeError, "invalid map, total of keys and values is odd" if count.odd? + enter_exit do + m = {} + m[object] = next_object while self.next + raise TypeError, "map expected #{count/2} entries, got #{m.size}" unless m.size == count/2 + m + end end - # Checks if the current node is a described value. - # - # The described and value may be accessed by entering the described value. - # - # @example - # - # if @impl.described? - # @impl.enter - # puts "The symbol is #{@impl.symbol}" - # puts "The value is #{@impl.string}" - # end - def described? - Cproton.pn_data_is_described(@impl) + def map= m + put_map + enter_exit { m.each_pair { |k,v| self << k << v } } end - # Puts a null value. - # - def null - check(Cproton.pn_data_put_null(@impl)) - end + # Return nil if vallue is null, raise exception otherwise. + def null() raise TypeError, "expected null, got #{type || 'empty'}" unless null?; end - # Utility method for Qpid::Proton::Codec::Mapping - # - # @private - # - def null=(value) - null - end + # Set the current value to null + def null=(dummy=nil) check(Cproton.pn_data_put_null(@impl)); end # Puts an arbitrary object type. # @@ -450,6 +212,16 @@ module Qpid::Proton module Codec # def object=(object) Mapping.for_class(object.class).put(self, object) + object + end + + # Add an arbitrary data value using object=, return self + def <<(x) self.object=x; self; end + + # Move forward to the next value and return it + def next_object + self.next or raise TypeError, "not enough data" + self.object end # Gets the current node, based on how it was encoded. @@ -457,9 +229,7 @@ module Qpid::Proton module Codec # @return [Object] The current node. # def object - type = self.type - return nil if type.nil? - type.get(data) + self.type.get(self) if self.type end # Checks if the current node is null. @@ -862,10 +632,10 @@ module Qpid::Proton module Codec # If the current node is a symbol, returns its value. Otherwise, it # returns an empty string (""). # - # @return [String] The symbolic string value. + # @return [Symbol] The symbol value. # def symbol - Cproton.pn_data_get_symbol(@impl) + Cproton.pn_data_get_symbol(@impl).to_sym end # Get the current value as a single object. @@ -901,13 +671,12 @@ module Qpid::Proton module Codec # @private def check(err) if err < 0 - raise DataError, "[#{err}]: #{Cproton.pn_data_error(@impl)}" + raise TypeError, "[#{err}]: #{Cproton.pn_data_error(@impl)}" else return err end end end - end end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/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 index 92d0858..1b8df6e 100644 --- a/proton-c/bindings/ruby/lib/codec/mapping.rb +++ b/proton-c/bindings/ruby/lib/codec/mapping.rb @@ -16,165 +16,170 @@ # under the License. -module Qpid::Proton::Codec +module Qpid::Proton + module Codec - # Maps between Proton types and their Ruby native language counterparts. - # - # @private - class Mapping + # Maps between Proton types and their Ruby native language counterparts. + # + # @private + class Mapping + + attr_reader :code + attr_reader :put_method + attr_reader :get_method + + @@by_code = {} + @@by_class = {} + + # Creates a new mapping. + # + # ==== Arguments + # + # * code - the AMQP code for this type + # * name - the AMQP name for this type + # * klasses - native Ruby classes that are mapped to this AMQP type + # * getter - overrides the get method for the type + def initialize(code, name, klasses = nil, getter = nil) + + @code = code + @name = name + + @@by_code[code] = self + + 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 - attr_reader :code - attr_reader :put_method - attr_reader :get_method + @put_method = (name + "=").intern - # Creates a new mapping. - # - # ==== Arguments - # - # * code - the AMQP code for this type - # * name - the AMQP name for this type - # * klasses - native Ruby classes that are mapped to this AMQP 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? + if getter.nil? + @get_method = name.intern + else + @get_method = getter.intern end end - @put_method = (name + "=").intern + def to_s; @name; end - if getter.nil? - @get_method = name.intern - else - @get_method = getter.intern + def put(data, value) + data.__send__(@put_method, value) end - end - def to_s; @name; end + def get(data) + data.__send__(@get_method) + end - def put(data, value) - data.__send__(@put_method, value) - end + def self.for_class(klass) + c = klass + c = c.superclass while c && (x = @@by_class[c]).nil? + raise TypeError, "#{klass} cannot be converted to AMQP" unless x + x + end - def get(data) - data.__send__(@get_method) - end + def self.for_code(code) + @@by_code[code] + end - def self.for_class(klass) - c = klass - c = c.superclass while c && (x = @@by_class[c]).nil? - raise DataError, "no mapping for #{klass.inspect}" unless x - x - end + # Convert x to a Mapping + def self.[](x) + case x + when Mapping then x + when Integer then @@by_code[x] + when Types::Type then @@by_code[x.code] + end + 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", [Integer]) - 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, - Qpid::Proton::Types::UTFString, - Qpid::Proton::Types::BinaryString]) - SYMBOL = Mapping.new(Cproton::PN_SYMBOL, "symbol", [::Symbol]) - DESCRIBED = Mapping.new(Cproton::PN_DESCRIBED, "described", [Qpid::Proton::Types::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") - - - private - - class << STRING - 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::Types::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 + NULL = Mapping.new(Cproton::PN_NULL, "null", [NilClass]) + BOOL = Mapping.new(Cproton::PN_BOOL, "bool", [TrueClass, FalseClass]) + 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", [Integer]) + 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, + Types::UTFString, + Types::BinaryString]) + SYMBOL = Mapping.new(Cproton::PN_SYMBOL, "symbol", [::Symbol]) + DESCRIBED = Mapping.new(Cproton::PN_DESCRIBED, "described", [Types::Described]) + ARRAY = Mapping.new(Cproton::PN_ARRAY, "array", [Types::UniformArray]) + LIST = Mapping.new(Cproton::PN_LIST, "list", [::Array]) + MAP = Mapping.new(Cproton::PN_MAP, "map", [::Hash]) + + private + + class << STRING + 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?(Types::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 - end - data.string = value if isutf - data.binary = value if !isutf + data.string = value if isutf + data.binary = value if !isutf + end end - end - class << MAP - 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 + class << MAP + 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 + data.object = key + end - if value.nil? - data.null - else - Mapping.for_class(value.class).put(data, value) + if value.nil? + data.null + else + data.object = value + end end + data.exit end - data.exit end - end - class << DESCRIBED - def put(data, described) - data.put_described - data.enter - data.object = described.descriptor - data.object = described.value - data.exit + class << DESCRIBED + def put(data, described) + data.put_described + data.enter + data.object = described.descriptor + data.object = described.value + data.exit + end end end - end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/core/container.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/core/container.rb b/proton-c/bindings/ruby/lib/core/container.rb index 91a3d2a..dddde03 100644 --- a/proton-c/bindings/ruby/lib/core/container.rb +++ b/proton-c/bindings/ruby/lib/core/container.rb @@ -105,7 +105,7 @@ module Qpid::Proton def initialize(handler = nil, id = nil) # Allow ID as sole argument (handler, id = nil, handler.to_str) if (id.nil? && handler.respond_to?(:to_str)) - # Allow multiple handlers for backwards compatibility + # Allow multiple handlers ofor backwards compatibility a = Array(handler) @handler = a.size > 1 ? MessagingHandlers.new(a) : handler @id = ((id && id.to_s) || SecureRandom.uuid).freeze http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/core/event.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/core/event.rb b/proton-c/bindings/ruby/lib/core/event.rb index a5aa08e..88fdbaf 100644 --- a/proton-c/bindings/ruby/lib/core/event.rb +++ b/proton-c/bindings/ruby/lib/core/event.rb @@ -84,7 +84,6 @@ module Qpid::Proton when Cproton::CID_pn_session then Session.wrap(Cproton.pn_cast_pn_session(x)) when Cproton::CID_pn_link then Link.wrap(Cproton.pn_cast_pn_link(x)) when Cproton::CID_pn_delivery then Delivery.wrap(Cproton.pn_cast_pn_delivery(x)) - else raise TypeError, "bad class-id #{pn_class_id(Cproton.pn_event_class(impl))}" end end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/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 index f88b3c8..34a3e60 100644 --- a/proton-c/bindings/ruby/lib/core/exceptions.rb +++ b/proton-c/bindings/ruby/lib/core/exceptions.rb @@ -18,8 +18,8 @@ module Qpid::Proton + # @private module Error - NONE = 0 EOS = Cproton::PN_EOS ERROR = Cproton::PN_ERR @@ -30,7 +30,6 @@ module Qpid::Proton TIMEOUT = Cproton::PN_TIMEOUT INTERRUPTED = Cproton::PN_INTR INPROGRESS = Cproton::PN_INPROGRESS - end # Represents a generic error at the messaging level. http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/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 index 8f4f67c..7041d04 100644 --- a/proton-c/bindings/ruby/lib/core/message.rb +++ b/proton-c/bindings/ruby/lib/core/message.rb @@ -48,26 +48,10 @@ module Qpid::Proton # @private def post_decode # decode elements from the message - @properties = {} - props = Codec::Data.new(Cproton::pn_message_properties(@impl)) - if props.next - @properties = props.type.get(props) - end - @instructions = nil - insts = Codec::Data.new(Cproton::pn_message_instructions(@impl)) - if insts.next - @instructions = insts.type.get(insts) - end - @annotations = nil - annts = Codec::Data.new(Cproton::pn_message_annotations(@impl)) - if annts.next - @annotations = annts.type.get(annts) - end - @body = nil - body = Codec::Data.new(Cproton::pn_message_body(@impl)) - if body.next - @body = body.type.get(body) - end + @properties = Codec::Data.to_object(Cproton::pn_message_properties(@impl)) || {} + @instructions = Codec:: Data.to_object(Cproton::pn_message_instructions(@impl)) || {} + @annotations = Codec::Data.to_object(Cproton::pn_message_annotations(@impl)) || {} + @body = Codec::Data.to_object(Cproton::pn_message_body(@impl)) end # Encodes the message. @@ -88,27 +72,15 @@ module Qpid::Proton # @private def pre_encode # encode elements from the message - props = Codec::Data.new(Cproton::pn_message_properties(@impl)) - props.clear - Codec::Mapping.for_class(@properties.class).put(props, @properties) unless @properties.empty? - insts = Codec::Data.new(Cproton::pn_message_instructions(@impl)) - insts.clear - if [email protected]? - mapping = Codec::Mapping.for_class(@instructions.class) - mapping.put(insts, @instructions) - end - annts = Codec::Data.new(Cproton::pn_message_annotations(@impl)) - annts.clear - if [email protected]? - mapping = Codec::Mapping.for_class(@annotations.class) - mapping.put(annts, @annotations, :keys => :SYMBOL) - end - body = Codec::Data.new(Cproton::pn_message_body(@impl)) - body.clear - if [email protected]? - mapping = Codec::Mapping.for_class(@body.class) - mapping.put(body, @body) + Codec::Data.from_object(Cproton::pn_message_properties(@impl), [email protected]? && @properties) + Codec::Data.from_object(Cproton::pn_message_instructions(@impl), [email protected]? && @instructions) + if @annotations # Make sure keys are symbols + @annotations.keys.each do |k| + @annotations[k.to_sym] = @annotations.delete(k) unless k.is_a? Symbol + end end + Codec::Data.from_object(Cproton::pn_message_annotations(@impl), [email protected]? && @annotations) + Codec::Data.from_object(Cproton::pn_message_body(@impl), @body) end # Creates a new +Message+ instance. @@ -512,89 +484,32 @@ module Qpid::Proton 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 + # @return [Hash] Application properties for the message + attr_accessor :properties - # Use +properties+ as the message properties. - # @param properties [Hash] new properties - def properties=(properties) - @properties = properties - end + # Equivalent to +{#properties}[name] = value+ + def []=(name, value) @properties[name] = value; 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 + # Equivalent to +{#properties}[name]+ + def [](name) @properties[name]; end - # Retrieves the value for the specified property name. If not found, then - # it returns nil. - # - def [](name) - @properties[name] - end + # Equivalent to +{#properties}.delete(name)+ + def delete_property(name) @properties.delete(name); end - # Deletes the named property. - # - def delete_property(name) - @properties.delete(name) - end - - # Returns the instructions for this message. - # - def instructions - @instructions - end + # @return [Hash] Delivery instructions for this message. + attr_accessor :instructions - # Assigns instructions to this message. - # - def instructions=(instr) - @instructions = instr - end + # @return [Hash] Delivery annotations for this message. + attr_accessor :annotations - # 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) - Qpid::Proton::Codec::Mapping.for_class(body.class) unless body.nil? # Fail now if not convertible - @body = body - end + # @return [Object] body of the message. + attr_accessor :body private def check(err) # :nodoc: if err < 0 - raise DataError, "[#{err}]: #{Cproton.pn_message_error(@data)}" + raise TypeError, "[#{err}]: #{Cproton.pn_message_error(@data)}" else return err end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/qpid_proton.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/qpid_proton.rb b/proton-c/bindings/ruby/lib/qpid_proton.rb index a226838..3af6d39 100644 --- a/proton-c/bindings/ruby/lib/qpid_proton.rb +++ b/proton-c/bindings/ruby/lib/qpid_proton.rb @@ -51,6 +51,7 @@ require "util/wrapper" require "util/timeout" # Types +require "types/type" require "types/strings" require "types/hash" require "types/array" http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/types/array.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/types/array.rb b/proton-c/bindings/ruby/lib/types/array.rb index 88eb26b..3051f31 100644 --- a/proton-c/bindings/ruby/lib/types/array.rb +++ b/proton-c/bindings/ruby/lib/types/array.rb @@ -21,151 +21,83 @@ # to a Qpid::Proton::Data instance. #++ -module Qpid::Proton::Types +module Qpid::Proton + module Types + + # @deprecated use {UniformArray} + class ArrayHeader + def initialize(type, descriptor = nil) @type, @descriptor = Codec::Mapping[type], descriptor; end + attr_reader :type, :descriptor + def described?() [email protected]?; end + def <=>(x) [@type, @descriptor] <=> [x.type, x.descriptor]; end + include Comparable + end - # Holds the information for an AMQP Array compound type. - # - # It holds the type for the array and the descriptor if the - # array is described. - # - # @private - # - class ArrayHeader - attr_reader :type - attr_reader :descriptor + # *Unsettled API* - An array that is converted to/from an AMQP array of uniform element type. + # A plain ruby +::Array+ is converted to/from an AMQP list, which can contain mixed type elements. + # If invalid elements are included, then {TypeError} will be raised when encoding to AMQP. + class UniformArray < ::Array + + # Construct a uniform array, which will be converted to an AMQP array. + # A plain ruby +::Array+ is converted to/from an AMQP list, containing mixed type elements. + # + # @param type [Type] Elements must be convertible to this AMQP type. + # @param elements [Enumerator] Initial elements for the array + # @param descriptor [Object] Optional array descriptor + def initialize(type, elements=nil, descriptor=nil) + @type, @descriptor = type, descriptor + raise ArgumentError, "no type specified for array" if @type.nil? + super elements if elements + @proton_array_header = ArrayHeader.new(@type, @descriptor) # Deprecated + end - def initialize(type, descriptor = nil) - @type = type - @descriptor = descriptor - end + # @return [Type] Array elements must be convertible to this AMQP type + attr_reader :type - # Returns true if the array is described. - def described? - [email protected]? - end + # @return [Object] Optional descriptor. + def attr_reader() descriptor; end - def ==(that) - ((@type == that.type) && (@descriptor == that.descriptor)) + def inspect() "#{self.class.name}<#{type}>#{super}"; end end end - end -# @private -class Array # :nodoc: +# {Array} is converted to/from an AMQP list, which is allowed to hold mixed-type elements. +# Use {UniformArray} to convert/from an AMQP array with uniform element type. +class ::Array + # @deprecated use {UniformArray} + def proton_array_header + Qpid.deprecated __method__, "UniformArray" + @proton_array_header + end - # Used to declare an array as an AMQP array. - # - # The value, if defined, is an instance of Qpid::Proton::Types::ArrayHeader - attr_accessor :proton_array_header + # @deprecated use {UniformArray} + def proton_array_header=(h) + Qpid.deprecated __method__, "UniformArray" + @proton_array_header= h + end - # Returns true if the array is the a Proton described type. - def proton_described? - !@proton_array_header.nil? && @proton_array_header.described? + # @deprecated use {UniformArray} + def proton_described?() + Qpid.deprecated __method__, "UniformArray" + @proton_array_header && @proton_array_header.described? end - # Puts the elements of the array into the specified Qpid::Proton::Data object. + # @deprecated def proton_put(data) - raise TypeError, "data object cannot be nil" if data.nil? - - if @proton_array_header.nil? - proton_put_list(data) + Qpid.deprecated __method__, "Codec::Data#array=, Codec::Data#list=" + raise TypeError, "nil data" unless data + if @proton_array_header && @proton_array_header.type + data.array = self else - proton_put_array(data) + data.list = self end end - private - - def proton_put_list(data) - # create a list, then enter it and add each element - data.put_list - data.enter - each do |element| - # get the proton type for the element - mapping = Qpid::Proton::Codec::Mapping.for_class(element.class) - # add the element - mapping.put(data, element) - end - # exit the list - data.exit + # @deprecated + def self.proton_get(data) + Qpid.deprecated __method__, "Codec::Data#list" + data.list end - - def proton_put_array(data) - data.put_array(@proton_array_header.described?, @proton_array_header.type) - data.enter - if @proton_array_header.described? - data.symbol = @proton_array_header.descriptor - end - - each do |element| - @proton_array_header.type.put(data, element) - end - - data.exit - end - - class << self - - # Gets the elements of an array or list out of the specified - # Qpid::Proton::Data object. - def proton_get(data) - raise TypeError, "can't convert nil into Qpid::Proton::Data" if data.nil? - - type = data.type - - if type == Qpid::Proton::Codec::LIST - result = proton_get_list(data) - elsif type == Qpid::Proton::Codec::ARRAY - result = proton_get_array(data) - else - raise TypeError, "element is not a list and not an array" - end - end - - private - - def proton_get_list(data) - size = data.list - raise TypeError, "not a list" unless data.enter - elements = [] - (0...size).each do - data.next - type = data.type - raise TypeError, "missing next element in list" unless type - elements << type.get(data) - end - data.exit - return elements - end - - def proton_get_array(data) - count, described, type = data.array - - raise TypeError, "not an array" unless data.enter - elements = [] - - descriptor = nil - - if described - data.next - descriptor = data.symbol - end - - elements.proton_array_header = Qpid::Proton::Types::ArrayHeader.new(type, descriptor) - (0...count).each do |which| - if data.next - etype = data.type - raise TypeError, "missing next element in array" unless etype - raise TypeError, "invalid array element: #{etype}" unless etype == type - elements << type.get(data) - end - end - data.exit - return elements - end - - end - end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/types/described.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/types/described.rb b/proton-c/bindings/ruby/lib/types/described.rb index fb880ba..41d7ed2 100644 --- a/proton-c/bindings/ruby/lib/types/described.rb +++ b/proton-c/bindings/ruby/lib/types/described.rb @@ -17,46 +17,5 @@ module Qpid::Proton::Types - - # @private - class Described - - attr_reader :descriptor - attr_reader :value - - def initialize(descriptor, value) - @descriptor = descriptor - @value = value - end - - # Puts the description into the Data object. - # - # ==== Arguments - # - # * data - the Qpid::Proton::Data instance - # - # ==== Examples - # - # described = Qpid::Proton::Described.new("my-descriptor", "the value") - # data = Qpid::Proton::Data.new - # ... - # described.put(data) - # - def put(data) - data.symbol = @descriptor - data.string = @value - end - - def ==(that) # :nodoc: - (that.is_a?(Qpid::Proton::Types::Described) && - (self.descriptor == that.descriptor) && - (self.value == that.value)) - end - - def to_s # :nodoc: - "descriptor=#{descriptor} value=#{value}" - end - - end - + Described = Struct.new(:descriptor, :value) end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/types/hash.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/types/hash.rb b/proton-c/bindings/ruby/lib/types/hash.rb index 9415f86..736bb8f 100644 --- a/proton-c/bindings/ruby/lib/types/hash.rb +++ b/proton-c/bindings/ruby/lib/types/hash.rb @@ -23,64 +23,15 @@ # @private class Hash # :nodoc: - - # Places the contents of the hash into the specified data object. - # - # ==== Arguments - # - # * data - the Qpid::Proton::Data instance - # - # ==== Examples - # - # data = Qpid::Proton::Data.new - # values = {:foo => :bar} - # values.proton_data_put(data) - # + # @deprecated def proton_data_put(data) - raise TypeError, "data object cannot be nil" if data.nil? - - data.put_map - data.enter - - each_pair do |key, value| - type = Qpid::Proton::Codec::Mapping.for_class(key.class) - type.put(data, key) - type = Qpid::Proton::Codec::Mapping.for_class(value.class) - type.put(data, value) - end - - data.exit + Qpid.deprecated(__method__, "Codec::Data#map=") + data.map = self end - class << self - - def proton_data_get(data) - raise TypeError, "data object cannot be nil" if data.nil? - - type = data.type - - raise TypeError, "element is not a map" unless type == Qpid::Proton::Codec::MAP - - count = data.map - result = {} - - data.enter - - (0...(count/2)).each do - data.next - type = data.type - key = type.get(data) - data.next - type = data.type - value = type.get(data) - result[key] = value - end - - data.exit - - return result - end - + # @deprecated + def self.proton_data_get(data) + Qpid.deprecated(__method__, "Codec::Data#map") + data.map end - end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/types/type.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/types/type.rb b/proton-c/bindings/ruby/lib/types/type.rb new file mode 100644 index 0000000..8defa42 --- /dev/null +++ b/proton-c/bindings/ruby/lib/types/type.rb @@ -0,0 +1,68 @@ +#-- +# 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::Proton + module Types + + # Represents an AMQP Type + class Type + private + @@builtin = {} + def initialize(code) @code = code; @@builtin[code] = self; end + + public + def self.try_convert(code) code.is_a?(Type) ? code : @@builtin[code]; end + def self.[](code) try_convert(code) or raise IndexError, "unknown type code #{code}"; end + + attr_reader :code + def name() Cproton.pn_type_name(@code); end + alias to_s name + def <=>(x) @code <=> x; end + def hash() @code.hash; end + end + + # @!group + NULL = Type.new(Cproton::PN_NULL) + BOOL = Type.new(Cproton::PN_BOOL) + UBYTE = Type.new(Cproton::PN_UBYTE) + BYTE = Type.new(Cproton::PN_BYTE) + USHORT = Type.new(Cproton::PN_USHORT) + SHORT = Type.new(Cproton::PN_SHORT) + UINT = Type.new(Cproton::PN_UINT) + INT = Type.new(Cproton::PN_INT) + CHAR = Type.new(Cproton::PN_CHAR) + ULONG = Type.new(Cproton::PN_ULONG) + LONG = Type.new(Cproton::PN_LONG) + TIMESTAMP = Type.new(Cproton::PN_TIMESTAMP) + FLOAT = Type.new(Cproton::PN_FLOAT) + DOUBLE = Type.new(Cproton::PN_DOUBLE) + DECIMAL32 = Type.new(Cproton::PN_DECIMAL32) + DECIMAL64 = Type.new(Cproton::PN_DECIMAL64) + DECIMAL128 = Type.new(Cproton::PN_DECIMAL128) + UUID = Type.new(Cproton::PN_UUID) + BINARY = Type.new(Cproton::PN_BINARY) + STRING = Type.new(Cproton::PN_STRING) + SYMBOL = Type.new(Cproton::PN_SYMBOL) + DESCRIBED = Type.new(Cproton::PN_DESCRIBED) + ARRAY = Type.new(Cproton::PN_ARRAY) + LIST = Type.new(Cproton::PN_LIST) + MAP = Type.new(Cproton::PN_MAP) + #@!endgroup + end +end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/lib/util/wrapper.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/util/wrapper.rb b/proton-c/bindings/ruby/lib/util/wrapper.rb index 39cd7b4..347a9a5 100644 --- a/proton-c/bindings/ruby/lib/util/wrapper.rb +++ b/proton-c/bindings/ruby/lib/util/wrapper.rb @@ -113,6 +113,7 @@ module Qpid::Proton end RBCTX = self.hash.to_i end + # @private module Wrapper http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/spec/array_spec.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/spec/array_spec.rb b/proton-c/bindings/ruby/spec/array_spec.rb index 3bfe559..e760877 100644 --- a/proton-c/bindings/ruby/spec/array_spec.rb +++ b/proton-c/bindings/ruby/spec/array_spec.rb @@ -38,20 +38,10 @@ describe "The extended array type" do expect(value).respond_to? :proton_described? end - it "raises an error when putting into a nil Data object" do - expect { @list.proton_put(nil) }.must_raise(TypeError) - end - it "raises an error when getting from a nil Data object" do expect { Array.proton_get(nil) - }.must_raise(TypeError) - end - - it "raises an error when the data object is empty" do - expect { - Array.proton_get(@data) - }.must_raise(TypeError) + }.must_raise end it "raises an error when the current object is not a list" do @@ -92,6 +82,7 @@ describe "The extended array type" do it "can be put into a Data object as an undescribed array" do @undescribed.proton_put(@data) result = Array.proton_get(@data) + expect(result).is_a? Qpid::Proton::Types::UniformArray expect(@undescribed).must_equal(result) expect(result.proton_array_header).wont_be_nil expect(result.proton_array_header).must_equal(@undescribed.proton_array_header) @@ -101,8 +92,8 @@ describe "The extended array type" do it "can be put into a Data object as a described array" do @described.proton_put(@data) result = Array.proton_get(@data) - expect(@described) == result - + expect(@described).must_equal(result) + expect(result).is_a? Qpid::Proton::Types::UniformArray expect(result.proton_array_header).wont_be_nil expect(result.proton_array_header).must_equal(@described.proton_array_header) expect(result.proton_array_header.described?).must_equal(true) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/spec/data_spec.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/spec/data_spec.rb b/proton-c/bindings/ruby/spec/data_spec.rb index f4041e4..d5c92fb 100644 --- a/proton-c/bindings/ruby/spec/data_spec.rb +++ b/proton-c/bindings/ruby/spec/data_spec.rb @@ -34,7 +34,7 @@ module Qpid end it "can hold a null" do - @data.null + @data.null = nil expect(@data.null?).must_equal(true) end @@ -385,17 +385,17 @@ module Qpid it "can hold a null symbol" do @data.symbol = nil - expect(@data.symbol).must_equal("") + expect(@data.symbol).must_equal(:"") end it "can hold a symbol" do - value = random_string(128) + value = random_string(128).to_sym @data.symbol = value expect(@data.symbol).must_equal(value) end it "can hold a described value" do - name = random_string(16) + name = random_string(16).to_sym value = random_string(16) @data.put_described @data.enter @@ -411,12 +411,16 @@ module Qpid expect(@data.string).must_equal(value) end - it "raises an error when setting the wrong type in an array" + it "raises an error when setting the wrong type in an array" do + expect { + @data << Qpid::Proton::Types::UniformArray.new(Qpid::Proton::Types::INT, [1, 2.0, :a, "b"]) + }.must_raise(TypeError) + end it "can hold an array" do values = [] (1..(rand(100) + 5)).each { values << rand(2**16) } - @data.put_array false, Qpid::Proton::Codec::INT + @data.put_array false, Qpid::Proton::Codec::INT.code @data.enter values.each { |value| @data.int = value } @data.exit @@ -431,14 +435,14 @@ module Qpid it "can hold a described array" do values = [] (1..(rand(100) + 5)).each { values << random_string(64) } - descriptor = random_string(32) - @data.put_array true, Qpid::Proton::Codec::STRING + descriptor = random_string(32).to_sym + @data.put_array true, Qpid::Proton::Codec::STRING.code @data.enter @data.symbol = descriptor values.each { |value| @data.string = value } @data.exit - expect(@data.array).must_equal([values.size, true, Qpid::Proton::Codec::STRING]) + expect(@data.get_array).must_equal([values.size, true, Qpid::Proton::Codec::STRING.code]) @data.enter @data.next expect(@data.symbol).must_equal(descriptor) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/spec/hash_spec.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/spec/hash_spec.rb b/proton-c/bindings/ruby/spec/hash_spec.rb index cd661c2..92acd0a 100644 --- a/proton-c/bindings/ruby/spec/hash_spec.rb +++ b/proton-c/bindings/ruby/spec/hash_spec.rb @@ -26,12 +26,6 @@ describe "The extended hash type" do @hash = random_hash(rand(128) + 64) end - it "raises an error when put into a nil Data instance" do - expect { - @hash.proton_data_put(nil) - }.must_raise(TypeError) - end - it "can be put into an instance of Data" do @hash.proton_data_put(@data) result = Hash.proton_data_get(@data) @@ -39,12 +33,6 @@ describe "The extended hash type" do expect(result.values).must_equal(@hash.values) end - it "raises an error when retrieved from a nil Data instance" do - expect { - Hash.proton_data_get(nil) - }.must_raise(TypeError) - end - it "raises an error when trying to get what is not a Hash" do @data.string = random_string(128) @data.rewind http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/tests/test_data.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/tests/test_data.rb b/proton-c/bindings/ruby/tests/test_data.rb new file mode 100644 index 0000000..b1ae2d9 --- /dev/null +++ b/proton-c/bindings/ruby/tests/test_data.rb @@ -0,0 +1,66 @@ +# 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. + + +require 'minitest/autorun' +require "securerandom" +require 'qpid_proton' + +class TestData < Minitest::Test + include Qpid::Proton + + def assert_from_to(*values) + d = Codec::Data.new + values.each do |x| + Codec::Data.from_object(d.impl, x) + assert_equal x, Codec::Data.to_object(d.impl) + end + end + + def test_from_to + assert_from_to({ 1 => :one, 2=>:two }) + assert_from_to([{:a => 1, "b" => 2}, 3, 4.4, :five]) + assert_from_to(Types::UniformArray.new(Types::INT, [1, 2, 3, 4])) + end + + def rnum(*arg) SecureRandom.random_number(*arg); end + def rstr(*arg) SecureRandom.base64(*arg); end + + def test_nil() + assert_nil((Codec::Data.new << nil).object) + end + + def assert_convert(*values) + values.each { |x| assert_equal x, ((Codec::Data.new << x).object) } + end + + def test_bool() + assert_convert(true, false) + end + + def test_float() + assert_convert(0.0, 1.0, -1.0, 1.23e123, rnum(), rnum(), rnum(), rnum()) + end + + def test_string() + assert_convert("", "foo", rstr(100000), rstr(rnum(1000)), rstr(rnum(1000))) + end + + def test_symbol() + assert_convert(:"", :foo, rstr(256).to_sym) + end +end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/c172383d/proton-c/bindings/ruby/tests/test_interop.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/tests/test_interop.rb b/proton-c/bindings/ruby/tests/test_interop.rb index e08ada1..0a13a3d 100755 --- a/proton-c/bindings/ruby/tests/test_interop.rb +++ b/proton-c/bindings/ruby/tests/test_interop.rb @@ -14,8 +14,8 @@ if ((RUBY_VERSION.split(".").map {|x| x.to_i} <=> [1, 9]) < 0) end class InteropTest < MiniTest::Test - Data = Qpid::Proton::Codec::Data - Message = Qpid::Proton::Message + include Qpid::Proton + Data = Codec::Data def setup @data = Data.new @@ -53,87 +53,81 @@ class InteropTest < MiniTest::Test def assert_next(type, value) assert @data.next assert_equal(type, @data.type) - assert_equal(value, type.get(@data)) + assert_equal(value, @data.object) end - def assert_array_next(expected, header) - assert_next(Qpid::Proton::Codec::ARRAY, expected) - result = @data.type.get(@data) - assert_equal(result.proton_array_header, header) + def assert_array_next(expected) + result = @data.next_object + assert_equal(expected, result) end def test_message decode_message_file("message") - assert_next(Qpid::Proton::Codec::STRING, "hello") + assert_next(Codec::STRING, "hello") assert [email protected] end def test_primitives decode_data_file("primitives") - assert_next(Qpid::Proton::Codec::BOOL, true) - assert_next(Qpid::Proton::Codec::BOOL, false) - assert_next(Qpid::Proton::Codec::UBYTE, 42) - assert_next(Qpid::Proton::Codec::USHORT, 42) - assert_next(Qpid::Proton::Codec::SHORT, -42) - assert_next(Qpid::Proton::Codec::UINT, 12345) - assert_next(Qpid::Proton::Codec::INT, -12345) - assert_next(Qpid::Proton::Codec::ULONG, 12345) - assert_next(Qpid::Proton::Codec::LONG, -12345) - assert_next(Qpid::Proton::Codec::FLOAT, 0.125) - assert_next(Qpid::Proton::Codec::DOUBLE, 0.125) + assert_next(Codec::BOOL, true) + assert_next(Codec::BOOL, false) + assert_next(Codec::UBYTE, 42) + assert_next(Codec::USHORT, 42) + assert_next(Codec::SHORT, -42) + assert_next(Codec::UINT, 12345) + assert_next(Codec::INT, -12345) + assert_next(Codec::ULONG, 12345) + assert_next(Codec::LONG, -12345) + assert_next(Codec::FLOAT, 0.125) + assert_next(Codec::DOUBLE, 0.125) assert [email protected] end def test_strings decode_data_file("strings") - assert_next(Qpid::Proton::Codec::BINARY, "abc\0defg") - assert_next(Qpid::Proton::Codec::STRING, "abcdefg") - assert_next(Qpid::Proton::Codec::SYMBOL, "abcdefg") - assert_next(Qpid::Proton::Codec::BINARY, "") - assert_next(Qpid::Proton::Codec::STRING, "") - assert_next(Qpid::Proton::Codec::SYMBOL, "") + assert_next(Codec::BINARY, "abc\0defg") + assert_next(Codec::STRING, "abcdefg") + assert_next(Codec::SYMBOL, :abcdefg) + assert_next(Codec::BINARY, "") + assert_next(Codec::STRING, "") + assert_next(Codec::SYMBOL, :"") assert [email protected] end def test_described decode_data_file("described") - assert_next(Qpid::Proton::Codec::DESCRIBED, Qpid::Proton::Types::Described.new("foo-descriptor", "foo-value")) + assert_next(Codec::DESCRIBED, Types::Described.new(:"foo-descriptor", "foo-value")) assert(@data.described?) - assert_next(Qpid::Proton::Codec::DESCRIBED, Qpid::Proton::Types::Described.new(12, 13)) + assert_next(Codec::DESCRIBED, Types::Described.new(12, 13)) assert(@data.described?) assert [email protected] end def test_described_array decode_data_file("described_array") - assert_array_next((0...10).to_a, - Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::INT, - "int-array")) + assert_array_next(Types::UniformArray.new(Types::INT, (0...10).to_a, :"int-array")) end def test_arrays decode_data_file("arrays") - assert_array_next((0...100).to_a, - Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::INT)) - assert_array_next(["a", "b", "c"], - Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::STRING)) - assert_array_next([], - Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::INT)) + assert_array_next(Types::UniformArray.new(Codec::INT, (0...100).to_a)) + assert_array_next(Types::UniformArray.new(Codec::STRING, ["a", "b", "c"])) + assert_array_next(Types::UniformArray.new(Codec::INT)) assert [email protected] end def test_lists decode_data_file("lists") - assert_next(Qpid::Proton::Codec::LIST, [32, "foo", true]) - assert_next(Qpid::Proton::Codec::LIST, []) + assert_next(Codec::LIST, [32, "foo", true]) + assert_next(Codec::LIST, []) assert [email protected] end def test_maps decode_data_file("maps") - assert_next(Qpid::Proton::Codec::MAP, {"one" => 1, "two" => 2, "three" => 3 }) - assert_next(Qpid::Proton::Codec::MAP, {1 => "one", 2 => "two", 3 => "three"}) - assert_next(Qpid::Proton::Codec::MAP, {}) + assert_next(Codec::MAP, {"one" => 1, "two" => 2, "three" => 3 }) + assert_next(Codec::MAP, {1 => "one", 2 => "two", 3 => "three"}) + assert_next(Codec::MAP, {}) assert [email protected] end end --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
