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,12 +1,10 @@
1
1
  require 'rational' unless RUBY_VERSION >= '1.9.2'
2
- require 'active_support/core_ext/object/acts_like'
3
- require 'active_support/core_ext/time/zones'
4
2
 
5
3
  class DateTime
6
4
  class << self
7
5
  # DateTimes aren't aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone
8
6
  def local_offset
9
- ::Time.local(2012).utc_offset.to_r / 86400
7
+ ::Time.local(2007).utc_offset.to_r / 86400
10
8
  end
11
9
 
12
10
  # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise returns <tt>Time.now.to_datetime</tt>.
@@ -83,6 +81,29 @@ class DateTime
83
81
  change(:hour => 23, :min => 59, :sec => 59)
84
82
  end
85
83
 
84
+ # 1.9.3 defines + and - on DateTime, < 1.9.3 do not.
85
+ if DateTime.public_instance_methods(false).include?(:+)
86
+ def plus_with_duration(other) #:nodoc:
87
+ if ActiveSupport::Duration === other
88
+ other.since(self)
89
+ else
90
+ plus_without_duration(other)
91
+ end
92
+ end
93
+ alias_method :plus_without_duration, :+
94
+ alias_method :+, :plus_with_duration
95
+
96
+ def minus_with_duration(other) #:nodoc:
97
+ if ActiveSupport::Duration === other
98
+ plus_with_duration(-other)
99
+ else
100
+ minus_without_duration(other)
101
+ end
102
+ end
103
+ alias_method :minus_without_duration, :-
104
+ alias_method :-, :minus_with_duration
105
+ end
106
+
86
107
  # Adjusts DateTime to UTC by adding its offset value; offset is set to 0
87
108
  #
88
109
  # Example:
@@ -105,11 +126,7 @@ class DateTime
105
126
  end
106
127
 
107
128
  # Layers additional behavior on DateTime#<=> so that Time and ActiveSupport::TimeWithZone instances can be compared with a DateTime
108
- def compare_with_coercion(other)
109
- other = other.comparable_time if other.respond_to?(:comparable_time)
110
- other = other.to_datetime unless other.acts_like?(:date)
111
- compare_without_coercion(other)
129
+ def <=>(other)
130
+ super other.to_datetime
112
131
  end
113
- alias_method :compare_without_coercion, :<=>
114
- alias_method :<=>, :compare_with_coercion
115
132
  end
@@ -51,25 +51,25 @@ class DateTime
51
51
  utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
52
52
  end
53
53
 
54
- # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000"
54
+ # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000".
55
55
  def readable_inspect
56
56
  to_s(:rfc822)
57
57
  end
58
58
  alias_method :default_inspect, :inspect
59
59
  alias_method :inspect, :readable_inspect
60
60
 
61
- # Converts self to a Ruby Date object; time portion is discarded
61
+ # Converts self to a Ruby Date object; time portion is discarded.
62
62
  def to_date
63
63
  ::Date.new(year, month, day)
64
64
  end unless instance_methods(false).include?(:to_date)
65
65
 
66
- # Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
67
- # If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time
66
+ # Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class.
67
+ # If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time.
68
68
  def to_time
69
- self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec) : self
69
+ self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec, sec_fraction * (RUBY_VERSION < '1.9' ? 86400000000 : 1000000)) : self
70
70
  end
71
71
 
72
- # To be able to keep Times, Dates and DateTimes interchangeable on conversions
72
+ # To be able to keep Times, Dates and DateTimes interchangeable on conversions.
73
73
  def to_datetime
74
74
  self
75
75
  end unless instance_methods(false).include?(:to_datetime)
@@ -79,17 +79,17 @@ class DateTime
79
79
  civil(year, month, day, hour, min, sec, offset)
80
80
  end
81
81
 
82
- # Converts datetime to an appropriate format for use in XML
82
+ # Converts datetime to an appropriate format for use in XML.
83
83
  def xmlschema
84
84
  strftime("%Y-%m-%dT%H:%M:%S%Z")
85
85
  end unless instance_methods(false).include?(:xmlschema)
86
86
 
