Class: Array

Inherits:
Object show all
Defined in:
motion/core_ext/object/to_json.rb,
motion/_stdlib/array.rb,
motion/core_ext/array.rb,
motion/core_ext/array/wrap.rb,
motion/core_ext/array/access.rb,
motion/core_ext/object/blank.rb,
motion/core_ext/array/grouping.rb,
motion/core_ext/object/deep_dup.rb,
motion/core_ext/object/to_param.rb,
motion/core_ext/object/to_query.rb,
motion/core_ext/array/conversions.rb,
motion/core_ext/array/extract_options.rb,
motion/core_ext/array/prepend_and_append.rb

Overview

For more complex objects (Array/Hash): Convert an object into a “JSON-ready” representation composed of primitives like Hash, Array, String, Numeric, and true/false/nil. Recursively calls #as_json to the object to recursively build a fully JSON-ready object.

This allows developers to implement #as_json without having to worry about what base types of objects they are allowed to return or having to remember to call #as_json recursively.

Direct Known Subclasses

MotionSupport::Callbacks::CallbackChain

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.wrap(object) ⇒ Object

Wraps its argument in an array unless it is already an array (or array-like).

Specifically:

  • If the argument is nil an empty list is returned.

  • Otherwise, if the argument responds to to_ary it is invoked, and its result returned.

  • Otherwise, returns an array with the argument as its single element.

    Array.wrap(nil)       # => []
    Array.wrap([1, 2, 3]) # => [1, 2, 3]
    Array.wrap(0)         # => [0]
    

This method is similar in purpose to Kernel#Array, but there are some differences:

  • If the argument responds to to_ary the method is invoked. Kernel#Array moves on to try to_a if the returned value is nil, but Array.wrap returns such a nil right away.

  • If the returned value from to_ary is neither nil nor an Array object, Kernel#Array raises an exception, while Array.wrap does not, it just returns the value.

  • It does not call to_a on the argument, though special-cases nil to return an empty array.

The last point is particularly worth comparing for some enumerables:

Array(foo: :bar)      # => [[:foo, :bar]]
Array.wrap(foo: :bar) # => [{:foo=>:bar}]

There’s also a related idiom that uses the splat operator:

[*object]

which for nil returns [], and calls to Array(object) otherwise.

Thus, in this case the behavior may be different for nil, and the differences with Kernel#Array explained above apply to the rest of objects.



36
37
38
39
40
41
42
43
44
# File 'motion/core_ext/array/wrap.rb', line 36

def self.wrap(object)
  if object.nil?
    []
  elsif object.respond_to?(:to_ary)
    object.to_ary || [object]
  else
    [object]
  end
end

Instance Method Details

#as_jsonObject



125
126
127
# File 'motion/core_ext/object/to_json.rb', line 125

def as_json
  map { |v| (v.respond_to?(:as_json) ? v.as_json : v) }
end

#deep_dupObject

Returns a deep copy of array.

array = [1, [2, 3]]
dup   = array.deep_dup
dup[1][2] = 4

array[1][2] #=> nil
dup[1][2]   #=> 4


25
26
27
# File 'motion/core_ext/object/deep_dup.rb', line 25

def deep_dup
  map { |it| it.deep_dup }
end

#extract_options!Object

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.



4
5
6
7
8
9
10
# File 'motion/core_ext/array/extract_options.rb', line 4

def extract_options!
  if last.is_a?(Hash)
    pop
  else
    {}
  end
end

#from(position) ⇒ Object

Returns the tail of the array from position.

%w( a b c d ).from(0)  # => ["a", "b", "c", "d"]
%w( a b c d ).from(2)  # => ["c", "d"]
%w( a b c d ).from(10) # => []
%w().from(0)           # => []


8
9
10
# File 'motion/core_ext/array/access.rb', line 8

def from(position)
  self[position, length] || []
end

#has_hash_key?(key) ⇒ Boolean

If any item in the array has the key == ‘key` true, otherwise false. Of good use when writing specs.

Returns:

  • (Boolean)


4
5
6
7
8
9
# File 'motion/core_ext/array.rb', line 4

def has_hash_key?(key)
  self.each do |entity|
    return true if entity.has_key? key
  end
  return false
end

#has_hash_value?(key) ⇒ Boolean

If any item in the array has the value == ‘key` true, otherwise false Of good use when writing specs.

Returns:

  • (Boolean)


13
14
15
16
17
18
# File 'motion/core_ext/array.rb', line 13

def has_hash_value?(key)
  self.each do |entity|
    entity.each_pair{|hash_key, value| return true if value == key}
  end
  return false
end

#in_groups(number, fill_with = nil) ⇒ Object

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 8 9 10).in_groups(3, ' ') {|group| p group}
["1", "2", "3", "4"]
["5", "6", "7", " "]
["8", "9", "10", " "]

