activesupport 3.0.20 → 3.1.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 (132) hide show
  1. data/CHANGELOG +24 -28
  2. data/README.rdoc +2 -2
  3. data/lib/active_support/backtrace_cleaner.rb +17 -12
  4. data/lib/active_support/buffered_logger.rb +7 -9
  5. data/lib/active_support/cache/file_store.rb +4 -3
  6. data/lib/active_support/cache/mem_cache_store.rb +10 -2
  7. data/lib/active_support/cache/strategy/local_cache.rb +28 -23
  8. data/lib/active_support/cache.rb +11 -14
  9. data/lib/active_support/callbacks.rb +195 -175
  10. data/lib/active_support/concern.rb +105 -35
  11. data/lib/active_support/configurable.rb +50 -8
  12. data/lib/active_support/core_ext/array/access.rb +2 -2
  13. data/lib/active_support/core_ext/array/conversions.rb +2 -2
  14. data/lib/active_support/core_ext/array/random_access.rb +10 -7
  15. data/lib/active_support/core_ext/array/uniq_by.rb +2 -3
  16. data/lib/active_support/core_ext/array/wrap.rb +1 -1
  17. data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -2
  18. data/lib/active_support/core_ext/class/attribute.rb +15 -1
  19. data/lib/active_support/core_ext/class/inheritable_attributes.rb +10 -86
  20. data/lib/active_support/core_ext/class/subclasses.rb +20 -34
  21. data/lib/active_support/core_ext/date/calculations.rb +17 -5
  22. data/lib/active_support/core_ext/date/conversions.rb +9 -2
  23. data/lib/active_support/core_ext/date_time/calculations.rb +26 -9
  24. data/lib/active_support/core_ext/date_time/conversions.rb +9 -9
  25. data/lib/active_support/core_ext/date_time/zones.rb +1 -1
  26. data/lib/active_support/core_ext/enumerable.rb +3 -6
  27. data/lib/active_support/core_ext/float/rounding.rb +1 -1
  28. data/lib/active_support/core_ext/hash/conversions.rb +22 -34
  29. data/lib/active_support/core_ext/hash/deep_dup.rb +11 -0
  30. data/lib/active_support/core_ext/hash/indifferent_access.rb +12 -0
  31. data/lib/active_support/core_ext/hash/keys.rb +6 -4
  32. data/lib/active_support/core_ext/hash/reverse_merge.rb +9 -14
  33. data/lib/active_support/core_ext/hash/slice.rb +3 -1
  34. data/lib/active_support/core_ext/hash.rb +1 -0
  35. data/lib/active_support/core_ext/integer/inflections.rb +7 -4
  36. data/lib/active_support/core_ext/kernel/reporting.rb +31 -0
  37. data/lib/active_support/core_ext/kernel/requires.rb +2 -0
  38. data/lib/active_support/core_ext/logger.rb +11 -38
  39. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +12 -12
  40. data/lib/active_support/core_ext/module/attr_internal.rb +13 -6
  41. data/lib/active_support/core_ext/module/delegation.rb +1 -5
  42. data/lib/active_support/core_ext/module/remove_method.rb +7 -2
  43. data/lib/active_support/core_ext/numeric/time.rb +2 -0
  44. data/lib/active_support/core_ext/object/blank.rb +45 -12
  45. data/lib/active_support/core_ext/object/duplicable.rb +50 -9
  46. data/lib/active_support/core_ext/object/inclusion.rb +15 -0
  47. data/lib/active_support/core_ext/object/instance_variables.rb +1 -35
  48. data/lib/active_support/core_ext/object/to_param.rb +13 -8
  49. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  50. data/lib/active_support/core_ext/object/try.rb +29 -10
  51. data/lib/active_support/core_ext/object/with_options.rb +25 -8
  52. data/lib/active_support/core_ext/object.rb +1 -1
  53. data/lib/active_support/core_ext/range/cover.rb +3 -0
  54. data/lib/active_support/core_ext/range.rb +1 -0
  55. data/lib/active_support/core_ext/string/behavior.rb +1 -2
  56. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  57. data/lib/active_support/core_ext/string/exclude.rb +1 -1
  58. data/lib/active_support/core_ext/string/filters.rb +3 -3
  59. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  60. data/lib/active_support/core_ext/string/inquiry.rb +13 -0
  61. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  62. data/lib/active_support/core_ext/string/output_safety.rb +45 -62
  63. data/lib/active_support/core_ext/string.rb +1 -0
  64. data/lib/active_support/core_ext/time/calculations.rb +19 -16
  65. data/lib/active_support/core_ext/time/conversions.rb +2 -24
  66. data/lib/active_support/core_ext/time/zones.rb +32 -21
  67. data/lib/active_support/core_ext/uri.rb +8 -0
  68. data/lib/active_support/dependencies.rb +74 -28
  69. data/lib/active_support/deprecation/behaviors.rb +7 -0
  70. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  71. data/lib/active_support/deprecation/reporting.rb +4 -0
  72. data/lib/active_support/deprecation.rb +2 -2
  73. data/lib/active_support/descendants_tracker.rb +9 -7
  74. data/lib/active_support/duration.rb +5 -0
  75. data/lib/active_support/file_update_checker.rb +1 -1
  76. data/lib/active_support/file_watcher.rb +36 -0
  77. data/lib/active_support/hash_with_indifferent_access.rb +20 -8
  78. data/lib/active_support/i18n.rb +0 -1
  79. data/lib/active_support/i18n_railtie.rb +2 -2
  80. data/lib/active_support/inflections.rb +1 -0
  81. data/lib/active_support/inflector/inflections.rb +1 -1
  82. data/lib/active_support/inflector/methods.rb +5 -3
  83. data/lib/active_support/json/decoding.rb +37 -23
  84. data/lib/active_support/json/encoding.rb +12 -4
  85. data/lib/active_support/lazy_load_hooks.rb +7 -7
  86. data/lib/active_support/log_subscriber/test_helper.rb +5 -3
  87. data/lib/active_support/log_subscriber.rb +6 -6
  88. data/lib/active_support/message_encryptor.rb +1 -1
  89. data/lib/active_support/message_verifier.rb +1 -1
  90. data/lib/active_support/multibyte/chars.rb +5 -5
  91. data/lib/active_support/multibyte/unicode.rb +2 -1
  92. data/lib/active_support/notifications/fanout.rb +3 -3
  93. data/lib/active_support/notifications/instrumenter.rb +1 -1
  94. data/lib/active_support/notifications.rb +9 -10
  95. data/lib/active_support/ordered_hash.rb +23 -2
  96. data/lib/active_support/ordered_options.rb +37 -3
  97. data/lib/active_support/railtie.rb +1 -1
  98. data/lib/active_support/rescuable.rb +1 -0
  99. data/lib/active_support/secure_random.rb +3 -196
  100. data/lib/active_support/test_case.rb +2 -10
  101. data/lib/active_support/testing/assertions.rb +20 -7
  102. data/lib/active_support/testing/mochaing.rb +7 -0
  103. data/lib/active_support/testing/pending.rb +27 -23
  104. data/lib/active_support/testing/performance/jruby.rb +115 -0
  105. data/lib/active_support/testing/performance/rubinius.rb +113 -0
  106. data/lib/active_support/testing/performance/ruby/mri.rb +57 -0
  107. data/lib/active_support/testing/performance/ruby/yarv.rb +57 -0
  108. data/lib/active_support/testing/performance/ruby.rb +152 -0
  109. data/lib/active_support/testing/performance.rb +214 -322
  110. data/lib/active_support/testing/setup_and_teardown.rb +8 -11
  111. data/lib/active_support/time_with_zone.rb +6 -3
  112. data/lib/active_support/values/time_zone.rb +26 -8
  113. data/lib/active_support/version.rb +2 -2
  114. data/lib/active_support/whiny_nil.rb +1 -1
  115. data/lib/active_support/xml_mini/jdom.rb +1 -1
  116. data/lib/active_support/xml_mini/libxml.rb +1 -0
  117. data/lib/active_support/xml_mini/libxmlsax.rb +2 -1
  118. data/lib/active_support/xml_mini/nokogiri.rb +1 -0
  119. data/lib/active_support/xml_mini/nokogirisax.rb +1 -0
  120. data/lib/active_support/xml_mini/rexml.rb +1 -0
  121. data/lib/active_support/xml_mini.rb +8 -3
  122. data/lib/active_support.rb +4 -2
  123. metadata +70 -32
  124. checksums.yaml +0 -7
  125. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -19
  126. data/lib/active_support/core_ext/cgi.rb +0 -1
  127. data/lib/active_support/core_ext/object/returning.rb +0 -43
  128. data/lib/active_support/json/backends/jsongem.rb +0 -47
  129. data/lib/active_support/json/backends/okjson.rb +0 -644
  130. data/lib/active_support/json/backends/yajl.rb +0 -44
  131. data/lib/active_support/json/backends/yaml.rb +0 -19
  132. data/lib/active_support/testing/default.rb +0 -9
