From 205e4500f9212ee3689fd973ca4e7b4886d2ed1d Mon Sep 17 00:00:00 2001 From: Bryan Duxbury Date: Thu, 18 Feb 2010 23:19:42 +0000 Subject: [PATCH] THRIFT-553. rb: thrift structs should be comparable (<=>) This patch adds the spaceship operator to the struct and union base classes, enabling object comparisons between objects without regenerating code. git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@911644 13f79535-47bb-0310-9956-ffa450edef68 --- lib/rb/Rakefile | 2 +- lib/rb/lib/thrift/struct.rb | 24 +++++++++++++++++++++ lib/rb/lib/thrift/struct_union.rb | 1 - lib/rb/lib/thrift/union.rb | 30 +++++++++++++++++++++++++- lib/rb/spec/struct_spec.rb | 10 +++++++++ lib/rb/spec/union_spec.rb | 35 ++++++++++++++++++++++++++----- 6 files changed, 94 insertions(+), 8 deletions(-) diff --git a/lib/rb/Rakefile b/lib/rb/Rakefile index bd385613..10383e71 100644 --- a/lib/rb/Rakefile +++ b/lib/rb/Rakefile @@ -82,7 +82,7 @@ begin p.summary = "Ruby libraries for Thrift (a language-agnostic RPC system)" p.url = "http://incubator.apache.org/thrift/" p.include_rakefile = true - p.version = "0.2.4" + p.version = "0.2.5" p.rubygems_version = ">= 1.2.0" end diff --git a/lib/rb/lib/thrift/struct.rb b/lib/rb/lib/thrift/struct.rb index 48353d30..9ee6912d 100644 --- a/lib/rb/lib/thrift/struct.rb +++ b/lib/rb/lib/thrift/struct.rb @@ -167,6 +167,30 @@ module Thrift end end + def <=>(other) + if self.class == other.class + each_field do |fid, field_info| + v1 = self.send(field_info[:name]) + v1_set = !v1.nil? + v2 = other.send(field_info[:name]) + v2_set = !v2.nil? + if v1_set && !v2_set + return -1 + elsif !v1_set && v2_set + return 1 + elsif v1_set && v2_set + cmp = v1 <=> v2 + if cmp != 0 + return cmp + end + end + end + 0 + else + self.class <=> other.class + end + end + protected def self.append_features(mod) diff --git a/lib/rb/lib/thrift/struct_union.rb b/lib/rb/lib/thrift/struct_union.rb index ddd7938d..9bfbed5a 100644 --- a/lib/rb/lib/thrift/struct_union.rb +++ b/lib/rb/lib/thrift/struct_union.rb @@ -155,6 +155,5 @@ module Thrift end "[" + buf.join(", ") + "]" end - end end \ No newline at end of file diff --git a/lib/rb/lib/thrift/union.rb b/lib/rb/lib/thrift/union.rb index 9fde8fcc..a7058f2c 100644 --- a/lib/rb/lib/thrift/union.rb +++ b/lib/rb/lib/thrift/union.rb @@ -46,7 +46,11 @@ module Thrift end def inspect - "<#{self.class} #{@setfield}: #{inspect_field(@value, struct_fields[name_to_id(@setfield.to_s)])}>" + if get_set_field + "<#{self.class} #{@setfield}: #{inspect_field(@value, struct_fields[name_to_id(@setfield.to_s)])}>" + else + "<#{self.class} >" + end end def read(iprot) @@ -135,6 +139,30 @@ module Thrift @value end + def <=>(other) + if self.class == other.class + if get_set_field == other.get_set_field + if get_set_field.nil? + 0 + else + get_value <=> other.get_value + end + else + if get_set_field && other.get_set_field.nil? + -1 + elsif get_set_field.nil? && other.get_set_field + 1 + elsif get_set_field.nil? && other.get_set_field.nil? + 0 + else + name_to_id(get_set_field.to_s) <=> name_to_id(other.get_set_field.to_s) + end + end + else + self.class <=> other.class + end + end + protected def handle_message(iprot, fid, ftype) diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb index c1271b90..c937023d 100644 --- a/lib/rb/spec/struct_spec.rb +++ b/lib/rb/spec/struct_spec.rb @@ -79,6 +79,16 @@ class ThriftStructSpec < Spec::ExampleGroup Foo.new(:my_bool => true).my_bool?.should be_true end + it "should be comparable" do + s1 = StructWithSomeEnum.new(:some_enum => SomeEnum::ONE) + s2 = StructWithSomeEnum.new(:some_enum => SomeEnum::TWO) + + (s1 <=> s2).should == -1 + (s2 <=> s1).should == 1 + (s1 <=> s1).should == 0 + (s1 <=> StructWithSomeEnum.new()).should == -1 + end + it "should read itself off the wire" do struct = Foo.new prot = BaseProtocol.new(mock("transport")) diff --git a/lib/rb/spec/union_spec.rb b/lib/rb/spec/union_spec.rb index 33df251a..702e9200 100644 --- a/lib/rb/spec/union_spec.rb +++ b/lib/rb/spec/union_spec.rb @@ -141,28 +141,53 @@ class ThriftUnionSpec < Spec::ExampleGroup swu2.read(proto) swu2.should == swu end - + it "should support old style constructor" do union = My_union.new(:integer32 => 26) union.get_set_field.should == :integer32 union.get_value.should == 26 end - + + it "should not throw an error when inspected and unset" do + lambda{TestUnion.new().inspect}.should_not raise_error + end + it "should print enum value name when inspected" do My_union.new(:some_enum => SomeEnum::ONE).inspect.should == "" - + My_union.new(:my_map => {SomeEnum::ONE => [SomeEnum::TWO]}).inspect.should == "" end - + it "should offer field? methods" do My_union.new.some_enum?.should be_false My_union.new(:some_enum => SomeEnum::ONE).some_enum?.should be_true My_union.new(:im_true => false).im_true?.should be_true My_union.new(:im_true => true).im_true?.should be_true end - + it "should pretty print binary fields" do TestUnion.new(:binary_field => "\001\002\003").inspect.should == "" end + + it "should be comparable" do + relationships = [ + [0, -1, -1, -1], + [1, 0, -1, -1], + [1, 1, 0, -1], + [1, 1, 1, 0]] + + objs = [ + TestUnion.new(:string_field, "blah"), + TestUnion.new(:string_field, "blahblah"), + TestUnion.new(:i32_field, 1), + TestUnion.new()] + + for y in 0..3 + for x in 0..3 + # puts "#{objs[y].inspect} <=> #{objs[x].inspect} should == #{relationships[y][x]}" + (objs[y] <=> objs[x]).should == relationships[y][x] + end + end + end end end -- 2.17.1