solutious-stella 0.7.0.004 → 0.7.0.005

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/bin/stella +16 -20
  2. data/examples/essentials/logo.png +0 -0
  3. data/examples/{basic → essentials}/plan.rb +7 -3
  4. data/examples/{basic → essentials}/search_terms.csv +0 -0
  5. data/examples/example_webapp.rb +7 -4
  6. data/examples/example_webapp.ru +3 -0
  7. data/lib/stella.rb +18 -26
  8. data/lib/stella/cli.rb +4 -1
  9. data/lib/stella/client.rb +49 -26
  10. data/lib/stella/data.rb +35 -9
  11. data/lib/stella/data/http.rb +1 -1
  12. data/lib/stella/data/http/request.rb +3 -14
  13. data/lib/stella/engine.rb +10 -4
  14. data/lib/stella/engine/functional.rb +2 -4
  15. data/lib/stella/engine/load.rb +24 -21
  16. data/lib/stella/mixins.rb +1 -1
  17. data/lib/stella/stats.rb +17 -4
  18. data/lib/stella/testplan/usecase.rb +2 -2
  19. data/lib/stella/utils.rb +16 -1
  20. data/lib/stella/version.rb +1 -1
  21. data/stella.gemspec +17 -4
  22. data/vendor/httpclient-2.1.5.2/httpclient.rb +1025 -0
  23. data/vendor/httpclient-2.1.5.2/httpclient/auth.rb +522 -0
  24. data/vendor/httpclient-2.1.5.2/httpclient/cacert.p7s +1579 -0
  25. data/vendor/httpclient-2.1.5.2/httpclient/cacert_sha1.p7s +1579 -0
  26. data/vendor/httpclient-2.1.5.2/httpclient/connection.rb +84 -0
  27. data/vendor/httpclient-2.1.5.2/httpclient/cookie.rb +562 -0
  28. data/vendor/httpclient-2.1.5.2/httpclient/http.rb +867 -0
  29. data/vendor/httpclient-2.1.5.2/httpclient/session.rb +864 -0
  30. data/vendor/httpclient-2.1.5.2/httpclient/ssl_config.rb +417 -0
  31. data/vendor/httpclient-2.1.5.2/httpclient/stats.rb +90 -0
  32. data/vendor/httpclient-2.1.5.2/httpclient/timeout.rb +136 -0
  33. data/vendor/httpclient-2.1.5.2/httpclient/util.rb +86 -0
  34. metadata +17 -4
  35. data/lib/stella/dsl.rb +0 -5