@@ -1,7 +1,26 @@
1
1
  require 'active_support/ordered_hash'
2
2
 
3
+ # Usually key value pairs are handled something like this:
4
+ #
5
+ # h = {}
6
+ # h[:boy] = 'John'
7
+ # h[:girl] = 'Mary'
8
+ # h[:boy] # => 'John'
9
+ # h[:girl] # => 'Mary'
10
+ #
11
+ # Using <tt>OrderedOptions</tt>, the above code could be reduced to:
12
+ #
13
+ # h = ActiveSupport::OrderedOptions.new
14
+ # h.boy = 'John'
15
+ # h.girl = 'Mary'
16
+ # h.boy # => 'John'
17
+ # h.girl # => 'Mary'
18
+ #
3
19
  module ActiveSupport #:nodoc:
4
20
  class OrderedOptions < OrderedHash
21
+ alias_method :_get, :[] # preserve the original #[] method
22
+ protected :_get # make it protected
23
+
5
24
  def []=(key, value)
6
25
  super(key.to_sym, value)
7
26
  end
@@ -12,16 +31,31 @@ module ActiveSupport #:nodoc:
12
31
 
13
32
  def method_missing(name, *args)
14
33
  if name.to_s =~ /(.*)=$/
15
- self[$1.to_sym] = args.first
34
+ self[$1] = args.first
16
35
  else
