rb: Add helpers for optional type-checking
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@669013 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/rb/lib/thrift/types.rb b/lib/rb/lib/thrift/types.rb
index 237df3c..bc09195 100644
--- a/lib/rb/lib/thrift/types.rb
+++ b/lib/rb/lib/thrift/types.rb
@@ -1,3 +1,5 @@
+require 'set'
+
module Thrift
module Types
STOP = 0
@@ -16,6 +18,46 @@
end
deprecate_module! :TType => Types
+ class << self
+ attr_accessor :type_checking
+ end
+
+ class TypeError < Exception
+ end
+
+ def self.check_type(value, type)
+ return unless Thrift.type_checking
+ klasses = case type
+ when Types::VOID
+ NilClass
+ when Types::BOOL
+ [TrueClass, FalseClass]
+ when Types::BYTE, Types::I16, Types::I32, Types::I64
+ Integer
+ when Types::DOUBLE
+ Float
+ when Types::STRING
+ String
+ when Types::STRUCT
+ Struct
+ when Types::MAP
+ Hash
+ when Types::SET
+ Set
+ when Types::LIST
+ Array
+ end
+ valid = klasses && [*klasses].any? { |klass| klass === value }
+ raise TypeError, "Expected #{type_name(type)}, received #{value.class}" unless valid
+ end
+
+ def self.type_name(type)
+ Types.constants.each do |const|
+ return "Types::#{const}" if Types.const_get(const) == type
+ end
+ nil
+ end
+
module MessageTypes
CALL = 1
REPLY = 2
@@ -23,3 +65,5 @@
end
deprecate_module! :TMessageType => MessageTypes
end
+
+Thrift.type_checking = false if Thrift.type_checking.nil?
diff --git a/lib/rb/spec/types_spec.rb b/lib/rb/spec/types_spec.rb
new file mode 100644
index 0000000..d40e492
--- /dev/null
+++ b/lib/rb/spec/types_spec.rb
@@ -0,0 +1,54 @@
+require File.dirname(__FILE__) + '/spec_helper'
+$:.unshift File.dirname(__FILE__) + "/gen-rb"
+require 'ThriftSpec_types'
+
+class ThriftTypesSpec < Spec::ExampleGroup
+ include Thrift
+
+ describe "Type checking" do
+ it "should return the proper name for each type" do
+ Thrift.type_name(Types::I16).should == "Types::I16"
+ Thrift.type_name(Types::VOID).should == "Types::VOID"
+ Thrift.type_name(Types::LIST).should == "Types::LIST"
+ Thrift.type_name(42).should be_nil
+ end
+
+ it "should check types properly" do
+ Thrift.type_checking = true
+ begin
+ lambda { Thrift.check_type(nil, Types::STOP) }.should raise_error(TypeError)
+ lambda { Thrift.check_type(nil, Types::VOID) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(3, Types::VOID) }.should raise_error(TypeError)
+ lambda { Thrift.check_type(true, Types::BOOL) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(3, Types::BOOL) }.should raise_error(TypeError)
+ lambda { Thrift.check_type(nil, Types::BOOL) }.should raise_error(TypeError)
+ lambda { Thrift.check_type(42, Types::BYTE) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(42, Types::I16) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(42, Types::I32) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(42, Types::I64) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(3.14, Types::I32) }.should raise_error(TypeError)
+ lambda { Thrift.check_type(3.14, Types::DOUBLE) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(3, Types::DOUBLE) }.should raise_error(TypeError)
+ lambda { Thrift.check_type("3", Types::STRING) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type(3, Types::STRING) }.should raise_error(TypeError)
+ hello = SpecNamespace::Hello.new
+ lambda { Thrift.check_type(hello, Types::STRUCT) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type("foo", Types::STRUCT) }.should raise_error(TypeError)
+ lambda { Thrift.check_type({:foo => 1}, Types::MAP) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type([1], Types::MAP) }.should raise_error(TypeError)
+ lambda { Thrift.check_type([1], Types::LIST) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type({:foo => 1}, Types::LIST) }.should raise_error(TypeError)
+ lambda { Thrift.check_type(Set.new([1,2]), Types::SET) }.should_not raise_error(TypeError)
+ lambda { Thrift.check_type([1,2], Types::SET) }.should raise_error(TypeError)
+ lambda { Thrift.check_type({:foo => true}, Types::SET) }.should raise_error(TypeError)
+ ensure
+ Thrift.type_checking = false
+ end
+ end
+
+ it "should be disabled when Thrift.type_checking = false" do
+ Thrift.type_checking = false
+ lambda { Thrift.check_type(3, Types::STRING) }.should_not raise_error(TypeError)
+ end
+ end
+end