activesupport 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

data/CHANGELOG CHANGED
@@ -1,6 +1,12 @@
1
+ *Rails 3.0.2 (November 15, 2010)*
2
+
3
+ * Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White]
4
+
5
+
1
6
  *Rails 3.0.1 (October 15, 2010)*
2
7
 
3
- * No Changes, just a version bump.
8
+ * No changes.
9
+
4
10
 
5
11
  *Rails 3.0.0 (August 29, 2010)*
6
12
 
@@ -35,6 +35,7 @@ module ActiveSupport
35
35
  end
36
36
 
37
37
  require "active_support/dependencies/autoload"
38
+ require "active_support/version"
38
39
 
39
40
  module ActiveSupport
40
41
  extend ActiveSupport::Autoload
@@ -61,8 +61,8 @@ module ActiveSupport
61
61
  store_class =
62
62
  begin
63
63
  require "active_support/cache/#{store}"
64
- rescue LoadError
65
- raise "Could not find cache store adapter for #{store} (#{$!})"
64
+ rescue LoadError => e
65
+ raise "Could not find cache store adapter for #{store} (#{e})"
66
66
  else
67
67
  ActiveSupport::Cache.const_get(store_class_name)
68
68
  end
@@ -1,5 +1,6 @@
1
1
  require 'active_support/core_ext/file/atomic'
2
2
  require 'active_support/core_ext/string/conversions'
3
+ require 'rack/utils'
3
4
 
4
5
  module ActiveSupport
5
6
  module Cache
@@ -11,8 +12,6 @@ module ActiveSupport
11
12
  attr_reader :cache_path
12
13
 
13
14
  DIR_FORMATTER = "%03X"
14
- ESCAPE_FILENAME_CHARS = /[^a-z0-9_.-]/i
15
- UNESCAPE_FILENAME_CHARS = /%[0-9A-F]{2}/
16
15
 
17
16
  def initialize(cache_path, options = nil)
18
17
  super(options)
@@ -136,7 +135,7 @@ module ActiveSupport
136
135
 
137
136
  # Translate a key into a file path.
138
137
  def key_file_path(key)
139
- fname = key.to_s.gsub(ESCAPE_FILENAME_CHARS){|match| "%#{match.ord.to_s(16).upcase}"}
138
+ fname = Rack::Utils.escape(key)
140
139
  hash = Zlib.adler32(fname)
141
140
  hash, dir_1 = hash.divmod(0x1000)
142
141
  dir_2 = hash.modulo(0x1000)
@@ -156,7 +155,7 @@ module ActiveSupport
156
155
  # Translate a file path into a key.
157
156
  def file_path_key(path)
158
157
  fname = path[cache_path.size, path.size].split(File::SEPARATOR, 4).last
159
- fname.gsub(UNESCAPE_FILENAME_CHARS){|match| $1.ord.to_s(16)}
158
+ Rack::Utils.unescape(fname)
160
159
  end
161
160
 
162
161
  # Delete empty directories in the cache.
@@ -1,7 +1,7 @@
1
1
  begin
2
2
  require 'memcache'
3
3
  rescue LoadError => e
4
- $stderr.puts "You don't have memcache installed in your application. Please add it to your Gemfile and run bundle install"
4
+ $stderr.puts "You don't have memcache-client installed in your application. Please add it to your Gemfile and run bundle install"
5
5
  raise e
6
6
  end
7
7
  require 'digest/md5'
@@ -487,7 +487,7 @@ module ActiveSupport
487
487
  chain.delete_if {|c| c.matches?(type, filter) }
488
488
  end
489
489
 
490
- options[:prepend] ? chain.unshift(*mapped) : chain.push(*mapped)
490
+ options[:prepend] ? chain.unshift(*(mapped.reverse)) : chain.push(*mapped)
491
491
  end
492
492
  end
493
493
 
@@ -113,7 +113,7 @@ class Module
113
113
  raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
