activesupport 4.0.0.beta1 → 4.0.0.rc1

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.

Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/README.rdoc +2 -2
  4. data/lib/active_support/cache.rb +62 -49
  5. data/lib/active_support/cache/file_store.rb +2 -2
  6. data/lib/active_support/cache/strategy/local_cache.rb +48 -37
  7. data/lib/active_support/callbacks.rb +27 -8
  8. data/lib/active_support/core_ext.rb +2 -2
  9. data/lib/active_support/core_ext/array/conversions.rb +5 -3
  10. data/lib/active_support/core_ext/array/uniq_by.rb +2 -2
  11. data/lib/active_support/core_ext/benchmark.rb +7 -0
  12. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -0
  13. data/lib/active_support/core_ext/class/attribute.rb +31 -27
  14. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -2
  15. data/lib/active_support/core_ext/date_and_time/calculations.rb +6 -6
  16. data/lib/active_support/core_ext/module/delegation.rb +50 -24
  17. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  18. data/lib/active_support/core_ext/string.rb +0 -1
  19. data/lib/active_support/core_ext/string/conversions.rb +6 -8
  20. data/lib/active_support/core_ext/string/filters.rb +1 -1
  21. data/lib/active_support/core_ext/string/indent.rb +1 -1
  22. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  23. data/lib/active_support/core_ext/string/output_safety.rb +2 -2
  24. data/lib/active_support/hash_with_indifferent_access.rb +2 -2
  25. data/lib/active_support/key_generator.rb +1 -1
  26. data/lib/active_support/log_subscriber.rb +9 -46
  27. data/lib/active_support/message_encryptor.rb +9 -9
  28. data/lib/active_support/message_verifier.rb +3 -3
  29. data/lib/active_support/notifications.rb +22 -1
  30. data/lib/active_support/notifications/instrumenter.rb +2 -2
  31. data/lib/active_support/number_helper.rb +3 -2
  32. data/lib/active_support/per_thread_registry.rb +52 -0
  33. data/lib/active_support/subscriber.rb +93 -0
  34. data/lib/active_support/testing/constant_lookup.rb +2 -0
  35. data/lib/active_support/time_with_zone.rb +2 -0
  36. data/lib/active_support/values/time_zone.rb +5 -3
  37. data/lib/active_support/version.rb +7 -6
  38. data/lib/active_support/xml_mini/jdom.rb +6 -0
  39. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  40. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  41. metadata +14 -7
  42. data/lib/active_support/core_ext/string/xchar.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 78f08847e1d3d08c65ad482067228990e85ae1aa
4
- data.tar.gz: 2267d7e11f8bd76ea6ce4a89ca4f41417ee2778f
3
+ metadata.gz: 787831cae30c98f2e6f3e06b1ac405a5c5597861
4
+ data.tar.gz: 34441857e5037fdaa192293f732de973fa362f22
5
5
  SHA512:
6
- metadata.gz: bf18285e1446e0a6b2a2a7f4986bb331a69032fa1e67d5b8dd12a6c828e46d7321f4360709b05e40c9fb0a45df1a8c68e179583906f769f5f329357b077a2177
7
- data.tar.gz: 9364c3e0046164fd3a8789f1a679ea8a43bbaf71b108ac3617536c4b3a28013bb20c02fd9f094a0a71db8886c0b668c8c5af2ad2ebf02a4a0659d8ee9ebc5c12
6
+ metadata.gz: 2af16317b996dfcdef387e1e8c68fc488b80d85329339c71f640faf69212fb308b2f24723a6134911eddc9358bf87a194363f7bab0997d05ec574ec8345b645e
7
+ data.tar.gz: c5ea3235e50432543c82825c40e44d34e765d7bb94c5c3b586a179b015f21df62c8fc18458cdb2a63430a6a66db8f72eb58ca68c72000527462241059cf5c2ca
@@ -1,5 +1,52 @@
1
+ ## Rails 4.0.0 (unreleased) ##
2
+
3
+ * Fix skipping of filters defined by objects in `ActiveSupport::Callbacks::Callback`.
4
+
5
+ *Ben McRedmond*
6
+
7
+ * An `ActiveSupport::Subscriber` class has been extracted from
8
+ `ActiveSupport::LogSubscriber`, allowing you to use the event attachment
9
+ API for other kinds of subscribers.
10
+
11
+ *Daniel Schierbeck*
12
+
13
+ * `Class#class_attribute` accepts an `instance_predicate` option which
14
+ defaults to `true`. If set to `false` the predicate method will not
15
+ be defined.
16
+
17
+ *Agis Anastasopoulos*
18
+
19
+ * `fast_xs` support has been removed. Use `String#encode(xml: :attr)`.
20
+
21
+ * `ActiveSupport::Notifications::Instrumenter#instrument` should
22
+ yield its payload.
23
+
24
+ *stopdropandrew*
25
+
26
+ * `ActiveSupport::TimeWithZone` raises `NoMethodError` in proper context.
27
+ Fixes #9772.
28
+
29
+ *Yves Senn*
30
+
31
+ * Fix deletion of empty directories in `ActiveSupport::Cache::FileStore`.
32
+
33
+ *Charles Jones*
34
+
1
35
  ## Rails 4.0.0.beta1 (February 25, 2013) ##