87
- # Converts self to a floating-point number of seconds since the Unix epoch
87
+ # Converts self to a floating-point number of seconds since the Unix epoch.
88
88
  def to_f
89
89
  seconds_since_unix_epoch.to_f
90
90
  end
91
91
 
92
- # Converts self to an integer number of seconds since the Unix epoch
92
+ # Converts self to an integer number of seconds since the Unix epoch.
93
93
  def to_i
94
94
  seconds_since_unix_epoch.to_i
95
95
  end
@@ -16,6 +16,6 @@ class DateTime
16
16
  def in_time_zone(zone = ::Time.zone)
17
17
  return self unless zone
18
18
 
19
- ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.__send__(:get_zone, zone))
19
+ ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.find_zone!(zone))
20
20
  end
21
21
  end
@@ -90,16 +90,13 @@ module Enumerable
90
90
  # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
91
91
  #
92
92
  def index_by
93
- inject({}) do |accum, elem|
94
- accum[yield(elem)] = elem
95
- accum
96
- end
93
+ Hash[map { |elem| [yield(elem), elem] }]
97
94
  end
98
95
 
99
96
  # Returns true if the collection has more than 1 element. Functionally equivalent to collection.size > 1.
100
- # Works with a block too ala any?, so people.many? { |p| p.age > 26 } # => returns true if more than 1 person is over 26.
97
+ # Can be called with a block too, much like any?, so people.many? { |p| p.age > 26 } returns true if more than 1 person is over 26.
101
98
  def many?(&block)
102
- size = block_given? ? select(&block).size : self.size
99
+ size = block_given? ? count(&block) : self.size
103
100
  size > 1
104
101
  end
105
102
 
@@ -16,4 +16,4 @@ class Float
16
16
  precisionless_round
17
17
  end
18
18
  end
19
- end
19
+ end if RUBY_VERSION < '1.9'
@@ -26,10 +26,22 @@ class Hash
26
26
  #
27
27
  # * If +value+ is a callable object it must expect one or two arguments. Depending
28
28
  # on the arity, the callable is invoked with the +options+ hash as first argument
29
- # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. Its
30
- # return value becomes a new node.
29
+ # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
30
+ # callable can add nodes by using <tt>options[:builder]</tt>.
31
+ #
32
+ # "foo".to_xml(lambda { |options, key| options[:builder].b(key) })
33
+ # # => "<b>foo</b>"
31
34
  #
32
35
  # * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
36
+ #
37
+ # class Foo
38
+ # def to_xml(options)
39
+ # options[:builder].bar "fooing!"
40
+ # end
41
+ # end
42
+ #
43
+ # {:foo => Foo.new}.to_xml(:skip_instruct => true)
44
+ # # => "<hash><bar>fooing!</bar></hash>"
33
45
  #
34
46
  # * Otherwise, a node with +key+ as tag is created with a string representation of
35
47
  # +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
@@ -73,33 +85,15 @@ class Hash
73
85
  end
74
86
  end
75
87
 
76
- class DisallowedType < StandardError #:nodoc:
77
- def initialize(type)
78
- super "Disallowed type attribute: #{type.inspect}"
79
- end
80
- end
81
-
82
- DISALLOWED_XML_TYPES = %w(symbol yaml)
83
-
84
88
  class << self
85
- def from_xml(xml, disallowed_types = nil)
86
- typecast_xml_value(unrename_keys(ActiveSupport::XmlMini.parse(xml)), disallowed_types)
87
- end
88
-
89
- def from_trusted_xml(xml)
90
- from_xml xml, []
89
+ def from_xml(xml)
90
+ typecast_xml_value(unrename_keys(ActiveSupport::XmlMini.parse(xml)))
91
91
  end
92
92
 
93
93
  private
94
- def typecast_xml_value(value, disallowed_types = nil)
95
- disallowed_types ||= DISALLOWED_XML_TYPES
96
-
94
+ def typecast_xml_value(value)
97
95
  case value.class.to_s
98
96
  when 'Hash'
99
- if value.include?('type') && !value['type'].is_a?(Hash) && disallowed_types.include?(value['type'])
100
- raise DisallowedType, value['type']
101
- end
102
-
103
97
  if value['type'] == 'array'