114
114
  end
115
115
 
116
- prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"
116
+ prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" || ''
117
117
 
118
118
  file, line = caller.first.split(':', 2)
119
119
  line = line.to_i
@@ -60,7 +60,7 @@ class Numeric
60
60
  alias :fortnight :fortnights
61
61
 
62
62
  # Reads best without arguments: 10.minutes.ago
63
- def ago(time = ::Time.now)
63
+ def ago(time = ::Time.current)
64
64
  time - self
65
65
  end
66
66
 
@@ -68,7 +68,7 @@ class Numeric
68
68
  alias :until :ago
69
69
 
70
70
  # Reads best with argument: 10.minutes.since(time)
71
- def since(time = ::Time.now)
71
+ def since(time = ::Time.current)
72
72
  time + self
73
73
  end
74
74
 
@@ -35,7 +35,8 @@ end
35
35
 
36
36
  class Hash
37
37
  # Converts a hash into a string suitable for use as a URL query string. An optional <tt>namespace</tt> can be
38
- # passed to enclose the param names (see example below).
38
+ # passed to enclose the param names (see example below). The string pairs "key=value" that conform the query
39
+ # string are sorted lexicographically in ascending order.
39
40
  #
40
41
  # ==== Examples
41
42
  # { :name => 'David', :nationality => 'Danish' }.to_param # => "name=David&nationality=Danish"
@@ -44,6 +45,6 @@ class Hash
44
45
  def to_param(namespace = nil)
45
46
  collect do |key, value|
46
47
  value.to_query(namespace ? "#{namespace}[#{key}]" : key)
47
- end * '&'
48
+ end.sort * '&'
48
49
  end
49
50
  end
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/object/try'
2
+
1
3
  class String
2
4
  # Strips indentation in heredocs.
3
5
  #
@@ -18,7 +20,7 @@ class String
18
20
  # Technically, it looks for the least indented line in the whole string, and removes
19
21
  # that amount of leading whitespace.
20
22
  def strip_heredoc
