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.

Files changed (63) hide show
  1. data/CHANGELOG +57 -0
  2. data/lib/active_support/builder.rb +6 -0
  3. data/lib/active_support/cache.rb +428 -70
  4. data/lib/active_support/cache/compressed_mem_cache_store.rb +6 -15
  5. data/lib/active_support/cache/file_store.rb +139 -41
  6. data/lib/active_support/cache/mem_cache_store.rb +115 -76
  7. data/lib/active_support/cache/memory_store.rb +127 -27
  8. data/lib/active_support/cache/strategy/local_cache.rb +109 -57
  9. data/lib/active_support/cache/synchronized_memory_store.rb +2 -38
  10. data/lib/active_support/callbacks.rb +27 -27
  11. data/lib/active_support/configurable.rb +19 -18
  12. data/lib/active_support/core_ext/array/conversions.rb +30 -26
  13. data/lib/active_support/core_ext/array/random_access.rb +19 -5
  14. data/lib/active_support/core_ext/benchmark.rb +0 -12
  15. data/lib/active_support/core_ext/class/attribute.rb +1 -4
  16. data/lib/active_support/core_ext/class/inheritable_attributes.rb +3 -0
  17. data/lib/active_support/core_ext/date/calculations.rb +27 -8
  18. data/lib/active_support/core_ext/date/conversions.rb +1 -0
  19. data/lib/active_support/core_ext/date_time/conversions.rb +9 -3
  20. data/lib/active_support/core_ext/file.rb +1 -0
  21. data/lib/active_support/core_ext/hash/conversions.rb +14 -137
  22. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  23. data/lib/active_support/core_ext/kernel/reporting.rb +2 -1
  24. data/lib/active_support/core_ext/load_error.rb +1 -0
  25. data/lib/active_support/core_ext/logger.rb +1 -1
  26. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  27. data/lib/active_support/core_ext/object/to_param.rb +2 -2
  28. data/lib/active_support/core_ext/object/with_options.rb +2 -0
  29. data/lib/active_support/core_ext/string.rb +1 -0
  30. data/lib/active_support/core_ext/string/conversions.rb +35 -1
  31. data/lib/active_support/core_ext/string/encoding.rb +11 -0
  32. data/lib/active_support/core_ext/string/filters.rb +29 -0
  33. data/lib/active_support/core_ext/string/inflections.rb +0 -11
  34. data/lib/active_support/core_ext/string/interpolation.rb +1 -0
  35. data/lib/active_support/core_ext/string/multibyte.rb +16 -19
  36. data/lib/active_support/core_ext/time/calculations.rb +7 -6
  37. data/lib/active_support/core_ext/uri.rb +8 -3
  38. data/lib/active_support/dependencies.rb +33 -1
  39. data/lib/active_support/duration.rb +1 -0
  40. data/lib/active_support/hash_with_indifferent_access.rb +5 -1
  41. data/lib/active_support/i18n.rb +7 -2
  42. data/lib/active_support/inflector/transliterate.rb +58 -38
  43. data/lib/active_support/json/encoding.rb +28 -5
  44. data/lib/active_support/lazy_load_hooks.rb +14 -4
  45. data/lib/active_support/locale/en.yml +4 -1
  46. data/lib/active_support/message_verifier.rb +4 -4
  47. data/lib/active_support/multibyte.rb +1 -19
  48. data/lib/active_support/multibyte/chars.rb +143 -427
  49. data/lib/active_support/multibyte/unicode.rb +393 -0
  50. data/lib/active_support/notifications/fanout.rb +15 -5
  51. data/lib/active_support/notifications/instrumenter.rb +10 -4
  52. data/lib/active_support/railtie.rb +36 -0
  53. data/lib/active_support/rescuable.rb +1 -0
  54. data/lib/active_support/ruby/shim.rb +1 -0
  55. data/lib/active_support/testing/declarative.rb +1 -1
  56. data/lib/active_support/testing/isolation.rb +2 -1
  57. data/lib/active_support/testing/setup_and_teardown.rb +3 -0
  58. data/lib/active_support/values/time_zone.rb +20 -30
  59. data/lib/active_support/values/unicode_tables.dat +0 -0
  60. data/lib/active_support/version.rb +1 -1
  61. data/lib/active_support/xml_mini.rb +126 -1
  62. metadata +8 -61
  63. 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