104
98
  _, entries = Array.wrap(value.detect { |k,v| k != 'type' })
105
99
  if entries.nil? || (c = value['__content__'] && c.blank?)
@@ -107,9 +101,9 @@ class Hash
107
101
  else
108
102
  case entries.class.to_s # something weird with classes not matching here. maybe singleton methods breaking is_a?
109
103
  when "Array"
110
- entries.collect { |v| typecast_xml_value(v, disallowed_types) }
104
+ entries.collect { |v| typecast_xml_value(v) }
111
105
  when "Hash"
112
- [typecast_xml_value(entries, disallowed_types)]
106
+ [typecast_xml_value(entries)]
113
107
  else
114
108
  raise "can't typecast #{entries.inspect}"
115
109
  end
@@ -133,17 +127,14 @@ class Hash
133
127
  elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
134
128
  nil
135
129
  else
136
- xml_value = value.inject({}) do |h,(k,v)|
137
- h[k] = typecast_xml_value(v, disallowed_types)
138
- h
139
- end
130
+ xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
140
131
 
141
132
  # Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
142
133
  # how multipart uploaded files from HTML appear
143
134
  xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
144
135
  end
145
136
  when 'Array'
146
- value.map! { |i| typecast_xml_value(i, disallowed_types) }
137
+ value.map! { |i| typecast_xml_value(i) }
147
138
  value.length > 1 ? value : value.first
148
139
  when 'String'
149
140
  value
@@ -155,10 +146,7 @@ class Hash
155
146
  def unrename_keys(params)
156
147
  case params.class.to_s
157
148
  when "Hash"
158
- params.inject({}) do |h,(k,v)|
159
- h[k.to_s.tr("-", "_")] = unrename_keys(v)
160
- h
161
- end
149
+ Hash[params.map { |k,v| [k.to_s.tr("-", "_"), unrename_keys(v)] } ]
162
150
  when "Array"
163
151
  params.map { |v| unrename_keys(v) }
164
152
  else
@@ -0,0 +1,11 @@
1
+ class Hash
2
+ # Returns a deep copy of hash.
3
+ def deep_dup
4
+ duplicate = self.dup
5
+ duplicate.each_pair do |k,v|
6
+ tv = duplicate[k]
7
+ duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v
8
+ end
9
+ duplicate
10
+ end
11
+ end
@@ -9,4 +9,16 @@ class Hash
9
9
  def with_indifferent_access
10
10
  ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
11
11
  end
12
+
13
+ # Called when object is nested under an object that receives
14
+ # #with_indifferent_access. This method will be called on the current object
15
+ # by the enclosing object and is aliased to #with_indifferent_access by
16
+ # default. Subclasses of Hash may overwrite this method to return +self+ if
17
+ # converting to an +ActiveSupport::HashWithIndifferentAccess+ would not be
18
+ # desirable.
19
+ #
20
+ # b = {:b => 1}
21
+ # {:a => b}.with_indifferent_access["a"] # calls b.nested_under_indifferent_access
22
+ #
23
+ alias nested_under_indifferent_access with_indifferent_access
12
24
  end
@@ -35,11 +35,13 @@ class Hash
35
35
  # as keys, this will fail.
36
36
  #
37
37
  # ==== Examples
38
- # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
39
- # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
38
+ # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
39
+ # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key: name"
40
40
  # { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
41
41
  def assert_valid_keys(*valid_keys)
42
- unknown_keys = keys - [valid_keys].flatten
43
- raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
42
+ valid_keys.flatten!
43
+ each_key do |k|
44
+ raise(ArgumentError, "Unknown key: #{k}") unless valid_keys.include?(k)
45
+ end
44
46
  end
45
47
  end
@@ -1,27 +1,22 @@
1
1
  class Hash
2
- # Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
3
- # in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
2
+ # Merges the caller into +other_hash+. For example,
4
3
  #
5
- # def setup(options = {})
6
- # options.reverse_merge! :size => 25, :velocity => 10
7
- # end
4
+ # options = options.reverse_merge(:size => 25, :velocity => 10)
8
5
  #