21
- indent = chomp.scan(/^\s*/).min.size
22
- gsub(/^\s{#{indent}}/, '')
23
+ indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
24
+ gsub(/^[ \t]{#{indent}}/, '')
23
25
  end
24
- end
26
+ end
@@ -511,7 +511,12 @@ module ActiveSupport #:nodoc:
511
511
  end
512
512
 
513
513
  # Remove the constants that have been autoloaded, and those that have been
514
- # marked for unloading.
514
+ # marked for unloading. Before each constant is removed a callback is sent
515
+ # to its class/module if it implements +before_remove_const+.
516
+ #
517
+ # The callback implementation should be restricted to cleaning up caches, etc.
518
+ # as the enviroment will be in an inconsistent state, e.g. other constants
519
+ # may have already been unloaded and not accessible.
515
520
  def remove_unloadable_constants!
516
521
  autoloaded_constants.each { |const| remove_constant const }
517
522
  autoloaded_constants.clear
@@ -636,6 +641,7 @@ module ActiveSupport #:nodoc:
636
641
  parent = Inflector.constantize(names * '::')
637
642
 
638
643
  log "removing constant #{const}"
644
+ constantize(const).before_remove_const if constantize(const).respond_to?(:before_remove_const)
639
645
  parent.instance_eval { remove_const to_remove }
640
646
 
641
647
  return true
@@ -99,7 +99,7 @@ module ActiveSupport
99
99
  private
100
100
 
101
101
  def method_missing(method, *args, &block) #:nodoc:
102
- value.send(method, *args)
102
+ value.send(method, *args, &block)
103
103
  end
104
104
  end
105
105
  end
@@ -45,6 +45,8 @@ module ActiveSupport
45
45
  regular_writer(convert_key(key), convert_value(value))
46
46
  end
47
47
 
48
+ alias_method :store, :[]=
49
+
48
50
  # Updates the instantized hash with values from the second:
49
51
  #
50
52
  # hash_1 = HashWithIndifferentAccess.new
@@ -1,5 +1,6 @@
1
1
  begin
2
2
  require 'i18n'
3
+ require 'active_support/lazy_load_hooks'
3
4
  rescue LoadError => e
4
5
  $stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install"
5
6
  raise e
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  require 'active_support/core_ext/string/multibyte'
3
+ require 'active_support/i18n'
3
4
 
4
5
  module ActiveSupport
5
6
  module Inflector
@@ -41,9 +41,26 @@ module ActiveSupport
41
41
  @seen = []
42
42
  end
43
43
 
44
- def encode(value)
44
+ def encode(value, use_options = true)
45
45
  check_for_circular_references(value) do
46
- value.as_json(options).encode_json(self)
46
+ jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
47
+ jsonified.encode_json(self)
48
+ end
49
+ end
50
+
51
+ # like encode, but only calls as_json, without encoding to string
52
+ def as_json(value)
53
+ check_for_circular_references(value) do
54
+ value.as_json(options_for(value))
55
+ end
56
+ end
57
+
58
+ def options_for(value)
59
+ if value.is_a?(Array) || value.is_a?(Hash)
60
+ # hashes and arrays need to get encoder in the options, so that they can detect circular references
61
+ (options || {}).merge(:encoder => self)
62
+ else
63
+ options
47
64
  end
48
65
  end
49
66
 
@@ -186,13 +203,22 @@ module Enumerable
186
203
  end
187
204
 
188
205
  class Array
189
- def as_json(options = nil) self end #:nodoc:
190
- def encode_json(encoder) "[#{map { |v| encoder.encode(v) } * ','}]" end #:nodoc:
206
+ def as_json(options = nil) #:nodoc:
207
+ # use encoder as a proxy to call as_json on all elements, to protect from circular references
208
+ encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
209
+ map { |v| encoder.as_json(v) }
210
+ end
211
+
212
+ def encode_json(encoder) #:nodoc:
213
+ # we assume here that the encoder has already run as_json on self and the elements, so we run encode_json directly
214
+ "[#{map { |v| v.encode_json(encoder) } * ','}]"
215
+ end
191
216
  end
192
217
 
193
218
  class Hash
194
219
  def as_json(options = nil) #:nodoc:
195
- if options
220
+ # create a subset of the hash by applying :only or :except
221
+ subset = if options
196
222
  if attrs = options[:only]
197
223
  slice(*Array.wrap(attrs))
198
224
  elsif attrs = options[:except]
@@ -203,10 +229,22 @@ class Hash
203
229
  else
204
230
  self
205
231
  end
232
+
233
+ # use encoder as a proxy to call as_json on all values in the subset, to protect from circular references
234
+ encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options)
235
+ pairs = subset.map { |k, v| [k.to_s, encoder.as_json(v)] }
236
+ result = self.is_a?(ActiveSupport::OrderedHash) ? ActiveSupport::OrderedHash.new : Hash.new
237
+ pairs.inject(result) { |hash, pair| hash[pair.first] = pair.last; hash }
206
238
  end
207
239
 
208
240
  def encode_json(encoder)
209
- "{#{map { |k,v| "#{encoder.encode(k.to_s)}:#{encoder.encode(v)}" } * ','}}"
241
+ # values are encoded with use_options = false, because we don't want hash representations from ActiveModel to be
242
+ # processed once again with as_json with options, as this could cause unexpected results (i.e. missing fields);
243
+
244
+ # on the other hand, we need to run as_json on the elements, because the model representation may contain fields
245
+ # like Time/Date in their original (not jsonified) form, etc.
246
+
247
+ "{#{map { |k,v| "#{encoder.encode(k.to_s)}:#{encoder.encode(v, false)}" } * ','}}"
210
248
  end
211
249
  end
212
250
 
@@ -95,6 +95,8 @@ module ActiveSupport
95
95
  #
96
96
  if private_method_defined?(#{original_method.inspect}) # if private_method_defined?(:_unmemoized_mime_type)
97
97
  private #{symbol.inspect} # private :mime_type
98
+ elsif protected_method_defined?(#{original_method.inspect}) # elsif protected_method_defined?(:_unmemoized_mime_type)
99
+ protected #{symbol.inspect} # protected :mime_type
98
100
  end # end
99
101
  EOS
100
102
  end
@@ -58,16 +58,16 @@ begin
58
58
  metric.send(mode) { __send__ @method_name }
59
59
  rescue ::Test::Unit::AssertionFailedError => e
60
60
  add_failure(e.message, e.backtrace)
61
- rescue StandardError, ScriptError
62
- add_error($!)
61
+ rescue StandardError, ScriptError => e
62
+ add_error(e)
63
63
  ensure
64
64
  begin
65
65
  teardown
66
66
  run_callbacks :teardown, :enumerator => :reverse_each
67
67
  rescue ::Test::Unit::AssertionFailedError => e
68
68
  add_failure(e.message, e.backtrace)
69
- rescue StandardError, ScriptError
70
- add_error($!)
69
+ rescue StandardError, ScriptError => e
70
+ add_error(e)
71
71
  end
72
72
  end
73
73
 
@@ -72,7 +72,7 @@ module ActiveSupport
72
72
 
73
73
  # Returns a <tt>Time.local()</tt> instance of the simultaneous time in your system's <tt>ENV['TZ']</tt> zone
74
74
  def localtime
75
- utc.getlocal
75
+ utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal
76
76
  end
77
77
  alias_method :getlocal, :localtime
78
78
 
@@ -2,8 +2,8 @@ module ActiveSupport
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 0
5
- TINY = 1
6
-
5
+ TINY = 2
6
+
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
9
9
  end
@@ -25,7 +25,7 @@ module ActiveSupport
25
25
 
26
26
  DEFAULT_ENCODINGS = {
27
27
  "binary" => "base64"
28
- } unless defined?(TYPE_NAMES)
28
+ } unless defined?(DEFAULT_ENCODINGS)
29
29
 
30
30
  TYPE_NAMES = {
31
31
  "Symbol" => "symbol",
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activesupport
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 3
4
5
  prerelease: false
5
6
  segments:
6
7
  - 3
7
8
  - 0
8
- - 1
9
- version: 3.0.1
9
+ - 2
10
+ version: 3.0.2
10
11
  platform: ruby
11
12
  authors:
12
13
  - David Heinemeier Hansson
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-10-15 00:00:00 +13:00
18
+ date: 2010-11-15 00:00:00 -06:00
18
19
  default_executable:
19
20
  dependencies: []
20
21
 
@@ -246,25 +247,29 @@ rdoc_options: []
246
247
  require_paths:
247
248
  - lib
248
249
  required_ruby_version: !ruby/object:Gem::Requirement
250
+ none: false
249
251
  requirements:
250
252
  - - ">="
251
253
  - !ruby/object:Gem::Version
254
+ hash: 57
252
255
  segments:
253
256
  - 1
254
257
  - 8
255
258
  - 7
256
259
  version: 1.8.7
257
260
  required_rubygems_version: !ruby/object:Gem::Requirement
261
+ none: false
258
262
  requirements:
259
263
  - - ">="
260
264
  - !ruby/object:Gem::Version
265
+ hash: 3
261
266
  segments:
262
267
  - 0
263
268
  version: "0"
264
269
  requirements: []
265
270
 
266
271
  rubyforge_project: activesupport
267
- rubygems_version: 1.3.6
272
+ rubygems_version: 1.3.7
268
273
  signing_key:
269
274
  specification_version: 3
270
275
  summary: A toolkit of support libraries and Ruby core extensions extracted from the Rails framework.