@@ -0,0 +1,417 @@
1
+ # HTTPClient - HTTP client library.
2
+ # Copyright (C) 2000-2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+ #
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ class HTTPClient
10
+
11
+ begin
12
+ require 'openssl'
13
+ SSLEnabled = true
14
+ rescue LoadError
15
+ SSLEnabled = false
16
+ end
17
+
18
+ # Represents SSL configuration for HTTPClient instance.
19
+ # The implementation depends on OpenSSL.
20
+ #
21
+ # == Trust Anchor Control
22
+ #
23
+ # SSLConfig loads 'httpclient/cacert.p7s' as a trust anchor
24
+ # (trusted certificate(s)) with set_trust_ca in initialization time.
25
+ # This means that HTTPClient instance trusts some CA certificates by default,
26
+ # like Web browsers. 'httpclient/cacert.p7s' is created by the author and
27
+ # included in released package.
28
+ #
29
+ # 'cacert.p7s' is automatically generated from JDK 1.6.
30
+ #
31
+ # You may want to change trust anchor by yourself. Call clear_cert_store
32
+ # then set_trust_ca for that purpose.
33
+ class SSLConfig
34
+ include OpenSSL if SSLEnabled
35
+
36
+ # OpenSSL::X509::Certificate:: certificate for SSL client authenticateion.
37
+ # nil by default. (no client authenticateion)
38
+ attr_reader :client_cert
39
+ # OpenSSL::PKey::PKey:: private key for SSL client authentication.
40
+ # nil by default. (no client authenticateion)
41
+ attr_reader :client_key
42
+
43
+ # A number which represents OpenSSL's verify mode. Default value is
44
+ # OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.
45
+ attr_reader :verify_mode
46
+ # A number of verify depth. Certification path which length is longer than
47
+ # this depth is not allowed.
48
+ attr_reader :verify_depth
49
+ # A callback handler for custom certificate verification. nil by default.
50
+ # If the handler is set, handler.call is invoked just after general
51
+ # OpenSSL's verification. handler.call is invoked with 2 arguments,
52
+ # ok and ctx; ok is a result of general OpenSSL's verification. ctx is a
53
+ # OpenSSL::X509::StoreContext.
54
+ attr_reader :verify_callback
55
+ # SSL timeout in sec. nil by default.
56
+ attr_reader :timeout
57
+ # A number of OpenSSL's SSL options. Default value is
58
+ # OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2
59
+ attr_reader :options
60
+ # A String of OpenSSL's cipher configuration. Default value is
61
+ # ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH
62
+ # See ciphers(1) man in OpenSSL for more detail.
63
+ attr_reader :ciphers
64
+
65
+ # OpenSSL::X509::X509::Store used for verification. You can reset the
66
+ # store with clear_cert_store and set the new store with cert_store=.
67
+ attr_reader :cert_store # don't use if you don't know what it is.
68
+
69
+ # For server side configuration. Ignore this.
70
+ attr_reader :client_ca # :nodoc:
71
+
72
+ # Creates a SSLConfig.
73
+ def initialize(client)
74
+ return unless SSLEnabled
75
+ @client = client
76
+ @cert_store = X509::Store.new
77
+ @client_cert = @client_key = @client_ca = nil
78
+ @verify_mode = SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
79
+ @verify_depth = nil
80
+ @verify_callback = nil
81
+ @dest = nil
82
+ @timeout = nil
83
+ @options = defined?(SSL::OP_ALL) ? SSL::OP_ALL | SSL::OP_NO_SSLv2 : nil
84
+ @ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
85
+ load_cacerts
86
+ end
87
+
88
+ # Sets certificate (OpenSSL::X509::Certificate) for SSL client
89
+ # authentication.
90
+ # client_key and client_cert must be a pair.
91
+ #
92
+ # Calling this method resets all existing sessions.
93
+ def client_cert=(client_cert)
94
+ @client_cert = client_cert
95
+ change_notify
96
+ end
97
+
98
+ # Sets private key (OpenSSL::PKey::PKey) for SSL client authentication.
99
+ # client_key and client_cert must be a pair.
100
+ #
101
+ # Calling this method resets all existing sessions.
102
+ def client_key=(client_key)
103
+ @client_key = client_key
104
+ change_notify
105
+ end
106
+
107
+ # Sets certificate and private key for SSL client authentication.
108
+ # cert_file:: must be a filename of PEM/DER formatted file.
109
+ # key_file:: must be a filename of PEM/DER formatted file. Key must be an
110
+ # RSA key. If you want to use other PKey algorithm,
111
+ # use client_key=.
112
+ #
113
+ # Calling this method resets all existing sessions.
114
+ def set_client_cert_file(cert_file, key_file)
115
+ @client_cert = X509::Certificate.new(File.open(cert_file).read)
116
+ @client_key = PKey::RSA.new(File.open(key_file).read)
117
+ change_notify
118
+ end
119
+
120
+ # Drops current certificate store (OpenSSL::X509::Store) for SSL and create
121
+ # new one for the next session.
122
+ #
123
+ # Calling this method resets all existing sessions.
124
+ def clear_cert_store
125
+ @cert_store = X509::Store.new
126
+ change_notify
127
+ end
128
+
129
+ # Sets new certificate store (OpenSSL::X509::Store).
130
+ # don't use if you don't know what it is.
131
+ #
132
+ # Calling this method resets all existing sessions.
133
+ def cert_store=(cert_store)
134
+ @cert_store = cert_store
135
+ change_notify
136
+ end
137
+
138
+ # Sets trust anchor certificate(s) for verification.
139
+ # trust_ca_file_or_hashed_dir:: a filename of a PEM/DER formatted
140
+ # OpenSSL::X509::Certificate or
141
+ # a 'c-rehash'eddirectory name which stores
142
+ # trusted certificate files.
143
+ #
144
+ # Calling this method resets all existing sessions.
145
+ def set_trust_ca(trust_ca_file_or_hashed_dir)
146
+ if FileTest.directory?(trust_ca_file_or_hashed_dir)
147
+ @cert_store.add_path(trust_ca_file_or_hashed_dir)
148
+ else
149
+ @cert_store.add_file(trust_ca_file_or_hashed_dir)
150
+ end
151
+ change_notify
152
+ end
153
+
154
+ # Adds CRL for verification.
155
+ # crl:: a OpenSSL::X509::CRL or a filename of a PEM/DER formatted
156
+ # OpenSSL::X509::CRL.
157
+ #
158
+ # Calling this method resets all existing sessions.
159
+ def set_crl(crl)
160
+ unless crl.is_a?(X509::CRL)
161
+ crl = X509::CRL.new(File.open(crl).read)
162
+ end
163
+ @cert_store.add_crl(crl)
164
+ @cert_store.flags = X509::V_FLAG_CRL_CHECK | X509::V_FLAG_CRL_CHECK_ALL
165
+ change_notify
166
+ end
167
+
168
+ # Sets verify mode of OpenSSL. New value must be a combination of
169
+ # constants OpenSSL::SSL::VERIFY_*
170
+ #
171
+ # Calling this method resets all existing sessions.
172
+ def verify_mode=(verify_mode)
173
+ @verify_mode = verify_mode
174
+ change_notify
175
+ end
176
+
177
+ # Sets verify depth. New value must be a number.
178
+ #
179
+ # Calling this method resets all existing sessions.
180
+ def verify_depth=(verify_depth)
181
+ @verify_depth = verify_depth
182
+ change_notify
183
+ end
184
+
185
+ # Sets callback handler for custom certificate verification.
186
+ # See verify_callback.
187
+ #
188
+ # Calling this method resets all existing sessions.
189
+ def verify_callback=(verify_callback)
190
+ @verify_callback = verify_callback
191
+ change_notify
192
+ end
193
+
194
+ # Sets SSL timeout in sec.
195
+ #
196
+ # Calling this method resets all existing sessions.
197
+ def timeout=(timeout)
198
+ @timeout = timeout
199
+ change_notify
200
+ end
201
+
202
+ # Sets SSL options. New value must be a combination of # constants
203
+ # OpenSSL::SSL::OP_*
204
+ #
205
+ # Calling this method resets all existing sessions.
206
+ def options=(options)
207
+ @options = options
208
+ change_notify
209
+ end
210
+
211
+ # Sets cipher configuration. New value must be a String.
212
+ #
213
+ # Calling this method resets all existing sessions.
214
+ def ciphers=(ciphers)
215
+ @ciphers = ciphers
216
+ change_notify
217
+ end
218
+
219
+ def client_ca=(client_ca) # :nodoc:
220
+ @client_ca = client_ca
221
+ change_notify
222
+ end
223
+
224
+ # interfaces for SSLSocketWrap.
225
+ def set_context(ctx) # :nodoc:
226
+ # Verification: Use Store#verify_callback instead of SSLContext#verify*?
227
+ ctx.cert_store = @cert_store
228
+ ctx.verify_mode = @verify_mode
229
+ ctx.verify_depth = @verify_depth if @verify_depth
230
+ ctx.verify_callback = @verify_callback || method(:default_verify_callback)
231
+ # SSL config
232
+ ctx.cert = @client_cert
233
+ ctx.key = @client_key
234
+ ctx.client_ca = @client_ca
235
+ ctx.timeout = @timeout
236
+ ctx.options = @options
237
+ ctx.ciphers = @ciphers
238
+ end
239
+
240
+ # post connection check proc for ruby < 1.8.5.
241
+ # this definition must match with the one in ext/openssl/lib/openssl/ssl.rb
242
+ def post_connection_check(peer_cert, hostname) # :nodoc:
243
+ check_common_name = true
244
+ cert = peer_cert
245
+ cert.extensions.each{|ext|
246
+ next if ext.oid != "subjectAltName"
247
+ ext.value.split(/,\s+/).each{|general_name|
248
+ if /\ADNS:(.*)/ =~ general_name
249
+ check_common_name = false
250
+ reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
251
+ return true if /\A#{reg}\z/i =~ hostname
252
+ elsif /\AIP Address:(.*)/ =~ general_name
253
+ check_common_name = false
254
+ return true if $1 == hostname
255
+ end
256
+ }
257
+ }
258
+ if check_common_name
259
+ cert.subject.to_a.each{|oid, value|
260
+ if oid == "CN"
261
+ reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
262
+ return true if /\A#{reg}\z/i =~ hostname
263
+ end
264
+ }
265
+ end
266
+ raise SSL::SSLError, "hostname was not match with the server certificate"
267
+ end
268
+
269
+ # Default callback for verification: only dumps error.
270
+ def default_verify_callback(is_ok, ctx)
271
+ if $DEBUG
272
+ puts "#{ is_ok ? 'ok' : 'ng' }: #{ctx.current_cert.subject}"
273
+ end
274
+ if !is_ok
275
+ depth = ctx.error_depth
276
+ code = ctx.error
277
+ msg = ctx.error_string
278
+ STDERR.puts "at depth #{depth} - #{code}: #{msg}"
279
+ end
280
+ is_ok
281
+ end
282
+
283
+ # Sample callback method: CAUTION: does not check CRL/ARL.
284
+ def sample_verify_callback(is_ok, ctx)
285
+ unless is_ok
286
+ depth = ctx.error_depth
287
+ code = ctx.error
288
+ msg = ctx.error_string
289
+ STDERR.puts "at depth #{depth} - #{code}: #{msg}" if $DEBUG
290
+ return false
291
+ end
292
+
293
+ cert = ctx.current_cert
294
+ self_signed = false
295
+ ca = false
296
+ pathlen = nil
297
+ server_auth = true
298
+ self_signed = (cert.subject.cmp(cert.issuer) == 0)
299
+
300
+ # Check extensions whatever its criticality is. (sample)
301
+ cert.extensions.each do |ex|
302
+ case ex.oid
303
+ when 'basicConstraints'
304
+ /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ex.value
305
+ ca = ($1 == 'TRUE')
306
+ pathlen = $2.to_i
307
+ when 'keyUsage'
308
+ usage = ex.value.split(/\s*,\s*/)
309
+ ca = usage.include?('Certificate Sign')
310
+ server_auth = usage.include?('Key Encipherment')
311
+ when 'extendedKeyUsage'
312
+ usage = ex.value.split(/\s*,\s*/)
313
+ server_auth = usage.include?('Netscape Server Gated Crypto')
314
+ when 'nsCertType'
315
+ usage = ex.value.split(/\s*,\s*/)
316
+ ca = usage.include?('SSL CA')
317
+ server_auth = usage.include?('SSL Server')
318
+ end
319
+ end
320
+
321
+ if self_signed
322
+ STDERR.puts 'self signing CA' if $DEBUG
323
+ return true
324
+ elsif ca
325
+ STDERR.puts 'middle level CA' if $DEBUG
326
+ return true
327
+ elsif server_auth
328
+ STDERR.puts 'for server authentication' if $DEBUG
329
+ return true
330
+ end
331
+
332
+ return false
333
+ end
334
+
335
+ private
336
+
337
+ def change_notify
338
+ @client.reset_all
339
+ end
340
+
341
+ def load_cacerts
342
+ [
343
+ [DIST_CERT, 'cacert.p7s'],
344
+ [DIST_CERT_SHA1, 'cacert_sha1.p7s']
345
+ ].each do |cert_str, ca_file|
346
+ file = File.join(File.dirname(__FILE__), ca_file)
347
+ if File.exist?(file)
348
+ p7 = PKCS7.read_smime(File.open(file) { |f| f.read })
349
+ selfcert = X509::Certificate.new(cert_str)
350
+ store = X509::Store.new
351
+ store.add_cert(selfcert)
352
+ if (p7.verify(nil, store, p7.data, 0))
353
+ set_trust_ca(file)
354
+ return
355
+ end
356
+ end
357
+ end
358
+ STDERR.puts("cacerts loading failed")
359
+ end
360
+
361
+ DIST_CERT =<<__DIST_CERT__
362
+ -----BEGIN CERTIFICATE-----
363
+ MIID/TCCAuWgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBLMQswCQYDVQQGEwJKUDER
364
+ MA8GA1UECgwIY3Rvci5vcmcxFDASBgNVBAsMC0RldmVsb3BtZW50MRMwEQYDVQQD
365
+ DApodHRwY2xpZW50MB4XDTA5MDUyMTEyMzkwNVoXDTM3MTIzMTIzNTk1OVowSzEL
366
+ MAkGA1UEBhMCSlAxETAPBgNVBAoMCGN0b3Iub3JnMRQwEgYDVQQLDAtEZXZlbG9w
367
+ bWVudDETMBEGA1UEAwwKaHR0cGNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEP
368
+ ADCCAQoCggEBAM2PlkdTH97zvIHoPIMj87wnNvpqIQUD7L/hlysO0XBsmR/XZUeU
369
+ ZKB10JQqMXviWpTnU9KU6xGTx3EI4wfd2dpLwH/d4d7K4LngW1kY7kJlZeJhakno
370
+ GzQ40RSI9WkQ0R9KOE888f7OkTBafcL8UyWFVIMhQBw2d9iNl4Jc69QojayCDoSX
371
+ XbbEP0n8yi7HwIU3RFuX6DtMpOx4/1K7Z002ccOGJ3J9kHgeDQSQtF42cQYC7qj2
372
+ 67I/OQgnB7ycxTCP0E7bdXQg+zqsngrhaoNn/+I+CoO7nD4t4uQ+B4agALh4PPxs
373
+ bQD9MCL+VurNGLYv0HVd+ZlLblpddC9PLTsCAwEAAaOB6zCB6DAPBgNVHRMBAf8E
374
+ BTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09wZW5TU0wgR2VuZXJhdGVkIENl
375
+ cnRpZmljYXRlMB0GA1UdDgQWBBRAnB6XlMoOcm7HVAw+JWxY205PHTAOBgNVHQ8B
376
+ Af8EBAMCAQYwcwYDVR0jBGwwaoAUQJwel5TKDnJux1QMPiVsWNtOTx2hT6RNMEsx
377
+ CzAJBgNVBAYTAkpQMREwDwYDVQQKDAhjdG9yLm9yZzEUMBIGA1UECwwLRGV2ZWxv
378
+ cG1lbnQxEzARBgNVBAMMCmh0dHBjbGllbnSCAQEwDQYJKoZIhvcNAQENBQADggEB
379
+ ABVFepybD5XqsBnOn/oDHvK0xAPMF4Ap4Ht1yMQLObg8paVhANSdqIevPlCr/mPL
380
+ DRjcy+J1fCnE6lCfsfLdTgAjirqt8pm92NccxmJ8hTmMd3LWC1n+eYWaolqTCVRM
381
+ Bpe8UY9enyXrFoudHlr9epr18E6As6VrCSfpXFZkD9WHVSWpzkB3qATu5qcDCzCH
382
+ bI0755Mdm/1hKJCD4l69h3J3OhRIEUPJfHnPvM5wtiyC2dcE9itwE/wdVzBJeIBX
383
+ JQm+Qj+K8qXcRTzZZGIBjw2n46xJgW6YncNCHU/WWfNCYwdkngHS/aN8IbEjhCwf
384
+ viXFisVrDN/+pZZGMf67ZaY=
385
+ -----END CERTIFICATE-----
386
+ __DIST_CERT__
387
+
388
+ DIST_CERT_SHA1 =<<__DIST_CERT__
389
+ -----BEGIN CERTIFICATE-----
390
+ MIID/TCCAuWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJKUDER
391
+ MA8GA1UECgwIY3Rvci5vcmcxFDASBgNVBAsMC0RldmVsb3BtZW50MRMwEQYDVQQD
392
+ DApodHRwY2xpZW50MB4XDTA5MDYyNTE0MjUzN1oXDTEwMTIzMTIzNTk1OVowSzEL
393
+ MAkGA1UEBhMCSlAxETAPBgNVBAoMCGN0b3Iub3JnMRQwEgYDVQQLDAtEZXZlbG9w
394
+ bWVudDETMBEGA1UEAwwKaHR0cGNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEP
395
+ ADCCAQoCggEBAM2PlkdTH97zvIHoPIMj87wnNvpqIQUD7L/hlysO0XBsmR/XZUeU
396
+ ZKB10JQqMXviWpTnU9KU6xGTx3EI4wfd2dpLwH/d4d7K4LngW1kY7kJlZeJhakno
397
+ GzQ40RSI9WkQ0R9KOE888f7OkTBafcL8UyWFVIMhQBw2d9iNl4Jc69QojayCDoSX
398
+ XbbEP0n8yi7HwIU3RFuX6DtMpOx4/1K7Z002ccOGJ3J9kHgeDQSQtF42cQYC7qj2
399
+ 67I/OQgnB7ycxTCP0E7bdXQg+zqsngrhaoNn/+I+CoO7nD4t4uQ+B4agALh4PPxs
400
+ bQD9MCL+VurNGLYv0HVd+ZlLblpddC9PLTsCAwEAAaOB6zCB6DAPBgNVHRMBAf8E
401
+ BTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09wZW5TU0wgR2VuZXJhdGVkIENl
402
+ cnRpZmljYXRlMB0GA1UdDgQWBBRAnB6XlMoOcm7HVAw+JWxY205PHTAOBgNVHQ8B
403
+ Af8EBAMCAQYwcwYDVR0jBGwwaoAUQJwel5TKDnJux1QMPiVsWNtOTx2hT6RNMEsx
404
+ CzAJBgNVBAYTAkpQMREwDwYDVQQKDAhjdG9yLm9yZzEUMBIGA1UECwwLRGV2ZWxv
405
+ cG1lbnQxEzARBgNVBAMMCmh0dHBjbGllbnSCAQIwDQYJKoZIhvcNAQEFBQADggEB
406
+ AGKhgByl/ur6SBFFKJcISJONFRaxf2ji0l6ut9XO1H2BSOSRjUbsFDWdWZG+D24Q
407
+ JKKseSWPWAC5uHq00sBWkvmtip+duESPeDEdumdBhdiUUgGamW2Ew2y4yAdAVDeG
408
+ t1p2fs8SylQN6AMTG/+R+MGHxhvg+UELYLcvAjjcDW2VhDQaJ1eFEfcMW1zRtvvh
409
+ LJmVErouwFKyAjwhbF6sNxmToSnbO1ciWwIILMsOBNHMETCp+SzkRDIRWIkm6m+q
410
+ RwRyYoHysODGvnu8VXS1hGRr2GIxeBga7dAGa2VLE/iUQ0d4lEskYU+6C4ZLyAWF
411
+ O89dvLNRzpL10MaWCYVREks=
412
+ -----END CERTIFICATE-----
413
+ __DIST_CERT__
414
+ end
415
+
416
+
417
+ end
@@ -0,0 +1,90 @@
1
+
2
+ class HTTPClient
3
+
4
+ # Based on Mongrel::Stats, Copyright (c) 2005 Zed A. Shaw
5
+ class Stats
6
+
7
+ attr_reader :sum, :sumsq, :n, :min, :max
8
+
9
+ def initialize
10
+ reset
11
+ end
12
+
13
+ def +(obj)
14
+ puts obj.class
15
+ end
16
+
17
+ # Resets the internal counters so you can start sampling again.
18
+ def reset
19
+ @n, @sum, @sumsq = 0.0, 0.0, 0.0
20
+ @last_time = Time.new
21
+ @min, @max = 0.0, 0.0
22
+ end
23
+
24
+ # Adds a sampling to the calculations.
25
+ def sample(s)
26
+ @sum += s
27
+ @sumsq += s * s
28
+ if @n == 0
29
+ @min = @max = s
30
+ else
31
+ @min = s if @min > s
32
+ @max = s if @max < s
33
+ end
34
+ @n+=1
35
+ end
36
+
37
+ # Dump this Stats object with an optional additional message.
38
+ def dump(msg = "", out=STDERR)
39
+ out.puts "#{msg}: #{self.to_s}"
40
+ end
41
+
42
+ # Returns a common display (used by dump)
43
+ def to_s
44
+ "[#{@name}]: SUM=%0.4f, SUMSQ=%0.4f, N=%0.4f, MEAN=%0.4f, SD=%0.4f, MIN=%0.4f, MAX=%0.4f" % [@sum, @sumsq, @n, mean, sd, @min, @max]
45
+ end
46
+
47
+
48
+ # Calculates and returns the mean for the data passed so far.
49
+ def mean
50
+ @sum / @n
51
+ end
52
+
53
+ # Calculates the standard deviation of the data so far.
54
+ def sd
55
+ return 0.0 if @n <= 1
56
+ # (sqrt( ((s).sumsq - ( (s).sum * (s).sum / (s).n)) / ((s).n-1) ))
57
+ begin
58
+ return Math.sqrt( (@sumsq - ( @sum * @sum / @n)) / (@n-1) )
59
+ rescue Errno::EDOM
60
+ return 0.0
61
+ end
62
+ end
63
+
64
+
65
+ # Adds a time delta between now and the last time you called this. This
66
+ # will give you the average time between two activities.
67
+ #
68
+ # An example is:
69
+ #
70
+ # t = Stats.new("do_stuff")
71
+ # 10000.times { do_stuff(); t.tick }
72
+ # t.dump("time")
73
+ #
74
+ def tick
75
+ now = Time.now
76
+ sample(now - @last_time)
77
+ @last_time = now
78
+ end
79
+ end
80
+
81
+ class Timer
82
+ attr_reader :initialized
83
+ attr_reader :stats
84
+ def initialized
85
+ @initialized = Time.now
86
+ @stats = Stats.new
87
+ end
88
+ end
89
+ end
90
+