stomper 1.0.0 → 2.0.0

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 (152) hide show
  1. data/.gitignore +5 -0
  2. data/{spec/spec.opts → .rspec} +0 -2
  3. data/Gemfile +4 -0
  4. data/LICENSE +201 -201
  5. data/README.md +130 -0
  6. data/Rakefile +5 -0
  7. data/examples/basic.rb +38 -0
  8. data/examples/events.rb +54 -0
  9. data/features/acking_messages.feature +147 -0
  10. data/features/disconnecting.feature +12 -0
  11. data/features/establish_connection.feature +44 -0
  12. data/features/protocol_version_negotiation.feature +61 -0
  13. data/features/receipts.feature +72 -0
  14. data/features/scopes.feature +32 -0
  15. data/features/secure_connections.feature +38 -0
  16. data/features/send_and_message.feature +28 -0
  17. data/features/steps/acking_messages_steps.rb +39 -0
  18. data/features/steps/disconnecting_steps.rb +8 -0
  19. data/features/steps/establish_connection_steps.rb +74 -0
  20. data/features/steps/frame_transmission_steps.rb +35 -0
  21. data/features/steps/protocol_version_negotiation_steps.rb +15 -0
  22. data/features/steps/receipts_steps.rb +79 -0
  23. data/features/steps/scopes_steps.rb +52 -0
  24. data/features/steps/secure_connections_steps.rb +41 -0
  25. data/features/steps/send_and_message_steps.rb +35 -0
  26. data/features/steps/subscribing_steps.rb +36 -0
  27. data/features/steps/threaded_receiver_steps.rb +8 -0
  28. data/features/steps/transactions_steps.rb +0 -0
  29. data/features/subscribing.feature +151 -0
  30. data/features/support/env.rb +11 -0
  31. data/features/support/header_helpers.rb +12 -0
  32. data/features/support/ssl/README +6 -0
  33. data/features/support/ssl/broker_cert.csr +17 -0
  34. data/features/support/ssl/broker_cert.pem +72 -0
  35. data/features/support/ssl/broker_key.pem +27 -0
  36. data/features/support/ssl/client_cert.csr +17 -0
  37. data/features/support/ssl/client_cert.pem +72 -0
  38. data/features/support/ssl/client_key.pem +27 -0
  39. data/features/support/ssl/demoCA/cacert.pem +17 -0
  40. data/features/support/ssl/demoCA/index.txt +2 -0
  41. data/features/support/ssl/demoCA/index.txt.attr +1 -0
  42. data/features/support/ssl/demoCA/index.txt.attr.old +1 -0
  43. data/features/support/ssl/demoCA/index.txt.old +1 -0
  44. data/features/support/ssl/demoCA/newcerts/01.pem +72 -0
  45. data/features/support/ssl/demoCA/newcerts/02.pem +72 -0
  46. data/features/support/ssl/demoCA/private/cakey.pem +17 -0
  47. data/features/support/ssl/demoCA/serial +1 -0
  48. data/features/support/ssl/demoCA/serial.old +1 -0
  49. data/features/support/test_stomp_server.rb +150 -0
  50. data/features/threaded_receiver.feature +11 -0
  51. data/features/transactions.feature +66 -0
  52. data/lib/stomper.rb +30 -20
  53. data/lib/stomper/connection.rb +442 -102
  54. data/lib/stomper/errors.rb +59 -0
  55. data/lib/stomper/extensions.rb +10 -0
  56. data/lib/stomper/extensions/common.rb +258 -0
  57. data/lib/stomper/extensions/events.rb +213 -0
  58. data/lib/stomper/extensions/heartbeat.rb +101 -0
  59. data/lib/stomper/extensions/scoping.rb +56 -0
  60. data/lib/stomper/frame.rb +54 -0
  61. data/lib/stomper/frame_serializer.rb +217 -0
  62. data/lib/stomper/headers.rb +15 -0
  63. data/lib/stomper/receipt_manager.rb +36 -0
  64. data/lib/stomper/receivers.rb +7 -0
  65. data/lib/stomper/receivers/threaded.rb +71 -0
  66. data/lib/stomper/scopes.rb +9 -0
  67. data/lib/stomper/scopes/header_scope.rb +49 -0
  68. data/lib/stomper/scopes/receipt_scope.rb +44 -0
  69. data/lib/stomper/scopes/transaction_scope.rb +109 -0
  70. data/lib/stomper/sockets.rb +66 -28
  71. data/lib/stomper/subscription_manager.rb +79 -0
  72. data/lib/stomper/support.rb +68 -0
  73. data/lib/stomper/support/1.8/frame_serializer.rb +53 -0
  74. data/lib/stomper/support/1.8/headers.rb +183 -0
  75. data/lib/stomper/support/1.9/frame_serializer.rb +64 -0
  76. data/lib/stomper/support/1.9/headers.rb +172 -0
  77. data/lib/stomper/support/ruby.rb +13 -0
  78. data/lib/stomper/uris.rb +49 -0
  79. data/lib/stomper/version.rb +7 -0
  80. data/spec/spec_helper.rb +13 -9
  81. data/spec/stomper/connection_spec.rb +712 -0
  82. data/spec/stomper/extensions/common_spec.rb +187 -0
  83. data/spec/stomper/extensions/events_spec.rb +78 -0
  84. data/spec/stomper/extensions/heartbeat_spec.rb +103 -0
  85. data/spec/stomper/extensions/scoping_spec.rb +21 -0
  86. data/spec/stomper/frame_serializer_1.8_spec.rb +318 -0
  87. data/spec/stomper/frame_serializer_spec.rb +316 -0
  88. data/spec/stomper/frame_spec.rb +36 -0
  89. data/spec/stomper/headers_spec.rb +224 -0
  90. data/spec/stomper/receipt_manager_spec.rb +91 -0
  91. data/spec/stomper/receivers/threaded_spec.rb +116 -0
  92. data/spec/stomper/scopes/header_scope_spec.rb +42 -0
  93. data/spec/stomper/scopes/receipt_scope_spec.rb +51 -0
  94. data/spec/stomper/scopes/transaction_scope_spec.rb +183 -0
  95. data/spec/stomper/sockets_spec.rb +113 -0
  96. data/spec/stomper/subscription_manager_spec.rb +107 -0
  97. data/spec/stomper/support_spec.rb +69 -0
  98. data/spec/stomper/uris_spec.rb +54 -0
  99. data/spec/stomper_spec.rb +9 -0
  100. data/spec/support/custom_argument_matchers.rb +57 -0
  101. data/spec/support/existential_frame_matchers.rb +19 -0
  102. data/spec/support/frame_header_matchers.rb +10 -0
  103. data/stomper.gemspec +30 -0
  104. metadata +272 -97
  105. data/AUTHORS +0 -21
  106. data/CHANGELOG +0 -20
  107. data/README.rdoc +0 -120
  108. data/lib/stomper/client.rb +0 -34
  109. data/lib/stomper/frame_reader.rb +0 -73
  110. data/lib/stomper/frame_writer.rb +0 -21
  111. data/lib/stomper/frames.rb +0 -39
  112. data/lib/stomper/frames/abort.rb +0 -10
  113. data/lib/stomper/frames/ack.rb +0 -25
  114. data/lib/stomper/frames/begin.rb +0 -11
  115. data/lib/stomper/frames/client_frame.rb +0 -89
  116. data/lib/stomper/frames/commit.rb +0 -10
  117. data/lib/stomper/frames/connect.rb +0 -10
  118. data/lib/stomper/frames/connected.rb +0 -30
  119. data/lib/stomper/frames/disconnect.rb +0 -10
  120. data/lib/stomper/frames/error.rb +0 -21
  121. data/lib/stomper/frames/message.rb +0 -48
  122. data/lib/stomper/frames/receipt.rb +0 -19
  123. data/lib/stomper/frames/send.rb +0 -10
  124. data/lib/stomper/frames/server_frame.rb +0 -38
  125. data/lib/stomper/frames/subscribe.rb +0 -42
  126. data/lib/stomper/frames/unsubscribe.rb +0 -19
  127. data/lib/stomper/open_uri_interface.rb +0 -41
  128. data/lib/stomper/receipt_handlers.rb +0 -23
  129. data/lib/stomper/receiptor.rb +0 -38
  130. data/lib/stomper/subscriber.rb +0 -76
  131. data/lib/stomper/subscription.rb +0 -128
  132. data/lib/stomper/subscriptions.rb +0 -95
  133. data/lib/stomper/threaded_receiver.rb +0 -59
  134. data/lib/stomper/transaction.rb +0 -185
  135. data/lib/stomper/transactor.rb +0 -50
  136. data/lib/stomper/uri.rb +0 -55
  137. data/spec/client_spec.rb +0 -29
  138. data/spec/connection_spec.rb +0 -22
  139. data/spec/frame_reader_spec.rb +0 -37
  140. data/spec/frame_writer_spec.rb +0 -27
  141. data/spec/frames/client_frame_spec.rb +0 -66
  142. data/spec/frames/indirect_frame_spec.rb +0 -45
  143. data/spec/frames/server_frame_spec.rb +0 -85
  144. data/spec/open_uri_interface_spec.rb +0 -132
  145. data/spec/receiptor_spec.rb +0 -35
  146. data/spec/shared_connection_examples.rb +0 -79
  147. data/spec/subscriber_spec.rb +0 -77
  148. data/spec/subscription_spec.rb +0 -157
  149. data/spec/subscriptions_spec.rb +0 -145
  150. data/spec/threaded_receiver_spec.rb +0 -33
  151. data/spec/transaction_spec.rb +0 -139
  152. data/spec/transactor_spec.rb +0 -46
