# Slices an array or hash into pieces of a given size.
#
# This function takes two mandatory arguments: the first should be an array or hash, and the second specifies
# the number of elements to include in each slice.
#
# When the first argument is a hash, each key value pair is counted as one. For example, a slice size of 2 will produce
# an array of two arrays with key, and value.
#
# @example Slicing a Hash
#
# ```puppet
# $a.slice(2) |$entry| { notice "first ${$entry[0]}, second ${$entry[1]}" }
# $a.slice(2) |$first, $second| { notice "first ${first}, second ${second}" }
# ```
# The function produces a concatenated result of the slices.
#
# @example Slicing an Array
#
# ```puppet
# slice([1,2,3,4,5,6], 2) # produces [[1,2], [3,4], [5,6]]
# slice(Integer[1,6], 2) # produces [[1,2], [3,4], [5,6]]
# slice(4,2) # produces [[0,1], [2,3]]
# slice('hello',2) # produces [[h, e], [l, l], [o]]
# ```
#
# @example Passing a lambda to a slice (optional)
#
# ```puppet
# $a.slice($n) |$x| { ... }
# slice($a) |$x| { ... }
# ```
#
# The lambda should have either one parameter (receiving an array with the slice), or the same number
# of parameters as specified by the slice size (each parameter receiving its part of the slice).
# If there are fewer remaining elements than the slice size for the last slice, it will contain the remaining
# elements. If the lambda has multiple parameters, excess parameters are set to undef for an array, or
# to empty arrays for a hash.
#
# @example Getting individual values of a slice
#
# ```puppet
# $a.slice(2) |$first, $second| { ... }
# ```
#
# @since 4.0.0
#
Puppet::Functions.create_function(:slice) do
dispatch :slice_Hash do
param 'Hash[Any, Any]', :hash
param 'Integer[1, default]', :slice_size
optional_block_param
end
dispatch :slice_Enumerable do
param 'Iterable', :enumerable
param 'Integer[1, default]', :slice_size
optional_block_param
end
def slice_Hash(hash, slice_size, &pblock)
result = slice_Common(hash, slice_size, [], block_given? ? pblock : nil)
block_given? ? hash : result
end
def slice_Enumerable(enumerable, slice_size, &pblock)
enum = Puppet::Pops::Types::Iterable.asserted_iterable(self, enumerable)
result = slice_Common(enum, slice_size, nil, block_given? ? pblock : nil)
block_given? ? enumerable : result
end
def slice_Common(o, slice_size, filler, pblock)
serving_size = asserted_slice_serving_size(pblock, slice_size)
enumerator = o.each_slice(slice_size)
result = []
if serving_size == 1
begin
if pblock
loop do
pblock.call(enumerator.next)
end
else
loop do
result << enumerator.next
end
end
rescue StopIteration
end
else
begin
loop do
a = enumerator.next
if a.size < serving_size
a = a.dup.fill(filler, a.length...serving_size)
end
pblock.call(*a)
end
rescue StopIteration
end
end
if pblock
o
else
result
end
end
def asserted_slice_serving_size(pblock, slice_size)
if pblock
arity = pblock.arity
serving_size = arity < 0 ? slice_size : arity
else
serving_size = 1
end
if serving_size == 0
raise ArgumentError, _("slice(): block must define at least one parameter. Block has 0.")
end
unless serving_size == 1 || serving_size == slice_size
raise ArgumentError, _("slice(): block must define one parameter, or the same number of parameters as the given size of the slice (%{slice_size}). Block has %{serving_size}; %{parameter_names}") %
{ slice_size: slice_size, serving_size: serving_size, parameter_names: pblock.parameter_names.join(', ') }
end
serving_size
end
end
Copyright 2K16 - 2K18 Indonesian Hacker Rulez