diff options
Diffstat (limited to 'activesupport/lib')
6 files changed, 314 insertions, 348 deletions
diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb index 56e7b37715..b583c7533e 100644 --- a/activesupport/lib/active_support/core_ext/array.rb +++ b/activesupport/lib/active_support/core_ext/array.rb @@ -1,3 +1,6 @@ -require 'active_support/core_ext/util' require 'active_support/core_ext/array/wrap' -ActiveSupport.core_ext Array, %w(access conversions extract_options grouping random_access) +require 'active_support/core_ext/array/access' +require 'active_support/core_ext/array/conversions' +require 'active_support/core_ext/array/extract_options' +require 'active_support/core_ext/array/grouping' +require 'active_support/core_ext/array/random_access' diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index 6de338bfcc..d7606bb9b0 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -1,53 +1,46 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Array #:nodoc: - # Makes it easier to access parts of an array. - module Access - # Returns the tail of the array from +position+. - # - # %w( a b c d ).from(0) # => %w( a b c d ) - # %w( a b c d ).from(2) # => %w( c d ) - # %w( a b c d ).from(10) # => nil - # %w().from(0) # => nil - def from(position) - self[position..-1] - end - - # Returns the beginning of the array up to +position+. - # - # %w( a b c d ).to(0) # => %w( a ) - # %w( a b c d ).to(2) # => %w( a b c ) - # %w( a b c d ).to(10) # => %w( a b c d ) - # %w().to(0) # => %w() - def to(position) - self[0..position] - end +class Array + # Returns the tail of the array from +position+. + # + # %w( a b c d ).from(0) # => %w( a b c d ) + # %w( a b c d ).from(2) # => %w( c d ) + # %w( a b c d ).from(10) # => nil + # %w().from(0) # => nil + def from(position) + self[position..-1] + end - # Equal to <tt>self[1]</tt>. - def second - self[1] - end + # Returns the beginning of the array up to +position+. + # + # %w( a b c d ).to(0) # => %w( a ) + # %w( a b c d ).to(2) # => %w( a b c ) + # %w( a b c d ).to(10) # => %w( a b c d ) + # %w().to(0) # => %w() + def to(position) + self[0..position] + end - # Equal to <tt>self[2]</tt>. - def third - self[2] - end + # Equal to <tt>self[1]</tt>. + def second + self[1] + end - # Equal to <tt>self[3]</tt>. - def fourth - self[3] - end + # Equal to <tt>self[2]</tt>. + def third + self[2] + end - # Equal to <tt>self[4]</tt>. - def fifth - self[4] - end + # Equal to <tt>self[3]</tt>. + def fourth + self[3] + end + + # Equal to <tt>self[4]</tt>. + def fifth + self[4] + end - # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit". - def forty_two - self[41] - end - end - end + # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit". + def forty_two + self[41] end end diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index ba8e022fb2..81e466779e 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -1,196 +1,184 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Array #:nodoc: - module Conversions - # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options: - # * <tt>:words_connector</tt> - The sign or word used to join the elements in arrays with two or more elements (default: ", ") - # * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ") - # * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ") - def to_sentence(options = {}) - default_words_connector = I18n.translate(:'support.array.words_connector', :locale => options[:locale]) - default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale]) - default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale]) +class Array + # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options: + # * <tt>:words_connector</tt> - The sign or word used to join the elements in arrays with two or more elements (default: ", ") + # * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ") + # * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ") + def to_sentence(options = {}) + default_words_connector = I18n.translate(:'support.array.words_connector', :locale => options[:locale]) + default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale]) + default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale]) - # Try to emulate to_senteces previous to 2.3 - if options.has_key?(:connector) || options.has_key?(:skip_last_comma) - ::ActiveSupport::Deprecation.warn(":connector has been deprecated. Use :words_connector instead", caller) if options.has_key? :connector - ::ActiveSupport::Deprecation.warn(":skip_last_comma has been deprecated. Use :last_word_connector instead", caller) if options.has_key? :skip_last_comma + # Try to emulate to_senteces previous to 2.3 + if options.has_key?(:connector) || options.has_key?(:skip_last_comma) + ::ActiveSupport::Deprecation.warn(":connector has been deprecated. Use :words_connector instead", caller) if options.has_key? :connector + ::ActiveSupport::Deprecation.warn(":skip_last_comma has been deprecated. Use :last_word_connector instead", caller) if options.has_key? :skip_last_comma - skip_last_comma = options.delete :skip_last_comma - if connector = options.delete(:connector) - options[:last_word_connector] ||= skip_last_comma ? connector : ", #{connector}" - else - options[:last_word_connector] ||= skip_last_comma ? default_two_words_connector : default_last_word_connector - end - end - - options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) - options.reverse_merge! :words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector - - case length - when 0 - "" - when 1 - self[0].to_s - when 2 - "#{self[0]}#{options[:two_words_connector]}#{self[1]}" - else - "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}" - end - end - + skip_last_comma = options.delete :skip_last_comma + if connector = options.delete(:connector) + options[:last_word_connector] ||= skip_last_comma ? connector : ", #{connector}" + else + options[:last_word_connector] ||= skip_last_comma ? default_two_words_connector : default_last_word_connector + end + end - # Calls <tt>to_param</tt> on all its elements and joins the result with - # slashes. This is used by <tt>url_for</tt> in Action Pack. - def to_param - collect { |e| e.to_param }.join '/' - end + options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) + options.reverse_merge! :words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector - # Converts an array into a string suitable for use as a URL query string, - # using the given +key+ as the param name. - # - # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding" - def to_query(key) - prefix = "#{key}[]" - collect { |value| value.to_query(prefix) }.join '&' - end + case length + when 0 + "" + when 1 + self[0].to_s + when 2 + "#{self[0]}#{options[:two_words_connector]}#{self[1]}" + else + "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}" + end + end - def self.included(base) #:nodoc: - base.class_eval do - alias_method :to_default_s, :to_s - alias_method :to_s, :to_formatted_s - end - end - # Converts a collection of elements into a formatted string by calling - # <tt>to_s</tt> on all elements and joining them: - # - # Blog.find(:all).to_formatted_s # => "First PostSecond PostThird Post" - # - # Adding in the <tt>:db</tt> argument as the format yields a prettier - # output: - # - # Blog.find(:all).to_formatted_s(:db) # => "First Post,Second Post,Third Post" - def to_formatted_s(format = :default) - case format - when :db - if respond_to?(:empty?) && self.empty? - "null" - else - collect { |element| element.id }.join(",") - end - else - to_default_s - end - end + # Calls <tt>to_param</tt> on all its elements and joins the result with + # slashes. This is used by <tt>url_for</tt> in Action Pack. + def to_param + collect { |e| e.to_param }.join '/' + end - # Returns a string that represents this array in XML by sending +to_xml+ - # to each element. Active Record collections delegate their representation - # in XML to this method. - # - # All elements are expected to respond to +to_xml+, if any of them does - # not an exception is raised. - # - # The root node reflects the class name of the first element in plural - # if all elements belong to the same type and that's not Hash: - # - # customer.projects.to_xml - # - # <?xml version="1.0" encoding="UTF-8"?> - # <projects type="array"> - # <project> - # <amount type="decimal">20000.0</amount> - # <customer-id type="integer">1567</customer-id> - # <deal-date type="date">2008-04-09</deal-date> - # ... - # </project> - # <project> - # <amount type="decimal">57230.0</amount> - # <customer-id type="integer">1567</customer-id> - # <deal-date type="date">2008-04-15</deal-date> - # ... - # </project> - # </projects> - # - # Otherwise the root element is "records": - # - # [{:foo => 1, :bar => 2}, {:baz => 3}].to_xml - # - # <?xml version="1.0" encoding="UTF-8"?> - # <records type="array"> - # <record> - # <bar type="integer">2</bar> - # <foo type="integer">1</foo> - # </record> - # <record> - # <baz type="integer">3</baz> - # </record> - # </records> - # - # If the collection is empty the root element is "nil-classes" by default: - # - # [].to_xml - # - # <?xml version="1.0" encoding="UTF-8"?> - # <nil-classes type="array"/> - # - # To ensure a meaningful root element use the <tt>:root</tt> option: - # - # customer_with_no_projects.projects.to_xml(:root => "projects") - # - # <?xml version="1.0" encoding="UTF-8"?> - # <projects type="array"/> - # - # By default root children have as node name the one of the root - # singularized. You can change it with the <tt>:children</tt> option. - # - # The +options+ hash is passed downwards: - # - # Message.all.to_xml(:skip_types => true) - # - # <?xml version="1.0" encoding="UTF-8"?> - # <messages> - # <message> - # <created-at>2008-03-07T09:58:18+01:00</created-at> - # <id>1</id> - # <name>1</name> - # <updated-at>2008-03-07T09:58:18+01:00</updated-at> - # <user-id>1</user-id> - # </message> - # </messages> - # - def to_xml(options = {}) - raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml } - require 'builder' unless defined?(Builder) + # Converts an array into a string suitable for use as a URL query string, + # using the given +key+ as the param name. + # + # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding" + def to_query(key) + prefix = "#{key}[]" + collect { |value| value.to_query(prefix) }.join '&' + end - options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records" - options[:children] ||= options[:root].singularize - options[:indent] ||= 2 - options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) + # Converts a collection of elements into a formatted string by calling + # <tt>to_s</tt> on all elements and joining them: + # + # Blog.find(:all).to_formatted_s # => "First PostSecond PostThird Post" + # + # Adding in the <tt>:db</tt> argument as the format yields a prettier + # output: + # + # Blog.find(:all).to_formatted_s(:db) # => "First Post,Second Post,Third Post" + def to_formatted_s(format = :default) + case format + when :db + if respond_to?(:empty?) && self.empty? + "null" + else + collect { |element| element.id }.join(",") + end + else + to_default_s + end + end + alias_method :to_default_s, :to_s + alias_method :to_s, :to_formatted_s - root = options.delete(:root).to_s - children = options.delete(:children) + # Returns a string that represents this array in XML by sending +to_xml+ + # to each element. Active Record collections delegate their representation + # in XML to this method. + # + # All elements are expected to respond to +to_xml+, if any of them does + # not an exception is raised. + # + # The root node reflects the class name of the first element in plural + # if all elements belong to the same type and that's not Hash: + # + # customer.projects.to_xml + # + # <?xml version="1.0" encoding="UTF-8"?> + # <projects type="array"> + # <project> + # <amount type="decimal">20000.0</amount> + # <customer-id type="integer">1567</customer-id> + # <deal-date type="date">2008-04-09</deal-date> + # ... + # </project> + # <project> + # <amount type="decimal">57230.0</amount> + # <customer-id type="integer">1567</customer-id> + # <deal-date type="date">2008-04-15</deal-date> + # ... + # </project> + # </projects> + # + # Otherwise the root element is "records": + # + # [{:foo => 1, :bar => 2}, {:baz => 3}].to_xml + # + # <?xml version="1.0" encoding="UTF-8"?> + # <records type="array"> + # <record> + # <bar type="integer">2</bar> + # <foo type="integer">1</foo> + # </record> + # <record> + # <baz type="integer">3</baz> + # </record> + # </records> + # + # If the collection is empty the root element is "nil-classes" by default: + # + # [].to_xml + # + # <?xml version="1.0" encoding="UTF-8"?> + # <nil-classes type="array"/> + # + # To ensure a meaningful root element use the <tt>:root</tt> option: + # + # customer_with_no_projects.projects.to_xml(:root => "projects") + # + # <?xml version="1.0" encoding="UTF-8"?> + # <projects type="array"/> + # + # By default root children have as node name the one of the root + # singularized. You can change it with the <tt>:children</tt> option. + # + # The +options+ hash is passed downwards: + # + # Message.all.to_xml(:skip_types => true) + # + # <?xml version="1.0" encoding="UTF-8"?> + # <messages> + # <message> + # <created-at>2008-03-07T09:58:18+01:00</created-at> + # <id>1</id> + # <name>1</name> + # <updated-at>2008-03-07T09:58:18+01:00</updated-at> + # <user-id>1</user-id> + # </message> + # </messages> + # + def to_xml(options = {}) + raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml } + require 'builder' unless defined?(Builder) - if !options.has_key?(:dasherize) || options[:dasherize] - root = root.dasherize - end + options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records" + options[:children] ||= options[:root].singularize + options[:indent] ||= 2 + options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) - options[:builder].instruct! unless options.delete(:skip_instruct) + root = options.delete(:root).to_s + children = options.delete(:children) - opts = options.merge({ :root => children }) + if !options.has_key?(:dasherize) || options[:dasherize] + root = root.dasherize + end - xml = options[:builder] - if empty? - xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) - else - xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) { - yield xml if block_given? - each { |e| e.to_xml(opts.merge({ :skip_instruct => true })) } - } - end - end + options[:builder].instruct! unless options.delete(:skip_instruct) - end + opts = options.merge({ :root => children }) + + xml = options[:builder] + if empty? + xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) + else + xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) { + yield xml if block_given? + each { |e| e.to_xml(opts.merge({ :skip_instruct => true })) } + } end end end diff --git a/activesupport/lib/active_support/core_ext/array/extract_options.rb b/activesupport/lib/active_support/core_ext/array/extract_options.rb index eb917576d7..9ca32dc7aa 100644 --- a/activesupport/lib/active_support/core_ext/array/extract_options.rb +++ b/activesupport/lib/active_support/core_ext/array/extract_options.rb @@ -1,20 +1,14 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Array #:nodoc: - module ExtractOptions - # Extracts options from a set of arguments. Removes and returns the last - # element in the array if it's a hash, otherwise returns a blank hash. - # - # def options(*args) - # args.extract_options! - # end - # - # options(1, 2) # => {} - # options(1, 2, :a => :b) # => {:a=>:b} - def extract_options! - last.is_a?(::Hash) ? pop : {} - end - end - end +class Array + # Extracts options from a set of arguments. Removes and returns the last + # element in the array if it's a hash, otherwise returns a blank hash. + # + # def options(*args) + # args.extract_options! + # end + # + # options(1, 2) # => {} + # options(1, 2, :a => :b) # => {:a=>:b} + def extract_options! + last.is_a?(::Hash) ? pop : {} end end diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index f782f8facf..ef416787a9 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -1,106 +1,100 @@ require 'enumerator' -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Array #:nodoc: - module Grouping - # Splits or iterates over the array in groups of size +number+, - # padding any remaining slots with +fill_with+ unless it is +false+. - # - # %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group} - # ["1", "2", "3"] - # ["4", "5", "6"] - # ["7", nil, nil] - # - # %w(1 2 3).in_groups_of(2, ' ') {|group| p group} - # ["1", "2"] - # ["3", " "] - # - # %w(1 2 3).in_groups_of(2, false) {|group| p group} - # ["1", "2"] - # ["3"] - def in_groups_of(number, fill_with = nil) - if fill_with == false - collection = self - else - # size % number gives how many extra we have; - # subtracting from number gives how many to add; - # modulo number ensures we don't add group of just fill. - padding = (number - size % number) % number - collection = dup.concat([fill_with] * padding) - end - - if block_given? - collection.each_slice(number) { |slice| yield(slice) } - else - returning [] do |groups| - collection.each_slice(number) { |group| groups << group } - end - end - end +class Array + # Splits or iterates over the array in groups of size +number+, + # padding any remaining slots with +fill_with+ unless it is +false+. + # + # %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group} + # ["1", "2", "3"] + # ["4", "5", "6"] + # ["7", nil, nil] + # + # %w(1 2 3).in_groups_of(2, ' ') {|group| p group} + # ["1", "2"] + # ["3", " "] + # + # %w(1 2 3).in_groups_of(2, false) {|group| p group} + # ["1", "2"] + # ["3"] + def in_groups_of(number, fill_with = nil) + if fill_with == false + collection = self + else + # size % number gives how many extra we have; + # subtracting from number gives how many to add; + # modulo number ensures we don't add group of just fill. + padding = (number - size % number) % number + collection = dup.concat([fill_with] * padding) + end - # Splits or iterates over the array in +number+ of groups, padding any - # remaining slots with +fill_with+ unless it is +false+. - # - # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group} - # ["1", "2", "3", "4"] - # ["5", "6", "7", nil] - # ["8", "9", "10", nil] - # - # %w(1 2 3 4 5 6 7).in_groups(3, ' ') {|group| p group} - # ["1", "2", "3"] - # ["4", "5", " "] - # ["6", "7", " "] - # - # %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group} - # ["1", "2", "3"] - # ["4", "5"] - # ["6", "7"] - def in_groups(number, fill_with = nil) - # size / number gives minor group size; - # size % number gives how many objects need extra accomodation; - # each group hold either division or division + 1 items. - division = size / number - modulo = size % number + if block_given? + collection.each_slice(number) { |slice| yield(slice) } + else + groups = [] + collection.each_slice(number) { |group| groups << group } + groups + end + end - # create a new array avoiding dup - groups = [] - start = 0 + # Splits or iterates over the array in +number+ of groups, padding any + # remaining slots with +fill_with+ unless it is +false+. + # + # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group} + # ["1", "2", "3", "4"] + # ["5", "6", "7", nil] + # ["8", "9", "10", nil] + # + # %w(1 2 3 4 5 6 7).in_groups(3, ' ') {|group| p group} + # ["1", "2", "3"] + # ["4", "5", " "] + # ["6", "7", " "] + # + # %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group} + # ["1", "2", "3"] + # ["4", "5"] + # ["6", "7"] + def in_groups(number, fill_with = nil) + # size / number gives minor group size; + # size % number gives how many objects need extra accomodation; + # each group hold either division or division + 1 items. + division = size / number + modulo = size % number - number.times do |index| - length = division + (modulo > 0 && modulo > index ? 1 : 0) - padding = fill_with != false && - modulo > 0 && length == division ? 1 : 0 - groups << slice(start, length).concat([fill_with] * padding) - start += length - end + # create a new array avoiding dup + groups = [] + start = 0 - if block_given? - groups.each{|g| yield(g) } - else - groups - end - end + number.times do |index| + length = division + (modulo > 0 && modulo > index ? 1 : 0) + padding = fill_with != false && + modulo > 0 && length == division ? 1 : 0 + groups << slice(start, length).concat([fill_with] * padding) + start += length + end - # Divides the array into one or more subarrays based on a delimiting +value+ - # or the result of an optional block. - # - # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]] - # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]] - def split(value = nil) - using_block = block_given? + if block_given? + groups.each { |g| yield(g) } + else + groups + end + end - inject([[]]) do |results, element| - if (using_block && yield(element)) || (value == element) - results << [] - else - results.last << element - end + # Divides the array into one or more subarrays based on a delimiting +value+ + # or the result of an optional block. + # + # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]] + # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]] + def split(value = nil) + using_block = block_given? - results - end - end + inject([[]]) do |results, element| + if (using_block && yield(element)) || (value == element) + results << [] + else + results.last << element end + + results end end end diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb index 54d17cbf30..343003f6f7 100644 --- a/activesupport/lib/active_support/core_ext/array/random_access.rb +++ b/activesupport/lib/active_support/core_ext/array/random_access.rb @@ -1,12 +1,6 @@ -module ActiveSupport #:nodoc: - module CoreExtensions #:nodoc: - module Array #:nodoc: - module RandomAccess - # Returns a random element from the array. - def rand - self[Kernel.rand(length)] - end - end - end +class Array + # Returns a random element from the array. + def rand + self[Kernel.rand(length)] end end |