2
36
 
37
+ * Improve singularizing a singular for multiple cases.
38
+ Fixes #2608 #1825 #2395.
39
+
40
+ Example:
41
+
42
+ # Before
43
+ 'address'.singularize # => 'addres'
44
+
45
+ # After
46
+ 'address'.singularize # => 'address'
47
+
48
+ *Mark McSpadden*
49
+
3
50
  * Prevent `DateTime#change` from truncating the second fraction, when seconds
4
51
  do not need to be changed.
5
52
 
@@ -12,7 +12,7 @@ The latest version of Active Support can be installed with RubyGems:
12
12
 
13
13
  % [sudo] gem install activesupport
14
14
 
15
- Source code can be downloaded as part of the Rails project on GitHub
15
+ Source code can be downloaded as part of the Rails project on GitHub:
16
16
 
17
17
  * https://github.com/rails/rails/tree/master/activesupport
18
18
 
@@ -26,7 +26,7 @@ Active Support is released under the MIT license:
26
26
 
27
27
  == Support
28
28
 
29
- API documentation is at
29
+ API documentation is at:
30
30
 
31
31
  * http://api.rubyonrails.org
32
32
 
@@ -56,16 +56,7 @@ module ActiveSupport
56
56
 
57
57
  case store
58
58
  when Symbol
59
- store_class_name = store.to_s.camelize
60
- store_class =
61
- begin
62
- require "active_support/cache/#{store}"
63
- rescue LoadError => e
64
- raise "Could not find cache store adapter for #{store} (#{e})"
65
- else
66
- ActiveSupport::Cache.const_get(store_class_name)
67
- end
68
- store_class.new(*parameters)
59
+ retrieve_store_class(store).new(*parameters)
69
60
  when nil
70
61
  ActiveSupport::Cache::MemoryStore.new
71
62
  else
@@ -73,6 +64,18 @@ module ActiveSupport
73
64
  end
74
65
  end
75
66
 
67
+ # Expands out the +key+ argument into a key that can be used for the
68
+ # cache store. Optionally accepts a namespace, and all keys will be
69
+ # scoped within that namespace.
70
+ #
71
+ # If the +key+ argument provided is an array, or responds to +to_a+, then
72
+ # each of elements in the array will be turned into parameters/keys and
73
+ # concatenated into a single key. For example:
74
+ #
75
+ # expand_cache_key([:foo, :bar]) # => "foo/bar"
76
+ # expand_cache_key([:foo, :bar], "namespace") # => "namespace/foo/bar"
77
+ #
78
+ # The +key+ argument can also respond to +cache_key+ or +to_param+.
76
79
  def expand_cache_key(key, namespace = nil)
77
80
  expanded_cache_key = namespace ? "#{namespace}/" : ""
78
81
 
@@ -94,6 +97,16 @@ module ActiveSupport
94
97
  else key.to_param
95
98
  end.to_s
96
99
  end