17
36
  self[name]
18
37
  end
19
38
  end
39
+
40
+ def respond_to?(name)
41
+ true
42
+ end
20
43
  end
21
44
 
22
45
  class InheritableOptions < OrderedOptions
23
- def initialize(parent)
24
- super() { |h,k| parent[k] }
46
+ def initialize(parent = nil)
47
+ if parent.kind_of?(OrderedOptions)
48
+ # use the faster _get when dealing with OrderedOptions
49
+ super() { |h,k| parent._get(k) }
50
+ elsif parent
51
+ super() { |h,k| parent[k] }
52
+ else
53
+ super()
54
+ end
55
+ end
56
+
57
+ def inheritable_copy
58
+ self.class.new(self)
25
59
  end
26
60
  end
27
61
  end
@@ -46,7 +46,7 @@ module ActiveSupport
46
46
  # If assigned value cannot be matched to a TimeZone, an exception will be raised.
47
47
  initializer "active_support.initialize_time_zone" do |app|
48
48
  require 'active_support/core_ext/time/zones'
49
- zone_default = Time.__send__(:get_zone, app.config.time_zone)
49
+ zone_default = Time.find_zone!(app.config.time_zone)
50
50
 
51
51
  unless zone_default
52
52
  raise \
@@ -47,6 +47,7 @@ module ActiveSupport
47
47
  # exception.record.new_record? ? ...
48
48
  # end
49
49
  # end