- txt, line = <<-RUBY_EVAL, __LINE__ + 1
207
- def #{name}(halted)
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
- "def #{kind}(context, &block) filter(context, &block) end",
317
- __FILE__, __LINE__ - 1)
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
- body, line = <<-RUBY_EVAL, __LINE__ + 1
391
- def _run_#{symbol}_callbacks(key = nil, &blk)
392
- if self.class.send("_update_#{symbol}_superclass_callbacks")
393
- self.class.__define_runner(#{symbol.inspect})
394
- return _run_#{symbol}_callbacks(key, &blk)
395
- end
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
- if key
398
- name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
401
+ if key
402
+ name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
399
403
 
400
- unless respond_to?(name)
401
- self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
402
- end
404
+ unless respond_to?(name)
405
+ self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
406
+ end
403
407
 
404
- send(name, &blk)
405
- else
406
- #{body}
408
+ send(name, &blk)
409
+ else
410
+ #{body}
411
+ end
407
412
  end
408
- end
409
- private :_run_#{symbol}_callbacks
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 "active_support/concern"
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
- self.config = get_config unless @config
20
- @config
12
+ @config ||= ActiveSupport::InheritableOptions.new(superclass.respond_to?(:config) ? superclass.config : {})
21
13
  end
22
14
 
23
- def config=(hash)
24
- @config = ActiveSupport::OrderedOptions.new
25
- hash.each do |key, value|
26
- @config[key] = value
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/inflector'
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
- default_words_connector = I18n.translate(:'support.array.words_connector', :locale => options[:locale])
12
- default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale])
13
- default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale])
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
- raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml }
131
- require 'builder' unless defined?(Builder)
137
+ require 'active_support/builder' unless defined?(Builder)
132
138
 
133
139
  options = options.dup
134
- options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? ActiveSupport::Inflector.pluralize(ActiveSupport::Inflector.underscore(first.class.name)).tr('/', '_') : "records"
135
- options[:children] ||= options[:root].singularize
136
- options[:indent] ||= 2
137
- options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
138
-
139
- root = options.delete(:root).to_s
140
- children = options.delete(:children)
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].instruct! unless options.delete(:skip_instruct)
149
+ builder = options[:builder]
150
+ builder.instruct! unless options.delete(:skip_instruct)
147
151
 
148
- opts = options.merge({ :root => children })
152
+ root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
153
+ children = options.delete(:children) || root.singularize
149
154
 
150
- xml = options[:builder]
151
- if empty?
152
- xml.tag!(root, options[:skip_types] ? {} : {:type => "array"})
153
- else
154
- xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) {
155
- yield xml if block_given?
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
- # Returns a random element from the array.
3
- def rand
4
- self[Kernel.rand(length)]
5
- end
6
- end
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
@@ -61,10 +61,7 @@ class Class
61
61
  end
62
62
  RUBY
63
63
 
64
- if instance_writer
65
- body = "def #{name}=(value) @#{name} = value end"
66
- class_eval body, __FILE__, __LINE__ - 1
67
- end
64
+ attr_writer name if instance_writer
68
65
  end
69
66
  end
70
67
  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.today.yesterday
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.today.tomorrow
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
- # Short-hand for years_ago(1)
132
- def last_year
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 last_month
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 'date'
2
2
  require 'active_support/inflector'
3
+ require 'active_support/core_ext/time/calculations'
3
4
 
4
5
  class Date
5
6
  DATE_FORMATS = {
@@ -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 method_defined?(:to_date)
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 method_defined?(:to_datetime)
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 method_defined?(:xmlschema)
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 +1,2 @@
1
1
  require 'active_support/core_ext/file/atomic'
2
+ require 'active_support/core_ext/file/path'
@@ -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] ||= 2
134
- options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]),
135
- :root => "hash" })
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].__send__(:method_missing, root) do
140
- each do |key, value|
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
- key = rename_key(key.to_s, options)
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
- options[:builder].tag!(key,
172
- XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value,
173
- attributes
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 = XML_PARSING[value["type"]]
217
- if parser.arity == 2
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
- case value.length
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