activesupport 3.0.20 → 3.1.0.beta1
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 +14 -66
- data/README.rdoc +1 -1
- data/lib/active_support/backtrace_cleaner.rb +1 -1
- data/lib/active_support/buffered_logger.rb +4 -11
- data/lib/active_support/cache.rb +12 -15
- data/lib/active_support/cache/file_store.rb +3 -2
- data/lib/active_support/cache/mem_cache_store.rb +11 -3
- data/lib/active_support/cache/strategy/local_cache.rb +28 -23
- data/lib/active_support/callbacks.rb +195 -175
- data/lib/active_support/concern.rb +105 -35
- data/lib/active_support/configurable.rb +41 -2
- data/lib/active_support/core_ext/array/access.rb +2 -2
- data/lib/active_support/core_ext/array/random_access.rb +10 -7
- data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -2
- data/lib/active_support/core_ext/class/attribute.rb +27 -17
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +12 -86
- data/lib/active_support/core_ext/class/subclasses.rb +20 -34
- data/lib/active_support/core_ext/date/calculations.rb +14 -2
- data/lib/active_support/core_ext/date/conversions.rb +6 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +26 -9
- data/lib/active_support/core_ext/date_time/conversions.rb +1 -1
- data/lib/active_support/core_ext/date_time/zones.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +2 -5
- data/lib/active_support/core_ext/float/rounding.rb +1 -1
- data/lib/active_support/core_ext/hash.rb +1 -0
- data/lib/active_support/core_ext/hash/conversions.rb +23 -36
- data/lib/active_support/core_ext/hash/deep_dup.rb +11 -0
- data/lib/active_support/core_ext/hash/keys.rb +6 -4
- data/lib/active_support/core_ext/hash/reverse_merge.rb +9 -14
- data/lib/active_support/core_ext/kernel/reporting.rb +19 -0
- data/lib/active_support/core_ext/logger.rb +11 -38
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +11 -12
- data/lib/active_support/core_ext/module/attr_internal.rb +13 -6
- data/lib/active_support/core_ext/module/deprecation.rb +2 -0
- data/lib/active_support/core_ext/object.rb +1 -1
- data/lib/active_support/core_ext/object/blank.rb +42 -9
- data/lib/active_support/core_ext/object/duplicable.rb +48 -9
- data/lib/active_support/core_ext/object/inclusion.rb +15 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +1 -35
- data/lib/active_support/core_ext/object/to_param.rb +13 -8
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +27 -10
- data/lib/active_support/core_ext/object/with_options.rb +19 -5
- data/lib/active_support/core_ext/range.rb +1 -0
- data/lib/active_support/core_ext/range/cover.rb +3 -0
- data/lib/active_support/core_ext/string.rb +1 -0
- data/lib/active_support/core_ext/string/filters.rb +3 -3
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/inquiry.rb +13 -0
- data/lib/active_support/core_ext/string/multibyte.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +33 -89
- data/lib/active_support/core_ext/time/calculations.rb +14 -13
- data/lib/active_support/core_ext/time/conversions.rb +2 -24
- data/lib/active_support/core_ext/time/marshal.rb +0 -1
- data/lib/active_support/core_ext/time/zones.rb +32 -21
- data/lib/active_support/core_ext/uri.rb +8 -0
- data/lib/active_support/dependencies.rb +93 -37
- data/lib/active_support/deprecation.rb +2 -2
- data/lib/active_support/deprecation/behaviors.rb +7 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
- data/lib/active_support/deprecation/reporting.rb +4 -0
- data/lib/active_support/duration.rb +4 -0
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/file_watcher.rb +36 -0
- data/lib/active_support/gzip.rb +0 -1
- data/lib/active_support/hash_with_indifferent_access.rb +6 -4
- data/lib/active_support/i18n.rb +0 -1
- data/lib/active_support/i18n_railtie.rb +2 -2
- data/lib/active_support/inflector/inflections.rb +1 -1
- data/lib/active_support/json/decoding.rb +37 -23
- data/lib/active_support/json/encoding.rb +8 -3
- data/lib/active_support/lazy_load_hooks.rb +7 -7
- data/lib/active_support/log_subscriber.rb +3 -3
- data/lib/active_support/log_subscriber/test_helper.rb +4 -3
- data/lib/active_support/message_encryptor.rb +1 -1
- data/lib/active_support/message_verifier.rb +1 -1
- data/lib/active_support/multibyte/chars.rb +4 -3
- data/lib/active_support/multibyte/unicode.rb +1 -1
- data/lib/active_support/notifications.rb +9 -8
- data/lib/active_support/notifications/fanout.rb +3 -3
- data/lib/active_support/ordered_hash.rb +19 -2
- data/lib/active_support/ordered_options.rb +33 -3
- data/lib/active_support/railtie.rb +1 -1
- data/lib/active_support/rescuable.rb +1 -0
- data/lib/active_support/secure_random.rb +11 -5
- data/lib/active_support/test_case.rb +2 -10
- data/lib/active_support/testing/assertions.rb +17 -6
- data/lib/active_support/testing/mochaing.rb +7 -0
- data/lib/active_support/testing/pending.rb +27 -23
- data/lib/active_support/testing/setup_and_teardown.rb +8 -11
- data/lib/active_support/time_with_zone.rb +6 -3
- data/lib/active_support/version.rb +3 -3
- data/lib/active_support/whiny_nil.rb +1 -1
- data/lib/active_support/xml_mini.rb +4 -2
- data/lib/active_support/xml_mini/jdom.rb +9 -16
- data/lib/active_support/xml_mini/libxml.rb +1 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +2 -1
- data/lib/active_support/xml_mini/nokogiri.rb +1 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -0
- data/lib/active_support/xml_mini/rexml.rb +1 -0
- metadata +50 -32
- checksums.yaml +0 -7
- data/lib/active_support/core_ext/cgi.rb +0 -1
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -19
- data/lib/active_support/core_ext/object/returning.rb +0 -43
- data/lib/active_support/json/backends/jsongem.rb +0 -47
- data/lib/active_support/json/backends/okjson.rb +0 -644
- data/lib/active_support/json/backends/yajl.rb +0 -44
- data/lib/active_support/json/backends/yaml.rb +0 -19
- data/lib/active_support/testing/default.rb +0 -9
@@ -2,49 +2,35 @@ require 'active_support/core_ext/module/anonymous'
|
|
2
2
|
require 'active_support/core_ext/module/reachable'
|
3
3
|
|
4
4
|
class Class #:nodoc:
|
5
|
-
|
6
|
-
|
7
|
-
alias :subclasses :__subclasses__
|
5
|
+
begin
|
6
|
+
ObjectSpace.each_object(Class.new) {}
|
8
7
|
|
9
8
|
def descendants
|
10
9
|
descendants = []
|
11
|
-
|
12
|
-
descendants
|
13
|
-
descendants.concat k.descendants
|
10
|
+
ObjectSpace.each_object(class << self; self; end) do |k|
|
11
|
+
descendants.unshift k unless k == self
|
14
12
|
end
|
15
13
|
descendants
|
16
14
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
descendants = []
|
23
|
-
ObjectSpace.each_object(class << self; self; end) do |k|
|
24
|
-
descendants.unshift k unless k == self
|
25
|
-
end
|
26
|
-
descendants
|
27
|
-
end
|
28
|
-
rescue StandardError # JRuby
|
29
|
-
def descendants
|
30
|
-
descendants = []
|
31
|
-
ObjectSpace.each_object(Class) do |k|
|
32
|
-
descendants.unshift k if k < self
|
33
|
-
end
|
34
|
-
descendants.uniq!
|
35
|
-
descendants
|
15
|
+
rescue StandardError # JRuby
|
16
|
+
def descendants
|
17
|
+
descendants = []
|
18
|
+
ObjectSpace.each_object(Class) do |k|
|
19
|
+
descendants.unshift k if k < self
|
36
20
|
end
|
21
|
+
descendants.uniq!
|
22
|
+
descendants
|
37
23
|
end
|
24
|
+
end
|
38
25
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
subclasses
|
26
|
+
# Returns an array with the direct children of +self+.
|
27
|
+
#
|
28
|
+
# Integer.subclasses # => [Bignum, Fixnum]
|
29
|
+
def subclasses
|
30
|
+
subclasses, chain = [], descendants
|
31
|
+
chain.each do |k|
|
32
|
+
subclasses << k unless chain.any? { |c| c > k }
|
48
33
|
end
|
34
|
+
subclasses
|
49
35
|
end
|
50
36
|
end
|
@@ -5,6 +5,8 @@ require 'active_support/core_ext/date/zones'
|
|
5
5
|
require 'active_support/core_ext/time/zones'
|
6
6
|
|
7
7
|
class Date
|
8
|
+
DAYS_INTO_WEEK = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6 }
|
9
|
+
|
8
10
|
if RUBY_VERSION < '1.9'
|
9
11
|
undef :>>
|
10
12
|
|
@@ -127,6 +129,11 @@ class Date
|
|
127
129
|
)
|
128
130
|
end
|
129
131
|
|
132
|
+
# Returns a new Date/DateTime representing the time a number of specified weeks ago.
|
133
|
+
def weeks_ago(weeks)
|
134
|
+
advance(:weeks => -weeks)
|
135
|
+
end
|
136
|
+
|
130
137
|
# Returns a new Date/DateTime representing the time a number of specified months ago.
|
131
138
|
def months_ago(months)
|
132
139
|
advance(:months => -months)
|
@@ -185,10 +192,15 @@ class Date
|
|
185
192
|
alias :sunday :end_of_week
|
186
193
|
alias :at_end_of_week :end_of_week
|
187
194
|
|
195
|
+
# Returns a new Date/DateTime representing the start of the given day in the previous week (default is Monday).
|
196
|
+
def prev_week(day = :monday)
|
197
|
+
result = (self - 7).beginning_of_week + DAYS_INTO_WEEK[day]
|
198
|
+
self.acts_like?(:time) ? result.change(:hour => 0) : result
|
199
|
+
end
|
200
|
+
|
188
201
|
# Returns a new Date/DateTime representing the start of the given day in next week (default is Monday).
|
189
202
|
def next_week(day = :monday)
|
190
|
-
|
191
|
-
result = (self + 7).beginning_of_week + days_into_week[day]
|
203
|
+
result = (self + 7).beginning_of_week + DAYS_INTO_WEEK[day]
|
192
204
|
self.acts_like?(:time) ? result.change(:hour => 0) : result
|
193
205
|
end
|
194
206
|
|
@@ -93,6 +93,12 @@ class Date
|
|
93
93
|
::DateTime.civil(year, month, day, 0, 0, 0, 0)
|
94
94
|
end if RUBY_VERSION < '1.9'
|
95
95
|
|
96
|
+
def iso8601
|
97
|
+
strftime('%F')
|
98
|
+
end if RUBY_VERSION < '1.9'
|
99
|
+
|
100
|
+
alias_method :rfc3339, :iso8601 if RUBY_VERSION < '1.9'
|
101
|
+
|
96
102
|
def xmlschema
|
97
103
|
to_time_in_current_zone.xmlschema
|
98
104
|
end
|
@@ -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(
|
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
|
109
|
-
|
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
|
@@ -66,7 +66,7 @@ class DateTime
|
|
66
66
|
# Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
|
67
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
72
|
# To be able to keep Times, Dates and DateTimes interchangeable on conversions
|
@@ -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.
|
19
|
+
ActiveSupport::TimeWithZone.new(utc? ? self : getutc, ::Time.find_zone!(zone))
|
20
20
|
end
|
21
21
|
end
|
@@ -90,14 +90,11 @@ module Enumerable
|
|
90
90
|
# => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
|
91
91
|
#
|
92
92
|
def index_by
|
93
|
-
|
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
|
-
#
|
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
99
|
size = block_given? ? select(&block).size : self.size
|
103
100
|
size > 1
|
@@ -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'
|
@@ -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.
|
30
|
-
#
|
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
|
86
|
-
typecast_xml_value(unrename_keys(ActiveSupport::XmlMini.parse(xml))
|
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
|
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,15 +101,14 @@ 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
|
104
|
+
entries.collect { |v| typecast_xml_value(v) }
|
111
105
|
when "Hash"
|
112
|
-
[typecast_xml_value(entries
|
106
|
+
[typecast_xml_value(entries)]
|
113
107
|
else
|
114
108
|
raise "can't typecast #{entries.inspect}"
|
115
109
|
end
|
116
110
|
end
|
117
|
-
elsif value['type'] == 'file' ||
|
118
|
-
(value["__content__"] && (value.keys.size == 1 || value["__content__"].present?))
|
111
|
+
elsif value['type'] == 'file' || value["__content__"].present?
|
119
112
|
content = value["__content__"]
|
120
113
|
if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
|
121
114
|
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
|
@@ -133,17 +126,14 @@ class Hash
|
|
133
126
|
elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash)
|
134
127
|
nil
|
135
128
|
else
|
136
|
-
xml_value = value.
|
137
|
-
h[k] = typecast_xml_value(v, disallowed_types)
|
138
|
-
h
|
139
|
-
end
|
129
|
+
xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
|
140
130
|
|
141
131
|
# Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
|
142
132
|
# how multipart uploaded files from HTML appear
|
143
133
|
xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
|
144
134
|
end
|
145
135
|
when 'Array'
|
146
|
-
value.map! { |i| typecast_xml_value(i
|
136
|
+
value.map! { |i| typecast_xml_value(i) }
|
147
137
|
value.length > 1 ? value : value.first
|
148
138
|
when 'String'
|
149
139
|
value
|
@@ -155,10 +145,7 @@ class Hash
|
|
155
145
|
def unrename_keys(params)
|
156
146
|
case params.class.to_s
|
157
147
|
when "Hash"
|
158
|
-
params.
|
159
|
-
h[k.to_s.tr("-", "_")] = unrename_keys(v)
|
160
|
-
h
|
161
|
-
end
|
148
|
+
Hash[params.map { |k,v| [k.to_s.tr("-", "_"), unrename_keys(v)] } ]
|
162
149
|
when "Array"
|
163
150
|
params.map { |v| unrename_keys(v) }
|
164
151
|
else
|
@@ -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
|
39
|
-
# { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key
|
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
|
-
|
43
|
-
|
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
|
-
#
|
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
|
-
#
|
6
|
-
# options.reverse_merge! :size => 25, :velocity => 10
|
7
|
-
# end
|
4
|
+
# options = options.reverse_merge(:size => 25, :velocity => 10)
|
8
5
|
#
|
9
|
-
#
|
6
|
+
# is equivalent to
|
10
7
|
#
|
11
|
-
#
|
12
|
-
# { :size => 25, :velocity => 10 }.merge(options)
|
13
|
-
# end
|
8
|
+
# options = {:size => 25, :velocity => 10}.merge(options)
|
14
9
|
#
|
15
|
-
#
|
16
|
-
#
|
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
|
-
#
|
22
|
-
# Modifies the receiver in place.
|
16
|
+
# Destructive +reverse_merge+.
|
23
17
|
def reverse_merge!(other_hash)
|
24
|
-
|
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!
|
@@ -59,4 +59,23 @@ 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
|
62
81
|
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
|
8
|
-
self.#{level}(before_message)
|
9
|
-
return_value =
|
10
|
-
self.#{level}(after_message)
|
11
|
-
|
12
|
-
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 :
|
69
|
-
#
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|