9
- # Using <tt>merge</tt>, the above example would look as follows:
6
+ # is equivalent to
10
7
  #
11
- # def setup(options = {})
12
- # { :size => 25, :velocity => 10 }.merge(options)
13
- # end
8
+ # options = {:size => 25, :velocity => 10}.merge(options)
14
9
  #
15
- # The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
16
- # have the respective key.
10
+ # This is particularly useful for initializing an options hash
11
+ # with default values.
17
12
  def reverse_merge(other_hash)
18
13
  other_hash.merge(self)
19
14
  end
20
15
 
21
- # Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
22
- # Modifies the receiver in place.
16
+ # Destructive +reverse_merge+.
23
17
  def reverse_merge!(other_hash)
24
- merge!( other_hash ){|k,o,n| o }
18
+ # right wins if there is no left
19
+ merge!( other_hash ){|key,left,right| left }
25
20
  end
26
21
 
27
22
  alias_method :reverse_update, :reverse_merge!
@@ -21,7 +21,7 @@ class Hash
21
21
 
22
22
  # Replaces the hash with only the given keys.
23
23
  # Returns a hash contained the removed key/value pairs
24
- # {:a => 1, :b => 2, :c => 3, :d => 4}.slice!(:a, :b) # => {:c => 3, :d =>4}
24
+ # {:a => 1, :b => 2, :c => 3, :d => 4}.slice!(:a, :b) # => {:c => 3, :d => 4}
25
25
  def slice!(*keys)
26
26
  keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
27
27
  omit = slice(*self.keys - keys)
@@ -30,6 +30,8 @@ class Hash
30
30
  omit
31
31
  end
32
32
 
33
+ # Removes and returns the key/value pairs matching the given keys.
34
+ # {:a => 1, :b => 2, :c => 3, :d => 4}.extract!(:a, :b) # => {:a => 1, :b => 2}
33
35
  def extract!(*keys)
34
36
  result = {}
35
37
  keys.each {|key| result[key] = delete(key) }
@@ -1,5 +1,6 @@
1
1
  require 'active_support/core_ext/hash/conversions'
2
2
  require 'active_support/core_ext/hash/deep_merge'
3
+ require 'active_support/core_ext/hash/deep_dup'
3
4
  require 'active_support/core_ext/hash/diff'
4
5
  require 'active_support/core_ext/hash/except'
5
6
  require 'active_support/core_ext/hash/indifferent_access'
@@ -4,10 +4,13 @@ class Integer
4
4
  # Ordinalize turns a number into an ordinal string used to denote the
5
5
  # position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
6
6
  #
7
- # 1.ordinalize # => "1st"
8
- # 2.ordinalize # => "2nd"
9
- # 1002.ordinalize # => "1002nd"
10
- # 1003.ordinalize # => "1003rd"
7
+ # 1.ordinalize # => "1st"
8
+ # 2.ordinalize # => "2nd"
9
+ # 1002.ordinalize # => "1002nd"
10
+ # 1003.ordinalize # => "1003rd"
11
+ # -11.ordinalize # => "-11th"
12
+ # -1001.ordinalize # => "-1001st"
13
+ #
11
14
  def ordinalize
12
15
  ActiveSupport::Inflector.ordinalize(self)
13
16
  end
@@ -59,4 +59,35 @@ module Kernel
59
59
  raise unless exception_classes.any? { |cls| e.kind_of?(cls) }
60
60
  end
61
61
  end
62
+
63
+ # Captures the given stream and returns it:
64
+ #
65
+ # stream = capture(:stdout) { puts "Cool" }
66
+ # stream # => "Cool\n"
67
+ #
68
+ def capture(stream)
69
+ begin
70
+ stream = stream.to_s
71
+ eval "$#{stream} = StringIO.new"
72
+ yield
73
+ result = eval("$#{stream}").string
74
+ ensure
75
+ eval("$#{stream} = #{stream.upcase}")
76
+ end
77
+
78
+ result
79
+ end
80
+ alias :silence :capture
81
+
82
+ # Silences both STDOUT and STDERR, even for subprocesses.
83
+ #
84
+ # quietly { system 'bundle install' }
85
+ #
86
+ def quietly
87
+ silence_stream(STDOUT) do
88
+ silence_stream(STDERR) do
89
+ yield
90
+ end
91
+ end
92
+ end
62
93
  end
