activesupport 3.0.0.beta3 → 3.0.0.beta4
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.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- data/CHANGELOG +57 -0
- data/lib/active_support/builder.rb +6 -0
- data/lib/active_support/cache.rb +428 -70
- data/lib/active_support/cache/compressed_mem_cache_store.rb +6 -15
- data/lib/active_support/cache/file_store.rb +139 -41
- data/lib/active_support/cache/mem_cache_store.rb +115 -76
- data/lib/active_support/cache/memory_store.rb +127 -27
- data/lib/active_support/cache/strategy/local_cache.rb +109 -57
- data/lib/active_support/cache/synchronized_memory_store.rb +2 -38
- data/lib/active_support/callbacks.rb +27 -27
- data/lib/active_support/configurable.rb +19 -18
- data/lib/active_support/core_ext/array/conversions.rb +30 -26
- data/lib/active_support/core_ext/array/random_access.rb +19 -5
- data/lib/active_support/core_ext/benchmark.rb +0 -12
- data/lib/active_support/core_ext/class/attribute.rb +1 -4
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +3 -0
- data/lib/active_support/core_ext/date/calculations.rb +27 -8
- data/lib/active_support/core_ext/date/conversions.rb +1 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +9 -3
- data/lib/active_support/core_ext/file.rb +1 -0
- data/lib/active_support/core_ext/hash/conversions.rb +14 -137
- data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -1
- data/lib/active_support/core_ext/load_error.rb +1 -0
- data/lib/active_support/core_ext/logger.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/object/to_param.rb +2 -2
- data/lib/active_support/core_ext/object/with_options.rb +2 -0
- data/lib/active_support/core_ext/string.rb +1 -0
- data/lib/active_support/core_ext/string/conversions.rb +35 -1
- data/lib/active_support/core_ext/string/encoding.rb +11 -0
- data/lib/active_support/core_ext/string/filters.rb +29 -0
- data/lib/active_support/core_ext/string/inflections.rb +0 -11
- data/lib/active_support/core_ext/string/interpolation.rb +1 -0
- data/lib/active_support/core_ext/string/multibyte.rb +16 -19
- data/lib/active_support/core_ext/time/calculations.rb +7 -6
- data/lib/active_support/core_ext/uri.rb +8 -3
- data/lib/active_support/dependencies.rb +33 -1
- data/lib/active_support/duration.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +5 -1
- data/lib/active_support/i18n.rb +7 -2
- data/lib/active_support/inflector/transliterate.rb +58 -38
- data/lib/active_support/json/encoding.rb +28 -5
- data/lib/active_support/lazy_load_hooks.rb +14 -4
- data/lib/active_support/locale/en.yml +4 -1
- data/lib/active_support/message_verifier.rb +4 -4
- data/lib/active_support/multibyte.rb +1 -19
- data/lib/active_support/multibyte/chars.rb +143 -427
- data/lib/active_support/multibyte/unicode.rb +393 -0
- data/lib/active_support/notifications/fanout.rb +15 -5
- data/lib/active_support/notifications/instrumenter.rb +10 -4
- data/lib/active_support/railtie.rb +36 -0
- data/lib/active_support/rescuable.rb +1 -0
- data/lib/active_support/ruby/shim.rb +1 -0
- data/lib/active_support/testing/declarative.rb +1 -1
- data/lib/active_support/testing/isolation.rb +2 -1
- data/lib/active_support/testing/setup_and_teardown.rb +3 -0
- data/lib/active_support/values/time_zone.rb +20 -30
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini.rb +126 -1
- metadata +8 -61
- data/lib/active_support/multibyte/unicode_database.rb +0 -71
@@ -203,8 +203,8 @@ module ActiveSupport
|
|
203
203
|
# end
|
204
204
|
#
|
205
205
|
name = "_conditional_callback_#{@kind}_#{next_id}"
|
206
|
-
|
207
|
-
|
206
|
+
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
207
|
+
def #{name}(halted)
|
208
208
|
#{@compiled_options[0] || "if true"} && !halted
|
209
209
|
#{@filter} do
|
210
210
|
yield self
|
@@ -214,7 +214,6 @@ module ActiveSupport
|
|
214
214
|
end
|
215
215
|
end
|
216
216
|
RUBY_EVAL
|
217
|
-
@klass.class_eval(txt, __FILE__, line)
|
218
217
|
"#{name}(halted) do"
|
219
218
|
end
|
220
219
|
end
|
@@ -312,9 +311,9 @@ module ActiveSupport
|
|
312
311
|
|
313
312
|
def _normalize_legacy_filter(kind, filter)
|
314
313
|
if !filter.respond_to?(kind) && filter.respond_to?(:filter)
|
315
|
-
filter.singleton_class.class_eval
|
316
|
-
|
317
|
-
|
314
|
+
filter.singleton_class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
315
|
+
def #{kind}(context, &block) filter(context, &block) end
|
316
|
+
RUBY_EVAL
|
318
317
|
elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around
|
319
318
|
def filter.around(context)
|
320
319
|
should_continue = before(context)
|
@@ -387,31 +386,32 @@ module ActiveSupport
|
|
387
386
|
send("_update_#{symbol}_superclass_callbacks")
|
388
387
|
body = send("_#{symbol}_callbacks").compile(nil)
|
389
388
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
389
|
+
silence_warnings do
|
390
|
+
undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
|
391
|
+
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
392
|
+
def _run_#{symbol}_callbacks(key = nil, &blk)
|
393
|
+
@_initialized_#{symbol}_callbacks ||= begin
|
394
|
+
if self.class.send("_update_#{symbol}_superclass_callbacks")
|
395
|
+
self.class.__define_runner(#{symbol.inspect})
|
396
|
+
return _run_#{symbol}_callbacks(key, &blk)
|
397
|
+
end
|
398
|
+
true
|
399
|
+
end
|
396
400
|
|
397
|
-
|
398
|
-
|
401
|
+
if key
|
402
|
+
name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
|
399
403
|
|
400
|
-
|
401
|
-
|
402
|
-
|
404
|
+
unless respond_to?(name)
|
405
|
+
self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
|
406
|
+
end
|
403
407
|
|
404
|
-
|
405
|
-
|
406
|
-
|
408
|
+
send(name, &blk)
|
409
|
+
else
|
410
|
+
#{body}
|
411
|
+
end
|
407
412
|
end
|
408
|
-
|
409
|
-
|
410
|
-
RUBY_EVAL
|
411
|
-
|
412
|
-
silence_warnings do
|
413
|
-
undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
|
414
|
-
class_eval body, __FILE__, line
|
413
|
+
private :_run_#{symbol}_callbacks
|
414
|
+
RUBY_EVAL
|
415
415
|
end
|
416
416
|
end
|
417
417
|
|
@@ -1,35 +1,36 @@
|
|
1
|
-
require
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/ordered_options'
|
3
|
+
require 'active_support/core_ext/kernel/singleton_class'
|
4
|
+
require 'active_support/core_ext/module/delegation'
|
2
5
|
|
3
6
|
module ActiveSupport
|
4
7
|
module Configurable
|
5
8
|
extend ActiveSupport::Concern
|
6
9
|
|
7
10
|
module ClassMethods
|
8
|
-
def get_config
|
9
|
-
module_parts = name.split("::")
|
10
|
-
modules = [Object]
|
11
|
-
module_parts.each {|name| modules.push modules.last.const_get(name) }
|
12
|
-
modules.reverse_each do |mod|
|
13
|
-
return mod.const_get(:DEFAULT_CONFIG) if const_defined?(:DEFAULT_CONFIG)
|
14
|
-
end
|
15
|
-
{}
|
16
|
-
end
|
17
|
-
|
18
11
|
def config
|
19
|
-
|
20
|
-
@config
|
12
|
+
@config ||= ActiveSupport::InheritableOptions.new(superclass.respond_to?(:config) ? superclass.config : {})
|
21
13
|
end
|
22
14
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
15
|
+
def configure
|
16
|
+
yield config
|
17
|
+
end
|
18
|
+
|
19
|
+
def config_accessor(*names)
|
20
|
+
names.each do |name|
|
21
|
+
code, line = <<-RUBY, __LINE__ + 1
|
22
|
+
def #{name}; config.#{name}; end
|
23
|
+
def #{name}=(value); config.#{name} = value; end
|
24
|
+
RUBY
|
25
|
+
|
26
|
+
singleton_class.class_eval code, __FILE__, line
|
27
|
+
class_eval code, __FILE__, line
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
32
|
def config
|
32
|
-
self.class.config
|
33
|
+
@config ||= ActiveSupport::InheritableOptions.new(self.class.config)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
require 'active_support/xml_mini'
|
1
2
|
require 'active_support/core_ext/hash/keys'
|
2
3
|
require 'active_support/core_ext/hash/reverse_merge'
|
3
|
-
require 'active_support/
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
4
5
|
|
5
6
|
class Array
|
6
7
|
# Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
|
@@ -8,9 +9,15 @@ class Array
|
|
8
9
|
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ")
|
9
10
|
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ")
|
10
11
|
def to_sentence(options = {})
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
if defined?(I18n)
|
13
|
+
default_words_connector = I18n.translate(:'support.array.words_connector', :locale => options[:locale])
|
14
|
+
default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale])
|
15
|
+
default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale])
|
16
|
+
else
|
17
|
+
default_words_connector = ", "
|
18
|
+
default_two_words_connector = " and "
|
19
|
+
default_last_word_connector = ", and "
|
20
|
+
end
|
14
21
|
|
15
22
|
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
16
23
|
options.reverse_merge! :words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector
|
@@ -127,34 +134,31 @@ class Array
|
|
127
134
|
# </messages>
|
128
135
|
#
|
129
136
|
def to_xml(options = {})
|
130
|
-
|
131
|
-
require 'builder' unless defined?(Builder)
|
137
|
+
require 'active_support/builder' unless defined?(Builder)
|
132
138
|
|
133
139
|
options = options.dup
|
134
|
-
options[:
|
135
|
-
options[:
|
136
|
-
options[:
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
if !options.has_key?(:dasherize) || options[:dasherize]
|
143
|
-
root = root.dasherize
|
140
|
+
options[:indent] ||= 2
|
141
|
+
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
142
|
+
options[:root] ||= if first.class.to_s != "Hash" && all? { |e| e.is_a?(first.class) }
|
143
|
+
underscored = ActiveSupport::Inflector.underscore(first.class.name)
|
144
|
+
ActiveSupport::Inflector.pluralize(underscored).tr('/', '_')
|
145
|
+
else
|
146
|
+
"objects"
|
144
147
|
end
|
145
148
|
|
146
|
-
options[:builder]
|
149
|
+
builder = options[:builder]
|
150
|
+
builder.instruct! unless options.delete(:skip_instruct)
|
147
151
|
|
148
|
-
|
152
|
+
root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
|
153
|
+
children = options.delete(:children) || root.singularize
|
149
154
|
|
150
|
-
|
151
|
-
if empty?
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
each { |e| e.to_xml(opts.merge({ :skip_instruct => true })) }
|
157
|
-
}
|
155
|
+
attributes = options[:skip_types] ? {} : {:type => "array"}
|
156
|
+
return builder.tag!(root, attributes) if empty?
|
157
|
+
|
158
|
+
builder.__send__(:method_missing, root, attributes) do
|
159
|
+
each { |value| ActiveSupport::XmlMini.to_tag(children, value, options) }
|
160
|
+
yield builder if block_given?
|
158
161
|
end
|
159
162
|
end
|
163
|
+
|
160
164
|
end
|
@@ -1,6 +1,20 @@
|
|
1
1
|
class Array
|
2
|
-
#
|
3
|
-
def
|
4
|
-
self[Kernel.rand(
|
5
|
-
|
6
|
-
|
2
|
+
# Backport of Array#sample based on Marc-Andre Lafortune's http://github.com/marcandre/backports/
|
3
|
+
def sample(n=nil)
|
4
|
+
return self[Kernel.rand(size)] if n.nil?
|
5
|
+
n = n.to_int
|
6
|
+
rescue Exception => e
|
7
|
+
raise TypeError, "Coercion error: #{n.inspect}.to_int => Integer failed:\n(#{e.message})"
|
8
|
+
else
|
9
|
+
raise TypeError, "Coercion error: obj.to_int did NOT return an Integer (was #{n.class})" unless n.kind_of? Integer
|
10
|
+
raise ArgumentError, "negative array size" if n < 0
|
11
|
+
n = size if n > size
|
12
|
+
result = Array.new(self)
|
13
|
+
n.times do |i|
|
14
|
+
r = i + Kernel.rand(size - i)
|
15
|
+
result[i], result[r] = result[r], result[i]
|
16
|
+
end
|
17
|
+
result[n..size] = []
|
18
|
+
result
|
19
|
+
end unless method_defined? :sample
|
20
|
+
end
|
@@ -1,18 +1,6 @@
|
|
1
1
|
require 'benchmark'
|
2
2
|
|
3
3
|
class << Benchmark
|
4
|
-
# Earlier Ruby had a slower implementation.
|
5
|
-
if RUBY_VERSION < '1.8.7'
|
6
|
-
remove_method :realtime
|
7
|
-
|
8
|
-
def realtime
|
9
|
-
r0 = Time.now
|
10
|
-
yield
|
11
|
-
r1 = Time.now
|
12
|
-
r1.to_f - r0.to_f
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
4
|
def ms
|
17
5
|
1000 * realtime { yield }
|
18
6
|
end
|
@@ -9,6 +9,9 @@ end
|
|
9
9
|
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
|
10
10
|
# to, for example, an array without those additions being shared with either their parent, siblings, or
|
11
11
|
# children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
|
12
|
+
#
|
13
|
+
# The copies of inheritable parent attributes are added to subclasses when they are created, via the
|
14
|
+
# +inherited+ hook.
|
12
15
|
class Class # :nodoc:
|
13
16
|
def class_inheritable_reader(*syms)
|
14
17
|
options = syms.extract_options!
|
@@ -4,15 +4,33 @@ require 'active_support/core_ext/time/zones'
|
|
4
4
|
require 'active_support/core_ext/object/acts_like'
|
5
5
|
|
6
6
|
class Date
|
7
|
+
if RUBY_VERSION < '1.9'
|
8
|
+
undef :>>
|
9
|
+
|
10
|
+
# Backported from 1.9. The one in 1.8 leads to incorrect next_month and
|
11
|
+
# friends for dates where the calendar reform is involved. It additionally
|
12
|
+
# prevents an infinite loop fixed in r27013.
|
13
|
+
def >>(n)
|
14
|
+
y, m = (year * 12 + (mon - 1) + n).divmod(12)
|
15
|
+
m, = (m + 1) .divmod(1)
|
16
|
+
d = mday
|
17
|
+
until jd2 = self.class.valid_civil?(y, m, d, start)
|
18
|
+
d -= 1
|
19
|
+
raise ArgumentError, 'invalid date' unless d > 0
|
20
|
+
end
|
21
|
+
self + (jd2 - jd)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
7
25
|
class << self
|
8
26
|
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
|
9
27
|
def yesterday
|
10
|
-
::Date.
|
28
|
+
::Date.current.yesterday
|
11
29
|
end
|
12
30
|
|
13
31
|
# Returns a new Date representing the date 1 day after today (i.e. tomorrow's date).
|
14
32
|
def tomorrow
|
15
|
-
::Date.
|
33
|
+
::Date.current.tomorrow
|
16
34
|
end
|
17
35
|
|
18
36
|
# Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today.
|
@@ -128,20 +146,20 @@ class Date
|
|
128
146
|
advance(:years => years)
|
129
147
|
end
|
130
148
|
|
131
|
-
#
|
132
|
-
def
|
149
|
+
# Shorthand for years_ago(1)
|
150
|
+
def prev_year
|
133
151
|
years_ago(1)
|
134
|
-
end
|
152
|
+
end unless method_defined?(:prev_year)
|
135
153
|
|
136
154
|
# Short-hand for years_since(1)
|
137
155
|
def next_year
|
138
156
|
years_since(1)
|
139
157
|
end unless method_defined?(:next_year)
|
140
|
-
|
158
|
+
|
141
159
|
# Short-hand for months_ago(1)
|
142
|
-
def
|
160
|
+
def prev_month
|
143
161
|
months_ago(1)
|
144
|
-
end
|
162
|
+
end unless method_defined?(:prev_month)
|
145
163
|
|
146
164
|
# Short-hand for months_since(1)
|
147
165
|
def next_month
|
@@ -163,6 +181,7 @@ class Date
|
|
163
181
|
result = self + days_to_sunday.days
|
164
182
|
self.acts_like?(:time) ? result.end_of_day : result
|
165
183
|
end
|
184
|
+
alias :sunday :end_of_week
|
166
185
|
alias :at_end_of_week :end_of_week
|
167
186
|
|
168
187
|
# Returns a new Date/DateTime representing the start of the given day in next week (default is Monday).
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
2
|
require 'active_support/core_ext/time/conversions'
|
3
|
+
require 'active_support/core_ext/date_time/calculations'
|
3
4
|
|
4
5
|
class DateTime
|
5
6
|
# Ruby 1.9 has DateTime#to_time which internally relies on Time. We define our own #to_time which allows
|
@@ -59,7 +60,7 @@ class DateTime
|
|
59
60
|
# Converts self to a Ruby Date object; time portion is discarded
|
60
61
|
def to_date
|
61
62
|
::Date.new(year, month, day)
|
62
|
-
end unless
|
63
|
+
end unless instance_methods(false).include?(:to_date)
|
63
64
|
|
64
65
|
# Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
|
65
66
|
# 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
|
@@ -70,12 +71,17 @@ class DateTime
|
|
70
71
|
# To be able to keep Times, Dates and DateTimes interchangeable on conversions
|
71
72
|
def to_datetime
|
72
73
|
self
|
73
|
-
end unless
|
74
|
+
end unless instance_methods(false).include?(:to_datetime)
|
75
|
+
|
76
|
+
def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0)
|
77
|
+
offset = utc_or_local.to_sym == :local ? local_offset : 0
|
78
|
+
civil(year, month, day, hour, min, sec, offset)
|
79
|
+
end
|
74
80
|
|
75
81
|
# Converts datetime to an appropriate format for use in XML
|
76
82
|
def xmlschema
|
77
83
|
strftime("%Y-%m-%dT%H:%M:%S%Z")
|
78
|
-
end unless
|
84
|
+
end unless instance_methods(false).include?(:xmlschema)
|
79
85
|
|
80
86
|
# Converts self to a floating-point number of seconds since the Unix epoch
|
81
87
|
def to_f
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'active_support/xml_mini'
|
1
2
|
require 'active_support/time'
|
2
3
|
require 'active_support/core_ext/array/wrap'
|
3
4
|
require 'active_support/core_ext/hash/reverse_merge'
|
@@ -5,79 +6,6 @@ require 'active_support/core_ext/object/blank'
|
|
5
6
|
require 'active_support/core_ext/string/inflections'
|
6
7
|
|
7
8
|
class Hash
|
8
|
-
# This module exists to decorate files deserialized using Hash.from_xml with
|
9
|
-
# the <tt>original_filename</tt> and <tt>content_type</tt> methods.
|
10
|
-
module FileLike #:nodoc:
|
11
|
-
attr_writer :original_filename, :content_type
|
12
|
-
|
13
|
-
def original_filename
|
14
|
-
@original_filename || 'untitled'
|
15
|
-
end
|
16
|
-
|
17
|
-
def content_type
|
18
|
-
@content_type || 'application/octet-stream'
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
XML_TYPE_NAMES = {
|
23
|
-
"Symbol" => "symbol",
|
24
|
-
"Fixnum" => "integer",
|
25
|
-
"Bignum" => "integer",
|
26
|
-
"BigDecimal" => "decimal",
|
27
|
-
"Float" => "float",
|
28
|
-
"TrueClass" => "boolean",
|
29
|
-
"FalseClass" => "boolean",
|
30
|
-
"Date" => "date",
|
31
|
-
"DateTime" => "datetime",
|
32
|
-
"Time" => "datetime"
|
33
|
-
} unless defined?(XML_TYPE_NAMES)
|
34
|
-
|
35
|
-
XML_FORMATTING = {
|
36
|
-
"symbol" => Proc.new { |symbol| symbol.to_s },
|
37
|
-
"date" => Proc.new { |date| date.to_s(:db) },
|
38
|
-
"datetime" => Proc.new { |time| time.xmlschema },
|
39
|
-
"binary" => Proc.new { |binary| ActiveSupport::Base64.encode64(binary) },
|
40
|
-
"yaml" => Proc.new { |yaml| yaml.to_yaml }
|
41
|
-
} unless defined?(XML_FORMATTING)
|
42
|
-
|
43
|
-
# TODO: use Time.xmlschema instead of Time.parse;
|
44
|
-
# use regexp instead of Date.parse
|
45
|
-
unless defined?(XML_PARSING)
|
46
|
-
XML_PARSING = {
|
47
|
-
"symbol" => Proc.new { |symbol| symbol.to_sym },
|
48
|
-
"date" => Proc.new { |date| ::Date.parse(date) },
|
49
|
-
"datetime" => Proc.new { |time| ::Time.parse(time).utc rescue ::DateTime.parse(time).utc },
|
50
|
-
"integer" => Proc.new { |integer| integer.to_i },
|
51
|
-
"float" => Proc.new { |float| float.to_f },
|
52
|
-
"decimal" => Proc.new { |number| BigDecimal(number) },
|
53
|
-
"boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
|
54
|
-
"string" => Proc.new { |string| string.to_s },
|
55
|
-
"yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml },
|
56
|
-
"base64Binary" => Proc.new { |bin| ActiveSupport::Base64.decode64(bin) },
|
57
|
-
"binary" => Proc.new do |bin, entity|
|
58
|
-
case entity['encoding']
|
59
|
-
when 'base64'
|
60
|
-
ActiveSupport::Base64.decode64(bin)
|
61
|
-
# TODO: Add support for other encodings
|
62
|
-
else
|
63
|
-
bin
|
64
|
-
end
|
65
|
-
end,
|
66
|
-
"file" => Proc.new do |file, entity|
|
67
|
-
f = StringIO.new(ActiveSupport::Base64.decode64(file))
|
68
|
-
f.extend(FileLike)
|
69
|
-
f.original_filename = entity['name']
|
70
|
-
f.content_type = entity['content_type']
|
71
|
-
f
|
72
|
-
end
|
73
|
-
}
|
74
|
-
|
75
|
-
XML_PARSING.update(
|
76
|
-
"double" => XML_PARSING["float"],
|
77
|
-
"dateTime" => XML_PARSING["datetime"]
|
78
|
-
)
|
79
|
-
end
|
80
|
-
|
81
9
|
# Returns a string containing an XML representation of its receiver:
|
82
10
|
#
|
83
11
|
# {"foo" => 1, "bar" => 2}.to_xml
|
@@ -127,65 +55,22 @@ class Hash
|
|
127
55
|
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
|
128
56
|
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
|
129
57
|
def to_xml(options = {})
|
130
|
-
require 'builder' unless defined?(Builder)
|
58
|
+
require 'active_support/builder' unless defined?(Builder)
|
131
59
|
|
132
60
|
options = options.dup
|
133
|
-
options[:indent]
|
134
|
-
options
|
135
|
-
|
136
|
-
options[:builder].instruct! unless options.delete(:skip_instruct)
|
137
|
-
root = rename_key(options[:root].to_s, options)
|
61
|
+
options[:indent] ||= 2
|
62
|
+
options[:root] ||= "hash"
|
63
|
+
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
138
64
|
|
139
|
-
options[:builder]
|
140
|
-
|
141
|
-
case value
|
142
|
-
when ::Hash
|
143
|
-
value.to_xml(options.merge({ :root => key, :skip_instruct => true }))
|
144
|
-
when ::Array
|
145
|
-
value.to_xml(options.merge({ :root => key, :children => key.to_s.singularize, :skip_instruct => true}))
|
146
|
-
when ::Method, ::Proc
|
147
|
-
# If the Method or Proc takes two arguments, then
|
148
|
-
# pass the suggested child element name. This is
|
149
|
-
# used if the Method or Proc will be operating over
|
150
|
-
# multiple records and needs to create an containing
|
151
|
-
# element that will contain the objects being
|
152
|
-
# serialized.
|
153
|
-
if 1 == value.arity
|
154
|
-
value.call(options.merge({ :root => key, :skip_instruct => true }))
|
155
|
-
else
|
156
|
-
value.call(options.merge({ :root => key, :skip_instruct => true }), key.to_s.singularize)
|
157
|
-
end
|
158
|
-
else
|
159
|
-
if value.respond_to?(:to_xml)
|
160
|
-
value.to_xml(options.merge({ :root => key, :skip_instruct => true }))
|
161
|
-
else
|
162
|
-
type_name = XML_TYPE_NAMES[value.class.name]
|
65
|
+
builder = options[:builder]
|
66
|
+
builder.instruct! unless options.delete(:skip_instruct)
|
163
67
|
|
164
|
-
|
165
|
-
|
166
|
-
attributes = options[:skip_types] || value.nil? || type_name.nil? ? { } : { :type => type_name }
|
167
|
-
if value.nil?
|
168
|
-
attributes[:nil] = true
|
169
|
-
end
|
68
|
+
root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
|
170
69
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
yield options[:builder] if block_given?
|
70
|
+
builder.__send__(:method_missing, root) do
|
71
|
+
each { |key, value| ActiveSupport::XmlMini.to_tag(key, value, options) }
|
72
|
+
yield builder if block_given?
|
180
73
|
end
|
181
|
-
|
182
|
-
end
|
183
|
-
|
184
|
-
def rename_key(key, options = {})
|
185
|
-
camelize = options.has_key?(:camelize) && options[:camelize]
|
186
|
-
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
|
187
|
-
key = key.camelize if camelize
|
188
|
-
dasherize ? key.dasherize : key
|
189
74
|
end
|
190
75
|
|
191
76
|
class << self
|
@@ -213,12 +98,8 @@ class Hash
|
|
213
98
|
end
|
214
99
|
elsif value.has_key?("__content__")
|
215
100
|
content = value["__content__"]
|
216
|
-
if parser =
|
217
|
-
|
218
|
-
XML_PARSING[value["type"]].call(content, value)
|
219
|
-
else
|
220
|
-
XML_PARSING[value["type"]].call(content)
|
221
|
-
end
|
101
|
+
if parser = ActiveSupport::XmlMini::PARSING[value["type"]]
|
102
|
+
parser.arity == 1 ? parser.call(content) : parser.call(content, value)
|
222
103
|
else
|
223
104
|
content
|
224
105
|
end
|
@@ -244,11 +125,7 @@ class Hash
|
|
244
125
|
end
|
245
126
|
when 'Array'
|
246
127
|
value.map! { |i| typecast_xml_value(i) }
|
247
|
-
|
248
|
-
when 0 then nil
|
249
|
-
when 1 then value.first
|
250
|
-
else value
|
251
|
-
end
|
128
|
+
value.length > 1 ? value : value.first
|
252
129
|
when 'String'
|
253
130
|
value
|
254
131
|
else
|