100
+
101
+ # Obtains the specified cache store class, given the name of the +store+.
102
+ # Raises an error when the store class cannot be found.
103
+ def retrieve_store_class(store)
104
+ require "active_support/cache/#{store}"
105
+ rescue LoadError => e
106
+ raise "Could not find cache store adapter for #{store} (#{e})"
107
+ else
108
+ ActiveSupport::Cache.const_get(store.to_s.camelize)
109
+ end
97
110
  end
98
111
 
99
112
  # An abstract cache store class. There are multiple cache store
@@ -344,7 +357,7 @@ module ActiveSupport
344
357
  # Options are passed to the underlying cache implementation.
345
358
  def write(name, value, options = nil)
346
359
  options = merged_options(options)
347
- instrument(:write, name, options) do |payload|
360
+ instrument(:write, name, options) do
348
361
  entry = Entry.new(value, options)
349
362
  write_entry(namespaced_key(name, options), entry, options)
350
363
  end
@@ -355,7 +368,7 @@ module ActiveSupport
355
368
  # Options are passed to the underlying cache implementation.
356
369
  def delete(name, options = nil)
357
370
  options = merged_options(options)
358
- instrument(:delete, name) do |payload|
371
+ instrument(:delete, name) do
359
372
  delete_entry(namespaced_key(name, options), options)
360
373
  end
361
374
  end
@@ -365,7 +378,7 @@ module ActiveSupport
365
378
  # Options are passed to the underlying cache implementation.
366
379
  def exist?(name, options = nil)
367
380
  options = merged_options(options)
368
- instrument(:exist?, name) do |payload|
381
+ instrument(:exist?, name) do
369
382
  entry = read_entry(namespaced_key(name, options), options)
370
383
  entry && !entry.expired?
371
384
  end
@@ -522,7 +535,7 @@ module ActiveSupport
522
535
  def handle_expired_entry(entry, key, options)
523
536
  if entry && entry.expired?
524
537
  race_ttl = options[:race_condition_ttl].to_i
525
- if race_ttl && (Time.now - entry.expires_at <= race_ttl)
538
+ if race_ttl && (Time.now.to_f - entry.expires_at <= race_ttl)
526
539
  # When an entry has :race_condition_ttl defined, put the stale entry back into the cache
527
540
  # for a brief period while the entry is begin recalculated.
528
541
  entry.expires_at = Time.now + race_ttl
@@ -562,38 +575,38 @@ module ActiveSupport
562
575
  # +:compress+, +:compress_threshold+, and +:expires_in+.
563
576
  def initialize(value, options = {})
564
577
  if should_compress?(value, options)
565
- @v = compress(value)
566
- @c = true
578
+ @value = compress(value)
579
+ @compressed = true
567
580
  else
568
- @v = value
569
- end
570
- if expires_in = options[:expires_in]
571
- @x = (Time.now + expires_in).to_i
581
+ @value = value
572
582
  end
583
+ @created_at = Time.now.to_f
584
+ @expires_in = options[:expires_in]
585
+ @expires_in = @expires_in.to_f if @expires_in
573
586
  end
574
587
 
575
588
  def value
576
- convert_version_3_entry! if defined?(@value)
577
- compressed? ? uncompress(@v) : @v
589
+ convert_version_4beta1_entry! if defined?(@v)
590
+ compressed? ? uncompress(@value) : @value
578
591
  end
579
592
 
580
593
  # Check if the entry is expired. The +expires_in+ parameter can override
581
594
  # the value set when the entry was created.
582
595
  def expired?
583
- convert_version_3_entry! if defined?(@value)
584
- if defined?(@x)
585
- @x && @x < Time.now.to_i
586
- else
587
- false
588
- end
596
+ convert_version_4beta1_entry! if defined?(@value)
597
+ @expires_in && @created_at + @expires_in <= Time.now.to_f
589
598
  end
590
599
 
591
600
  def expires_at
592
- Time.at(@x) if defined?(@x)
601
+ @expires_in ? @created_at + @expires_in : nil
593
602
  end
594
603
 
595
604
  def expires_at=(value)
596
- @x = value.to_i
605
+ if value
606
+ @expires_in = value.to_f - @created_at
607
+ else
608
+ @expires_in = nil
609
+ end
597
610
  end
598
611
 
599
612
  # Returns the size of the cached value. This could be less than
@@ -606,9 +619,9 @@ module ActiveSupport
606
619
  when NilClass