%w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
["1", "2", "3"]
["4", "5"]
["6", "7"]


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'motion/core_ext/array/grouping.rb', line 57

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

#in_groups_of(number, fill_with = nil) ⇒ Object

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 8 9 10).in_groups_of(3) {|group| p group}
["1", "2", "3"]
["4", "5", "6"]
["7", "8", "9"]
["10", nil, nil]

%w(1 2 3 4 5).in_groups_of(2, '&nbsp;') {|group| p group}
["1", "2"]
["3", "4"]
["5", "&nbsp;"]

%w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
["1", "2"]
["3", "4"]
["5"]


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'motion/core_ext/array/grouping.rb', line 20

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

#reverse_eachObject



2
3
4
5
6
7
8
9
10
11
12
# File 'motion/_stdlib/array.rb', line 2

def reverse_each
  return to_enum(:reverse_each) unless block_given?

  i = size - 1
  while i >= 0
    yield self[i]
    i -= 1
  end
  
  self
end

#secondObject

Equal to self[1].

%w( a b c d e ).second # => "b"


25
26
27
# File 'motion/core_ext/array/access.rb', line 25

def second
  self[1]
end

#split(value = nil, &block) ⇒ Object

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]]


88
89
90
91
92
93
94
95
96
97
98
# File 'motion/core_ext/array/grouping.rb', line 88

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

#to(position) ⇒ Object

Returns the beginning of the array up to position.

%w( a b c d ).to(0)  # => ["a"]
%w( a b c d ).to(2)  # => ["a", "b", "c"]
%w( a b c d ).to(10) # => ["a", "b", "c", "d"]
%w().to(0)           # => []


18
19
20
# File 'motion/core_ext/array/access.rb', line 18

def to(position)
  first position + 1
end

#to_formatted_s(format = :default) ⇒ Object Also known as: to_s

Converts a collection of elements into a formatted string by calling to_s on all elements and joining them. Having this model:

class Blog < ActiveRecord::Base
  def to_s
    title
  end
end

Blog.all.map(&:title) #=> ["First Post", "Second Post", "Third post"]

to_formatted_s shows us:

Blog.all.to_formatted_s # => "First PostSecond PostThird Post"

Adding in the :db argument as the format yields a comma separated id list:

Blog.all.to_formatted_s(:db) # => "1,2,3"


72
73
74
75
76
77
78
79
80
81
82
83
# File 'motion/core_ext/array/conversions.rb', line 72

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

#to_jsonObject

Calls as_json on all its elements and converts to a string.



130
131
132
# File 'motion/core_ext/object/to_json.rb', line 130

def to_json
  NSJSONSerialization.dataWithJSONObject(as_json, options: 0, error: nil).to_s
end

#to_paramObject

Calls to_param on all its elements and joins the result with slashes. This is used by url_for in Action Pack.



32
33
34
# File 'motion/core_ext/object/to_param.rb', line 32

def to_param
  collect { |e| e.to_param }.join '/'
end

#to_query(key) ⇒ Object

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"


16
17
18
19
# File 'motion/core_ext/object/to_query.rb', line 16

def to_query(key)
  prefix = "#{key}[]"
  collect { |value| value.to_query(prefix) }.join '&'
end

#to_sentence(options = {}) ⇒ Object

Converts the array to a comma-separated sentence where the last element is joined by the connector word.

You can pass the following options to change the default behavior. If you pass an option key that doesn’t exist in the list below, it will raise an ArgumentError.

Options:

  • :words_connector - The sign or word used to join the elements in arrays with two or more elements (default: “, ”).

  • :two_words_connector - The sign or word used to join the elements in arrays with two elements (default: “ and ”).

  • :last_word_connector - The sign or word used to join the last element in arrays with three or more elements (default: “, and ”).

    [].to_sentence # => “” [‘one’].to_sentence # => “one” [‘one’, ‘two’].to_sentence # => “one and two” [‘one’, ‘two’, ‘three’].to_sentence # => “one, two, and three”

    [‘one’, ‘two’].to_sentence(passing: ‘invalid option’) # => ArgumentError: Unknown key :passing

    [‘one’, ‘two’].to_sentence(two_words_connector: ‘-’) # => “one-two”

    [‘one’, ‘two’, ‘three’].to_sentence(words_connector: ‘ or ’, last_word_connector: ‘ or at least ’) # => “one or two or at least three”



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'motion/core_ext/array/conversions.rb', line 31

def to_sentence(options = {})
  options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector)

  default_connectors = {
    :words_connector     => ', ',
    :two_words_connector => ' and ',
    :last_word_connector => ', and '
  }
  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