@@ -1,4 +1,5 @@
1
1
  require 'active_support/core_ext/kernel/reporting'
2
+ require 'active_support/core_ext/module/deprecation'
2
3
 
3
4
  module Kernel
4
5
  # Require a library with fallback to RubyGems. Warnings during library
@@ -23,4 +24,5 @@ module Kernel
23
24
  end
24
25
  end
25
26
  end
27
+ deprecate :require_library_or_gem
26
28
  end
@@ -4,18 +4,17 @@ require 'active_support/core_ext/class/attribute_accessors'
4
4
  class Logger #:nodoc:
5
5
  def self.define_around_helper(level)
6
6
  module_eval <<-end_eval, __FILE__, __LINE__ + 1
7
- def around_#{level}(before_message, after_message, &block) # def around_debug(before_message, after_message, &block)
8
- self.#{level}(before_message) # self.debug(before_message)
9
- return_value = block.call(self) # return_value = block.call(self)
10
- self.#{level}(after_message) # self.debug(after_message)
11
- return return_value # return return_value
12
- end # end
7
+ def around_#{level}(before_message, after_message) # def around_debug(before_message, after_message, &block)
8
+ self.#{level}(before_message) # self.debug(before_message)
9
+ return_value = yield(self) # return_value = yield(self)
10
+ self.#{level}(after_message) # self.debug(after_message)
11
+ return_value # return_value
12
+ end # end
13
13
  end_eval
14
14
  end
15
15
  [:debug, :info, :error, :fatal].each {|level| define_around_helper(level) }
16
16
  end
17
17
 
18
-
19
18
  require 'logger'
20
19
 
21
20
  # Extensions to the built-in Ruby logger.
@@ -65,11 +64,11 @@ class Logger
65
64
  formatter.datetime_format if formatter.respond_to?(:datetime_format)
66
65
  end
67
66
 
68
- alias :old_formatter :formatter if method_defined?(:formatter)
69
- # Get the current formatter. The default formatter is a SimpleFormatter which only
70
- # displays the log message
71
- def formatter
72
- @formatter ||= SimpleFormatter.new
67
+ alias :old_initialize :initialize
68
+ # Overwrite initialize to set a default formatter.
69
+ def initialize(*args)
70
+ old_initialize(*args)
71
+ self.formatter = SimpleFormatter.new
73
72
  end
74
73
 
75
74
  # Simple formatter which only displays the message.
@@ -79,30 +78,4 @@ class Logger
79
78
  "#{String === msg ? msg : msg.inspect}\n"
80
79
  end
81
80
  end
82
-
83
- private
84
- alias old_format_message format_message
85
-
86
- # Ruby 1.8.3 transposed the msg and progname arguments to format_message.
87
- # We can't test RUBY_VERSION because some distributions don't keep Ruby
88
- # and its standard library in sync, leading to installations of Ruby 1.8.2
89
- # with Logger from 1.8.3 and vice versa.
90
- if method_defined?(:formatter=)
91
- def format_message(severity, timestamp, progname, msg)
92
- formatter.call(severity, timestamp, progname, msg)
93
- end
94
- else
95
- def format_message(severity, timestamp, msg, progname)
96
- formatter.call(severity, timestamp, progname, msg)
97
- end
98
-
99
- attr_writer :formatter
100
- public :formatter=
101
-
102
- alias old_format_datetime format_datetime
103
- def format_datetime(datetime) datetime end
104
-
105
- alias old_msg2str msg2str
106
- def msg2str(msg) msg end
107
- end
108
81
  end
@@ -7,25 +7,25 @@ class Module
7
7
  # attr_accessor_with_default :age, 25
8
8
  # end
9
9
  #
10
- # some_person.age
11
- # => 25
12
- # some_person.age = 26
13
- # some_person.age
14
- # => 26
10
+ # person = Person.new
11
+ # person.age # => 25
12
+ #
13
+ # person.age = 26
14
+ # person.age # => 26
15
15
  #