607
620
  0
608
621
  when String
609
- @v.bytesize
622
+ @value.bytesize
610
623
  else
611
- @s = Marshal.dump(@v).bytesize
624
+ @s = Marshal.dump(@value).bytesize
612
625
  end
613
626
  end
614
627
  end
@@ -616,12 +629,12 @@ module ActiveSupport
616
629
  # Duplicate the value in a class. This is used by cache implementations that don't natively
617
630
  # serialize entries to protect against accidental cache modifications.
618
631
  def dup_value!
619
- convert_version_3_entry! if defined?(@value)
620
- if @v && !compressed? && !(@v.is_a?(Numeric) || @v == true || @v == false)
621
- if @v.is_a?(String)
622
- @v = @v.dup
632
+ convert_version_4beta1_entry! if defined?(@v)
633
+ if @value && !compressed? && !(@value.is_a?(Numeric) || @value == true || @value == false)
634
+ if @value.is_a?(String)
635
+ @value = @value.dup
623
636
  else
624
- @v = Marshal.load(Marshal.dump(@v))
637
+ @value = Marshal.load(Marshal.dump(@value))
625
638
  end
626
639
  end
627
640
  end
@@ -637,7 +650,7 @@ module ActiveSupport
637
650
  end
638
651
 
639
652
  def compressed?
640
- defined?(@c) ? @c : false
653
+ defined?(@compressed) ? @compressed : false
641
654
  end
642
655
 
643
656
  def compress(value)
@@ -650,19 +663,19 @@ module ActiveSupport
650
663
 
651
664
  # The internals of this method changed between Rails 3.x and 4.0. This method provides the glue
652
665
  # to ensure that cache entries created under the old version still work with the new class definition.
653
- def convert_version_3_entry!
654
- if defined?(@value)
655
- @v = @value
656
- remove_instance_variable(:@value)
666
+ def convert_version_4beta1_entry!
667
+ if defined?(@v)
668
+ @value = @v
669
+ remove_instance_variable(:@v)
657
670
  end
658
- if defined?(@compressed)
659
- @c = @compressed
660
- remove_instance_variable(:@compressed)
671
+ if defined?(@c)
672
+ @compressed = @c
673
+ remove_instance_variable(:@c)
661
674
  end
662
- if defined?(@expires_in) && defined?(@created_at) && @expires_in && @created_at
663
- @x = (@created_at + @expires_in).to_i
664
- remove_instance_variable(:@created_at)
665
- remove_instance_variable(:@expires_in)
675
+ if defined?(@x) && @x
676
+ @created_at ||= Time.now.to_f
677
+ @expires_in = @x - @created_at
678
+ remove_instance_variable(:@x)
666
679
  end
667
680
  end
668
681
  end
@@ -150,9 +150,9 @@ module ActiveSupport
150
150
 
151
151
  # Delete empty directories in the cache.
152
152
  def delete_empty_directories(dir)
153
- return if dir == cache_path
153
+ return if File.realpath(dir) == File.realpath(cache_path)
154
154
  if Dir.entries(dir).reject {|f| EXCLUDED_DIRS.include?(f)}.empty?
155
- File.delete(dir) rescue nil
155
+ Dir.delete(dir) rescue nil
156
156
  delete_empty_directories(File.dirname(dir))
157
157
  end
158
158
  end
@@ -8,6 +8,23 @@ module ActiveSupport
8
8
  # duration of a block. Repeated calls to the cache for the same key will hit the
9
9
  # in-memory cache for faster access.
10
10
  module LocalCache
11
+ # Class for storing and registering the local caches.
12
+ class LocalCacheRegistry # :nodoc:
13
+ extend ActiveSupport::PerThreadRegistry
14
+
15
+ def initialize
16
+ @registry = {}
17
+ end
18
+
19
+ def cache_for(local_cache_key)
20
+ @registry[local_cache_key]
21
+ end
22
+
23
+ def set_cache_for(local_cache_key, value)
24
+ @registry[local_cache_key] = value
25
+ end
26
+ end
27
+
11
28
  # Simple memory backed cache. This cache is not thread safe and is intended only
12
29
  # for serving as a temporary memory cache for a single thread.
13
30
  class LocalStore < Store