50
+ #
50
51
  def rescue_from(*klasses, &block)
51
52
  options = klasses.extract_options!
52
53
 
@@ -1,199 +1,6 @@
1
- begin
2
- require 'securerandom'
3
- rescue LoadError
4
- end
1
+ require 'active_support/deprecation'
5
2
 
6
3
  module ActiveSupport
7
- if defined?(::SecureRandom)
8
- # Use Ruby's SecureRandom library if available.
9
- SecureRandom = ::SecureRandom # :nodoc:
10
- else
11
- # = Secure random number generator interface.
12
- #
13
- # This library is an interface for secure random number generator which is
14
- # suitable for generating session key in HTTP cookies, etc.
15
- #
16
- # It supports following secure random number generators.
17
- #
18
- # * openssl
19
- # * /dev/urandom
20
- # * Win32
21
- #
22
- # *Note*: This module is based on the SecureRandom library from Ruby 1.9,
23
- # revision 18786, August 23 2008. It's 100% interface-compatible with Ruby 1.9's
24
- # SecureRandom library.
25
- #
26
- # == Example
27
- #
28
- # # random hexadecimal string.
29
- # p SecureRandom.hex(10) # => "52750b30ffbc7de3b362"
30
- # p SecureRandom.hex(10) # => "92b15d6c8dc4beb5f559"
31
- # p SecureRandom.hex(11) # => "6aca1b5c58e4863e6b81b8"
32
- # p SecureRandom.hex(12) # => "94b2fff3e7fd9b9c391a2306"
33
- # p SecureRandom.hex(13) # => "39b290146bea6ce975c37cfc23"
34
- # ...
35
- #
36
- # # random base64 string.
37
- # p SecureRandom.base64(10) # => "EcmTPZwWRAozdA=="
38
- # p SecureRandom.base64(10) # => "9b0nsevdwNuM/w=="
39
- # p SecureRandom.base64(10) # => "KO1nIU+p9DKxGg=="
40
- # p SecureRandom.base64(11) # => "l7XEiFja+8EKEtY="
41
- # p SecureRandom.base64(12) # => "7kJSM/MzBJI+75j8"
42
- # p SecureRandom.base64(13) # => "vKLJ0tXBHqQOuIcSIg=="
43
- # ...
44
- #
45
- # # random binary string.
46
- # p SecureRandom.random_bytes(10) # => "\016\t{\370g\310pbr\301"
47
- # p SecureRandom.random_bytes(10) # => "\323U\030TO\234\357\020\a\337"
48
- # ...
49
- module SecureRandom
50
- # SecureRandom.random_bytes generates a random binary string.
51
- #
52
- # The argument n specifies the length of the result string.
53
- #
54
- # If n is not specified, 16 is assumed.
55
- # It may be larger in future.
56
- #
57
- # If secure random number generator is not available,
58
- # NotImplementedError is raised.
59
- def self.random_bytes(n=nil)
60
- n ||= 16
61
-
62
- unless defined? OpenSSL
63
- begin
64
- require 'openssl'
65
- rescue LoadError
66
- end
67
- end
68
-
69
- if defined? OpenSSL::Random
70
- return OpenSSL::Random.random_bytes(n)
71
- end
72
-
73
- if !defined?(@has_urandom) || @has_urandom
74
- flags = File::RDONLY
75
- flags |= File::NONBLOCK if defined? File::NONBLOCK
76
- flags |= File::NOCTTY if defined? File::NOCTTY
77
- flags |= File::NOFOLLOW if defined? File::NOFOLLOW
78
- begin
79
- File.open("/dev/urandom", flags) {|f|
80
- unless f.stat.chardev?
81
- raise Errno::ENOENT
82
- end
83
- @has_urandom = true
84
- ret = f.readpartial(n)
85
- if ret.length != n
86
- raise NotImplementedError, "Unexpected partial read from random device"
87
- end
88
- return ret
89
- }
90
- rescue Errno::ENOENT
91
- @has_urandom = false
92
- end
93
- end
94
-
95
- if !defined?(@has_win32)
96
- begin
97
- require 'Win32API'
98
-
99
- crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L')
100
- @crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'LIP', 'L')
101
-
102
- hProvStr = " " * 4
103
- prov_rsa_full = 1
104
- crypt_verifycontext = 0xF0000000
105
-
106
- if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
107
- raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
108
- end
109
- @hProv, = hProvStr.unpack('L')
110
-
111
- @has_win32 = true
112
- rescue LoadError
113
- @has_win32 = false
114
- end
115
- end
116
- if @has_win32
117
- bytes = " " * n
118
- if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
119
- raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
120
- end
121
- return bytes
122
- end
123
-
124
- raise NotImplementedError, "No random device"
125
- end
126
-
127
- # SecureRandom.hex generates a random hex string.
128
- #
129
- # The argument n specifies the length of the random length.
130
- # The length of the result string is twice of n.
131
- #
132
- # If n is not specified, 16 is assumed.
133
- # It may be larger in future.
134
- #
135
- # If secure random number generator is not available,
136
- # NotImplementedError is raised.
137
- def self.hex(n=nil)
138
- random_bytes(n).unpack("H*")[0]
139
- end
140
-
141
- # SecureRandom.base64 generates a random base64 string.
142
- #
143
- # The argument n specifies the length of the random length.
144
- # The length of the result string is about 4/3 of n.
145
- #
146
- # If n is not specified, 16 is assumed.
147
- # It may be larger in future.
148
- #
149
- # If secure random number generator is not available,
150
- # NotImplementedError is raised.
151
- def self.base64(n=nil)
152
- [random_bytes(n)].pack("m*").delete("\n")
153
- end
154
-
155
- # SecureRandom.random_number generates a random number.
156
- #
157
- # If an positive integer is given as n,
158
- # SecureRandom.random_number returns an integer:
159
- # 0 <= SecureRandom.random_number(n) < n.
160
- #
161
- # If 0 is given or an argument is not given,
162
- # SecureRandom.random_number returns an float:
163
- # 0.0 <= SecureRandom.random_number() < 1.0.
164
- def self.random_number(n=0)
165
- if 0 < n
166
- hex = n.to_s(16)
167
- hex = '0' + hex if (hex.length & 1) == 1
168
- bin = [hex].pack("H*")
169
- mask = bin[0]
170
- mask |= mask >> 1
171
- mask |= mask >> 2
172
- mask |= mask >> 4
173
- begin
174
- rnd = SecureRandom.random_bytes(bin.length)
175
- rnd[0] = rnd[0] & mask
176
- end until rnd < bin
177
- rnd.unpack("H*")[0].hex
178
- else
179
- # assumption: Float::MANT_DIG <= 64
180
- i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
181
- Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
182
- end
183
- end
184
-
185
- # Following code is based on David Garamond's GUID library for Ruby.
186
- def self.lastWin32ErrorMessage # :nodoc:
187
- get_last_error = Win32API.new("kernel32", "GetLastError", '', 'L')
188
- format_message = Win32API.new("kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L')
189
- format_message_ignore_inserts = 0x00000200
190
- format_message_from_system = 0x00001000
191
-
192
- code = get_last_error.call
193
- msg = "\0" * 1024
194
- len = format_message.call(format_message_ignore_inserts + format_message_from_system, 0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil)
195
- msg[0, len].tr("\r", '').chomp
196
- end
197
- end
198
- end
4
+ # Use Ruby's SecureRandom library.
5
+ SecureRandom = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveSupport::SecureRandom', ::SecureRandom) # :nodoc:
199
6
  end
@@ -5,16 +5,9 @@ require 'active_support/testing/deprecation'
5
5
  require 'active_support/testing/declarative'
6
6
  require 'active_support/testing/pending'
7
7
  require 'active_support/testing/isolation'
8
+ require 'active_support/testing/mochaing'
8
9
  require 'active_support/core_ext/kernel/reporting'
9
10
 
10
- begin
11
- silence_warnings { require 'mocha/setup' }
12
- rescue LoadError
13
- # Fake Mocha::ExpectationError so we can rescue it in #run. Bleh.
14
- Object.const_set :Mocha, Module.new
15
- Mocha.const_set :ExpectationError, Class.new(StandardError)
16
- end
17
-
18
11
  module ActiveSupport
19
12
  class TestCase < ::Test::Unit::TestCase
20
13
  if defined? MiniTest
@@ -24,8 +17,7 @@ module ActiveSupport
24
17
  else
25
18
  Assertion = Test::Unit::AssertionFailedError
26
19
 
27
- require 'active_support/testing/default'
28
- include ActiveSupport::Testing::Default
20
+ undef :default_test
29
21
  end
30
22
 
31
23
  $tags = {}
@@ -29,22 +29,35 @@ module ActiveSupport
29
29
  # post :create, :article => {...}
30
30
  # end
31
31
  #
32
+ # A lambda or a list of lambdas can be passed in and evaluated:
33
+ #
34
+ # assert_difference lambda { Article.count }, 2 do
35
+ # post :create, :article => {...}
36
+ # end
37
+ #
38
+ # assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
39
+ # post :create, :article => {...}
40
+ # end
41
+ #
32
42
  # A error message can be specified.
33
43
  #
34
44
  # assert_difference 'Article.count', -1, "An Article should be destroyed" do
35
45
  # post :delete, :id => ...
36
46
  # end
37
47
  def assert_difference(expression, difference = 1, message = nil, &block)
38
- b = block.send(:binding)
39
- exps = Array.wrap(expression)
40
- before = exps.map { |e| eval(e, b) }
48
+ expressions = Array.wrap expression
49
+
50
+ exps = expressions.map { |e|
51
+ e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
52
+ }
53
+ before = exps.map { |e| e.call }
41
54
 
42
55
  yield
43
56
 
44
- exps.each_with_index do |e, i|
45
- error = "#{e.inspect} didn't change by #{difference}"
46
- error = "#{message}.\n#{error}" if message
47
- assert_equal(before[i] + difference, eval(e, b), error)
57
+ expressions.zip(exps).each_with_index do |(code, e), i|
58
+ error = "#{code.inspect} didn't change by #{difference}"
59
+ error = "#{message}.\n#{error}" if message
60
+ assert_equal(before[i] + difference, e.call, error)
48
61
  end
49
62
  end
50
63
 
@@ -0,0 +1,7 @@
1
+ begin
2
+ silence_warnings { require 'mocha' }
3
+ rescue LoadError
4
+ # Fake Mocha::ExpectationError so we can rescue it in #run. Bleh.
5
+ Object.const_set :Mocha, Module.new
6
+ Mocha.const_set :ExpectationError, Class.new(StandardError)
7
+ end
@@ -1,5 +1,5 @@
1
1
  # Some code from jeremymcanally's "pending"
2
- # http://github.com/jeremymcanally/pending/tree/master
2
+ # https://github.com/jeremymcanally/pending/tree/master
3
3
 
4
4
  module ActiveSupport
5
5
  module Testing
@@ -11,32 +11,36 @@ module ActiveSupport
11
11
  @@at_exit = false
12
12
 
13
13
  def pending(description = "", &block)
14
- if description.is_a?(Symbol)
15
- is_pending = $tags[description]
16
- return block.call unless is_pending
17
- end
14
+ if defined?(::MiniTest)
15
+ skip(description.blank? ? nil : description)
16
+ else
17
+ if description.is_a?(Symbol)
18
+ is_pending = $tags[description]
19
+ return block.call unless is_pending
20
+ end
18
21
 
19
- if block_given?
20
- failed = false
22
+ if block_given?
23
+ failed = false
21
24
 
22
- begin
23
- block.call
24
- rescue Exception
25
- failed = true
26
- end
25
+ begin
26
+ block.call
27
+ rescue Exception
28
+ failed = true
29
+ end
27
30
 
28
- flunk("<#{description}> did not fail.") unless failed
29
- end
31
+ flunk("<#{description}> did not fail.") unless failed
32
+ end
30
33
 
31
- caller[0] =~ (/(.*):(.*):in `(.*)'/)
32
- @@pending_cases << "#{$3} at #{$1}, line #{$2}"
33
- print "P"
34
+ caller[0] =~ (/(.*):(.*):in `(.*)'/)
35
+ @@pending_cases << "#{$3} at #{$1}, line #{$2}"
36
+ print "P"
34
37
 
35
- @@at_exit ||= begin
36
- at_exit do
37
- puts "\nPending Cases:"
38
- @@pending_cases.each do |test_case|
39
- puts test_case
38
+ @@at_exit ||= begin
39
+ at_exit do
40
+ puts "\nPending Cases:"
41
+ @@pending_cases.each do |test_case|
42
+ puts test_case
43
+ end
40
44
  end
41
45
  end
42
46
  end
@@ -45,4 +49,4 @@ module ActiveSupport
45
49
 
46
50
  end
47
51
  end
48
- end
52
+ end
@@ -0,0 +1,115 @@
1
+ require 'jruby/profiler'
2
+ require 'java'
3
+ java_import java.lang.management.ManagementFactory
4
+
5
+ module ActiveSupport
6
+ module Testing
7
+ module Performance
8
+ DEFAULTS.merge!(
9
+ if ARGV.include?('--benchmark')
10
+ {:metrics => [:wall_time, :user_time, :memory, :gc_runs, :gc_time]}
11
+ else
12
+ { :metrics => [:wall_time],
13
+ :formats => [:flat, :graph] }
14
+ end).freeze
15
+
16
+ protected
17
+ def run_gc
18
+ ManagementFactory.memory_mx_bean.gc
19
+ end
20
+
21
+ class Profiler < Performer
22
+ def initialize(*args)
23
+ super
24
+ @supported = @metric.is_a?(Metrics::WallTime)
25
+ end
26
+
27
+ def run
28
+ return unless @supported
29
+
30
+ @total = time_with_block do
31
+ @data = JRuby::Profiler.profile do
32
+ full_profile_options[:runs].to_i.times { run_test(@metric, :profile) }
33
+ end
34
+ end
35
+ end
36
+
37
+ def record
38
+ return unless @supported
39
+
40
+ klasses = full_profile_options[:formats].map { |f| JRuby::Profiler.const_get("#{f.to_s.camelize}ProfilePrinter") }.compact
41
+
42
+ klasses.each do |klass|
43
+ fname = output_filename(klass)
44
+ FileUtils.mkdir_p(File.dirname(fname))
45
+ file = File.open(fname, 'wb') do |file|
46
+ klass.new(@data).printProfile(file)
47
+ end
48
+ end
49
+ end
50
+
51
+ protected
52
+ def output_filename(printer_class)
53
+ suffix =
54
+ case printer_class.name.demodulize
55
+ when 'FlatProfilePrinter'; 'flat.txt'
56
+ when 'GraphProfilePrinter'; 'graph.txt'
57
+ else printer_class.name.sub(/ProfilePrinter$/, '').underscore
58
+ end
59
+
60
+ "#{super()}_#{suffix}"
61
+ end
62
+ end
63
+
64
+ module Metrics
65
+ class Base
66
+ def profile
67
+ yield
68
+ end
69
+
70
+ protected
71
+ def with_gc_stats
72
+ ManagementFactory.memory_mx_bean.gc
73
+ yield
74
+ end
75
+ end
76
+
77
+ class WallTime < Time
78
+ def measure
79
+ super
80
+ end
81
+ end
82
+
83
+ class CpuTime < Time
84
+ def measure
85
+ ManagementFactory.thread_mx_bean.get_current_thread_cpu_time / 1000 / 1000 / 1000.0 # seconds
86
+ end
87
+ end
88
+
89
+ class UserTime < Time
90
+ def measure
91
+ ManagementFactory.thread_mx_bean.get_current_thread_user_time / 1000 / 1000 / 1000.0 # seconds
92
+ end
93
+ end
94
+
95
+ class Memory < DigitalInformationUnit
96
+ def measure
97
+ ManagementFactory.memory_mx_bean.non_heap_memory_usage.used + ManagementFactory.memory_mx_bean.heap_memory_usage.used
98
+ end
99
+ end
100
+
101
+ class GcRuns < Amount
102
+ def measure
103
+ ManagementFactory.garbage_collector_mx_beans.inject(0) { |total_runs, current_gc| total_runs += current_gc.collection_count }
104
+ end
105
+ end
106
+
107
+ class GcTime < Time
108
+ def measure
109
+ ManagementFactory.garbage_collector_mx_beans.inject(0) { |total_time, current_gc| total_time += current_gc.collection_time } / 1000.0 # seconds
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,113 @@
1
+ require 'rubinius/agent'
2
+
3
+ module ActiveSupport
4
+ module Testing
5
+ module Performance
6
+ DEFAULTS.merge!(
7
+ if ARGV.include?('--benchmark')
8
+ {:metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time]}
9
+ else
10
+ { :metrics => [:wall_time],
11
+ :formats => [:flat, :graph] }
12
+ end).freeze
13
+
14
+ protected
15
+ def run_gc
16
+ GC.run(true)
17
+ end
18
+
19
+ class Performer; end
20
+
21
+ class Profiler < Performer
22
+ def initialize(*args)
23
+ super
24
+ @supported = @metric.is_a?(Metrics::WallTime)
25
+ end
26
+
27
+ def run
28
+ return unless @supported
29
+
30
+ @profiler = Rubinius::Profiler::Instrumenter.new
31
+
32
+ @total = time_with_block do
33
+ @profiler.profile(false) do
34
+ full_profile_options[:runs].to_i.times { run_test(@metric, :profile) }
35
+ end
36
+ end
37
+ end
38
+
39
+ def record
40
+ return unless @supported
41
+
42
+ if(full_profile_options[:formats].include?(:flat))
43
+ create_path_and_open_file(:flat) do |file|
44
+ @profiler.show(file)
45
+ end
46
+ end
47
+
48
+ if(full_profile_options[:formats].include?(:graph))
49
+ create_path_and_open_file(:graph) do |file|
50
+ @profiler.show(file)
51
+ end
52
+ end
53
+ end
54
+
55
+ protected
56
+ def create_path_and_open_file(printer_name)
57
+ fname = "#{output_filename}_#{printer_name}.txt"
58
+ FileUtils.mkdir_p(File.dirname(fname))
59
+ File.open(fname, 'wb') do |file|
60
+ yield(file)
61
+ end
62
+ end
63
+ end
64
+
65
+ module Metrics
66
+ class Base
67
+ attr_reader :loopback
68
+
69
+ def profile
70
+ yield
71
+ end
72
+
73
+ protected
74
+ def with_gc_stats
75
+ @loopback = Rubinius::Agent.loopback
76
+ GC.run(true)
77
+ yield
78
+ end
79
+ end
80
+
81
+ class WallTime < Time
82
+ def measure
83
+ super
84
+ end
85
+ end
86
+
87
+ class Memory < DigitalInformationUnit
88
+ def measure
89
+ loopback.get("system.memory.counter.bytes").last
90
+ end
91
+ end
92
+
93
+ class Objects < Amount
94
+ def measure
95
+ loopback.get("system.memory.counter.objects").last
96
+ end
97
+ end
98
+
99
+ class GcRuns < Amount
100
+ def measure
101
+ loopback.get("system.gc.full.count").last + loopback.get("system.gc.young.count").last
102
+ end
103
+ end
104
+
105
+ class GcTime < Time
106
+ def measure
107
+ (loopback.get("system.gc.full.wallclock").last + loopback.get("system.gc.young.wallclock").last) / 1000.0
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end