16
16
  # To give attribute <tt>:element_name</tt> a dynamic default value, evaluated
17
17
  # in scope of self:
18
18
  #
19
19
  # attr_accessor_with_default(:element_name) { name.underscore }
20
20
  #
21
- def attr_accessor_with_default(sym, default = nil, &block)
22
- raise 'Default value or block required' unless !default.nil? || block
23
- define_method(sym, block_given? ? block : Proc.new { default })
21
+ def attr_accessor_with_default(sym, default = Proc.new)
22
+ ActiveSupport::Deprecation.warn "attr_accessor_with_default is deprecated. Use Ruby instead!"
23
+ define_method(sym, block_given? ? default : Proc.new { default })
24
24
  module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
25
- def #{sym}=(value) # def age=(value)
26
- class << self; attr_reader :#{sym} end # class << self; attr_reader :age end
27
- @#{sym} = value # @age = value
28
- end # end
25
+ def #{sym}=(value) # def age=(value)
26
+ class << self; attr_accessor :#{sym} end # class << self; attr_accessor :age end
27
+ @#{sym} = value # @age = value
28
+ end # end
29
29
  EVAL
30
30
  end
31
31
  end
@@ -1,16 +1,12 @@
1
1
  class Module
2
2
  # Declares an attribute reader backed by an internally-named instance variable.
3
3
  def attr_internal_reader(*attrs)
4
- attrs.each do |attr|
5
- module_eval "def #{attr}() #{attr_internal_ivar_name(attr)} end", __FILE__, __LINE__
6
- end
4
+ attrs.each {|attr_name| attr_internal_define(attr_name, :reader)}
7
5
  end
8
6
 
9
7
  # Declares an attribute writer backed by an internally-named instance variable.
10
8
  def attr_internal_writer(*attrs)
11
- attrs.each do |attr|
12
- module_eval "def #{attr}=(v) #{attr_internal_ivar_name(attr)} = v end", __FILE__, __LINE__
13
- end
9
+ attrs.each {|attr_name| attr_internal_define(attr_name, :writer)}
14
10
  end
15
11
 
16
12
  # Declares an attribute reader and writer backed by an internally-named instance
@@ -29,4 +25,15 @@ class Module
29
25
  def attr_internal_ivar_name(attr)
30
26
  Module.attr_internal_naming_format % attr
31
27
  end
28
+
29
+ def attr_internal_define(attr_name, type)
30
+ internal_name = attr_internal_ivar_name(attr_name).sub(/\A@/, '')
31
+ class_eval do # class_eval is necessary on 1.9 or else the methods a made private
32
+ # use native attr_* methods as they are faster on some Ruby implementations
33
+ send("attr_#{type}", internal_name)
34
+ end
35
+ attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
36
+ alias_method attr_name, internal_name
37
+ remove_method internal_name
38
+ end
32
39
  end
@@ -126,11 +126,7 @@ class Module
126
126
  %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
127
127
  end
128
128
 
129
- module_eval(<<-EOS, file, line - 5)
130
- if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}")
131
- remove_possible_method("#{prefix}#{method}")
132
- end
133
-
129
+ module_eval(<<-EOS, file, line - 1)
134
130
  def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block)
135
131
  #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block)
136
132
  rescue NoMethodError # rescue NoMethodError
@@ -1,11 +1,16 @@
1
1
  class Module
2
2
  def remove_possible_method(method)
3
- remove_method(method)
3
+ if method_defined?(method) || private_method_defined?(method)
4
+ remove_method(method)
5
+ end
4
6
  rescue NameError
7
+ # If the requested method is defined on a superclass or included module,
8
+ # method_defined? returns true but remove_method throws a NameError.
9
+ # Ignore this.
5
10
  end
6
11
 
7
12
  def redefine_method(method, &block)
8
13
  remove_possible_method(method)
9
14
  define_method(method, &block)
10
15
  end
11
- end
16
+ end
@@ -1,4 +1,6 @@
1
1
  require 'active_support/duration'
2
+ require 'active_support/core_ext/time/calculations'
3
+ require 'active_support/core_ext/time/acts_like'
2
4
 
3
5
  class Numeric
4
6
  # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.