@@ -41,24 +58,18 @@ module ActiveSupport
41
58
 
42
59
  # Use a local cache for the duration of block.
43
60
  def with_local_cache
44
- save_val = Thread.current[thread_local_key]
45
- begin
46
- Thread.current[thread_local_key] = LocalStore.new
47
- yield
48
- ensure
49
- Thread.current[thread_local_key] = save_val
50
- end
61
+ use_temporary_local_cache(LocalStore.new) { yield }
51
62
  end
52
63
 
53
64
  #--
54
65
  # This class wraps up local storage for middlewares. Only the middleware method should
55
66
  # construct them.
56
67
  class Middleware # :nodoc:
57
- attr_reader :name, :thread_local_key
68
+ attr_reader :name, :local_cache_key
58
69
 
59
- def initialize(name, thread_local_key)
70
+ def initialize(name, local_cache_key)
60
71
  @name = name
61
- @thread_local_key = thread_local_key
72
+ @local_cache_key = local_cache_key
62
73
  @app = nil
63
74
  end
64
75
 
@@ -68,10 +79,10 @@ module ActiveSupport
68
79
  end
69
80
 
70
81
  def call(env)
71
- Thread.current[thread_local_key] = LocalStore.new
82
+ LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
72
83
  @app.call(env)
73
84
  ensure
74
- Thread.current[thread_local_key] = nil
85
+ LocalCacheRegistry.set_cache_for(local_cache_key, nil)
75
86
  end
76
87
  end
77
88
 
@@ -80,7 +91,7 @@ module ActiveSupport
80
91
  def middleware
81
92
  @middleware ||= Middleware.new(
82
93
  "ActiveSupport::Cache::Strategy::LocalCache",
83
- thread_local_key)
94
+ local_cache_key)
84
95
  end
85
96
 
86
97
  def clear(options = nil) # :nodoc:
@@ -95,29 +106,13 @@ module ActiveSupport
95
106
 
96
107
  def increment(name, amount = 1, options = nil) # :nodoc:
97
108
  value = bypass_local_cache{super}
98
- if local_cache
99
- local_cache.mute do
100
- if value
101
- local_cache.write(name, value, options)
102
- else
103
- local_cache.delete(name, options)
104
- end
105
- end
106
- end
109
+ increment_or_decrement(value, name, amount, options)
107
110
  value
108
111
  end
109
112
 
110
113
  def decrement(name, amount = 1, options = nil) # :nodoc:
111
114
  value = bypass_local_cache{super}
112
- if local_cache
113
- local_cache.mute do
114
- if value
115
- local_cache.write(name, value, options)
116
- else
117
- local_cache.delete(name, options)
118
- end
119
- end
120
- end
115
+ increment_or_decrement(value, name, amount, options)
121
116
  value
122
117
  end
123
118
 
@@ -146,21 +141,37 @@ module ActiveSupport
146
141
  end
147
142
 
148
143
  private
149
- def thread_local_key
150
- @thread_local_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym
144
+ def increment_or_decrement(value, name, amount, options)
145
+ if local_cache
146
+ local_cache.mute do
147
+ if value
148
+ local_cache.write(name, value, options)
149
+ else
150
+ local_cache.delete(name, options)
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ def local_cache_key
157
+ @local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym
151
158
  end
152
159
 
153
160
  def local_cache
154
- Thread.current[thread_local_key]
161
+ LocalCacheRegistry.cache_for(local_cache_key)
155
162
  end
156
163
 
157
164
  def bypass_local_cache
158
- save_cache = Thread.current[thread_local_key]
165
+ use_temporary_local_cache(nil) { yield }
166
+ end
167
+
168
+ def use_temporary_local_cache(temporary_cache)
169
+ save_cache = LocalCacheRegistry.cache_for(local_cache_key)
159
170
  begin
160
- Thread.current[thread_local_key] = nil
171
+ LocalCacheRegistry.set_cache_for(local_cache_key, temporary_cache)
161
172
  yield
162
173
  ensure
163
- Thread.current[thread_local_key] = save_cache
174
+ LocalCacheRegistry.set_cache_for(local_cache_key, save_cache)
164
175
  end
165
176
  end
166
177
  end