提交 83fd1ae1 编写于 作者: J Jeremy Kemper

Convert array extension modules to class reopens

上级 d5e87e3b
require 'active_support/core_ext/util'
require 'active_support/core_ext/array/wrap' 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'
module ActiveSupport #:nodoc: class Array
module CoreExtensions #:nodoc: # Returns the tail of the array from +position+.
module Array #:nodoc: #
# Makes it easier to access parts of an array. # %w( a b c d ).from(0) # => %w( a b c d )
module Access # %w( a b c d ).from(2) # => %w( c d )
# Returns the tail of the array from +position+. # %w( a b c d ).from(10) # => nil
# # %w().from(0) # => nil
# %w( a b c d ).from(0) # => %w( a b c d ) def from(position)
# %w( a b c d ).from(2) # => %w( c d ) self[position..-1]
# %w( a b c d ).from(10) # => nil end
# %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
# Equal to <tt>self[1]</tt>. # Returns the beginning of the array up to +position+.
def second #
self[1] # %w( a b c d ).to(0) # => %w( a )
end # %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>. # Equal to <tt>self[1]</tt>.
def third def second
self[2] self[1]
end end
# Equal to <tt>self[3]</tt>. # Equal to <tt>self[2]</tt>.
def fourth def third
self[3] self[2]
end end
# Equal to <tt>self[4]</tt>. # Equal to <tt>self[3]</tt>.
def fifth def fourth
self[4] self[3]
end end
# Equal to <tt>self[4]</tt>.
def fifth
self[4]
end
# Equal to <tt>self[41]</tt>. Also known as accessing "the reddit". # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit".
def forty_two def forty_two
self[41] self[41]
end
end
end
end end
end end
module ActiveSupport #:nodoc: class Array
module CoreExtensions #:nodoc: # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
module Array #:nodoc: # * <tt>:words_connector</tt> - The sign or word used to join the elements in arrays with two or more elements (default: ", ")
module Conversions # * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ")
# Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options: # * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ")
# * <tt>:words_connector</tt> - The sign or word used to join the elements in arrays with two or more elements (default: ", ") def to_sentence(options = {})
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ") default_words_connector = I18n.translate(:'support.array.words_connector', :locale => options[:locale])
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ") default_two_words_connector = I18n.translate(:'support.array.two_words_connector', :locale => options[:locale])
def to_sentence(options = {}) default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale])
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 # Try to emulate to_senteces previous to 2.3
if options.has_key?(:connector) || options.has_key?(:skip_last_comma) 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(":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 ::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 skip_last_comma = options.delete :skip_last_comma
if connector = options.delete(:connector) if connector = options.delete(:connector)
options[:last_word_connector] ||= skip_last_comma ? connector : ", #{connector}" options[:last_word_connector] ||= skip_last_comma ? connector : ", #{connector}"
else else
options[:last_word_connector] ||= skip_last_comma ? default_two_words_connector : default_last_word_connector options[:last_word_connector] ||= skip_last_comma ? default_two_words_connector : default_last_word_connector
end end
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
# Calls <tt>to_param</tt> on all its elements and joins the result with options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
# slashes. This is used by <tt>url_for</tt> in Action Pack. options.reverse_merge! :words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector
def to_param
collect { |e| e.to_param }.join '/'
end
# Converts an array into a string suitable for use as a URL query string, case length
# using the given +key+ as the param name. when 0
# ""
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding" when 1
def to_query(key) self[0].to_s
prefix = "#{key}[]" when 2
collect { |value| value.to_query(prefix) }.join '&' "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
end 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 # Calls <tt>to_param</tt> on all its elements and joins the result with
# <tt>to_s</tt> on all elements and joining them: # slashes. This is used by <tt>url_for</tt> in Action Pack.
# def to_param
# Blog.find(:all).to_formatted_s # => "First PostSecond PostThird Post" collect { |e| e.to_param }.join '/'
# end
# 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
# Returns a string that represents this array in XML by sending +to_xml+ # Converts an array into a string suitable for use as a URL query string,
# to each element. Active Record collections delegate their representation # using the given +key+ as the param name.
# in XML to this method. #
# # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
# All elements are expected to respond to +to_xml+, if any of them does def to_query(key)
# not an exception is raised. prefix = "#{key}[]"
# collect { |value| value.to_query(prefix) }.join '&'
# The root node reflects the class name of the first element in plural end
# 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)
options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records" # Converts a collection of elements into a formatted string by calling
options[:children] ||= options[:root].singularize # <tt>to_s</tt> on all elements and joining them:
options[:indent] ||= 2 #
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) # 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 # Returns a string that represents this array in XML by sending +to_xml+
children = options.delete(:children) # 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] options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records"
root = root.dasherize options[:children] ||= options[:root].singularize
end 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] options[:builder].instruct! unless options.delete(:skip_instruct)
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 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 end
end end
module ActiveSupport #:nodoc: class Array
module CoreExtensions #:nodoc: # Extracts options from a set of arguments. Removes and returns the last
module Array #:nodoc: # element in the array if it's a hash, otherwise returns a blank hash.
module ExtractOptions #
# Extracts options from a set of arguments. Removes and returns the last # def options(*args)
# element in the array if it's a hash, otherwise returns a blank hash. # args.extract_options!
# # end
# def options(*args) #
# args.extract_options! # options(1, 2) # => {}
# end # options(1, 2, :a => :b) # => {:a=>:b}
# def extract_options!
# options(1, 2) # => {} last.is_a?(::Hash) ? pop : {}
# options(1, 2, :a => :b) # => {:a=>:b}
def extract_options!
last.is_a?(::Hash) ? pop : {}
end
end
end
end end
end end
require 'enumerator' require 'enumerator'
module ActiveSupport #:nodoc: class Array
module CoreExtensions #:nodoc: # Splits or iterates over the array in groups of size +number+,
module Array #:nodoc: # padding any remaining slots with +fill_with+ unless it is +false+.
module Grouping #
# Splits or iterates over the array in groups of size +number+, # %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
# padding any remaining slots with +fill_with+ unless it is +false+. # ["1", "2", "3"]
# # ["4", "5", "6"]
# %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group} # ["7", nil, nil]
# ["1", "2", "3"] #
# ["4", "5", "6"] # %w(1 2 3).in_groups_of(2, '&nbsp;') {|group| p group}
# ["7", nil, nil] # ["1", "2"]
# # ["3", "&nbsp;"]
# %w(1 2 3).in_groups_of(2, '&nbsp;') {|group| p group} #
# ["1", "2"] # %w(1 2 3).in_groups_of(2, false) {|group| p group}
# ["3", "&nbsp;"] # ["1", "2"]
# # ["3"]
# %w(1 2 3).in_groups_of(2, false) {|group| p group} def in_groups_of(number, fill_with = nil)
# ["1", "2"] if fill_with == false
# ["3"] collection = self
def in_groups_of(number, fill_with = nil) else
if fill_with == false # size % number gives how many extra we have;
collection = self # subtracting from number gives how many to add;
else # modulo number ensures we don't add group of just fill.
# size % number gives how many extra we have; padding = (number - size % number) % number
# subtracting from number gives how many to add; collection = dup.concat([fill_with] * padding)
# modulo number ensures we don't add group of just fill. end
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
# Splits or iterates over the array in +number+ of groups, padding any if block_given?
# remaining slots with +fill_with+ unless it is +false+. collection.each_slice(number) { |slice| yield(slice) }
# else
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group} groups = []
# ["1", "2", "3", "4"] collection.each_slice(number) { |group| groups << group }
# ["5", "6", "7", nil] groups
# ["8", "9", "10", nil] end
# end
# %w(1 2 3 4 5 6 7).in_groups(3, '&nbsp;') {|group| p group}
# ["1", "2", "3"]
# ["4", "5", "&nbsp;"]
# ["6", "7", "&nbsp;"]
#
# %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
# create a new array avoiding dup # Splits or iterates over the array in +number+ of groups, padding any
groups = [] # remaining slots with +fill_with+ unless it is +false+.
start = 0 #
# %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, '&nbsp;') {|group| p group}
# ["1", "2", "3"]
# ["4", "5", "&nbsp;"]
# ["6", "7", "&nbsp;"]
#
# %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| # create a new array avoiding dup
length = division + (modulo > 0 && modulo > index ? 1 : 0) groups = []
padding = fill_with != false && start = 0
modulo > 0 && length == division ? 1 : 0
groups << slice(start, length).concat([fill_with] * padding)
start += length
end
if block_given? number.times do |index|
groups.each{|g| yield(g) } length = division + (modulo > 0 && modulo > index ? 1 : 0)
else padding = fill_with != false &&
groups modulo > 0 && length == division ? 1 : 0
end groups << slice(start, length).concat([fill_with] * padding)
end start += length
end
# Divides the array into one or more subarrays based on a delimiting +value+ if block_given?
# or the result of an optional block. groups.each { |g| yield(g) }
# else
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]] groups
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]] end
def split(value = nil) end
using_block = block_given?
inject([[]]) do |results, element| # Divides the array into one or more subarrays based on a delimiting +value+
if (using_block && yield(element)) || (value == element) # or the result of an optional block.
results << [] #
else # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
results.last << element # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
end def split(value = nil)
using_block = block_given?
results inject([[]]) do |results, element|
end if (using_block && yield(element)) || (value == element)
end results << []
else
results.last << element
end end
results
end end
end end
end end
module ActiveSupport #:nodoc: class Array
module CoreExtensions #:nodoc: # Returns a random element from the array.
module Array #:nodoc: def rand
module RandomAccess self[Kernel.rand(length)]
# Returns a random element from the array.
def rand
self[Kernel.rand(length)]
end
end
end
end end
end end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册