2 # Licensed to the Apache Software Foundation (ASF) under one
3 # or more contributor license agreements. See the NOTICE file
4 # distributed with this work for additional information
5 # regarding copyright ownership. The ASF licenses this file
6 # to you under the Apache License, Version 2.0 (the
7 # "License"); you may not use this file except in compliance
8 # with the License. You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing,
13 # software distributed under the License is distributed on an
14 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 # KIND, either express or implied. See the License for the
16 # specific language governing permissions and limitations
24 def initialize(d
={}, &block
)
25 # get a copy of the default values to work on, removing defaults in favor of arguments
26 fields_with_defaults
= fields_with_default_values
.dup
28 # check if the defaults is empty, or if there are no parameters for this
29 # instantiation, and if so, don't bother overriding defaults.
30 unless fields_with_defaults
.empty
? || d
.empty
?
32 fields_with_defaults
.delete(name
.to_s
)
36 # assign all the user-specified arguments
38 d
.each
do |name
, value
|
39 unless name_to_id(name
.to_s
)
40 raise Exception
, "Unknown key given to #{self.class}.new: #{name}"
42 Thrift
.check_type(value
, struct_fields
[name_to_id(name
.to_s
)], name
) if Thrift
.type_checking
43 instance_variable_set("@#{name}", value
)
47 # assign all the default values
48 unless fields_with_defaults
.empty
?
49 fields_with_defaults
.each
do |name
, default_value
|
50 instance_variable_set("@#{name}", (default_value
.dup
rescue default_value
))
54 yield self if block_given
?
57 def fields_with_default_values
58 fields_with_default_values
= self.class.instance_variable_get(:@fields_with_default_values)
59 unless fields_with_default_values
60 fields_with_default_values
= {}
61 struct_fields
.each
do |fid
, field_def
|
62 unless field_def
[:default].nil?
63 fields_with_default_values
[field_def
[:name]] = field_def
[:default]
66 self.class.instance_variable_set(:@fields_with_default_values, fields_with_default_values
)
68 fields_with_default_values
71 def inspect(skip_optional_nulls
= true)
73 each_field
do |fid
, field_info
|
74 name
= field_info
[:name]
75 value
= instance_variable_get("@#{name}")
76 unless skip_optional_nulls
&& field_info
[:optional] && value
.nil?
77 fields
<< "#{name}:#{inspect_field(value, field_info)}"
80 "<#{self.class} #{fields.join(", ")}>"
84 iprot
.read_struct_begin
86 fname
, ftype
, fid
= iprot
.read_field_begin
87 break if (ftype
== Types
::STOP)
88 handle_message(iprot
, fid
, ftype
)
97 oprot
.write_struct_begin(self.class.name
)
98 each_field
do |fid
, field_info
|
99 name
= field_info
[:name]
100 type
= field_info
[:type]
101 value
= instance_variable_get("@#{name}")
103 if is_container
? type
104 oprot
.write_field_begin(name
, type
, fid
)
105 write_container(oprot
, value
, field_info
)
106 oprot
.write_field_end
108 oprot
.write_field(field_info
, fid
, value
)
112 oprot
.write_field_stop
113 oprot
.write_struct_end
117 return false if other
.nil?
118 each_field
do |fid
, field_info
|
119 name
= field_info
[:name]
120 return false unless other
.respond_to
?(name
) && self.send(name
) == other
.send(name
)
126 self.class == other
.class && self == other
129 # This implementation of hash() is inspired by Apache's Java HashCodeBuilder class.
132 each_field
do |fid
, field_info
|
133 name
= field_info
[:name]
134 value
= self.send(name
)
135 total
= (total
* 37 + value
.hash
) & 0xffffffff
140 def differences(other
)
142 unless other
.is_a
?(self.class)
143 diffs
<< "Different class!"
145 each_field
do |fid
, field_info
|
146 name
= field_info
[:name]
147 diffs
<< "#{name} differs!" unless self.instance_variable_get("@#{name}") == other
.instance_variable_get("@#{name}")
153 def self.field_accessor(klass
, field_info
)
154 field_name_sym
= field_info
[:name].to_sym
155 klass
.send
:attr_reader, field_name_sym
156 klass
.send
:define_method, "#{field_info[:name]}=" do |value
|
157 Thrift
.check_type(value
, field_info
, field_info
[:name]) if Thrift
.type_checking
158 instance_variable_set("@#{field_name_sym}", value
)
162 def self.generate_accessors(klass
)
163 klass
::FIELDS.values
.each
do |field_info
|
164 field_accessor(klass
, field_info
)
165 qmark_isset_method(klass
, field_info
)
169 def self.qmark_isset_method(klass
, field_info
)
170 klass
.send
:define_method, "#{field_info[:name]}?" do
171 !self.send(field_info
[:name].to_sym
).nil?
176 if self.class == other
.class
177 each_field
do |fid
, field_info
|
178 v1
= self.send(field_info
[:name])
180 v2
= other
.send(field_info
[:name])
184 elsif !v1_set
&& v2_set
186 elsif v1_set
&& v2_set
195 self.class <=> other
.class
201 def self.append_features(mod
)
202 if mod
.ancestors
.include? ::Exception
203 mod
.send
:class_variable_set, :'@@__thrift_struct_real_initialize', mod
.instance_method(:initialize)
205 # set up our custom initializer so `raise Xception, 'message'` works
206 mod
.send
:define_method, :struct_initialize, mod
.instance_method(:initialize)
207 mod
.send
:define_method, :initialize, mod
.instance_method(:exception_initialize)
213 def exception_initialize(*args
, &block
)
214 if args
.size
== 1 and args
.first
.is_a
? Hash
215 # looks like it's a regular Struct initialize
216 method(:struct_initialize).call(args
.first
)
218 # call the Struct initializer first with no args
219 # this will set our field default values
220 method(:struct_initialize).call()
221 # now give it to the exception
222 self.class.send(:class_variable_get, :'@@__thrift_struct_real_initialize').bind(self).call(*args
, &block
) if args
.size
> 0
223 # self.class.instance_method(:initialize).bind(self).call(*args, &block)
227 def handle_message(iprot
, fid
, ftype
)
228 field
= struct_fields
[fid
]
229 if field
and field
[:type] == ftype
230 value
= read_field(iprot
, field
)
231 instance_variable_set("@#{field[:name]}", value
)