class Array
def self.wrap(object)
The differences with Kernel#Array explained above
which returns [] for +nil+, but calls to Array(object) otherwise.
[*object]
There's also a related idiom that uses the splat operator:
Array.wrap(foo: :bar) # => [{:foo=>:bar}]
Array(foo: :bar) # => [[:foo, :bar]]
The second point is easily explained with some enumerables:
* It does not call +to_a+ on the argument, but returns an empty array if argument is +nil+.
raises an exception, while Array.wrap does not, it just returns the value.
* If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, Kernel#Array
+nil+ right away.
moves on to try +to_a+ if the returned value is +nil+, but Array.wrap returns
* If the argument responds to +to_ary+ the method is invoked. Kernel#Array
This method is similar in purpose to Kernel#Array, but there are some differences:
Array.wrap(0) # => [0]
Array.wrap([1, 2, 3]) # => [1, 2, 3]
Array.wrap(nil) # => []
* Otherwise, returns an array with the argument as its single element.
* Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
* If the argument is +nil+ an empty list is returned.
Specifically:
Wraps its argument in an array unless it is already an array (or array-like).
def self.wrap(object) if object.nil? [] elsif object.respond_to?(:to_ary) object.to_ary || [object] else [object] end end
def as_json(options = nil) #:nodoc:
def as_json(options = nil) #:nodoc: # use encoder as a proxy to call as_json on all elements, to protect from circular references encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options) map { |v| encoder.as_json(v, options) } end
def deep_dup
array[1][2] #=> nil
dup[1][2] = 4
dup = array.deep_dup
array = [1, [2, 3]]
Returns a deep copy of array.
def deep_dup map { |it| it.deep_dup } end
def encode_json(encoder) #:nodoc:
def encode_json(encoder) #:nodoc: # we assume here that the encoder has already run as_json on self and the elements, so we run encode_json directly "[#{map { |v| v.encode_json(encoder) } * ','}]" end
def extract_options!
options(1, 2) # => {}
end
args.extract_options!
def options(*args)
element in the array if it's a hash, otherwise returns a blank hash.
Extracts options from a set of arguments. Removes and returns the last
def extract_options! if last.is_a?(Hash) && last.extractable_options? pop else {} end end
def fifth
Equal to self[4].
def fifth self[4] end
def forty_two
def forty_two self[41] end
def fourth
Equal to self[3].
def fourth self[3] end
def from(position)
%w( a b c d ).from(10) # => []
%w( a b c d ).from(2) # => ["c", "d"]
%w( a b c d ).from(0) # => ["a", "b", "c", "d"]
Returns the tail of the array from +position+.
def from(position) self[position, length] || [] end
def in_groups(number, fill_with = nil)
["4", "5"]
["1", "2", "3"]
%w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
["8", "9", "10", " "]
["5", "6", "7", " "]
["1", "2", "3", "4"]
%w(1 2 3 4 5 6 7 8 9 10).in_groups(3, ' ') {|group| p group}
["8", "9", "10", nil]
["5", "6", "7", nil]
["1", "2", "3", "4"]
%w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
remaining slots with +fill_with+ unless it is +false+.
Splits or iterates over the array in +number+ of groups, padding any
def in_groups(number, fill_with = nil) # size / number gives minor group size; # size % number gives how many objects need extra accommodation; # each group hold either division or division + 1 items. division = size.div number modulo = size % number # create a new array avoiding dup groups = [] start = 0 number.times do |index| length = division + (modulo > 0 && modulo > index ? 1 : 0) groups << last_group = slice(start, length) last_group << fill_with if fill_with != false && modulo > 0 && length == division start += length end if block_given? groups.each { |g| yield(g) } else groups end end
def in_groups_of(number, fill_with = nil)
["3", "4"]
["1", "2"]
%w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
["5", " "]
["3", "4"]
["1", "2"]
%w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group}
["10", nil, nil]
["7", "8", "9"]
["4", "5", "6"]
["1", "2", "3"]
%w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
padding any remaining slots with +fill_with+ unless it is +false+.
Splits or iterates over the array in groups of size +number+,
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 groups = [] collection.each_slice(number) { |group| groups << group } groups end end
def second
Equal to self[1].
def second self[1] end
def split(value = nil, &block)
[1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
or the result of an optional block.
Divides the array into one or more subarrays based on a delimiting +value+
def split(value = nil, &block) inject([[]]) do |results, element| if block && block.call(element) || value == element results << [] else results.last << element end results end end
def third
Equal to self[2].
def third self[2] end
def to(position)
%w( a b c d ).to(10) # => ["a", "b", "c", "d"]
%w( a b c d ).to(2) # => ["a", "b", "c"]
%w( a b c d ).to(0) # => ["a"]
Returns the beginning of the array up to +position+.
def to(position) first position + 1 end
def to_formatted_s(format = :default)
id list:
Adding in the :db argument as the format yields a comma separated
Blog.all.to_formatted_s # => "First PostSecond PostThird Post"
to_formatted_s shows us:
Blog.all.map(&:title) #=> ["First Post", "Second Post", "Third post"]
end
end
title
def to_s
class Blog < ActiveRecord::Base
to_s on all elements and joining them. Having this model:
Converts a collection of elements into a formatted string by calling
def to_formatted_s(format = :default) case format when :db if empty? 'null' else collect { |element| element.id }.join(',') end else to_default_s end end
def to_param
Calls to_param on all its elements and joins the result with
def to_param collect { |e| e.to_param }.join '/' end
def to_query(key)
using the given +key+ as the param name.
Converts an array into a string suitable for use as a URL query string,
def to_query(key) prefix = "#{key}[]" collect { |value| value.to_query(prefix) }.join '&' end
def to_sentence(options = {})
['uno', 'dos', 'tres'].to_sentence(locale: :es)
# => "uno y dos"
['uno', 'dos'].to_sentence(locale: :es)
# last_word_connector: " o al menos "
# two_words_connector: " y "
# words_connector: " o "
# array:
# support:
# es:
#
# Given this locale dictionary:
Using :locale option:
# => "one or two or at least three"
['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
# => "one-two"
['one', 'two'].to_sentence(two_words_connector: '-')
# => ArgumentError: Unknown key :passing
['one', 'two'].to_sentence(passing: 'invalid option')
['one', 'two', 'three'].to_sentence # => "one, two, and three"
['one', 'two'].to_sentence # => "one and two"
['one'].to_sentence # => "one"
[].to_sentence # => ""
==== Examples
corresponding dictionary file.
the connector options defined on the 'support.array' namespace in the
* :locale - If +i18n+ is available, you can set a locale and use
in arrays with three or more elements (default: ", and ").
* :last_word_connector - The sign or word used to join the last element
in arrays with two elements (default: " and ").
* :two_words_connector - The sign or word used to join the elements
in arrays with two or more elements (default: ", ").
* :words_connector - The sign or word used to join the elements
==== Options
ArgumentError.
pass an option key that doesn't exist in the list below, it will raise an
You can pass the following options to change the default behavior. If you
joined by the connector word.
Converts the array to a comma-separated sentence where the last element is
def to_sentence(options = {}) options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) default_connectors = { :words_connector => ', ', :two_words_connector => ' and ', :last_word_connector => ', and ' } if defined?(I18n) i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {}) default_connectors.merge!(i18n_connectors) end options = default_connectors.merge!(options) case length when 0 '' when 1 self[0].to_s.dup 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 to_xml(options = {})
Message.all.to_xml(skip_types: true)
The +options+ hash is passed downwards:
You can change it with the :children option.
By default name of the node for the children of root is root.singularize.
customer_with_no_projects.projects.to_xml(root: 'projects')
To ensure a meaningful root element use the :root option:
[].to_xml
If the collection is empty the root element is "nil-classes" by default:
def to_xml(options = {}) require 'active_support/builder' unless defined?(Builder) options = options.dup options[:indent] ||= 2 options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent]) options[:root] ||= \ if first.class != Hash && all? { |e| e.is_a?(first.class) } underscored = ActiveSupport::Inflector.underscore(first.class.name) ActiveSupport::Inflector.pluralize(underscored).tr('/', '_') else 'objects' end builder = options[:builder] builder.instruct! unless options.delete(:skip_instruct) root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options) children = options.delete(:children) || root.singularize attributes = options[:skip_types] ? {} : { type: 'array' } if empty? builder.tag!(root, attributes) else builder.tag!(root, attributes) do each { |value| ActiveSupport::XmlMini.to_tag(children, value, options) } yield builder if block_given? end end end
def uniq_by(&block)
Returns a unique array based on the criteria in the block.
*DEPRECATED*: Use Array#uniq instead.
def uniq_by(&block) ActiveSupport::Deprecation.warn 'uniq_by is deprecated. Use Array#uniq instead' uniq(&block) end
def uniq_by!(&block)
*DEPRECATED*: Use Array#uniq! instead.
def uniq_by!(&block) ActiveSupport::Deprecation.warn 'uniq_by! is deprecated. Use Array#uniq! instead' uniq!(&block) end