Skip to content

Instantly share code, notes, and snippets.

@kwilczynski
Last active August 29, 2015 14:06
Show Gist options
  • Select an option

  • Save kwilczynski/e350623ffbaafd4e88fa to your computer and use it in GitHub Desktop.

Select an option

Save kwilczynski/e350623ffbaafd4e88fa to your computer and use it in GitHub Desktop.
values_at.rb
#
# values_at.rb
#
# Copyright 2012-2014 Krzysztof Wilczynski
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module Puppet::Parser::Functions
newfunction(:values_at, :type => :rvalue, :doc => <<-EOS
Returns
Prototype:
values_at()
Where
For example:
Given the following statements:
The result will be as follows:
EOS
) do |arguments|
raise Puppet::ParseError, "values_at(): Wrong number of " +
"arguments given (#{arguments.size} for 1)" if arguments.size < 1
array = arguments.shift
raise Puppet::ParseError, 'values_at(): Requires ' +
'an array to work with' unless array.is_a?(Array)
indices = *arguments # Get them all ...
# Anything to collect? If not then just return empty array ...
return [] if array.nil? || array.empty?
# This is to detect single empty string as first arguments ...
raise Puppet::ParseError, 'values_at(): Requires ' +
'a numeric value or range to work with' if indices.nil? || indices.empty?
indices_list = []
indices.each do |value|
# This should cover all the generic numeric types present in Puppet ...
unless value.class.ancestors.include?(Numeric) || value.is_a?(String)
raise Puppet::ParseError, 'values_at(): Requires ' +
'a numeric value or range to work with'
end
type_error = false
if value.is_a?(String)
type_error = true if value.empty?
# We support rages given as a..b, a...b and a-b which resembles a..b ...
if m = value.match(/^(-?\d+)(\.{2,3}|\-)(-?\d+)$/)
start = m[1]
stop = m[3]
range = m[2]
start = start.to_i
stop = stop.to_i
range = case range
when /^(\.{2}|\-)$/ then (start .. stop)
when /^\.{3}$/ then (start ... stop) # Exclusive of last element ...
end
indices_list += range.to_a
elsif value.match(/^-?(?:\d+)(?:\.\d+){1}$/) # Floating point
type_error = true
elsif value.match(/^-?\d+$/) # Integer
# In Puppet numbers are often string-encoded ...
indices_list << value.to_i
else
raise Puppet::ParseError, 'values_at(): Unknown type of ' +
'value for indices given'
end
raise Puppet::ParseError, 'values_at(): Requires ' +
'an integer value to work with' if type_error
else
indices_list << value
end
end
#
# We remove nil values as they make no sense in Puppet DSL
# and turn them into :undef value.
#
array.values_at(*indices_list).map {|i| i.nil? ? :undef : i }
end
end
# vim: set ts=2 sw=2 et :
# encoding: utf-8
@kwilczynski
Copy link
Author

Testing locally:

matti@acrux ~/test/lib $ ls -l puppet/parser/functions/
total 8
-rw-r--r-- 1 matti users 3795 wrz  8 19:30 dump.rb
-rw-r--r-- 1 matti users 3201 wrz  8 20:00 values_at.rb
matti@acrux ~/test/lib $ cat - | RUBYLIB=. puppet apply
$a = [1, 2, 3]
notice dump(values_at($a, 1, '2-3', 2, -1))
notice dump(values_at($a, 3, 2, 1, 0))
notice dump(values_at($a, '0..3'))
notice dump(values_at($a, '0...3'))
Notice: Scope(Class[main]): ["2", "3", :undef, "3", "3"]
Notice: Scope(Class[main]): [:undef, "3", "2", "1"]
Notice: Scope(Class[main]): ["1", "2", "3", :undef]
Notice: Scope(Class[main]): ["1", "2", "3"]
Notice: Compiled catalog for acrux.romke.net in environment production in 0.02 seconds
Notice: Finished catalog run in 1.32 seconds

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment