log4ever 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/.gitignore +33 -0
  2. data/.project +11 -0
  3. data/README.md +36 -0
  4. data/config/evernote.auth.test.yml +1 -0
  5. data/config/log4r.xml +19 -0
  6. data/lib/log4r/evernote/lib/Evernote/EDAM/errors_constants.rb +14 -0
  7. data/lib/log4r/evernote/lib/Evernote/EDAM/errors_types.rb +128 -0
  8. data/lib/log4r/evernote/lib/Evernote/EDAM/limits_constants.rb +240 -0
  9. data/lib/log4r/evernote/lib/Evernote/EDAM/limits_types.rb +13 -0
  10. data/lib/log4r/evernote/lib/Evernote/EDAM/note_store.rb +5487 -0
  11. data/lib/log4r/evernote/lib/Evernote/EDAM/note_store_constants.rb +14 -0
  12. data/lib/log4r/evernote/lib/Evernote/EDAM/note_store_types.rb +1012 -0
  13. data/lib/log4r/evernote/lib/Evernote/EDAM/types_constants.rb +20 -0
  14. data/lib/log4r/evernote/lib/Evernote/EDAM/types_types.rb +1792 -0
  15. data/lib/log4r/evernote/lib/Evernote/EDAM/user_store.rb +549 -0
  16. data/lib/log4r/evernote/lib/Evernote/EDAM/user_store_constants.rb +18 -0
  17. data/lib/log4r/evernote/lib/Evernote/EDAM/user_store_types.rb +415 -0
  18. data/lib/log4r/evernote/lib/thrift/client.rb +62 -0
  19. data/lib/log4r/evernote/lib/thrift/core_ext/fixnum.rb +29 -0
  20. data/lib/log4r/evernote/lib/thrift/core_ext.rb +23 -0
  21. data/lib/log4r/evernote/lib/thrift/exceptions.rb +84 -0
  22. data/lib/log4r/evernote/lib/thrift/processor.rb +57 -0
  23. data/lib/log4r/evernote/lib/thrift/protocol/base_protocol.rb +290 -0
  24. data/lib/log4r/evernote/lib/thrift/protocol/binary_protocol.rb +229 -0
  25. data/lib/log4r/evernote/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  26. data/lib/log4r/evernote/lib/thrift/protocol/compact_protocol.rb +426 -0
  27. data/lib/log4r/evernote/lib/thrift/serializer/deserializer.rb +33 -0
  28. data/lib/log4r/evernote/lib/thrift/serializer/serializer.rb +34 -0
  29. data/lib/log4r/evernote/lib/thrift/server/base_server.rb +31 -0
  30. data/lib/log4r/evernote/lib/thrift/server/mongrel_http_server.rb +58 -0
  31. data/lib/log4r/evernote/lib/thrift/server/nonblocking_server.rb +305 -0
  32. data/lib/log4r/evernote/lib/thrift/server/simple_server.rb +43 -0
  33. data/lib/log4r/evernote/lib/thrift/server/thread_pool_server.rb +75 -0
  34. data/lib/log4r/evernote/lib/thrift/server/threaded_server.rb +47 -0
  35. data/lib/log4r/evernote/lib/thrift/struct.rb +237 -0
  36. data/lib/log4r/evernote/lib/thrift/struct_union.rb +192 -0
  37. data/lib/log4r/evernote/lib/thrift/thrift_native.rb +24 -0
  38. data/lib/log4r/evernote/lib/thrift/transport/base_server_transport.rb +37 -0
  39. data/lib/log4r/evernote/lib/thrift/transport/base_transport.rb +107 -0
  40. data/lib/log4r/evernote/lib/thrift/transport/buffered_transport.rb +108 -0
  41. data/lib/log4r/evernote/lib/thrift/transport/framed_transport.rb +116 -0
  42. data/lib/log4r/evernote/lib/thrift/transport/http_client_transport.rb +53 -0
  43. data/lib/log4r/evernote/lib/thrift/transport/io_stream_transport.rb +39 -0
  44. data/lib/log4r/evernote/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  45. data/lib/log4r/evernote/lib/thrift/transport/server_socket.rb +63 -0
  46. data/lib/log4r/evernote/lib/thrift/transport/socket.rb +137 -0
  47. data/lib/log4r/evernote/lib/thrift/transport/unix_server_socket.rb +60 -0
  48. data/lib/log4r/evernote/lib/thrift/transport/unix_socket.rb +40 -0
  49. data/lib/log4r/evernote/lib/thrift/types.rb +101 -0
  50. data/lib/log4r/evernote/lib/thrift/union.rb +179 -0
  51. data/lib/log4r/evernote/lib/thrift.rb +64 -0
  52. data/lib/log4r/evernote.rb +206 -0
  53. data/lib/log4r/outputter/evernoteoutputter.rb +156 -0
  54. data/spec/log4ever_spec.rb +94 -0
  55. data/spec/spec_helper.rb +14 -0
  56. metadata +105 -0
@@ -0,0 +1,305 @@
1
+ #
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
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
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
17
+ # under the License.
18
+ #
19
+
20
+ require 'logger'
21
+ require 'thread'
22
+
23
+ module Thrift
24
+ # this class expects to always use a FramedTransport for reading messages
25
+ class NonblockingServer < BaseServer
26
+ def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20, logger=nil)
27
+ super(processor, server_transport, transport_factory, protocol_factory)
28
+ @num_threads = num
29
+ if logger.nil?
30
+ @logger = Logger.new(STDERR)
31
+ @logger.level = Logger::WARN
32
+ else
33
+ @logger = logger
34
+ end
35
+ @shutdown_semaphore = Mutex.new
36
+ @transport_semaphore = Mutex.new
37
+ end
38
+
39
+ def serve
40
+ @logger.info "Starting #{self}"
41
+ @server_transport.listen
42
+ @io_manager = start_io_manager
43
+
44
+ begin
45
+ loop do
46
+ break if @server_transport.closed?
47
+ begin
48
+ rd, = select([@server_transport], nil, nil, 0.1)
49
+ rescue Errno::EBADF => e
50
+ # In Ruby 1.9, calling @server_transport.close in shutdown paths causes the select() to raise an
51
+ # Errno::EBADF. If this happens, ignore it and retry the loop.
52
+ break
53
+ end
54
+ next if rd.nil?
55
+ socket = @server_transport.accept
56
+ @logger.debug "Accepted socket: #{socket.inspect}"
57
+ @io_manager.add_connection socket
58
+ end
59
+ rescue IOError => e
60
+ end
61
+ # we must be shutting down
62
+ @logger.info "#{self} is shutting down, goodbye"
63
+ ensure
64
+ @transport_semaphore.synchronize do
65
+ @server_transport.close
66
+ end
67
+ @io_manager.ensure_closed unless @io_manager.nil?
68
+ end
69
+
70
+ def shutdown(timeout = 0, block = true)
71
+ @shutdown_semaphore.synchronize do
72
+ return if @is_shutdown
73
+ @is_shutdown = true
74
+ end
75
+ # nonblocking is intended for calling from within a Handler
76
+ # but we can't change the order of operations here, so lets thread
77
+ shutdown_proc = lambda do
78
+ @io_manager.shutdown(timeout)
79
+ @transport_semaphore.synchronize do
80
+ @server_transport.close # this will break the accept loop
81
+ end
82
+ end
83
+ if block
84
+ shutdown_proc.call
85
+ else
86
+ Thread.new &shutdown_proc
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ def start_io_manager
93
+ iom = IOManager.new(@processor, @server_transport, @transport_factory, @protocol_factory, @num_threads, @logger)
94
+ iom.spawn
95
+ iom
96
+ end
97
+
98
+ class IOManager # :nodoc:
99
+ DEFAULT_BUFFER = 2**20
100
+
101
+ def initialize(processor, server_transport, transport_factory, protocol_factory, num, logger)
102
+ @processor = processor
103
+ @server_transport = server_transport
104
+ @transport_factory = transport_factory
105
+ @protocol_factory = protocol_factory
106
+ @num_threads = num
107
+ @logger = logger
108
+ @connections = []
109
+ @buffers = Hash.new { |h,k| h[k] = '' }
110
+ @signal_queue = Queue.new
111
+ @signal_pipes = IO.pipe
112
+ @signal_pipes[1].sync = true
113
+ @worker_queue = Queue.new
114
+ @shutdown_queue = Queue.new
115
+ end
116
+
117
+ def add_connection(socket)
118
+ signal [:connection, socket]
119
+ end
120
+
121
+ def spawn
122
+ @iom_thread = Thread.new do
123
+ @logger.debug "Starting #{self}"
124
+ run
125
+ end
126
+ end
127
+
128
+ def shutdown(timeout = 0)
129
+ @logger.debug "#{self} is shutting down workers"
130
+ @worker_queue.clear
131
+ @num_threads.times { @worker_queue.push [:shutdown] }
132
+ signal [:shutdown, timeout]
133
+ @shutdown_queue.pop
134
+ @signal_pipes[0].close
135
+ @signal_pipes[1].close
136
+ @logger.debug "#{self} is shutting down, goodbye"
137
+ end
138
+
139
+ def ensure_closed
140
+ kill_worker_threads if @worker_threads
141
+ @iom_thread.kill
142
+ end
143
+
144
+ private
145
+
146
+ def run
147
+ spin_worker_threads
148
+
149
+ loop do
150
+ rd, = select([@signal_pipes[0], *@connections])
151
+ if rd.delete @signal_pipes[0]
152
+ break if read_signals == :shutdown
153
+ end
154
+ rd.each do |fd|
155
+ begin
156
+ if fd.handle.eof?
157
+ remove_connection fd
158
+ else
159
+ read_connection fd
160
+ end
161
+ rescue Errno::ECONNRESET
162
+ remove_connection fd
163
+ end
164
+ end
165
+ end
166
+ join_worker_threads(@shutdown_timeout)
167
+ ensure
168
+ @shutdown_queue.push :shutdown
169
+ end
170
+
171
+ def read_connection(fd)
172
+ @buffers[fd] << fd.read(DEFAULT_BUFFER)
173
+ while(frame = slice_frame!(@buffers[fd]))
174
+ @logger.debug "#{self} is processing a frame"
175
+ @worker_queue.push [:frame, fd, frame]
176
+ end
177
+ end
178
+
179
+ def spin_worker_threads
180
+ @logger.debug "#{self} is spinning up worker threads"
181
+ @worker_threads = []
182
+ @num_threads.times do
183
+ @worker_threads << spin_thread
184
+ end
185
+ end
186
+
187
+ def spin_thread
188
+ Worker.new(@processor, @transport_factory, @protocol_factory, @logger, @worker_queue).spawn
189
+ end
190
+
191
+ def signal(msg)
192
+ @signal_queue << msg
193
+ @signal_pipes[1].write " "
194
+ end
195
+
196
+ def read_signals
197
+ # clear the signal pipe
198
+ # note that since read_nonblock is broken in jruby,
199
+ # we can only read up to a set number of signals at once
200
+ sigstr = @signal_pipes[0].readpartial(1024)
201
+ # now read the signals
202
+ begin
203
+ sigstr.length.times do
204
+ signal, obj = @signal_queue.pop(true)
205
+ case signal
206
+ when :connection
207
+ @connections << obj
208
+ when :shutdown
209
+ @shutdown_timeout = obj
210
+ return :shutdown
211
+ end
212
+ end
213
+ rescue ThreadError
214
+ # out of signals
215
+ # note that in a perfect world this would never happen, since we're
216
+ # only reading the number of signals pushed on the pipe, but given the lack
217
+ # of locks, in theory we could clear the pipe/queue while a new signal is being
218
+ # placed on the pipe, at which point our next read_signals would hit this error
219
+ end
220
+ end
221
+
222
+ def remove_connection(fd)
223
+ # don't explicitly close it, a thread may still be writing to it
224
+ @connections.delete fd
225
+ @buffers.delete fd
226
+ end
227
+
228
+ def join_worker_threads(shutdown_timeout)
229
+ start = Time.now
230
+ @worker_threads.each do |t|
231
+ if shutdown_timeout > 0
232
+ timeout = (start + shutdown_timeout) - Time.now
233
+ break if timeout <= 0
234
+ t.join(timeout)
235
+ else
236
+ t.join
237
+ end
238
+ end
239
+ kill_worker_threads
240
+ end
241
+
242
+ def kill_worker_threads
243
+ @worker_threads.each do |t|
244
+ t.kill if t.status
245
+ end
246
+ @worker_threads.clear
247
+ end
248
+
249
+ def slice_frame!(buf)
250
+ if buf.length >= 4
251
+ size = buf.unpack('N').first
252
+ if buf.length >= size + 4
253
+ buf.slice!(0, size + 4)
254
+ else
255
+ nil
256
+ end
257
+ else
258
+ nil
259
+ end
260
+ end
261
+
262
+ class Worker # :nodoc:
263
+ def initialize(processor, transport_factory, protocol_factory, logger, queue)
264
+ @processor = processor
265
+ @transport_factory = transport_factory
266
+ @protocol_factory = protocol_factory
267
+ @logger = logger
268
+ @queue = queue
269
+ end
270
+
271
+ def spawn
272
+ Thread.new do
273
+ @logger.debug "#{self} is spawning"
274
+ run
275
+ end
276
+ end
277
+
278
+ private
279
+
280
+ def run
281
+ loop do
282
+ cmd, *args = @queue.pop
283
+ case cmd
284
+ when :shutdown
285
+ @logger.debug "#{self} is shutting down, goodbye"
286
+ break
287
+ when :frame
288
+ fd, frame = args
289
+ begin
290
+ otrans = @transport_factory.get_transport(fd)
291
+ oprot = @protocol_factory.get_protocol(otrans)
292
+ membuf = MemoryBufferTransport.new(frame)
293
+ itrans = @transport_factory.get_transport(membuf)
294
+ iprot = @protocol_factory.get_protocol(itrans)
295
+ @processor.process(iprot, oprot)
296
+ rescue => e
297
+ @logger.error "#{Thread.current.inspect} raised error: #{e.inspect}\n#{e.backtrace.join("\n")}"
298
+ end
299
+ end
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,43 @@
1
+ #
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
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
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
17
+ # under the License.
18
+ #
19
+
20
+ module Thrift
21
+ class SimpleServer < BaseServer
22
+ def serve
23
+ begin
24
+ @server_transport.listen
25
+ loop do
26
+ client = @server_transport.accept
27
+ trans = @transport_factory.get_transport(client)
28
+ prot = @protocol_factory.get_protocol(trans)
29
+ begin
30
+ loop do
31
+ @processor.process(prot, prot)
32
+ end
33
+ rescue Thrift::TransportException, Thrift::ProtocolException
34
+ ensure
35
+ trans.close
36
+ end
37
+ end
38
+ ensure
39
+ @server_transport.close
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,75 @@
1
+ #
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
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
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
17
+ # under the License.
18
+ #
19
+
20
+ require 'thread'
21
+
22
+ module Thrift
23
+ class ThreadPoolServer < BaseServer
24
+ def initialize(processor, server_transport, transport_factory=nil, protocol_factory=nil, num=20)
25
+ super(processor, server_transport, transport_factory, protocol_factory)
26
+ @thread_q = SizedQueue.new(num)
27
+ @exception_q = Queue.new
28
+ @running = false
29
+ end
30
+
31
+ ## exceptions that happen in worker threads will be relayed here and
32
+ ## must be caught. 'retry' can be used to continue. (threads will
33
+ ## continue to run while the exception is being handled.)
34
+ def rescuable_serve
35
+ Thread.new { serve } unless @running
36
+ @running = true
37
+ raise @exception_q.pop
38
+ end
39
+
40
+ ## exceptions that happen in worker threads simply cause that thread
41
+ ## to die and another to be spawned in its place.
42
+ def serve
43
+ @server_transport.listen
44
+
45
+ begin
46
+ loop do
47
+ @thread_q.push(:token)
48
+ Thread.new do
49
+ begin
50
+ loop do
51
+ client = @server_transport.accept
52
+ trans = @transport_factory.get_transport(client)
53
+ prot = @protocol_factory.get_protocol(trans)
54
+ begin
55
+ loop do
56
+ @processor.process(prot, prot)
57
+ end
58
+ rescue Thrift::TransportException, Thrift::ProtocolException => e
59
+ ensure
60
+ trans.close
61
+ end
62
+ end
63
+ rescue => e
64
+ @exception_q.push(e)
65
+ ensure
66
+ @thread_q.pop # thread died!
67
+ end
68
+ end
69
+ end
70
+ ensure
71
+ @server_transport.close
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,47 @@
1
+ #
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
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
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
17
+ # under the License.
18
+ #
19
+
20
+ require 'thread'
21
+
22
+ module Thrift
23
+ class ThreadedServer < BaseServer
24
+ def serve
25
+ begin
26
+ @server_transport.listen
27
+ loop do
28
+ client = @server_transport.accept
29
+ trans = @transport_factory.get_transport(client)
30
+ prot = @protocol_factory.get_protocol(trans)
31
+ Thread.new(prot, trans) do |p, t|
32
+ begin
33
+ loop do
34
+ @processor.process(p, p)
35
+ end
36
+ rescue Thrift::TransportException, Thrift::ProtocolException
37
+ ensure
38
+ t.close
39
+ end
40
+ end
41
+ end
42
+ ensure
43
+ @server_transport.close
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,237 @@
1
+ #
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
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
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
17
+ # under the License.
18
+ #
19
+
20
+ require 'set'
21
+
22
+ module Thrift
23
+ module Struct
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
27
+
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?
31
+ d.each_key do |name|
32
+ fields_with_defaults.delete(name.to_s)
33
+ end
34
+ end
35
+
36
+ # assign all the user-specified arguments
37
+ unless d.empty?
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}"
41
+ end
42
+ Thrift.check_type(value, struct_fields[name_to_id(name.to_s)], name) if Thrift.type_checking
43
+ instance_variable_set("@#{name}", value)
44
+ end
45
+ end
46
+
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))
51
+ end
52
+ end
53
+
54
+ yield self if block_given?
55
+ end
56
+
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]
64
+ end
65
+ end
66
+ self.class.instance_variable_set(:@fields_with_default_values, fields_with_default_values)
67
+ end
68
+ fields_with_default_values
69
+ end
70
+
71
+ def inspect(skip_optional_nulls = true)
72
+ fields = []
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)}"
78
+ end
79
+ end
80
+ "<#{self.class} #{fields.join(", ")}>"
81
+ end
82
+
83
+ def read(iprot)
84
+ iprot.read_struct_begin
85
+ loop do
86
+ fname, ftype, fid = iprot.read_field_begin
87
+ break if (ftype == Types::STOP)
88
+ handle_message(iprot, fid, ftype)
89
+ iprot.read_field_end
90
+ end
91
+ iprot.read_struct_end
92
+ validate
93
+ end
94
+
95
+ def write(oprot)
96
+ validate
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}")
102
+ unless value.nil?
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
107
+ else
108
+ oprot.write_field(name, type, fid, value)
109
+ end
110
+ end
111
+ end
112
+ oprot.write_field_stop
113
+ oprot.write_struct_end
114
+ end
115
+
116
+ def ==(other)
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)
121
+ end
122
+ true
123
+ end
124
+
125
+ def eql?(other)
126
+ self.class == other.class && self == other
127
+ end
128
+
129
+ # This implementation of hash() is inspired by Apache's Java HashCodeBuilder class.
130
+ def hash
131
+ total = 17
132
+ each_field do |fid, field_info|
133
+ name = field_info[:name]
134
+ value = self.send(name)
135
+ total = (total * 37 + value.hash) & 0xffffffff
136
+ end
137
+ total
138
+ end
139
+
140
+ def differences(other)
141
+ diffs = []
142
+ unless other.is_a?(self.class)
143
+ diffs << "Different class!"
144
+ else
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}")
148
+ end
149
+ end
150
+ diffs
151
+ end
152
+
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)
159
+ end
160
+ end
161
+
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)
166
+ end
167
+ end
168
+
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?
172
+ end
173
+ end
174
+
175
+ def <=>(other)
176
+ if self.class == other.class
177
+ each_field do |fid, field_info|
178
+ v1 = self.send(field_info[:name])
179
+ v1_set = !v1.nil?
180
+ v2 = other.send(field_info[:name])
181
+ v2_set = !v2.nil?
182
+ if v1_set && !v2_set
183
+ return -1
184
+ elsif !v1_set && v2_set
185
+ return 1
186
+ elsif v1_set && v2_set
187
+ cmp = v1 <=> v2
188
+ if cmp != 0
189
+ return cmp
190
+ end
191
+ end
192
+ end
193
+ 0
194
+ else
195
+ self.class <=> other.class
196
+ end
197
+ end
198
+
199
+ protected
200
+
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)
204
+ super
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)
208
+ else
209
+ super
210
+ end
211
+ end
212
+
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)
217
+ else
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)
224
+ end
225
+ end
226
+
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)
232
+ else
233
+ iprot.skip(ftype)
234
+ end
235
+ end
236
+ end
237
+ end