diff options
Diffstat (limited to 'activesupport/lib/active_support/core_ext')
6 files changed, 113 insertions, 76 deletions
diff --git a/activesupport/lib/active_support/core_ext/array/wrap.rb b/activesupport/lib/active_support/core_ext/array/wrap.rb index 05b09a4c7f..1245768870 100644 --- a/activesupport/lib/active_support/core_ext/array/wrap.rb +++ b/activesupport/lib/active_support/core_ext/array/wrap.rb @@ -29,8 +29,7 @@ class Array # # [*object] # - # which for +nil+ returns <tt>[nil]</tt> (Ruby 1.8.7) or <tt>[]</tt> (Ruby - # 1.9), and calls to <tt>Array(object)</tt> otherwise. + # which for +nil+ returns <tt>[]</tt>, and calls to <tt>Array(object)</tt> otherwise. # # Thus, in this case the behavior may be different for +nil+, and the differences with # <tt>Kernel#Array</tt> explained above apply to the rest of <tt>object</tt>s. diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb index 1504e18839..5d8d09aa69 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -69,7 +69,8 @@ class Class # To opt out of both instance methods, pass <tt>instance_accessor: false</tt>. def class_attribute(*attrs) options = attrs.extract_options! - instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true) + # double assignment is used to avoid "assigned but unused variable" warning + instance_reader = instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true) instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true) # We use class_eval here rather than define_method because class_attribute diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index e1ce9f371a..6cb7434e5f 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -102,55 +102,41 @@ class Hash # hash = Hash.from_xml(xml) # # => {"hash"=>{"foo"=>1, "bar"=>2}} def from_xml(xml) - typecast_xml_value(unrename_keys(ActiveSupport::XmlMini.parse(xml))) + ActiveSupport::XMLConverter.new(xml).to_h + end + + end +end + +module ActiveSupport + class XMLConverter # :nodoc: + def initialize(xml) + @xml = normalize_keys(XmlMini.parse(xml)) + end + + def to_h + deep_to_h(@xml) end private - def typecast_xml_value(value) - case value + + def normalize_keys(params) + case params when Hash - if value['type'] == 'array' - _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) }) - if entries.nil? || (c = value['__content__'] && c.blank?) - [] - else - case entries # something weird with classes not matching here. maybe singleton methods breaking is_a? - when Array - entries.collect { |v| typecast_xml_value(v) } - when Hash - [typecast_xml_value(entries)] - else - raise "can't typecast #{entries.inspect}" - end - end - elsif value['type'] == 'file' || - (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?)) - content = value['__content__'] - if parser = ActiveSupport::XmlMini::PARSING[value['type']] - parser.arity == 1 ? parser.call(content) : parser.call(content, value) - else - content - end - elsif value['type'] == 'string' && value['nil'] != 'true' - '' - # blank or nil parsed values are represented by nil - elsif value.blank? || value['nil'] == 'true' - nil - # If the type is the only element which makes it then - # this still makes the value nil, except if type is - # a XML node(where type['value'] is a Hash) - elsif value['type'] && value.size == 1 && !value['type'].is_a?(::Hash) - nil - else - xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }] + Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ] + when Array + params.map { |v| normalize_keys(v) } + else + params + end + end - # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with - # how multipart uploaded files from HTML appear - xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value - end + def deep_to_h(value) + case value + when Hash + process_hash(value) when Array - value.map! { |i| typecast_xml_value(i) } - value.length > 1 ? value : value.first + process_array(value) when String value else @@ -158,15 +144,79 @@ class Hash end end - def unrename_keys(params) - case params - when Hash - Hash[params.map { |k,v| [k.to_s.tr('-', '_'), unrename_keys(v)] } ] - when Array - params.map { |v| unrename_keys(v) } + def process_hash(value) + if become_array?(value) + _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) }) + if entries.nil? || value['__content__'].try(:empty?) + [] else - params + case entries + when Array + entries.collect { |v| deep_to_h(v) } + when Hash + [deep_to_h(entries)] + else + raise "can't typecast #{entries.inspect}" + end + end + elsif become_content?(value) + process_content(value) + + elsif become_empty_string?(value) + '' + elsif become_hash?(value) + xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }] + + # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with + # how multipart uploaded files from HTML appear + xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value end end + + def become_content?(value) + value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?)) + end + + def become_array?(value) + value['type'] == 'array' + end + + def become_empty_string?(value) + # {"string" => true} + # No tests fail when the second term is removed. + value['type'] == 'string' && value['nil'] != 'true' + end + + def become_hash?(value) + !nothing?(value) && !garbage?(value) + end + + def nothing?(value) + # blank or nil parsed values are represented by nil + value.blank? || value['nil'] == 'true' + end + + def garbage?(value) + # If the type is the only element which makes it then + # this still makes the value nil, except if type is + # a XML node(where type['value'] is a Hash) + value['type'] && !value['type'].is_a?(::Hash) && value.size == 1 + end + + def process_content(value) + content = value['__content__'] + if parser = ActiveSupport::XmlMini::PARSING[value['type']] + parser.arity == 1 ? parser.call(content) : parser.call(content, value) + else + content + end + end + + def process_array(value) + value.map! { |i| deep_to_h(i) } + value.length > 1 ? value : value.first + end + end end + diff --git a/activesupport/lib/active_support/core_ext/logger.rb b/activesupport/lib/active_support/core_ext/logger.rb index 16fce81445..34de766331 100644 --- a/activesupport/lib/active_support/core_ext/logger.rb +++ b/activesupport/lib/active_support/core_ext/logger.rb @@ -1,5 +1,6 @@ require 'active_support/core_ext/class/attribute_accessors' require 'active_support/deprecation' +require 'active_support/logger_silence' ActiveSupport::Deprecation.warn 'this file is deprecated and will be removed' @@ -31,27 +32,9 @@ require 'logger' # # logger.datetime_format = "%Y-%m-%d" # -# Note: This logger is deprecated in favor of ActiveSupport::BufferedLogger +# Note: This logger is deprecated in favor of ActiveSupport::Logger class Logger - ## - # :singleton-method: - # Set to false to disable the silencer - cattr_accessor :silencer - self.silencer = true - - # Silences the logger for the duration of the block. - def silence(temporary_level = Logger::ERROR) - if silencer - begin - old_logger_level, self.level = level, temporary_level - yield self - ensure - self.level = old_logger_level - end - else - yield self - end - end + include LoggerSilence alias :old_datetime_format= :datetime_format= # Logging date-time format (string passed to +strftime+). Ignored if the formatter diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 341e2deec9..6522145572 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -193,8 +193,8 @@ class String # Capitalizes the first word, turns underscores into spaces, and strips '_id'. # Like +titleize+, this is meant for creating pretty output. # - # 'employee_salary' # => "Employee salary" - # 'author_id' # => "Author" + # 'employee_salary'.humanize # => "Employee salary" + # 'author_id'.humanize # => "Author" def humanize ActiveSupport::Inflector.humanize(self) end diff --git a/activesupport/lib/active_support/core_ext/thread.rb b/activesupport/lib/active_support/core_ext/thread.rb index 6ad0b2d69c..5481766f10 100644 --- a/activesupport/lib/active_support/core_ext/thread.rb +++ b/activesupport/lib/active_support/core_ext/thread.rb @@ -65,6 +65,10 @@ class Thread private def locals - @locals || LOCK.synchronize { @locals ||= {} } + if defined?(@locals) + @locals + else + LOCK.synchronize { @locals ||= {} } + end end end unless Thread.instance_methods.include?(:thread_variable_set) |