data/CHANGELOG DELETED
@@ -1,20 +0,0 @@
1
- == 1.0 2010-09-24
2
-
3
- * Major additions to api including open-uri style interface.
4
-
5
-
6
- == 0.4 2010-04-23
7
-
8
- * Incremented minor version, beginning expansion.
9
- * Need to make a list of changes I want to make.
10
-
11
-
12
- == 0.3 2010-03-04
13
-
14
- * Added sleep to receive loop to prevent it from running "too tightly", not ideal.
15
- * Bit of cleanup in response to reek report.
16
-
17
-
18
- == 0.2 2009-11-20
19
-
20
- * Officially moved to "stomper" library.
data/README.rdoc DELETED
@@ -1,120 +0,0 @@
1
- =README
2
-
3
- Stomper is a library for connecting to and interacting with a message broker
4
- service that supports the Stomp 1.0 Protocol
5
-
6
- @see http://stomp.github.com/stomp-specification-1-0.html Stomp 1.0 Specification
7
-
8
-
9
- == OpenURI Example Usage
10
-
11
- # A contrived example: Send two messages, receive them back
12
- open("stomp://localhost/queue/testing") do |s|
13
- s.puts "Hello World"
14
- s.write "You may disagree, but I find this useful!"
15
- messages = s.first(2) # => [ Message("Hello World"), Message("You may disagree...") ]
16
- end
17
-
18
- # Another example: connect, send a message to a destination and disconnect
19
- open("stomp://localhost/topic/whatever") do |s|
20
- s.put "PING!"
21
- end
22
-
23
- # Another example: connect, subscribe and process indefinitely
24
- open("stomp://localhost/queue/worker") do |s|
25
- s.each do |m|
26
- logger.info "Received a message: #{m.body}"
27
- # Do important work based on message
28
- end
29
- end
30
-
31
- # Final example: connect, get a single message, and disconnect
32
- open("stomp+ssl://localhost/queue/odd_jobs") do |s|
33
- # you can use get, gets, read or first, they're all the same at
34
- # this time and for the foreseeable future.
35
- incoming_message = s.get
36
- # Do some work on incoming_message
37
- end
38
-
39
- This interface has been a goal of mine for this library for some time now. I
40
- understand the value in a more typical socket object approach, and to that end
41
- the client interface still exists (albeit there's been quite a lot of refractoring.)
42
- However,
43
-
44
- stomp = Stomper::Connection.new("stomp://localhost/")
45
- stomp.subscribe("/queue/blather") do |m|
46
- # ...
47
- end
48
- stomp.send("/topic/other", "Hello")
49
-
50
- just doesn't feel very Ruby-esque to me. While the two methods for interacting with
51
- Stomper connections appear very different, +s+ in the OpenURI examples above
52
- really is a Stomper::Connection, but with some added extensions for handling
53
- +put+, +get+, +each+, and so forth. One note: +read+, +get+ and +gets+ are
54
- all aliases for +first+. Similarly, +puts+ is an alias for +put+. However,
55
- +write+ is slightly different. The message broker I most often use the
56
- STOMP protocol with is Apache ActiveMQ which, at the time of this writing, uses
57
- the absence or presence of a `content-length` header to discriminate between a
58
- JMS TextMessage and a BytesMessage. The +put+ and +puts+ methods will force
59
- Stomper to omit that header, while +write+ will force its presence.
60
-
61
- == Example Usage
62
-
63
- client = Stomper::Client.new("stomp://my_username:s3cr3tz@localhost:61613")
64
- # Clients must be explicitly started to automatically receive incoming
65
- # messages.
66
- client.start
67
-
68
- client.subscribe("/queue/hello") do |msg|
69
- puts msg.body
70
- end
71
-
72
- # Send a simple message
73
- client.send("/queue/hello", "hello world!")
74
-
75
- # Send a message within a transaction. This usage is new to stomper
76
- # however, one can manually manage transactions as well.
77
- client.transaction do |t|
78
- t.send("/queue/hello", "a transactioned message")
79
- end
80
-
81
- # If the block provided to #transaction accepts a single parameter,
82
- # the client yields the Transaction object to the block, otherwise
83
- # the block is instance_eval'd within the Transaction object.
84
- client.transaction do
85
- send("/queue/hello", "a message you will never receive")
86
- # Nested transactions, failures percolate up to parent transactions.
87
- transaction do
88
- send("/queue/hello", "because I am about to fail!")
89
- raise "by forcing an error in a nested transaction"
90
- end
91
- end
92
-
93
- # Later ...
94
- client.stop
95
- client.close
96
-
97
- == To-Do
98
- * Provide other methods for handling the receiver.
99
- * Provide the `pipe` method on Stomper::Client
100
- * Allow SSL verification if requested (option :verify_ssl?)
101
- * Re-evaluate how to handle a 'reliable' connection.
102
-
103
- == License
104
-
105
- Stomper is released under the Apache License 2.0
106
-
107
- == Pointless Backstory
108
-
109
- Stomper began its life as a mere fork of the stomp gem.
110
- However, as changes were made and desires grew, the fork began breaking
111
- API compatibility with the original gem, and thus Stomper was conceived.
112
-
113
- @see http://github.com/js/stomp Stomp
114
-
115
- == Other Stuff
116
-
117
- Primary Author:: Ian D. Eccles
118
- Source Repository:: http://github.com/iande/stomper
119
- Current Version:: 1.0.0
120
- Last Updated:: 2010-09-25
@@ -1,34 +0,0 @@
1
- module Stomper
2
- module Client
3
- # Sends a string message specified by +body+ to the appropriate stomp
4
- # broker destination given by +destination+. Additional headers for the
5
- # message may be specified by the +headers+ hash where the key is the header
6
- # property and the value is the corresponding property's value. The
7
- # keys of +headers+ may be symbols or strings.
8
- #
9
- # Examples:
10
- #
11
- # client.send("/topic/whatever", "hello world")
12
- #
13
- # client.send("/queue/some/destination", "hello world", { :persistent => true })
14
- #
15
- def send(destination, body, headers={})
16
- transmit(Stomper::Frames::Send.new(destination, body, headers))
17
- end
18
-
19
- # Acknowledge to the stomp broker that a given message was received.
20
- # The +id_or_frame+ parameter may be either the message-id header of
21
- # the received message, or an actual instance of Stomper::Frames::Message.
22
- # Additional headers may be specified through the +headers+ hash.
23
- #
24
- # Examples:
25
- #
26
- # client.ack(received_message)
27
- #
28
- # client.ack("message-0001-00451-003031")
29
- #
30
- def ack(id_or_frame, headers={})
31
- transmit(Stomper::Frames::Ack.ack_for(id_or_frame, headers))
32
- end
33
- end
34
- end
@@ -1,73 +0,0 @@
1
- module Stomper
2
- # Deserializes Stomp Frames from an input stream.
3
- # Any object that responds appropriately to +getc+, +gets+
4
- # and +read+ can be used as the input stream.
5
- module FrameReader
6
- # Receives the next Stomp Frame from the socket stream
7
- def receive_frame
8
- command = read_command
9
- headers = read_headers
10
- body = read_body(headers[:'content-length'])
11
- Stomper::Frames::ServerFrame.build(command, headers, body)
12
- end
13
-
14
- private
15
- def read_command
16
- command = ''
17
- while(command.size == 0)
18
- command = gets(Stomper::Frames::LINE_DELIMITER).chomp!
19
- end
20
- command
21
- end
22
-
23
- def read_headers
24
- headers = {}
25
- loop do
26
- line = gets(Stomper::Frames::LINE_DELIMITER).chomp!
27
- break if line.size == 0
28
- if (delim = line.index(':'))
29
- headers[ line[0..(delim-1)].to_sym ] = line[(delim+1)..-1]
30
- end
31
- end
32
- headers
33
- end
34
-
35
- def read_body(body_len)
36
- body_len &&= body_len.strip.to_i
37
- if body_len
38
- read_fixed_body(body_len)
39
- else
40
- read_null_terminated_body
41
- end
42
- end
43
-
44
- def read_null_terminated_body
45
- body = ''
46
- while next_byte = get_body_byte
47
- body << next_byte.chr
48
- end
49
- body
50
- end
51
-
52
- def read_fixed_body(num_bytes)
53
- body = read(num_bytes)
54
- raise MalformedFrameError if get_body_byte
55
- body
56
- end
57
-
58
- def get_body_byte
59
- next_byte = get_ord
60
- (next_byte == Stomper::Frames::TERMINATOR) ? nil : next_byte
61
- end
62
-
63
- if String.method_defined?(:ord)
64
- def get_ord
65
- getc.ord
66
- end
67
- else
68
- def get_ord
69
- getc
70
- end
71
- end
72
- end
73
- end
@@ -1,21 +0,0 @@
1
- module Stomper
2
- # Serializes Stomp Frames to an output stream.
3
- # Any object that responds appropriately to +write+
4
- # can be used as the input stream.
5
- module FrameWriter
6
- # Writes a Stomp Frame to the underlying output stream.
7
- def transmit_frame(frame)
8
- write([ frame.command, Stomper::Frames::LINE_DELIMITER,
9
- serialize_headers(frame.headers), Stomper::Frames::LINE_DELIMITER,
10
- frame.body, Stomper::Frames::TERMINATOR.chr].join)
11
- end
12
-
13
- private
14
- def serialize_headers(headers)
15
- headers.inject("") do |acc, (key, val)|
16
- acc << "#{key}#{Stomper::Frames::HEADER_DELIMITER}#{val}#{Stomper::Frames::LINE_DELIMITER}"
17
- acc
18
- end
19
- end
20
- end
21
- end
@@ -1,39 +0,0 @@
1
- module Stomper
2
- # This module holds all known encapsulations of
3
- # frames that are part of the Stomp Protocol specification.
4
- module Frames
5
- HEADER_DELIMITER = ':'
6
- TERMINATOR = 0
7
- LINE_DELIMITER = "\n"
8
-
9
- class IndirectFrame #:nodoc:
10
- attr_reader :headers, :body
11
-
12
- def initialize(headers={}, body=nil, command=nil)
13
- @command = command && command.to_s.upcase
14
- @headers = headers.dup
15
- @body = body
16
- end
17
-
18
- def command
19
- @command ||= self.class.name.split("::").last.upcase
20
- end
21
- end
22
- end
23
- end
24
-
25
- require 'stomper/frames/client_frame'
26
- require 'stomper/frames/server_frame'
27
- require 'stomper/frames/abort'
28
- require 'stomper/frames/ack'
29
- require 'stomper/frames/begin'
30
- require 'stomper/frames/commit'
31
- require 'stomper/frames/connect'
32
- require 'stomper/frames/connected'
33
- require 'stomper/frames/disconnect'
34
- require 'stomper/frames/error'
35
- require 'stomper/frames/message'
36
- require 'stomper/frames/receipt'
37
- require 'stomper/frames/send'
38
- require 'stomper/frames/subscribe'
39
- require 'stomper/frames/unsubscribe'
@@ -1,10 +0,0 @@
1
- module Stomper
2
- module Frames
3
- # Encapsulates an "ABORT" frame from the Stomp Protocol.
4
- class Abort < Stomper::Frames::ClientFrame
5
- def initialize(transaction_id, headers={})
6
- super(headers.merge(:transaction => transaction_id))
7
- end
8
- end
9
- end
10
- end
@@ -1,25 +0,0 @@
1
- module Stomper
2
- module Frames
3
- # Encapsulates an "ACK" frame from the Stomp Protocol.
4
- class Ack < Stomper::Frames::ClientFrame
5
- def initialize(message_id, headers={})
6
- super(headers.merge({ :'message-id' => message_id }))
7
- end
8
-
9
- # Creates a new Ack instance that corresponds to an acknowledgement
10
- # of the supplied +message+, with any additional +headers+. The
11
- # +message+ parameter may be an instance of Stomper::Frames::Message, or
12
- # a message id. If +message+ is an instance of Stomper::Frames::Message
13
- # and was exchanged as part of a transaction, the transaction header from
14
- # +message+ will be injected into the newly created Ack object's headers.
15
- def self.ack_for(message, headers = {})
16
- if message.is_a?(Message)
17
- headers[:transaction] = message.headers[:transaction] if message.headers[:transaction]
18
- new(message.id, headers)
19
- else
20
- new(message.to_s)
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,11 +0,0 @@
1
- module Stomper
2
- module Frames
3
- # Encapsulates a "BEGIN" frame from the Stomp Protocol.
4
- class Begin < Stomper::Frames::ClientFrame
5
- def initialize(transaction_id, headers={})
6
- super(headers.merge(:transaction => transaction_id))
7
- @headers[:transaction] = transaction_id
8
- end
9
- end
10
- end
11
- end
@@ -1,89 +0,0 @@
1
- module Stomper
2
- module Frames
3
- # Encapsulates a client side frame for the Stomp Protocol.
4
- class ClientFrame < IndirectFrame
5
-
6
- # Creates a new ClientFrame instance with the specified +command+,
7
- # +headers+ and +body+.
8
- # If +headers+ includes a key of :generate_content_length, the
9
- # associated value will determine if a 'content-length' header is automatically
10
- # generated for this particular frame instance. This key can be
11
- # specified in the +headers+ parameter of any of the subclasses of ClientFrame,
12
- # and it will be interpretted in the same fashion.
13
- def initialize(headers={}, body=nil, command = nil)
14
- @generate_content_length = headers.delete(:generate_content_length)
15
- super(headers, body, command)
16
- end
17
-
18
- # If +bool+ is false or nil, this frame instance will not attempt to
19
- # automatically generate a content-length header. This is useful when
20
- # dealing with ActiveMQ as a stomp message broker, which will treat incoming
21
- # messages lacking a content-length header as +TextMessage+s and
22
- # +BytesMessage+s if the header is present. For more information see:
23
- # {Apache ActiveMQ - Stomp}[http://activemq.apache.org/stomp.html]
24
- def generate_content_length=(bool)
25
- @generate_content_length=bool
26
- end
27
-
28
- # If generate_content_length= has been called on this instance, then the
29
- # value supplied there is returned here. Otherwise, we defer to the
30
- # class method of the same name.
31
- def generate_content_length?
32
- @generate_content_length.nil? ? self.class.generate_content_length? : @generate_content_length
33
- end
34
-
35
-
36
- # Returns the headers for this frame, including a +content-length+ header
37
- # set to the size of the current body, if +generate_content_length?+ is
38
- # not false.
39
- def headers
40
- if generate_content_length? && @body && !@body.empty?
41
- @headers[:'content-length'] ||= body_size
42
- end
43
- @headers
44
- end
45
-
46
- class << self
47
- # Sets a class level setting for determining if a content-length header
48
- # should automatically be generated.
49
- def generate_content_length=(bool)
50
- @generate_content_length = bool
51
- end
52
-
53
- # Returns the value passed to the class level generate_content_length=
54
- # method, or true if no value has been set (thus, defaults to true.)
55
- #
56
- # The precedence for resolving whether or not a content-length header
57
- # is generated by the +headers+ method is:
58
- # check the instance setting,
59
- # if it has not been set, defer to the class setting, if it hasn't
60
- # been set, default to true.
61
- def generate_content_length?
62
- if @generate_content_length.nil?
63
- @generate_content_length = true
64
- end
65
- @generate_content_length
66
- end
67
-
68
- def inherited(client_frame) #:nodoc:
69
- declared_frames << { :class => client_frame, :command => client_frame.name.split("::").last.downcase.to_sym }
70
- end
71
-
72
- def declared_frames
73
- @declared_frames ||= []
74
- end
75
- end
76
-
77
- private
78
- if String.method_defined?(:bytesize)
79
- def body_size
80
- @body.bytesize
81
- end
82
- else
83
- def body_size
84
- @body.size
85
- end
86
- end
87
- end
88
- end
89
- end