From: Kevin Clark Date: Wed, 18 Jun 2008 01:18:07 +0000 (+0000) Subject: rb: Implement type-checking in Thrift::Struct.new and field accessors X-Git-Tag: 0.2.0~536 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=23193757bc2d560d314fdd50e3b4093fdd6551a1;p=common%2Fthrift.git rb: Implement type-checking in Thrift::Struct.new and field accessors git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@669015 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc index 16cbe081..4336f658 100644 --- a/compiler/cpp/src/generate/t_rb_generator.cc +++ b/compiler/cpp/src/generate/t_rb_generator.cc @@ -490,12 +490,9 @@ void t_rb_generator::generate_accessors(std::ofstream& out, t_struct* tstruct) { vector::const_iterator m_iter; if (members.size() > 0) { - indent(out) << "attr_accessor "; + indent(out) << "Thrift::Struct.field_accessor self"; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { - if (m_iter != members.begin()) { - out << ", "; - } - out << ":" << (*m_iter)->get_name(); + out << ", :" << (*m_iter)->get_name(); } out << endl; } diff --git a/lib/rb/benchmark/gen-rb/BenchmarkService.rb b/lib/rb/benchmark/gen-rb/BenchmarkService.rb index 0370df00..ff4b10a9 100644 --- a/lib/rb/benchmark/gen-rb/BenchmarkService.rb +++ b/lib/rb/benchmark/gen-rb/BenchmarkService.rb @@ -46,7 +46,7 @@ require 'Benchmark_types' class Fibonacci_args include Thrift::Struct - attr_accessor :n + Thrift::Struct.field_accessor self, :n FIELDS = { 1 => {:type => Thrift::Types::BYTE, :name => 'n'} } @@ -54,7 +54,7 @@ require 'Benchmark_types' class Fibonacci_result include Thrift::Struct - attr_accessor :success + Thrift::Struct.field_accessor self, :success FIELDS = { 0 => {:type => Thrift::Types::I32, :name => 'success'} } diff --git a/lib/rb/lib/thrift/struct.rb b/lib/rb/lib/thrift/struct.rb index 32f43613..2d293664 100644 --- a/lib/rb/lib/thrift/struct.rb +++ b/lib/rb/lib/thrift/struct.rb @@ -1,11 +1,15 @@ +require 'thrift/types' require 'set' module Thrift module Struct def initialize(d={}) each_field do |fid, type, name, default| - instance_variable_set("@#{name}", d.fetch(name.to_s) { d.fetch(name.to_sym) { default.dup rescue default } }) + value = d.delete(name.to_s) { d.delete(name.to_sym) { default.dup rescue default } } + Thrift.check_type(value, type) + instance_variable_set("@#{name}", value) end + raise Exception, "Unknown arguments given to #{self.class}.new" unless d.empty? end def struct_fields @@ -54,6 +58,16 @@ module Thrift true end + def self.field_accessor(klass, *fields) + fields.each do |field| + klass.send :attr_reader, field + klass.send :define_method, "#{field}=" do |value| + Thrift.check_type(value, klass::FIELDS.values.find { |f| f[:name].to_s == field.to_s }[:type] ) + instance_variable_set("@#{field}", value) + end + end + end + protected def handle_message(iprot, fid, ftype) diff --git a/lib/rb/spec/gen-rb/NonblockingService.rb b/lib/rb/spec/gen-rb/NonblockingService.rb index 46e7c60f..411a6f07 100644 --- a/lib/rb/spec/gen-rb/NonblockingService.rb +++ b/lib/rb/spec/gen-rb/NonblockingService.rb @@ -115,7 +115,7 @@ require 'ThriftSpec_types' class Greeting_args include Thrift::Struct - attr_accessor :english + Thrift::Struct.field_accessor self, :english FIELDS = { 1 => {:type => Thrift::Types::BOOL, :name => 'english'} } @@ -123,7 +123,7 @@ require 'ThriftSpec_types' class Greeting_result include Thrift::Struct - attr_accessor :success + Thrift::Struct.field_accessor self, :success FIELDS = { 0 => {:type => Thrift::Types::STRUCT, :name => 'success', :class => Hello} } @@ -138,7 +138,7 @@ require 'ThriftSpec_types' class Block_result include Thrift::Struct - attr_accessor :success + Thrift::Struct.field_accessor self, :success FIELDS = { 0 => {:type => Thrift::Types::BOOL, :name => 'success'} } @@ -174,7 +174,7 @@ require 'ThriftSpec_types' class Sleep_args include Thrift::Struct - attr_accessor :seconds + Thrift::Struct.field_accessor self, :seconds FIELDS = { 1 => {:type => Thrift::Types::DOUBLE, :name => 'seconds'} } diff --git a/lib/rb/spec/gen-rb/ThriftSpec_types.rb b/lib/rb/spec/gen-rb/ThriftSpec_types.rb index f34b7bc8..b98ae7de 100644 --- a/lib/rb/spec/gen-rb/ThriftSpec_types.rb +++ b/lib/rb/spec/gen-rb/ThriftSpec_types.rb @@ -9,7 +9,7 @@ require 'thrift/protocol' module SpecNamespace class Hello include Thrift::Struct - attr_accessor :greeting + Thrift::Struct.field_accessor self, :greeting FIELDS = { 1 => {:type => Thrift::Types::STRING, :name => 'greeting', :default => 'hello world'} } @@ -17,7 +17,7 @@ module SpecNamespace class Foo include Thrift::Struct - attr_accessor :simple, :words, :hello, :ints, :complex, :shorts + Thrift::Struct.field_accessor self, :simple, :words, :hello, :ints, :complex, :shorts FIELDS = { 1 => {:type => Thrift::Types::I32, :name => 'simple', :default => 53}, 2 => {:type => Thrift::Types::STRING, :name => 'words', :default => 'words'}, @@ -40,7 +40,7 @@ module SpecNamespace class BoolStruct include Thrift::Struct - attr_accessor :yesno + Thrift::Struct.field_accessor self, :yesno FIELDS = { 1 => {:type => Thrift::Types::BOOL, :name => 'yesno', :default => true} } diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb index ef2354d8..44f0b277 100644 --- a/lib/rb/spec/struct_spec.rb +++ b/lib/rb/spec/struct_spec.rb @@ -174,5 +174,30 @@ class ThriftStructSpec < Spec::ExampleGroup struct = Foo.new lambda { struct.send :write_container, nil, nil, {:type => "foo"} }.should raise_error(StandardError, "Not a container type: foo") end + + it "should support optional type-checking in Thrift::Struct.new" do + Thrift.type_checking = true + begin + lambda { Hello.new(:greeting => 3) }.should raise_error(TypeError, "Expected Types::STRING, received Fixnum") + ensure + Thrift.type_checking = false + end + lambda { Hello.new(:greeting => 3) }.should_not raise_error(TypeError) + end + + it "should support optional type-checking in field accessors" do + Thrift.type_checking = true + begin + hello = Hello.new + lambda { hello.greeting = 3 }.should raise_error(TypeError, "Expected Types::STRING, received Fixnum") + ensure + Thrift.type_checking = false + end + lambda { hello.greeting = 3 }.should_not raise_error(TypeError) + end + + it "should raise an exception when unknown types are given to Thrift::Struct.new" do + lambda { Hello.new(:fish => 'salmon') }.should raise_error(Exception, "Unknown arguments given to SpecNamespace::Hello.new") + end end end