]> git.donarmstrong.com Git - dsa-puppet.git/commitdiff
add puppet stdlib
authorStephen Gran <steve@lobefin.net>
Sun, 15 Apr 2012 19:22:17 +0000 (20:22 +0100)
committerStephen Gran <steve@lobefin.net>
Sun, 15 Apr 2012 19:25:11 +0000 (20:25 +0100)
Signed-off-by: Stephen Gran <steve@lobefin.net>
139 files changed:
modules/stdlib/CHANGELOG [new file with mode: 0644]
modules/stdlib/LICENSE [new file with mode: 0644]
modules/stdlib/Modulefile [new file with mode: 0644]
modules/stdlib/README.markdown [new file with mode: 0644]
modules/stdlib/RELEASE_PROCESS.markdown [new file with mode: 0644]
modules/stdlib/Rakefile [new file with mode: 0644]
modules/stdlib/lib/facter/facter_dot_d.rb [new file with mode: 0644]
modules/stdlib/lib/facter/root_home.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/abs.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/bool2num.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/capitalize.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/chomp.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/chop.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/delete.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/delete_at.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/downcase.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/empty.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/flatten.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/getvar.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/grep.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/has_key.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/hash.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_array.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_float.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_hash.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_integer.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_numeric.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/is_string.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/join.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/keys.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/loadyaml.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/lstrip.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/member.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/merge.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/num2bool.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/parsejson.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/parseyaml.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/prefix.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/range.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/reverse.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/rstrip.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/shuffle.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/size.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/sort.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/squeeze.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/str2bool.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/strftime.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/strip.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/swapcase.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/time.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/type.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/unique.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/upcase.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/validate_array.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/validate_bool.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/validate_hash.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/validate_re.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/validate_string.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/values.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/values_at.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/parser/functions/zip.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/provider/file_line/ruby.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/type/anchor.rb [new file with mode: 0644]
modules/stdlib/lib/puppet/type/file_line.rb [new file with mode: 0644]
modules/stdlib/manifests/init.pp [new file with mode: 0644]
modules/stdlib/manifests/stages.pp [new file with mode: 0644]
modules/stdlib/metadata.json [new file with mode: 0644]
modules/stdlib/spec/lib/puppet_spec/files.rb [new file with mode: 0755]
modules/stdlib/spec/lib/puppet_spec/fixtures.rb [new file with mode: 0755]
modules/stdlib/spec/lib/puppet_spec/matchers.rb [new file with mode: 0644]
modules/stdlib/spec/lib/puppet_spec/verbose.rb [new file with mode: 0755]
modules/stdlib/spec/monkey_patches/alias_should_to_must.rb [new file with mode: 0755]
modules/stdlib/spec/monkey_patches/publicize_methods.rb [new file with mode: 0755]
modules/stdlib/spec/spec.opts [new file with mode: 0644]
modules/stdlib/spec/spec_helper.rb [new file with mode: 0644]
modules/stdlib/spec/unit/facter/root_home_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/abs_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/bool2num_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/capitalize_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/chomp_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/chop_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/delete_at_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/delete_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/downcase_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/empty_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/flatten_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/getvar_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/grep_spec.rb [new file with mode: 0755]
modules/stdlib/spec/unit/puppet/parser/functions/has_key_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/hash_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_array_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_domain_name_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_float_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_hash_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_integer_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_ip_address_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_mac_address_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_numeric_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/is_string_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/join_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/keys_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/lstrip_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/member_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/merge_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/num2bool_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/parsejson_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/parseyaml_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/prefix_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/range_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/reverse_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/rstrip_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/shuffle_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/size_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/sort_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/squeeze_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/str2bool_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/strftime_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/strip_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/swapcase_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/time_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/type_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/unique_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/upcase_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/validate_array_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/validate_bool_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/validate_hash_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/validate_string_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/values_at_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/values_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/parser/functions/zip_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/provider/file_line/ruby_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/type/anchor_spec.rb [new file with mode: 0644]
modules/stdlib/spec/unit/puppet/type/file_line_spec.rb [new file with mode: 0644]
modules/stdlib/spec/watchr.rb [new file with mode: 0644]
modules/stdlib/tests/file_line.pp [new file with mode: 0644]
modules/stdlib/tests/init.pp [new file with mode: 0644]

diff --git a/modules/stdlib/CHANGELOG b/modules/stdlib/CHANGELOG
new file mode 100644 (file)
index 0000000..318cbe9
--- /dev/null
@@ -0,0 +1,59 @@
+2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.2.1
+* Documentation only release for the Forge
+
+2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.1.2
+* Documentation only release for PE 2.0.x
+
+2011-11-08 Puppet Labs <support@puppetlabs.com> - 2.2.0
+* #10285 - Refactor json to use pson instead.
+* Maint  - Add watchr autotest script
+* Maint  - Make rspec tests work with Puppet 2.6.4
+* #9859  - Add root_home fact and tests
+
+2011-08-18 Puppet Labs <support@puppetlabs.com> - 2.1.1
+* Change facts.d paths to match Facter 2.0 paths.
+* /etc/facter/facts.d
+* /etc/puppetlabs/facter/facts.d
+
+2011-08-17 Puppet Labs <support@puppetlabs.com> - 2.1.0
+* Add R.I. Pienaar's facts.d custom facter fact
+* facts defined in /etc/facts.d and /etc/puppetlabs/facts.d are
+  automatically loaded now.
+
+2011-08-04 Puppet Labs <support@puppetlabs.com> - 2.0.0
+* Rename whole_line to file_line
+* This is an API change and as such motivating a 2.0.0 release according to semver.org.
+
+2011-08-04 Puppet Labs <support@puppetlabs.com> - 1.1.0
+* Rename append_line to whole_line
+* This is an API change and as such motivating a 1.1.0 release.
+
+2011-08-04 Puppet Labs <support@puppetlabs.com> - 1.0.0
+* Initial stable release
+* Add validate_array and validate_string functions
+* Make merge() function work with Ruby 1.8.5
+* Add hash merging function
+* Add has_key function
+* Add loadyaml() function
+* Add append_line native
+
+2011-06-21 Jeff McCune <jeff@puppetlabs.com> - 0.1.7
+* Add validate_hash() and getvar() functions
+
+2011-06-15 Jeff McCune <jeff@puppetlabs.com> - 0.1.6
+* Add anchor resource type to provide containment for composite classes
+
+2011-06-03 Jeff McCune <jeff@puppetlabs.com> - 0.1.5
+* Add validate_bool() function to stdlib
+
+0.1.4 2011-05-26 Jeff McCune <jeff@puppetlabs.com>
+* Move most stages after main
+
+0.1.3 2011-05-25 Jeff McCune <jeff@puppetlabs.com>
+* Add validate_re() function
+
+0.1.2 2011-05-24 Jeff McCune <jeff@puppetlabs.com>
+* Update to add annotated tag
+
+0.1.1 2011-05-24 Jeff McCune <jeff@puppetlabs.com>
+* Add stdlib::stages class with a standard set of stages
diff --git a/modules/stdlib/LICENSE b/modules/stdlib/LICENSE
new file mode 100644 (file)
index 0000000..ec0587c
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (C) 2011 Puppet Labs Inc
+
+and some parts:
+
+Copyright (C) 2011 Krzysztof Wilczynski
+
+Puppet Labs can be contacted at: info@puppetlabs.com
+
+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.
diff --git a/modules/stdlib/Modulefile b/modules/stdlib/Modulefile
new file mode 100644 (file)
index 0000000..3efa8b9
--- /dev/null
@@ -0,0 +1,11 @@
+name    'puppetlabs-stdlib'
+version '2.2.1'
+source 'git://github.com/puppetlabs/puppetlabs-stdlib'
+author 'puppetlabs'
+license 'Apache 2.0'
+summary 'Puppet Module Standard Library'
+description 'Standard Library for Puppet Modules'
+project_page 'https://github.com/puppetlabs/puppetlabs-stdlib'
+
+## Add dependencies, if any:
+# dependency 'username/name', '>= 1.2.0'
diff --git a/modules/stdlib/README.markdown b/modules/stdlib/README.markdown
new file mode 100644 (file)
index 0000000..9fa4c38
--- /dev/null
@@ -0,0 +1,82 @@
+# Puppet Labs Standard Library #
+
+This module provides a "standard library" of resources for developing Puppet
+Modules.  This modules will include the following additions to Puppet
+
+ * Stages
+ * Facts
+ * Functions
+ * Defined resource types
+ * Types
+ * Providers
+
+This module is officially curated and provided by Puppet Labs.  The modules
+Puppet Labs writes and distributes will make heavy use of this standard
+library.
+
+# Versions #
+
+This module follows semver.org (v1.0.0) versioning guidelines.  The standard
+library module is released as part of [Puppet
+Enterprise](http://puppetlabs.com/puppet/puppet-enterprise/) and as a result
+older versions of Puppet Enterprise that Puppet Labs still supports will have
+bugfix maintenance branches periodically "merged up" into master.  The current
+list of integration branches are:
+
+ * v2.1.x (v2.1.1 released in PE 1.2, 1.2.1, 1.2.3, 1.2.4)
+ * v2.2.x (Never released as part of PE, only to the Forge)
+ * v2.3.x (Scheduled for next PE feature release)
+ * master (mainline development branch)
+
+The first Puppet Enterprise version including the stdlib module is Puppet
+Enterprise 1.2.
+
+# Compatibility #
+
+## stdlib v2.1.x, v2.2.x ##
+
+v2.1.x and v2.2.x of this module are designed to work with Puppet versions
+2.6.x and 2.7.x.  There are currently no plans for a Puppet 0.25 standard
+library module.
+
+## stdlib v2.3.x ##
+
+While not yet released, the standard library may only work with Puppet 2.7.x.
+
+# Functions #
+
+  Please see `puppet doc -r function` for documentation on each function.  The
+  current list of functions is:
+
+ * getvar
+ * has\_key
+ * loadyaml
+ * merge.rb
+ * validate\_array
+ * validate\_bool
+ * validate\_hash
+ * validate\_re
+ * validate\_string
+
+## validate\_hash ##
+
+    $somehash = { 'one' => 'two' }
+    validate\_hash($somehash)
+
+## getvar() ##
+
+This function aims to look up variables in user-defined namespaces within
+puppet.  Note, if the namespace is a class, it should already be evaluated
+before the function is used.
+
+    $namespace = 'site::data'
+    include "${namespace}"
+    $myvar = getvar("${namespace}::myvar")
+
+## Facts ##
+
+Facts in `/etc/facter/facts.d` and `/etc/puppetlabs/facter/facts.d` are now loaded
+automatically.  This is a direct copy of R.I. Pienaar's custom facter fact
+located at:
+[https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d](https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d)
+
diff --git a/modules/stdlib/RELEASE_PROCESS.markdown b/modules/stdlib/RELEASE_PROCESS.markdown
new file mode 100644 (file)
index 0000000..ea40d5d
--- /dev/null
@@ -0,0 +1,13 @@
+# Releasing this module #
+
+ * Work in a topic branch
+ * Submit a github pull request
+ * Address any comments / feeback
+ * Merge into master using --no-ff
+ * Update the CHANGELOG
+ * Update the Modulefile
+ * Create an annotated tag with git tag -a X.Y.Z -m 'version X.Y.Z'
+ * Push the tag with git push origin --tags
+ * Build a new package with puppet-module
+ * Publish the new package to the forge
+
diff --git a/modules/stdlib/Rakefile b/modules/stdlib/Rakefile
new file mode 100644 (file)
index 0000000..01b2a31
--- /dev/null
@@ -0,0 +1,16 @@
+require 'rake'
+require 'rspec/core/rake_task'
+
+task :default => [:test]
+
+desc 'Run RSpec'
+RSpec::Core::RakeTask.new(:test) do |t|
+  t.pattern = 'spec/{unit}/**/*.rb'
+  t.rspec_opts = ['--color']
+end
+
+desc 'Generate code coverage'
+RSpec::Core::RakeTask.new(:coverage) do |t|
+  t.rcov = true
+  t.rcov_opts = ['--exclude', 'spec']
+end
diff --git a/modules/stdlib/lib/facter/facter_dot_d.rb b/modules/stdlib/lib/facter/facter_dot_d.rb
new file mode 100644 (file)
index 0000000..90586a9
--- /dev/null
@@ -0,0 +1,183 @@
+# A Facter plugin that loads facts from /etc/facts.d.
+#
+# Facts can be in the form of JSON, YAML or Text files
+# and any executable that returns key=value pairs.
+#
+# In the case of scripts you can also create a file that
+# contains a cache TTL.  For foo.sh store the ttl as just
+# a number in foo.sh.ttl
+#
+# The cache is stored in /tmp/facts_cache.yaml as a mode
+# 600 file and will have the end result of not calling your
+# fact scripts more often than is needed
+class Facter::Util::DotD
+    require 'yaml'
+
+    def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml")
+        @dir = dir
+        @cache_file = cache_file
+        @cache = nil
+        @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml}
+    end
+
+    def entries
+        Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) }
+    rescue
+        []
+    end
+
+    def fact_type(file)
+        extension = File.extname(file)
+
+        type = @types[extension] || :unknown
+
+        type = :script if type == :unknown && File.executable?(file)
+
+        return type
+    end
+
+    def txt_parser(file)
+        File.readlines(file).each do |line|
+            if line =~ /^(.+)=(.+)$/
+                var = $1; val = $2
+
+                Facter.add(var) do
+                    setcode { val }
+                end
+            end
+        end
+    rescue Exception => e
+        Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}")
+    end
+
+    def json_parser(file)
+        begin
+            require 'json'
+        rescue LoadError
+            require 'rubygems'
+            retry
+        end
+
+        JSON.load(File.read(file)).each_pair do |f, v|
+            Facter.add(f) do
+                setcode { v }
+            end
+        end
+    rescue Exception => e
+        Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}")
+    end
+
+    def yaml_parser(file)
+        require 'yaml'
+
+        YAML.load_file(file).each_pair do |f, v|
+            Facter.add(f) do
+                setcode { v }
+            end
+        end
+    rescue Exception => e
+        Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}")
+    end
+
+    def script_parser(file)
+        result = cache_lookup(file)
+        ttl = cache_time(file)
+
+        unless result
+            result = Facter::Util::Resolution.exec(file)
+
+            if ttl > 0
+                Facter.debug("Updating cache for #{file}")
+                cache_store(file, result)
+                cache_save!
+            end
+        else
+            Facter.debug("Using cached data for #{file}")
+        end
+
+        result.split("\n").each do |line|
+            if line =~ /^(.+)=(.+)$/
+                var = $1; val = $2
+
+                Facter.add(var) do
+                    setcode { val }
+                end
+            end
+        end
+    rescue Exception => e
+        Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}")
+        Facter.debug(e.backtrace.join("\n\t"))
+    end
+
+    def cache_save!
+        cache = load_cache
+        File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) }
+    rescue
+    end
+
+    def cache_store(file, data)
+        load_cache
+
+        @cache[file] = {:data => data, :stored => Time.now.to_i}
+    rescue
+    end
+
+    def cache_lookup(file)
+        cache = load_cache
+
+        return nil if cache.empty?
+
+        ttl = cache_time(file)
+
+        if cache[file]
+            now = Time.now.to_i
+
+            return cache[file][:data] if ttl == -1
+            return cache[file][:data] if (now - cache[file][:stored]) <= ttl
+            return nil
+        else
+            return nil
+        end
+    rescue
+        return nil
+    end
+
+    def cache_time(file)
+        meta = file + ".ttl"
+
+        return File.read(meta).chomp.to_i
+    rescue
+        return 0
+    end
+
+    def load_cache
+        unless @cache
+            if File.exist?(@cache_file)
+                @cache = YAML.load_file(@cache_file)
+            else
+                @cache = {}
+            end
+        end
+
+        return @cache
+    rescue
+        @cache = {}
+        return @cache
+    end
+
+    def create
+        entries.each do |fact|
+            type = fact_type(fact)
+            parser = "#{type}_parser"
+
+            if respond_to?("#{type}_parser")
+                Facter.debug("Parsing #{fact} using #{parser}")
+
+                send(parser, fact)
+            end
+        end
+    end
+end
+
+Facter::Util::DotD.new("/etc/facter/facts.d").create
+Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create
diff --git a/modules/stdlib/lib/facter/root_home.rb b/modules/stdlib/lib/facter/root_home.rb
new file mode 100644 (file)
index 0000000..61fcf39
--- /dev/null
@@ -0,0 +1,17 @@
+# A facter fact to determine the root home directory.
+# This varies on PE supported platforms and may be
+# reconfigured by the end user.
+
+module Facter::Util::RootHome
+  class << self
+  def get_root_home
+    root_ent = Facter::Util::Resolution.exec("getent passwd root")
+    # The home directory is the sixth element in the passwd entry
+    root_ent.split(":")[5]
+  end
+  end
+end
+
+Facter.add(:root_home) do
+  setcode { Facter::Util::RootHome.get_root_home }
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/abs.rb b/modules/stdlib/lib/puppet/parser/functions/abs.rb
new file mode 100644 (file)
index 0000000..ade5462
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# abs.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:abs, :type => :rvalue, :doc => <<-EOS
+    Returns the absolute value of a number, for example -34.56 becomes 
+    34.56. Takes a single integer and float value as an argument.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "abs(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    # Numbers in Puppet are often string-encoded which is troublesome ...
+    if value.is_a?(String)
+      if value.match(/^-?(?:\d+)(?:\.\d+){1}$/)
+        value = value.to_f
+      elsif value.match(/^-?\d+$/)
+        value = value.to_i
+      else
+        raise(Puppet::ParseError, 'abs(): Requires float or ' +
+          'integer to work with')
+      end
+    end
+
+    # We have numeric value to handle ...
+    result = value.abs
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/bool2num.rb b/modules/stdlib/lib/puppet/parser/functions/bool2num.rb
new file mode 100644 (file)
index 0000000..9a07a8a
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# bool2num.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:bool2num, :type => :rvalue, :doc => <<-EOS
+    Converts a boolean to a number. Converts the values:
+      false, f, 0, n, and no to 0
+      true, t, 1, y, and yes to 1
+    Requires a single boolean or string as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "bool2num(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    # We can have either true or false, or string which resembles boolean ...
+    unless [FalseClass, TrueClass, String].include?(klass)
+      raise(Puppet::ParseError, 'bool2num(): Requires either ' +
+        'boolean or string to work with')
+    end
+
+    if value.is_a?(String)
+      # We consider all the yes, no, y, n and so on too ...
+      value = case value
+        #
+        # This is how undef looks like in Puppet ...
+        # We yield 0 (or false if you wish) in this case.
+        #
+        when /^$/, '' then false # Empty string will be false ...
+        when /^(1|t|y|true|yes)$/  then true
+        when /^(0|f|n|false|no)$/  then false
+        when /^(undef|undefined)$/ then false # This is not likely to happen ...
+        else
+          raise(Puppet::ParseError, 'bool2num(): Unknown type of boolean given')
+      end
+    end
+
+    # We have real boolean values as well ...
+    result = value ? 1 : 0
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/capitalize.rb b/modules/stdlib/lib/puppet/parser/functions/capitalize.rb
new file mode 100644 (file)
index 0000000..640d00b
--- /dev/null
@@ -0,0 +1,34 @@
+#
+#  capitalize.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:capitalize, :type => :rvalue, :doc => <<-EOS
+    Capitalizes the first letter of a string or array of strings.
+    Requires either a single string or an array as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "capitalize(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'capitalize(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.capitalize : i }
+    else
+      result = value.capitalize
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/chomp.rb b/modules/stdlib/lib/puppet/parser/functions/chomp.rb
new file mode 100644 (file)
index 0000000..c99d139
--- /dev/null
@@ -0,0 +1,35 @@
+#
+#  chomp.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:chomp, :type => :rvalue, :doc => <<-'EOS'
+    Removes the record separator from the end of a string or an array of 
+    strings, for example `hello\n` becomes `hello`.
+    Requires a single string or array as an input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "chomp(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'chomp(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.chomp : i }
+    else
+      result = value.chomp
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/chop.rb b/modules/stdlib/lib/puppet/parser/functions/chop.rb
new file mode 100644 (file)
index 0000000..636b990
--- /dev/null
@@ -0,0 +1,37 @@
+#
+#  chop.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:chop, :type => :rvalue, :doc => <<-'EOS'
+    Returns a new string with the last character removed. If the string ends 
+    with `\r\n`, both characters are removed. Applying chop to an empty 
+    string returns an empty string. If you wish to merely remove record 
+    separators then you should use the `chomp` function.
+    Requires a string or array of strings as input.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "chop(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'chop(): Requires either an ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.chop : i }
+    else
+      result = value.chop
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/delete.rb b/modules/stdlib/lib/puppet/parser/functions/delete.rb
new file mode 100644 (file)
index 0000000..ab8f75b
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# delete.rb
+#
+
+# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
+# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...
+
+module Puppet::Parser::Functions
+  newfunction(:delete, :type => :rvalue, :doc => <<-EOS
+Deletes a selected element from an array.
+
+*Examples:*
+
+    delete(['a','b','c'], 'b')
+
+Would return: ['a','c']
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 2) then
+      raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
+        "given #{arguments.size} for 2")
+    end
+
+    a = arguments[0]
+    item = arguments[1]
+
+    a.delete(item)
+    a
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/delete_at.rb b/modules/stdlib/lib/puppet/parser/functions/delete_at.rb
new file mode 100644 (file)
index 0000000..3eb4b53
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# delete_at.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:delete_at, :type => :rvalue, :doc => <<-EOS
+Deletes a determined indexed value from an array.
+
+*Examples:*
+
+    delete_at(['a','b','c'], 1)
+
+Would return: ['a','c']
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "delete_at(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size < 2
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'delete_at(): Requires array to work with')
+    end
+
+    index = arguments[1]
+
+    if index.is_a?(String) and not index.match(/^\d+$/)
+      raise(Puppet::ParseError, 'delete_at(): You must provide ' +
+        'non-negative numeric index')
+    end
+
+    result = array.clone
+
+    # Numbers in Puppet are often string-encoded which is troublesome ...
+    index = index.to_i
+
+    if index > result.size - 1 # First element is at index 0 is it not?
+      raise(Puppet::ParseError, 'delete_at(): Given index ' +
+        'exceeds size of array given')
+    end
+
+    result.delete_at(index) # We ignore the element that got deleted ...
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/downcase.rb b/modules/stdlib/lib/puppet/parser/functions/downcase.rb
new file mode 100644 (file)
index 0000000..4066d21
--- /dev/null
@@ -0,0 +1,33 @@
+#
+#  downcase.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:downcase, :type => :rvalue, :doc => <<-EOS
+Converts the case of a string or all strings in an array to lower case.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "downcase(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'downcase(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.downcase : i }
+    else
+      result = value.downcase
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/empty.rb b/modules/stdlib/lib/puppet/parser/functions/empty.rb
new file mode 100644 (file)
index 0000000..80ebb86
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# empty.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:empty, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable is empty.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "empty(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, Hash, String].include?(klass)
+      raise(Puppet::ParseError, 'empty(): Requires either ' +
+        'array, hash or string to work with')
+    end
+
+    result = value.empty?
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/flatten.rb b/modules/stdlib/lib/puppet/parser/functions/flatten.rb
new file mode 100644 (file)
index 0000000..781da78
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# flatten.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:flatten, :type => :rvalue, :doc => <<-EOS
+This function flattens any deeply nested arrays and returns a single flat array
+as a result.
+
+*Examples:*
+
+    flatten(['a', ['b', ['c']]])
+
+Would return: ['a','b','c']
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "flatten(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'flatten(): Requires array to work with')
+    end
+
+    result = array.flatten
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/getvar.rb b/modules/stdlib/lib/puppet/parser/functions/getvar.rb
new file mode 100644 (file)
index 0000000..1621149
--- /dev/null
@@ -0,0 +1,26 @@
+module Puppet::Parser::Functions
+
+  newfunction(:getvar, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Lookup a variable in a remote namespace.
+
+    For example:
+
+        $foo = getvar('site::data::foo')
+        # Equivalent to $foo = $site::data::foo
+
+    This is useful if the namespace itself is stored in a string:
+
+        $datalocation = 'site::data'
+        $bar = getvar("${datalocation}::bar")
+        # Equivalent to $bar = $site::data::bar
+    ENDHEREDOC
+
+    unless args.length == 1
+      raise Puppet::ParseError, ("getvar(): wrong number of arguments (#{args.length}; must be 1)")
+    end
+
+    self.lookupvar("#{args[0]}")
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/grep.rb b/modules/stdlib/lib/puppet/parser/functions/grep.rb
new file mode 100644 (file)
index 0000000..ceba9ec
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# grep.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:grep, :type => :rvalue, :doc => <<-EOS
+This function searches through an array and returns any elements that match
+the provided regular expression.
+
+*Examples:*
+
+    grep(['aaa','bbb','ccc','aaaddd'], 'aaa')
+
+Would return:
+
+    ['aaa','aaaddd']
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 2) then
+      raise(Puppet::ParseError, "grep(): Wrong number of arguments "+
+        "given #{arguments.size} for 2")
+    end
+
+    a = arguments[0]
+    pattern = Regexp.new(arguments[1])
+
+    a.grep(pattern)
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/has_key.rb b/modules/stdlib/lib/puppet/parser/functions/has_key.rb
new file mode 100644 (file)
index 0000000..4657cc2
--- /dev/null
@@ -0,0 +1,28 @@
+module Puppet::Parser::Functions
+
+  newfunction(:has_key, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Determine if a hash has a certain key value.
+
+    Example:
+
+        $my_hash = {'key_one' => 'value_one'}
+        if has_key($my_hash, 'key_two') {
+          notice('we will not reach here')
+        }
+        if has_key($my_hash, 'key_one') {
+          notice('this will be printed')
+        }
+
+    ENDHEREDOC
+
+    unless args.length == 2
+      raise Puppet::ParseError, ("has_key(): wrong number of arguments (#{args.length}; must be 2)")
+    end
+    unless args[0].is_a?(Hash)
+      raise Puppet::ParseError, "has_key(): expects the first argument to be a hash, got #{args[0].inspect} which is of type #{args[0].class}"
+    end
+    args[0].has_key?(args[1])
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/hash.rb b/modules/stdlib/lib/puppet/parser/functions/hash.rb
new file mode 100644 (file)
index 0000000..453ba1e
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# hash.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:hash, :type => :rvalue, :doc => <<-EOS
+This function converts and array into a hash.
+
+*Examples:*
+
+    hash(['a',1,'b',2,'c',3])
+
+Would return: {'a'=>1,'b'=>2,'c'=>3}
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "hash(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'hash(): Requires array to work with')
+    end
+
+    result = {}
+
+    begin
+      # This is to make it compatible with older version of Ruby ...
+      array  = array.flatten
+      result = Hash[*array]
+    rescue Exception
+      raise(Puppet::ParseError, 'hash(): Unable to compute ' +
+        'hash from array given')
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_array.rb b/modules/stdlib/lib/puppet/parser/functions/is_array.rb
new file mode 100644 (file)
index 0000000..b39e184
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# is_array.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_array, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is an array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "is_array(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    type = arguments[0]
+
+    result = type.is_a?(Array)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb b/modules/stdlib/lib/puppet/parser/functions/is_domain_name.rb
new file mode 100644 (file)
index 0000000..4e92939
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# is_domain_name.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_domain_name, :type => :rvalue, :doc => <<-EOS
+Returns true if the string passed to this function is a valid IP address. Support for IPv4 and IPv6 address types is included.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_domain_name(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    domain = arguments[0]
+
+    if domain =~ /^(([a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])\.?$/ then
+      return true
+    else
+      return false
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_float.rb b/modules/stdlib/lib/puppet/parser/functions/is_float.rb
new file mode 100644 (file)
index 0000000..2fc05ba
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# is_float.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_float, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a float.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_float(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    if value != value.to_f.to_s then
+      return false
+    else
+      return true
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_hash.rb b/modules/stdlib/lib/puppet/parser/functions/is_hash.rb
new file mode 100644 (file)
index 0000000..ad907f0
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# is_hash.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_hash, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a hash.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "is_hash(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size != 1
+
+    type = arguments[0]
+
+    result = type.is_a?(Hash)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_integer.rb b/modules/stdlib/lib/puppet/parser/functions/is_integer.rb
new file mode 100644 (file)
index 0000000..8ee34f6
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# is_integer.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_integer, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable returned to this string is an integer.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_integer(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    if value != value.to_i.to_s then
+      return false
+    else
+      return true
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb b/modules/stdlib/lib/puppet/parser/functions/is_ip_address.rb
new file mode 100644 (file)
index 0000000..b4a9a15
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# is_ip_address.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_ip_address, :type => :rvalue, :doc => <<-EOS
+Returns true if the string passed to this function is a valid IP address.
+    EOS
+  ) do |arguments|
+
+    require 'ipaddr'
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_ip_address(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    begin 
+      ip = IPAddr.new(arguments[0])
+    rescue ArgumentError
+      return false
+    end
+
+    if ip.ipv4? or ip.ipv6? then
+      return true
+    else
+      return false
+    end
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb b/modules/stdlib/lib/puppet/parser/functions/is_mac_address.rb
new file mode 100644 (file)
index 0000000..1b3088a
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# is_mac_address.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_mac_address, :type => :rvalue, :doc => <<-EOS
+Returns true if the string passed to this function is a valid mac address.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_mac_address(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    mac = arguments[0]
+
+    if /^[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}$/.match(mac) then
+      return true
+    else
+      return false
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb b/modules/stdlib/lib/puppet/parser/functions/is_numeric.rb
new file mode 100644 (file)
index 0000000..ce13ece
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# is_numeric.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_numeric, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a number.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "is_numeric(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    if value == value.to_f.to_s or value == value.to_i.to_s then
+      return true
+    else
+      return false
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/is_string.rb b/modules/stdlib/lib/puppet/parser/functions/is_string.rb
new file mode 100644 (file)
index 0000000..f5bef04
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# is_string.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:is_string, :type => :rvalue, :doc => <<-EOS
+Returns true if the variable passed to this function is a string.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "is_string(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    type = arguments[0]
+
+    result = type.is_a?(String)
+
+    if result and (type == type.to_f.to_s or type == type.to_i.to_s) then
+      return false
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/join.rb b/modules/stdlib/lib/puppet/parser/functions/join.rb
new file mode 100644 (file)
index 0000000..005a46e
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# join.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:join, :type => :rvalue, :doc => <<-EOS
+This function joins an array into a string using a seperator.
+
+*Examples:*
+
+    join(['a','b','c'], ",")
+
+Would result in: "a,b,c"
+    EOS
+  ) do |arguments|
+
+    # Technically we support two arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "join(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'join(): Requires array to work with')
+    end
+
+    suffix = arguments[1] if arguments[1]
+
+    if suffix
+      unless suffix.is_a?(String)
+        raise(Puppet::ParseError, 'join(): Requires string to work with')
+      end
+    end
+
+    result = suffix ? array.join(suffix) : array.join
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/keys.rb b/modules/stdlib/lib/puppet/parser/functions/keys.rb
new file mode 100644 (file)
index 0000000..f0d13b6
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# keys.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:keys, :type => :rvalue, :doc => <<-EOS
+Returns the keys of a hash as an array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "keys(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    hash = arguments[0]
+
+    unless hash.is_a?(Hash)
+      raise(Puppet::ParseError, 'keys(): Requires hash to work with')
+    end
+
+    result = hash.keys
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb b/modules/stdlib/lib/puppet/parser/functions/loadyaml.rb
new file mode 100644 (file)
index 0000000..10c4005
--- /dev/null
@@ -0,0 +1,20 @@
+module Puppet::Parser::Functions
+
+  newfunction(:loadyaml, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Load a YAML file containing an array, string, or hash, and return the data
+    in the corresponding native data type.
+
+    For example:
+
+        $myhash = loadyaml('/etc/puppet/data/myhash.yaml')
+    ENDHEREDOC
+
+    unless args.length == 1
+      raise Puppet::ParseError, ("loadyaml(): wrong number of arguments (#{args.length}; must be 1)")
+    end
+
+    YAML.load_file(args[0])
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/lstrip.rb b/modules/stdlib/lib/puppet/parser/functions/lstrip.rb
new file mode 100644 (file)
index 0000000..3a64de3
--- /dev/null
@@ -0,0 +1,33 @@
+#
+#  lstrip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:lstrip, :type => :rvalue, :doc => <<-EOS
+Strips leading spaces to the left of a string.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "lstrip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'lstrip(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.lstrip : i }
+    else
+      result = value.lstrip
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/member.rb b/modules/stdlib/lib/puppet/parser/functions/member.rb
new file mode 100644 (file)
index 0000000..43d76af
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# member.rb
+#
+
+# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
+# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...
+
+module Puppet::Parser::Functions
+  newfunction(:member, :type => :rvalue, :doc => <<-EOS
+This function determines if a variable is a member of an array.
+
+*Examples:*
+
+    member(['a','b'], 'b')
+
+Would return: true
+
+    member(['a','b'], 'c')
+
+Would return: false
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "member(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size < 2
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'member(): Requires array to work with')
+    end
+
+    item = arguments[1]
+
+    raise(Puppet::ParseError, 'member(): You must provide item ' +
+      'to search for within array given') if item.empty?
+
+    result = array.include?(item)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/merge.rb b/modules/stdlib/lib/puppet/parser/functions/merge.rb
new file mode 100644 (file)
index 0000000..6ec085e
--- /dev/null
@@ -0,0 +1,33 @@
+module Puppet::Parser::Functions
+  newfunction(:merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+    Merges two or more hashes together and returns the resulting hash.
+
+    For example:
+
+        $hash1 = {'one' => 1, 'two', => 2}
+        $hash2 = {'two' => 'dos', 'three', => 'tres'}
+        $merged_hash = merge($hash1, $hash2)
+        # The resulting hash is equivalent to:
+        # $merged_hash =  {'one' => 1, 'two' => 'dos', 'three' => 'tres'}
+
+    When there is a duplicate key, the key in the rightmost hash will "win."
+
+    ENDHEREDOC
+
+    if args.length < 2
+      raise Puppet::ParseError, ("merge(): wrong number of arguments (#{args.length}; must be at least 2)")
+    end
+
+    # The hash we accumulate into
+    accumulator = Hash.new
+    # Merge into the accumulator hash
+    args.each do |arg|
+      unless arg.is_a?(Hash)
+        raise Puppet::ParseError, "merge: unexpected argument type #{arg.class}, only expects hash arguments"
+      end
+      accumulator.merge!(arg)
+    end
+    # Return the fully merged hash
+    accumulator
+  end
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/num2bool.rb b/modules/stdlib/lib/puppet/parser/functions/num2bool.rb
new file mode 100644 (file)
index 0000000..874db22
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# num2bool.rb
+#
+
+# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
+
+module Puppet::Parser::Functions
+  newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS
+This function converts a number into a true boolean. Zero becomes false. Numbers
+higher then 0 become true.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    number = arguments[0]
+
+    # Only numbers allowed ...
+    unless number.match(/^\-?\d+$/)
+      raise(Puppet::ParseError, 'num2bool(): Requires integer to work with')
+    end
+
+    result = case number
+      when /^0$/
+        false
+      when /^\-?\d+$/
+        # Numbers in Puppet are often string-encoded which is troublesome ...
+        number = number.to_i
+        # We yield true for any positive number and false otherwise ...
+        number > 0 ? true : false
+      else
+        raise(Puppet::ParseError, 'num2bool(): Unknown numeric format given')
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/parsejson.rb b/modules/stdlib/lib/puppet/parser/functions/parsejson.rb
new file mode 100644 (file)
index 0000000..a9a16a4
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# parsejson.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:parsejson, :type => :rvalue, :doc => <<-EOS
+This function accepts JSON as a string and converts into the correct Puppet
+structure.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "parsejson(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    json = arguments[0]
+
+    # PSON is natively available in puppet
+    PSON.load(json)
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb b/modules/stdlib/lib/puppet/parser/functions/parseyaml.rb
new file mode 100644 (file)
index 0000000..e8ac8a4
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# parseyaml.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS
+This function accepts YAML as a string and converts it into the correct 
+Puppet structure.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "parseyaml(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    require 'yaml'
+
+    YAML::load(arguments[0])
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/prefix.rb b/modules/stdlib/lib/puppet/parser/functions/prefix.rb
new file mode 100644 (file)
index 0000000..4593976
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# prefix.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
+This function applies a prefix to all elements in an array.
+
+*Examles:*
+
+    prefix(['a','b','c'], 'p')
+
+Will return: ['pa','pb','pc']
+    EOS
+  ) do |arguments|
+
+    # Technically we support two arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "prefix(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    array = arguments[0]
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'prefix(): Requires array to work with')
+    end
+
+    prefix = arguments[1] if arguments[1]
+
+    if prefix
+      unless prefix.is_a?(String)
+        raise(Puppet::ParseError, 'prefix(): Requires string to work with')
+      end
+    end
+
+    # Turn everything into string same as join would do ...
+    result = array.collect do |i|
+      i = i.to_s
+      prefix ? prefix + i : i
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/range.rb b/modules/stdlib/lib/puppet/parser/functions/range.rb
new file mode 100644 (file)
index 0000000..6e85422
--- /dev/null
@@ -0,0 +1,71 @@
+#
+# range.rb
+#
+
+# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
+
+module Puppet::Parser::Functions
+  newfunction(:range, :type => :rvalue, :doc => <<-EOS
+When given range in the form of (start, stop) it will extrapolate a range as
+an array.
+
+*Examples:*
+
+    range("0", "9")
+
+Will return: [0,1,2,3,4,5,6,7,8,9]
+
+    range("a", "c")
+
+Will return: ["a","b","c"]
+    EOS
+  ) do |arguments|
+
+    # We support more than one argument but at least one is mandatory ...
+    raise(Puppet::ParseError, "range(): Wrong number of " +
+      "arguments given (#{arguments.size} for 1)") if arguments.size < 1
+
+    if arguments.size > 1
+      start = arguments[0]
+      stop  = arguments[1]
+
+      type = '..' # We select simplest type for Range available in Ruby ...
+
+    elsif arguments.size > 0
+      value = arguments[0]
+
+      if m = value.match(/^(\w+)(\.\.\.?|\-)(\w+)$/)
+        start = m[1]
+        stop  = m[3]
+
+        type = m[2]
+
+      elsif value.match(/^.+$/)
+        raise(Puppet::ParseError, 'range(): Unable to compute range ' +
+          'from the value given')
+      else
+        raise(Puppet::ParseError, 'range(): Unknown format of range given')
+      end
+    end
+
+      # Check whether we have integer value if so then make it so ...
+      if start.match(/^\d+$/)
+        start = start.to_i
+        stop  = stop.to_i
+      else
+        start = start.to_s
+        stop  = stop.to_s
+      end
+
+      range = case type
+        when /^(\.\.|\-)$/ then (start .. stop)
+        when /^(\.\.\.)$/  then (start ... stop) # Exclusive of last element ...
+      end
+
+      result = range.collect { |i| i } # Get them all ... Pokemon ...
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/reverse.rb b/modules/stdlib/lib/puppet/parser/functions/reverse.rb
new file mode 100644 (file)
index 0000000..fe04869
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# reverse.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:reverse, :type => :rvalue, :doc => <<-EOS
+Reverses the order of a string or array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "reverse(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'reverse(): Requires either ' +
+        'array or string to work with')
+    end
+
+    result = value.reverse
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/rstrip.rb b/modules/stdlib/lib/puppet/parser/functions/rstrip.rb
new file mode 100644 (file)
index 0000000..29b0998
--- /dev/null
@@ -0,0 +1,32 @@
+#
+#  rstrip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:rstrip, :type => :rvalue, :doc => <<-EOS
+Strips leading spaces to the right of the string.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "rstrip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'rstrip(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      result = value.collect { |i| i.is_a?(String) ? i.rstrip : i }
+    else
+      result = value.rstrip
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/shuffle.rb b/modules/stdlib/lib/puppet/parser/functions/shuffle.rb
new file mode 100644 (file)
index 0000000..18134ab
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# shuffle.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:shuffle, :type => :rvalue, :doc => <<-EOS
+Randomizes the order of a string or array elements.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "shuffle(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'shuffle(): Requires either ' +
+        'array or string to work with')
+    end
+
+    result = value.clone
+
+    string = value.is_a?(String) ? true : false
+
+    # Check whether it makes sense to shuffle ...
+    return result if result.size <= 1
+
+    # We turn any string value into an array to be able to shuffle ...
+    result = string ? result.split('') : result
+
+    elements = result.size
+
+    # Simple implementation of Fisher–Yates in-place shuffle ...
+    elements.times do |i|
+      j = rand(elements - i) + i
+      result[j], result[i] = result[i], result[j]
+    end
+
+    result = string ? result.join : result
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/size.rb b/modules/stdlib/lib/puppet/parser/functions/size.rb
new file mode 100644 (file)
index 0000000..cc207e3
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# size.rb
+#
+
+# TODO(Krzysztof Wilczynski): Support for hashes would be nice too ...
+
+module Puppet::Parser::Functions
+  newfunction(:size, :type => :rvalue, :doc => <<-EOS
+Returns the number of elements in a string or array.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "size(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    item = arguments[0]
+
+    if item.is_a?(String)
+
+      begin
+        #
+        # Check whether your item is a numeric value or not ...
+        # This will take care about positive and/or negative numbers
+        # for both integer and floating-point values ...
+        #
+        # Please note that Puppet has no notion of hexadecimal
+        # nor octal numbers for its DSL at this point in time ...
+        #
+        Float(item)
+
+        raise(Puppet::ParseError, 'size(): Requires either ' +
+          'string or array to work with')
+
+      rescue ArgumentError
+        result = item.size
+      end
+
+    elsif item.is_a?(Array)
+      result = item.size
+    else
+      raise(Puppet::ParseError, 'size(): Unknown type given')
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/sort.rb b/modules/stdlib/lib/puppet/parser/functions/sort.rb
new file mode 100644 (file)
index 0000000..cefbe54
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# sort.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:sort, :type => :rvalue, :doc => <<-EOS
+Sorts strings and arrays lexically.
+    EOS
+  ) do |arguments|
+
+    if (arguments.size != 1) then
+      raise(Puppet::ParseError, "sort(): Wrong number of arguments "+
+        "given #{arguments.size} for 1")
+    end
+
+    value = arguments[0]
+
+    if value.is_a?(Array) then
+      value.sort
+    elsif value.is_a?(String) then
+      value.split("").sort.join("")
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/squeeze.rb b/modules/stdlib/lib/puppet/parser/functions/squeeze.rb
new file mode 100644 (file)
index 0000000..65c174a
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# squeeze.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:squeeze, :type => :rvalue, :doc => <<-EOS
+Returns a new string where runs of the same character that occur in this set are replaced by a single character.
+    EOS
+  ) do |arguments|
+
+    if ((arguments.size != 2) and (arguments.size != 1)) then
+      raise(Puppet::ParseError, "squeeze(): Wrong number of arguments "+
+        "given #{arguments.size} for 2 or 1")
+    end
+
+    item = arguments[0]
+    squeezeval = arguments[1] 
+
+    if item.is_a?(Array) then  
+      if squeezeval then
+        item.collect { |i| i.squeeze(squeezeval) }
+      else
+        item.collect { |i| i.squeeze }
+      end
+    else
+      if squeezeval then
+        item.squeeze(squeezeval)
+      else
+        item.squeeze
+      end
+    end
+
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/str2bool.rb b/modules/stdlib/lib/puppet/parser/functions/str2bool.rb
new file mode 100644 (file)
index 0000000..c320da6
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# str2bool.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS
+This converts a string to a boolean. This attempt to convert strings that 
+contain things like: y, 1, t, true to 'true' and strings that contain things
+like: 0, f, n, false, no to 'false'.
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "str2bool(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    string = arguments[0]
+
+    unless string.is_a?(String)
+      raise(Puppet::ParseError, 'str2bool(): Requires either ' +
+        'string to work with')
+    end
+
+    # We consider all the yes, no, y, n and so on too ...
+    result = case string
+      #
+      # This is how undef looks like in Puppet ...
+      # We yield false in this case.
+      #
+      when /^$/, '' then false # Empty string will be false ...
+      when /^(1|t|y|true|yes)$/  then true
+      when /^(0|f|n|false|no)$/  then false
+      when /^(undef|undefined)$/ then false # This is not likely to happen ...
+      else
+        raise(Puppet::ParseError, 'str2bool(): Unknown type of boolean given')
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/strftime.rb b/modules/stdlib/lib/puppet/parser/functions/strftime.rb
new file mode 100644 (file)
index 0000000..0b52ade
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# strftime.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:strftime, :type => :rvalue, :doc => <<-EOS
+This function returns formatted time.
+
+*Examples:*
+
+To return the time since epoch:
+
+    strftime("%s")
+
+To return the date:
+
+    strftime("%Y-%m-%d")
+
+*Format meaning:*
+
+    %a - The abbreviated weekday name (``Sun'')
+    %A - The  full  weekday  name (``Sunday'')
+    %b - The abbreviated month name (``Jan'')
+    %B - The  full  month  name (``January'')
+    %c - The preferred local date and time representation
+    %C - Century (20 in 2009)
+    %d - Day of the month (01..31)
+    %D - Date (%m/%d/%y)
+    %e - Day of the month, blank-padded ( 1..31)
+    %F - Equivalent to %Y-%m-%d (the ISO 8601 date format)
+    %h - Equivalent to %b
+    %H - Hour of the day, 24-hour clock (00..23)
+    %I - Hour of the day, 12-hour clock (01..12)
+    %j - Day of the year (001..366)
+    %k - hour, 24-hour clock, blank-padded ( 0..23)
+    %l - hour, 12-hour clock, blank-padded ( 0..12)
+    %L - Millisecond of the second (000..999)
+    %m - Month of the year (01..12)
+    %M - Minute of the hour (00..59)
+    %n - Newline (\n)
+    %N - Fractional seconds digits, default is 9 digits (nanosecond)
+            %3N  millisecond (3 digits)
+            %6N  microsecond (6 digits)
+            %9N  nanosecond (9 digits)
+    %p - Meridian indicator (``AM''  or  ``PM'')
+    %P - Meridian indicator (``am''  or  ``pm'')
+    %r - time, 12-hour (same as %I:%M:%S %p)
+    %R - time, 24-hour (%H:%M)
+    %s - Number of seconds since 1970-01-01 00:00:00 UTC.
+    %S - Second of the minute (00..60)
+    %t - Tab character (\t)
+    %T - time, 24-hour (%H:%M:%S)
+    %u - Day of the week as a decimal, Monday being 1. (1..7)
+    %U - Week  number  of the current year,
+            starting with the first Sunday as the first
+            day of the first week (00..53)
+    %v - VMS date (%e-%b-%Y)
+    %V - Week number of year according to ISO 8601 (01..53)
+    %W - Week  number  of the current year,
+            starting with the first Monday as the first
+            day of the first week (00..53)
+    %w - Day of the week (Sunday is 0, 0..6)
+    %x - Preferred representation for the date alone, no time
+    %X - Preferred representation for the time alone, no date
+    %y - Year without a century (00..99)
+    %Y - Year with century
+    %z - Time zone as  hour offset from UTC (e.g. +0900)
+    %Z - Time zone name
+    %% - Literal ``%'' character
+    EOS
+  ) do |arguments|
+
+    # Technically we support two arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "strftime(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    format = arguments[0]
+
+    raise(Puppet::ParseError, 'strftime(): You must provide ' +
+      'format for evaluation') if format.empty?
+
+    # The Time Zone argument is optional ...
+    time_zone = arguments[1] if arguments[1]
+
+    time = Time.new
+
+    # There is probably a better way to handle Time Zone ...
+    if time_zone and not time_zone.empty?
+      original_zone = ENV['TZ']
+
+      local_time = time.clone
+      local_time = local_time.utc
+
+      ENV['TZ'] = time_zone
+
+      time = local_time.localtime
+
+      ENV['TZ'] = original_zone
+    end
+
+    result = time.strftime(format)
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/strip.rb b/modules/stdlib/lib/puppet/parser/functions/strip.rb
new file mode 100644 (file)
index 0000000..5f4630d
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#  strip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:strip, :type => :rvalue, :doc => <<-EOS
+This function removes leading and trailing whitespace from a string or from
+every string inside an array.
+
+*Examples:*
+
+    strip("    aaa   ")
+
+Would result in: "aaa"
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "strip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'strip(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      result = value.collect { |i| i.is_a?(String) ? i.strip : i }
+    else
+      result = value.strip
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/swapcase.rb b/modules/stdlib/lib/puppet/parser/functions/swapcase.rb
new file mode 100644 (file)
index 0000000..b9e6632
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#  swapcase.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:swapcase, :type => :rvalue, :doc => <<-EOS
+This function will swap the existing case of a string.
+
+*Examples:*
+
+    swapcase("aBcD")
+
+Would result in: "AbCd"
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "swapcase(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'swapcase(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.swapcase : i }
+    else
+      result = value.swapcase
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/time.rb b/modules/stdlib/lib/puppet/parser/functions/time.rb
new file mode 100644 (file)
index 0000000..0cddaf8
--- /dev/null
@@ -0,0 +1,49 @@
+#
+# time.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:time, :type => :rvalue, :doc => <<-EOS
+This function will return the current time since epoch as an integer.
+
+*Examples:*
+
+    time()
+
+Will return something like: 1311972653
+    EOS
+  ) do |arguments|
+
+    # The Time Zone argument is optional ...
+    time_zone = arguments[0] if arguments[0]
+
+    if (arguments.size != 0) and (arguments.size != 1) then
+      raise(Puppet::ParseError, "time(): Wrong number of arguments "+
+        "given #{arguments.size} for 0 or 1")
+    end
+
+    time = Time.new
+
+    # There is probably a better way to handle Time Zone ...
+    if time_zone and not time_zone.empty?
+      original_zone = ENV['TZ']
+
+      local_time = time.clone
+      local_time = local_time.utc
+
+      ENV['TZ'] = time_zone
+
+      time = local_time.localtime
+
+      ENV['TZ'] = original_zone
+    end
+
+    # Calling Time#to_i on a receiver changes it.  Trust me I am the Doctor.
+    result = time.strftime('%s')
+    result = result.to_i
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/type.rb b/modules/stdlib/lib/puppet/parser/functions/type.rb
new file mode 100644 (file)
index 0000000..8d85f11
--- /dev/null
@@ -0,0 +1,50 @@
+#
+# type.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:type, :type => :rvalue, :doc => <<-EOS
+Returns the type when passed a variable. Type can be one of:
+
+* string
+* array
+* hash
+* float
+* integer
+* boolean
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "type(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+
+    klass = value.class
+
+    if not [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass)
+      raise(Puppet::ParseError, 'type(): Unknown type')
+    end
+
+    klass = klass.to_s # Ugly ...
+
+    # We note that Integer is the parent to Bignum and Fixnum ...
+    result = case klass
+      when /^(?:Big|Fix)num$/ then 'integer'
+      when /^(?:True|False)Class$/ then 'boolean'
+      else klass
+    end
+
+    if result == "String" then
+      if value == value.to_i.to_s then
+        result = "Integer"
+      elsif value == value.to_f.to_s then
+        result = "Float"
+      end
+    end
+
+    return result.downcase
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/unique.rb b/modules/stdlib/lib/puppet/parser/functions/unique.rb
new file mode 100644 (file)
index 0000000..8844a74
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# unique.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:unique, :type => :rvalue, :doc => <<-EOS
+This function will remove duplicates from strings and arrays.
+
+*Examples:*
+
+    unique("aabbcc")
+
+Will return:
+
+    abc
+
+You can also use this with arrays:
+
+    unique(["a","a","b","b","c","c"])
+
+This returns:
+
+    ["a","b","c"]
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "unique(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'unique(): Requires either ' +
+        'array or string to work with')
+    end
+
+    result = value.clone
+
+    string = value.is_a?(String) ? true : false
+
+    # We turn any string value into an array to be able to shuffle ...
+    result = string ? result.split('') : result
+    result = result.uniq # Remove duplicates ...
+    result = string ? result.join : result
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/upcase.rb b/modules/stdlib/lib/puppet/parser/functions/upcase.rb
new file mode 100644 (file)
index 0000000..fe6cadc
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# upcase.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:upcase, :type => :rvalue, :doc => <<-EOS
+Converts a string or an array of strings to uppercase.
+
+*Examples:*
+
+    upcase("abcd")
+
+Will return:
+
+    ASDF
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "upcase(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    value = arguments[0]
+    klass = value.class
+
+    unless [Array, String].include?(klass)
+      raise(Puppet::ParseError, 'upcase(): Requires either ' +
+        'array or string to work with')
+    end
+
+    if value.is_a?(Array)
+      # Numbers in Puppet are often string-encoded which is troublesome ...
+      result = value.collect { |i| i.is_a?(String) ? i.upcase : i }
+    else
+      result = value.upcase
+    end
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/validate_array.rb b/modules/stdlib/lib/puppet/parser/functions/validate_array.rb
new file mode 100644 (file)
index 0000000..34b5118
--- /dev/null
@@ -0,0 +1,33 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_array, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are array data structures. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $my_array = [ 'one', 'two' ]
+        validate_array($my_array)
+
+    The following values will fail, causing compilation to abort:
+
+        validate_array(true)
+        validate_array('some_string')
+        $undefined = undef
+        validate_array($undefined)
+
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_array(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(Array)
+        raise Puppet::ParseError, ("#{arg.inspect} is not an Array.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb b/modules/stdlib/lib/puppet/parser/functions/validate_bool.rb
new file mode 100644 (file)
index 0000000..62c1d88
--- /dev/null
@@ -0,0 +1,34 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_bool, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are either true or false. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $iamtrue = true
+        validate_bool(true)
+        validate_bool(true, true, false, $iamtrue)
+
+    The following values will fail, causing compilation to abort:
+
+        $some_array = [ true ]
+        validate_bool("false")
+        validate_bool("true")
+        validate_bool($some_array)
+
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_bool(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless (arg.is_a?(TrueClass) || arg.is_a?(FalseClass))
+        raise Puppet::ParseError, ("#{arg.inspect} is not a boolean.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb b/modules/stdlib/lib/puppet/parser/functions/validate_hash.rb
new file mode 100644 (file)
index 0000000..9bdd543
--- /dev/null
@@ -0,0 +1,33 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_hash, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are hash data structures. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $my_hash = { 'one' => 'two' }
+        validate_hash($my_hash)
+
+    The following values will fail, causing compilation to abort:
+
+        validate_hash(true)
+        validate_hash('some_string')
+        $undefined = undef
+        validate_hash($undefined)
+
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_hash(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(Hash)
+        raise Puppet::ParseError, ("#{arg.inspect} is not a Hash.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/validate_re.rb b/modules/stdlib/lib/puppet/parser/functions/validate_re.rb
new file mode 100644 (file)
index 0000000..8033ca3
--- /dev/null
@@ -0,0 +1,33 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args|
+    Perform simple validation of a string against one or more regular
+    expressions. The first argument of this function should be a string to
+    test, and the second argument should be a stringified regular expression
+    (without the // delimiters) or an array of regular expressions.  If none
+    of the regular expressions match the string passed in, compilation will
+    abort with a parse error.
+
+    The following strings will validate against the regular expressions:
+
+        validate_re('one', '^one$')
+        validate_re('one', [ '^one', '^two' ])
+
+    The following strings will fail to validate, causing compilation to abort:
+
+        validate_re('one', [ '^two', '^three' ])
+
+    ENDHEREDOC
+    if args.length != 2 then
+      raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2)")
+    end
+
+    msg = "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
+
+    raise Puppet::ParseError, (msg) unless args[1].any? do |re_str|
+      args[0] =~ Regexp.compile(re_str)
+    end
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/validate_string.rb b/modules/stdlib/lib/puppet/parser/functions/validate_string.rb
new file mode 100644 (file)
index 0000000..e667794
--- /dev/null
@@ -0,0 +1,33 @@
+module Puppet::Parser::Functions
+
+  newfunction(:validate_string, :doc => <<-'ENDHEREDOC') do |args|
+    Validate that all passed values are string data structures. Abort catalog
+    compilation if any value fails this check.
+
+    The following values will pass:
+
+        $my_string = "one two"
+        validate_string($my_string, 'three')
+
+    The following values will fail, causing compilation to abort:
+
+        validate_string(true)
+        validate_string([ 'some', 'array' ])
+        $undefined = undef
+        validate_string($undefined)
+
+    ENDHEREDOC
+
+    unless args.length > 0 then
+      raise Puppet::ParseError, ("validate_string(): wrong number of arguments (#{args.length}; must be > 0)")
+    end
+
+    args.each do |arg|
+      unless arg.is_a?(String)
+        raise Puppet::ParseError, ("#{arg.inspect} is not a string.  It looks to be a #{arg.class}")
+      end
+    end
+
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/parser/functions/values.rb b/modules/stdlib/lib/puppet/parser/functions/values.rb
new file mode 100644 (file)
index 0000000..1606756
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# values.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:values, :type => :rvalue, :doc => <<-EOS
+When given a hash this function will return the values of that hash.
+
+*Examples:*
+
+    $hash = {
+      'a' => 1,
+      'b' => 2,
+      'c' => 3,
+    }
+    values($hash)
+
+This example would return:
+
+    [1,2,3]
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "values(): Wrong number of arguments " +
+      "given (#{arguments.size} for 1)") if arguments.size < 1
+
+    hash = arguments[0]
+
+    unless hash.is_a?(Hash)
+      raise(Puppet::ParseError, 'values(): Requires hash to work with')
+    end
+
+    result = hash.values
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/values_at.rb b/modules/stdlib/lib/puppet/parser/functions/values_at.rb
new file mode 100644 (file)
index 0000000..d3e69d9
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# values_at.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:values_at, :type => :rvalue, :doc => <<-EOS
+Finds value inside an array based on location.
+
+The first argument is the array you want to analyze, and the second element can
+be a combination of:
+
+* A single numeric index
+* A range in the form of 'start-stop' (eg. 4-9)
+* An array combining the above
+
+*Examples*:
+
+    values_at(['a','b','c'], 2)
+
+Would return ['c'].
+
+    values_at(['a','b','c'], ["0-1"])
+
+Would return ['a','b'].
+
+    values_at(['a','b','c','d','e'], [0, "2-3"])
+
+Would return ['a','c','d'].
+    EOS
+  ) do |arguments|
+
+    raise(Puppet::ParseError, "values_at(): Wrong number of " +
+      "arguments given (#{arguments.size} for 2)") if arguments.size < 2
+
+    array = arguments.shift
+
+    unless array.is_a?(Array)
+      raise(Puppet::ParseError, 'values_at(): Requires array to work with')
+    end
+
+    indices = [arguments.shift].flatten() # Get them all ... Pokemon ...
+
+    if not indices or indices.empty?
+      raise(Puppet::ParseError, 'values_at(): You must provide ' +
+        'at least one positive index to collect')
+    end
+
+    result       = []
+    indices_list = []
+
+    indices.each do |i|
+      if m = i.match(/^(\d+)(\.\.\.?|\-)(\d+)$/)
+        start = m[1].to_i
+        stop  = m[3].to_i
+
+        type = m[2]
+
+        if start > stop
+          raise(Puppet::ParseError, 'values_at(): Stop index in ' +
+            'given indices range is smaller than the start index')
+        elsif stop > array.size - 1 # First element is at index 0 is it not?
+          raise(Puppet::ParseError, 'values_at(): Stop index in ' +
+            'given indices range exceeds array size')
+        end
+
+        range = case type
+          when /^(\.\.|\-)$/ then (start .. stop)
+          when /^(\.\.\.)$/  then (start ... stop) # Exclusive of last element ...
+        end
+
+        range.each { |i| indices_list << i.to_i }
+      else
+        # Only positive numbers allowed in this case ...
+        if not i.match(/^\d+$/)
+          raise(Puppet::ParseError, 'values_at(): Unknown format ' +
+            'of given index')
+        end
+
+        # In Puppet numbers are often string-encoded ...
+        i = i.to_i
+
+        if i > array.size - 1 # Same story.  First element is at index 0 ...
+          raise(Puppet::ParseError, 'values_at(): Given index ' +
+            'exceeds array size')
+        end
+
+        indices_list << i
+      end
+    end
+
+    # We remove nil values as they make no sense in Puppet DSL ...
+    result = indices_list.collect { |i| array[i] }.compact
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/parser/functions/zip.rb b/modules/stdlib/lib/puppet/parser/functions/zip.rb
new file mode 100644 (file)
index 0000000..2b56e9c
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# zip.rb
+#
+
+module Puppet::Parser::Functions
+  newfunction(:zip, :type => :rvalue, :doc => <<-EOS
+Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments.
+
+*Example:*
+
+    zip(['1','2','3'],['4','5','6'])
+
+Would result in:
+
+    ["1", "4"], ["2", "5"], ["3", "6"]
+    EOS
+  ) do |arguments|
+
+    # Technically we support three arguments but only first is mandatory ...
+    raise(Puppet::ParseError, "zip(): Wrong number of arguments " +
+      "given (#{arguments.size} for 2)") if arguments.size < 2
+
+    a = arguments[0]
+    b = arguments[1]
+
+    unless a.is_a?(Array) and b.is_a?(Array)
+      raise(Puppet::ParseError, 'zip(): Requires array to work with')
+    end
+
+    flatten = arguments[2] if arguments[2]
+
+    if flatten
+      klass = flatten.class
+
+      # We can have either true or false, or string which resembles boolean ...
+      unless [FalseClass, TrueClass, String].include?(klass)
+        raise(Puppet::ParseError, 'zip(): Requires either ' +
+          'boolean or string to work with')
+      end
+
+      if flatten.is_a?(String)
+        # We consider all the yes, no, y, n and so on too ...
+        flatten = case flatten
+          #
+          # This is how undef looks like in Puppet ...
+          # We yield false in this case.
+          #
+          when /^$/, '' then false # Empty string will be false ...
+          when /^(1|t|y|true|yes)$/  then true
+          when /^(0|f|n|false|no)$/  then false
+          when /^(undef|undefined)$/ then false # This is not likely to happen ...
+          else
+            raise(Puppet::ParseError, 'zip(): Unknown type of boolean given')
+        end
+      end
+    end
+
+    result = a.zip(b)
+    result = flatten ? result.flatten : result
+
+    return result
+  end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/modules/stdlib/lib/puppet/provider/file_line/ruby.rb b/modules/stdlib/lib/puppet/provider/file_line/ruby.rb
new file mode 100644 (file)
index 0000000..63bbd8e
--- /dev/null
@@ -0,0 +1,15 @@
+Puppet::Type.type(:file_line).provide(:ruby) do
+
+  def exists?
+    File.readlines(resource[:path]).find do |line|
+      line.chomp == resource[:line].chomp
+    end
+  end
+
+  def create
+    File.open(resource[:path], 'a') do |fh|
+      fh.puts resource[:line]
+    end
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/type/anchor.rb b/modules/stdlib/lib/puppet/type/anchor.rb
new file mode 100644 (file)
index 0000000..6b81732
--- /dev/null
@@ -0,0 +1,41 @@
+Puppet::Type.newtype(:anchor) do
+  desc <<-'ENDOFDESC'
+  A simple resource type intended to be used as an anchor in a composite class.
+
+  In Puppet 2.6, when a class declares another class, the resources in the
+  interior class are not contained by the exterior class. This interacts badly
+  with the pattern of composing complex modules from smaller classes, as it
+  makes it impossible for end users to specify order relationships between the
+  exterior class and other modules.
+
+  The anchor type lets you work around this. By sandwiching any interior
+  classes between two no-op resources that _are_ contained by the exterior
+  class, you can ensure that all resources in the module are contained.
+
+      class ntp {
+        # These classes will have the correct order relationship with each
+        # other. However, without anchors, they won't have any order
+        # relationship to Class['ntp'].
+        class { 'ntp::package': }
+        -> class { 'ntp::config': }
+        -> class { 'ntp::service': }
+
+        # These two resources "anchor" the composed classes within the ntp
+        # class.
+        anchor { 'ntp::begin': } -> Class['ntp::package']
+        Class['ntp::service']    -> anchor { 'ntp::end': }
+      }
+
+  This allows the end user of the ntp module to establish require and before
+  relationships with Class['ntp']:
+
+      class { 'ntp': } -> class { 'mcollective': }
+      class { 'mcollective': } -> class { 'ntp': }
+
+  ENDOFDESC
+
+  newparam :name do
+    desc "The name of the anchor resource."
+  end
+
+end
diff --git a/modules/stdlib/lib/puppet/type/file_line.rb b/modules/stdlib/lib/puppet/type/file_line.rb
new file mode 100644 (file)
index 0000000..8b45897
--- /dev/null
@@ -0,0 +1,55 @@
+Puppet::Type.newtype(:file_line) do
+
+  desc <<-EOT
+    Ensures that a given line is contained within a file.  The implementation
+    matches the full line, including whitespace at the beginning and end.  If
+    the line is not contained in the given file, Puppet will add the line to
+    ensure the desired state.  Multiple resources may be declared to manage
+    multiple lines in the same file.
+
+    Example:
+
+        file_line { 'sudo_rule':
+          path => '/etc/sudoers',
+          line => '%sudo ALL=(ALL) ALL',
+        }
+        file_line { 'sudo_rule_nopw':
+          path => '/etc/sudoers',
+          line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
+        }
+
+    In this example, Puppet will ensure both of the specified lines are
+    contained in the file /etc/sudoers.
+
+  EOT
+
+  ensurable do
+    defaultto :present
+    newvalue(:present) do
+      provider.create
+    end
+  end
+
+  newparam(:name, :namevar => true) do
+    desc 'arbitrary name used as identity'
+  end
+
+  newparam(:line) do
+    desc 'The line to be appended to the path.'
+  end
+
+  newparam(:path) do
+    desc 'File to possibly append a line to.'
+    validate do |value|
+      unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
+        raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
+      end
+    end
+  end
+
+  validate do
+    unless self[:line] and self[:path]
+      raise(Puppet::Error, "Both line and path are required attributes")
+    end
+  end
+end
diff --git a/modules/stdlib/manifests/init.pp b/modules/stdlib/manifests/init.pp
new file mode 100644 (file)
index 0000000..d8cea3c
--- /dev/null
@@ -0,0 +1,20 @@
+# Class: stdlib
+#
+# This module manages stdlib. Most of stdlib's features are automatically
+# loaded by Puppet, but this class should be declared in order to use the
+# standardized run stages.
+#
+# Parameters: none
+#
+# Actions:
+#
+#   Declares all other classes in the stdlib module. Currently, this consists
+#   of stdlib::stages.
+#
+# Requires: nothing
+#
+class stdlib {
+
+       class { 'stdlib::stages': }
+
+}
diff --git a/modules/stdlib/manifests/stages.pp b/modules/stdlib/manifests/stages.pp
new file mode 100644 (file)
index 0000000..8ac7c5b
--- /dev/null
@@ -0,0 +1,43 @@
+# Class: stdlib::stages
+#
+# This class manages a standard set of run stages for Puppet. It is managed by
+# the stdlib class, and should not be declared independently.
+#
+# The high level stages are (in order):
+#
+#  * setup
+#  * main
+#  * runtime
+#  * setup_infra
+#  * deploy_infra
+#  * setup_app
+#  * deploy_app
+#  * deploy
+#
+# Parameters: none
+#
+# Actions:
+#
+#   Declares various run-stages for deploying infrastructure,
+#   language runtimes, and application layers.
+#
+# Requires: nothing
+#
+# Sample Usage:
+#
+#  node default {
+#    include stdlib
+#    class { java: stage => 'runtime' }
+#  }
+#
+class stdlib::stages {
+
+       stage { 'setup':  before => Stage['main'] }
+       stage { 'runtime': require => Stage['main'] }
+       -> stage { 'setup_infra': }
+       -> stage { 'deploy_infra': }
+       -> stage { 'setup_app': }
+       -> stage { 'deploy_app': }
+       -> stage { 'deploy': }
+
+}
diff --git a/modules/stdlib/metadata.json b/modules/stdlib/metadata.json
new file mode 100644 (file)
index 0000000..c4d4979
--- /dev/null
@@ -0,0 +1,198 @@
+{
+  "version": "2.2.1",
+  "dependencies": [
+
+  ],
+  "description": "Standard Library for Puppet Modules",
+  "types": [
+    {
+      "parameters": [
+        {
+          "doc": "The name of the anchor resource.",
+          "name": "name"
+        }
+      ],
+      "properties": [
+
+      ],
+      "doc": "  A simple resource type intended to be used as an anchor in a composite class.\n\n  In Puppet 2.6, when a class declares another class, the resources in the\n  interior class are not contained by the exterior class. This interacts badly\n  with the pattern of composing complex modules from smaller classes, as it\n  makes it impossible for end users to specify order relationships between the\n  exterior class and other modules.\n\n  The anchor type lets you work around this. By sandwiching any interior\n  classes between two no-op resources that _are_ contained by the exterior\n  class, you can ensure that all resources in the module are contained.\n\n      class ntp {\n        # These classes will have the correct order relationship with each\n        # other. However, without anchors, they won't have any order\n        # relationship to Class['ntp'].\n        class { 'ntp::package': }\n        -> class { 'ntp::config': }\n        -> class { 'ntp::service': }\n\n        # These two resources \"anchor\" the composed classes within the ntp\n        # class.\n        anchor { 'ntp::begin': } -> Class['ntp::package']\n        Class['ntp::service']    -> anchor { 'ntp::end': }\n      }\n\n  This allows the end user of the ntp module to establish require and before\n  relationships with Class['ntp']:\n\n      class { 'ntp': } -> class { 'mcollective': }\n      class { 'mcollective': } -> class { 'ntp': }\n\n",
+      "name": "anchor"
+    },
+    {
+      "parameters": [
+        {
+          "doc": "arbitrary name used as identity",
+          "name": "name"
+        },
+        {
+          "doc": "The line to be appended to the path.",
+          "name": "line"
+        },
+        {
+          "doc": "File to possibly append a line to.",
+          "name": "path"
+        }
+      ],
+      "providers": [
+        {
+          "doc": "",
+          "name": "ruby"
+        }
+      ],
+      "properties": [
+        {
+          "doc": "  Valid values are `present`.",
+          "name": "ensure"
+        }
+      ],
+      "doc": "    Ensures that a given line is contained within a file.  The implementation\n    matches the full line, including whitespace at the beginning and end.  If\n    the line is not contained in the given file, Puppet will add the line to\n    ensure the desired state.  Multiple resources may be declared to manage\n    multiple lines in the same file.\n\n    Example:\n\n        file_line { 'sudo_rule':\n          path => '/etc/sudoers',\n          line => '%sudo ALL=(ALL) ALL',\n        }\n        file_line { 'sudo_rule_nopw':\n          path => '/etc/sudoers',\n          line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',\n        }\n\n    In this example, Puppet will ensure both of the specified lines are\n    contained in the file /etc/sudoers.\n\n",
+      "name": "file_line"
+    }
+  ],
+  "summary": "Puppet Module Standard Library",
+  "source": "git://github.com/puppetlabs/puppetlabs-stdlib",
+  "checksums": {
+    "spec/unit/puppet/parser/functions/is_mac_address_spec.rb": "38f1dc844e76ab1e653578d7de612377",
+    "spec/unit/puppet/parser/functions/type_spec.rb": "750538a9811f9ecdb435f4f3949916d6",
+    "lib/puppet/parser/functions/upcase.rb": "a5744a74577cfa136fca2835e75888d3",
+    "spec/unit/puppet/parser/functions/swapcase_spec.rb": "1752f73dedae50c90372f50364dd9649",
+    "lib/puppet/parser/functions/swapcase.rb": "4902f38f0b9292afec66d40fee4b02ec",
+    "spec/unit/puppet/parser/functions/prefix_spec.rb": "2631a72780efb517b19fbb71c058b388",
+    "spec/lib/puppet_spec/matchers.rb": "8e77dc7317de7fc2ff289fb716623b6c",
+    "spec/unit/puppet/provider/file_line/ruby_spec.rb": "baaf1e9f1679bb813ef6a117c4b0f1ec",
+    "spec/unit/puppet/parser/functions/squeeze_spec.rb": "c8656b5502127d418b4c72dcb5247550",
+    "lib/puppet/parser/functions/delete_at.rb": "6bc24b79390d463d8be95396c963381a",
+    "spec/unit/puppet/parser/functions/member_spec.rb": "16829dd5145e5e29b899885a0be6ce90",
+    "lib/puppet/parser/functions/is_mac_address.rb": "288bd4b38d4df42a83681f13e7eaaee0",
+    "lib/puppet/parser/functions/abs.rb": "c2f2c4a62a56e7adbf5cf0b292e081fc",
+    "lib/puppet/parser/functions/strftime.rb": "e02e01a598ca5d7d6eee0ba22440304a",
+    "spec/unit/puppet/parser/functions/hash_spec.rb": "546657ec64d425d6db4bec068c7fa8ab",
+    "lib/puppet/parser/functions/is_hash.rb": "8c7d9a05084dab0389d1b779c8a05b1a",
+    "lib/puppet/parser/functions/is_integer.rb": "6520458000b349f1c7ba7c9ed382ae0b",
+    "spec/unit/puppet/parser/functions/strip_spec.rb": "4648e46ecec2f272022f1397268b7d59",
+    "lib/puppet/type/anchor.rb": "cc1da7acfe1259d5b86a64e2dea42c34",
+    "spec/unit/puppet/parser/functions/getvar_spec.rb": "99880c2d16b329c872d22fe15bb05293",
+    "CHANGELOG": "0c7dcc8567ac920570b91e2e8764442a",
+    "lib/puppet/parser/functions/values_at.rb": "094ac110ce9f7a5b16d0c80a0cf2243c",
+    "spec/unit/puppet/parser/functions/shuffle_spec.rb": "1bf72145bf39edb1c6cd83df3b0b978a",
+    "lib/puppet/parser/functions/validate_hash.rb": "e9cfaca68751524efe16ecf2f958a9a0",
+    "spec/unit/puppet/parser/functions/has_key_spec.rb": "3ecc38a150d685db2b766c4d91ac77b4",
+    "spec/unit/puppet/parser/functions/abs_spec.rb": "7241e4f4762b1fa67408e178c7965b29",
+    "spec/spec_helper.rb": "fb1c0bd01f784cd326c2945fdf201cf8",
+    "lib/puppet/parser/functions/is_domain_name.rb": "4ddc0d7ff8855610660be9bf0eaf6382",
+    "spec/watchr.rb": "b588ddf9ef1c19ab97aa892cc776da73",
+    "lib/puppet/parser/functions/unique.rb": "217ccce6d23235af92923f50f8556963",
+    "lib/puppet/parser/functions/validate_bool.rb": "4ddffdf5954b15863d18f392950b88f4",
+    "lib/puppet/parser/functions/keys.rb": "eb6ac815ea14fbf423580ed903ef7bad",
+    "lib/puppet/parser/functions/validate_re.rb": "57bc0a1e1cc63eb8c9da801141765db7",
+    "spec/unit/puppet/parser/functions/is_string_spec.rb": "5c2387aa8b4cc98ecb5cf17df2b59137",
+    "spec/unit/puppet/parser/functions/unique_spec.rb": "0822a1eda9e3bb86cb58e66effb7d14c",
+    "spec/unit/puppet/parser/functions/str2bool_spec.rb": "fc3aaa818f0430d141e6dfda4a759148",
+    "spec/unit/facter/root_home_spec.rb": "bed727086f867d7c15a57324c636fe67",
+    "Modulefile": "558bf4531f74fc69c30284d05fa33275",
+    "lib/puppet/parser/functions/reverse.rb": "1386371c0f5301055fdf99079e862b3e",
+    "spec/unit/puppet/parser/functions/parsejson_spec.rb": "88b0f9b3050d72757f6c7848c9f7e14b",
+    "lib/puppet/parser/functions/values.rb": "066a6e4170e5034edb9a80463dff2bb5",
+    "lib/puppet/parser/functions/sort.rb": "504b033b438461ca4f9764feeb017833",
+    "lib/puppet/parser/functions/is_array.rb": "875ca4356cb0d7a10606fb146b4a3d11",
+    "lib/puppet/parser/functions/is_numeric.rb": "6283dd52935fb1aba41958e50c85b1ed",
+    "spec/unit/puppet/parser/functions/is_array_spec.rb": "5f1698b09f52c26f7754164525cf98af",
+    "lib/puppet/parser/functions/flatten.rb": "251d63696564254d41742ecbfbfcb9fd",
+    "lib/puppet/parser/functions/lstrip.rb": "210b103f78622e099f91cc2956b6f741",
+    "lib/puppet/parser/functions/hash.rb": "75fd86c01d5b1e50be1bc8b22d3d0a61",
+    "spec/unit/puppet/parser/functions/values_at_spec.rb": "c89e10ce6e1833c08813e747f4e4f0b3",
+    "spec/unit/puppet/parser/functions/sort_spec.rb": "3de167aceb5515bb183283d259065bf6",
+    "spec/unit/puppet/parser/functions/join_spec.rb": "c5ef77cddae27594a042a5dec43cd5d7",
+    "spec/unit/puppet/parser/functions/downcase_spec.rb": "465b4dc34a6d8b3f517fa4dfb6279999",
+    "lib/puppet/parser/functions/squeeze.rb": "ae5aafb7478cced0ba0c23856e45cec5",
+    "lib/puppet/parser/functions/capitalize.rb": "14481fc8c7c83fe002066ebcf6722f17",
+    "RELEASE_PROCESS.markdown": "e2d2140c3719f692899f73a754175d78",
+    "README.markdown": "c45c5ea68ce337f77addf217de9e8c9d",
+    "spec/monkey_patches/publicize_methods.rb": "1b03a4af94f7dac35f7c2809caf372ca",
+    "tests/init.pp": "1d98070412c76824e66db4b7eb74d433",
+    "spec/unit/puppet/parser/functions/is_numeric_spec.rb": "b123634167033ca7d40e2416a933abf0",
+    "lib/puppet/parser/functions/range.rb": "b9bab398bbaeb01b876674a8fbae9d67",
+    "lib/facter/facter_dot_d.rb": "bfe4cd4cfbb9e7f57e28f932c7d76c6e",
+    "lib/puppet/parser/functions/is_ip_address.rb": "a53f6e3a5855954148230846ccb3e04d",
+    "lib/puppet/parser/functions/loadyaml.rb": "2b912f257aa078e376d3b3f6a86c2a00",
+    "lib/puppet/parser/functions/prefix.rb": "6a2d86233c9435afc1738f60a0c34576",
+    "lib/facter/root_home.rb": "20c3734960a4be1693f1bec828facba4",
+    "spec/monkey_patches/alias_should_to_must.rb": "7cd4065c63f06f1ab3aaa1c5f92af947",
+    "lib/puppet/parser/functions/parseyaml.rb": "6cfee471d287c8d110a3629a9ac31b69",
+    "spec/unit/puppet/parser/functions/values_spec.rb": "591d6ac1a26e163f25dd88887e7a7e31",
+    "lib/puppet/parser/functions/type.rb": "62f914d6c90662aaae40c5539701be60",
+    "spec/unit/puppet/parser/functions/delete_at_spec.rb": "bbfdea3b0d6e8b898480095ab6250910",
+    "lib/puppet/parser/functions/str2bool.rb": "846b49d623cb847c1870d7ac4a6bedf3",
+    "lib/puppet/parser/functions/zip.rb": "a80782461ed9465f0cd0c010936f1855",
+    "spec/unit/puppet/parser/functions/capitalize_spec.rb": "ae5454a82cf5dcd3c24de4fa43ab7ef9",
+    "spec/unit/puppet/parser/functions/num2bool_spec.rb": "31df56ced10757974c2ebb68e9d7e962",
+    "spec/unit/puppet/parser/functions/rstrip_spec.rb": "2e1871218bf5ed32d9c900adc044db11",
+    "spec/unit/puppet/parser/functions/is_hash_spec.rb": "caafa394659af9013bf78578dca155ec",
+    "tests/file_line.pp": "67727539aa7b7dd76f06626fe734f7f7",
+    "spec/unit/puppet/parser/functions/strftime_spec.rb": "65f969afd72286b7687efbf5059a45fa",
+    "lib/puppet/parser/functions/grep.rb": "5682995af458b05f3b53dd794c4bf896",
+    "lib/puppet/type/file_line.rb": "eb3212776b27bb65d65eea36430d20c8",
+    "spec/unit/puppet/parser/functions/chomp_spec.rb": "4fbc9dfb1406b4f9efde5911ca94a2fd",
+    "spec/unit/puppet/parser/functions/range_spec.rb": "49df156b67467367f8bdd15a1849f6c8",
+    "spec/unit/puppet/parser/functions/empty_spec.rb": "92faf7b9f3d7f7ea70cfdd4df368cea5",
+    "spec/unit/puppet/parser/functions/validate_hash_spec.rb": "9d04db99b341c8e8a96a2e3594e15e09",
+    "lib/puppet/parser/functions/getvar.rb": "10bf744212947bc6a7bfd2c9836dbd23",
+    "lib/puppet/parser/functions/chop.rb": "4cc840d63ec172d8533a613676391d39",
+    "lib/puppet/parser/functions/bool2num.rb": "8e627eee990e811e35e7e838c586bd77",
+    "lib/puppet/parser/functions/validate_array.rb": "72b29289b8af1cfc3662ef9be78911b8",
+    "lib/puppet/parser/functions/validate_string.rb": "6afcbc51f83f0714348b8d61e06ea7eb",
+    "lib/puppet/parser/functions/time.rb": "08d88d52abd1e230e3a2f82107545d48",
+    "spec/unit/puppet/parser/functions/grep_spec.rb": "ac61b94f87f28d6271e83b7fb580e82a",
+    "spec/unit/puppet/parser/functions/size_spec.rb": "8bc0fe162722361e581110a9145dccc1",
+    "spec/unit/puppet/parser/functions/merge_spec.rb": "169ba6a18997b25250e893e07920e5eb",
+    "lib/puppet/parser/functions/delete.rb": "4a3c82d0ed8ea4c953658efdd06fe7c9",
+    "spec/unit/puppet/parser/functions/reverse_spec.rb": "6b8eaec24fe50ad337f16c9e1869dbe2",
+    "spec/unit/puppet/parser/functions/parseyaml_spec.rb": "c5e1b52e9cca526bd67c1d05507f03de",
+    "spec/unit/puppet/parser/functions/is_ip_address_spec.rb": "f07dff16f07bc66aeff3dbd159e628bb",
+    "lib/puppet/parser/functions/member.rb": "541e67d06bc4155e79b00843a125e9bc",
+    "spec/lib/puppet_spec/verbose.rb": "2e0e0e74f2c5ec0408d455e773755bf9",
+    "spec/unit/puppet/parser/functions/flatten_spec.rb": "ba9feb890d222cbb3cdbe44f60fc34a5",
+    "lib/puppet/parser/functions/parsejson.rb": "e7f968c34928107b84cd0860daf50ab1",
+    "lib/puppet/parser/functions/is_float.rb": "491937483b14fbe2594a6e0e9af6acf9",
+    "lib/puppet/parser/functions/rstrip.rb": "8a0d69876bdbc88a2054ba41c9c38961",
+    "spec/unit/puppet/parser/functions/lstrip_spec.rb": "77087828a0d1ae7ad2131019868a7d9b",
+    "lib/puppet/parser/functions/num2bool.rb": "dbdc81982468ebb8ac24ab78d7097ad3",
+    "spec/unit/puppet/parser/functions/is_float_spec.rb": "72202b9e106f0d7ddc4feb055e4d6ee4",
+    "spec/unit/puppet/parser/functions/zip_spec.rb": "5668bb74eba13a03c5ccbab85698502a",
+    "lib/puppet/parser/functions/join.rb": "b28087823456ca5cf943de4a233ac77f",
+    "spec/unit/puppet/type/file_line_spec.rb": "d91574136b6078f78a00ecc48f1e5655",
+    "spec/unit/puppet/parser/functions/validate_bool_spec.rb": "7de673f1da799e5cf4ce4203eac18a93",
+    "Rakefile": "1783f110354faf65bae54d394b639671",
+    "spec/unit/puppet/type/anchor_spec.rb": "a5478a72a7fab2d215f39982a9230c18",
+    "spec/unit/puppet/parser/functions/chop_spec.rb": "53430bd3884404952f3f7f634dfb743a",
+    "spec/unit/puppet/parser/functions/time_spec.rb": "9f0c4e73088ee2db967ce6f4291e60f5",
+    "lib/puppet/parser/functions/strip.rb": "273d547c7b05c0598556464dfd12f5fd",
+    "manifests/init.pp": "f2ba5f36e7227ed87bbb69034fc0de8b",
+    "spec/lib/puppet_spec/files.rb": "34e40f4dcdc90d1138a471d883c33d79",
+    "spec/unit/puppet/parser/functions/is_integer_spec.rb": "6d648bbaeac166babe835f1cec23070a",
+    "spec/lib/puppet_spec/fixtures.rb": "147446d18612c8395ac65be10b1cd9ab",
+    "spec/unit/puppet/parser/functions/delete_spec.rb": "7d6fa7f049f75b4b356ee3e6b1ad8d7a",
+    "lib/puppet/parser/functions/is_string.rb": "2bd9a652bbb2668323eee6c57729ff64",
+    "spec/unit/puppet/parser/functions/keys_spec.rb": "4d548018ab0a1e329285db8af92ae6a7",
+    "lib/puppet/parser/functions/shuffle.rb": "6445e6b4dc62c37b184a60eeaf34414b",
+    "spec/unit/puppet/parser/functions/bool2num_spec.rb": "7d465ea336aebb06d7aaff10862bb1bf",
+    "lib/puppet/parser/functions/downcase.rb": "9204a04c2a168375a38d502db8811bbe",
+    "LICENSE": "38a048b9d82e713d4e1b2573e370a756",
+    "spec/unit/puppet/parser/functions/is_domain_name_spec.rb": "a6b6bee60461a0fe51bb18e867db2337",
+    "lib/puppet/parser/functions/chomp.rb": "7040b3348d2f770f265cf4c8c25c51c5",
+    "lib/puppet/parser/functions/size.rb": "8972d48c0f9e487d659bd7326b40b642",
+    "manifests/stages.pp": "cc6ed1751d334b0ea278c0335c7f0b5a",
+    "spec/unit/puppet/parser/functions/validate_array_spec.rb": "9ff22cd8e660e244abac8993fc45037b",
+    "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c",
+    "lib/puppet/parser/functions/merge.rb": "52281fe881b762e2adfef20f58dc4180",
+    "lib/puppet/parser/functions/has_key.rb": "7cd9728c38f0b0065f832dabd62b0e7e",
+    "lib/puppet/parser/functions/empty.rb": "ae92905c9d94ddca30bf56b7b1dabedf",
+    "spec/unit/puppet/parser/functions/upcase_spec.rb": "aad3aa16fc8b930ca5fa53781f18be89",
+    "lib/puppet/provider/file_line/ruby.rb": "069761f23f95c078821024da9d916db4",
+    "spec/unit/puppet/parser/functions/validate_string_spec.rb": "2886898011792249e80837c6791639ba"
+  },
+  "author": "puppetlabs",
+  "project_page": "https://github.com/puppetlabs/puppetlabs-stdlib",
+  "name": "puppetlabs-stdlib",
+  "license": "Apache 2.0"
+}
\ No newline at end of file
diff --git a/modules/stdlib/spec/lib/puppet_spec/files.rb b/modules/stdlib/spec/lib/puppet_spec/files.rb
new file mode 100755 (executable)
index 0000000..30fb4fc
--- /dev/null
@@ -0,0 +1,53 @@
+require 'fileutils'
+require 'tempfile'
+
+# A support module for testing files.
+module PuppetSpec::Files
+  # This code exists only to support tests that run as root, pretty much.
+  # Once they have finally been eliminated this can all go... --daniel 2011-04-08
+  if Puppet.features.posix? then
+    def self.in_tmp(path)
+      path =~ /^\/tmp/ or path =~ /^\/var\/folders/
+    end
+  elsif Puppet.features.microsoft_windows?
+    def self.in_tmp(path)
+      tempdir = File.expand_path(File.join(Dir::LOCAL_APPDATA, "Temp"))
+      path =~ /^#{tempdir}/
+    end
+  else
+    fail "Help! Can't find in_tmp for this platform"
+  end
+
+  def self.cleanup
+    $global_tempfiles ||= []
+    while path = $global_tempfiles.pop do
+      fail "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path)
+
+      begin
+        FileUtils.rm_r path, :secure => true
+      rescue Errno::ENOENT
+        # nothing to do
+      end
+    end
+  end
+
+  def tmpfile(name)
+    # Generate a temporary file, just for the name...
+    source = Tempfile.new(name)
+    path = source.path
+    source.close!
+
+    # ...record it for cleanup,
+    $global_tempfiles ||= []
+    $global_tempfiles << File.expand_path(path)
+
+    # ...and bam.
+    path
+  end
+
+  def tmpdir(name)
+    path = tmpfile(name)
+    FileUtils.mkdir_p(path)
+    path
+  end
+end
diff --git a/modules/stdlib/spec/lib/puppet_spec/fixtures.rb b/modules/stdlib/spec/lib/puppet_spec/fixtures.rb
new file mode 100755 (executable)
index 0000000..7f6bc2a
--- /dev/null
@@ -0,0 +1,28 @@
+module PuppetSpec::Fixtures
+  def fixtures(*rest)
+    File.join(PuppetSpec::FIXTURE_DIR, *rest)
+  end
+  def my_fixture_dir
+    callers = caller
+    while line = callers.shift do
+      next unless found = line.match(%r{/spec/(.*)_spec\.rb:})
+      return fixtures(found[1])
+    end
+    fail "sorry, I couldn't work out your path from the caller stack!"
+  end
+  def my_fixture(name)
+    file = File.join(my_fixture_dir, name)
+    unless File.readable? file then
+      fail Puppet::DevError, "fixture '#{name}' for #{my_fixture_dir} is not readable"
+    end
+    return file
+  end
+  def my_fixtures(glob = '*', flags = 0)
+    files = Dir.glob(File.join(my_fixture_dir, glob), flags)
+    unless files.length > 0 then
+      fail Puppet::DevError, "fixture '#{glob}' for #{my_fixture_dir} had no files!"
+    end
+    block_given? and files.each do |file| yield file end
+    files
+  end
+end
diff --git a/modules/stdlib/spec/lib/puppet_spec/matchers.rb b/modules/stdlib/spec/lib/puppet_spec/matchers.rb
new file mode 100644 (file)
index 0000000..77f5803
--- /dev/null
@@ -0,0 +1,87 @@
+require 'stringio'
+
+########################################################################
+# Backward compatibility for Jenkins outdated environment.
+module RSpec
+  module Matchers
+    module BlockAliases
+      alias_method :to,     :should      unless method_defined? :to
+      alias_method :to_not, :should_not  unless method_defined? :to_not
+      alias_method :not_to, :should_not  unless method_defined? :not_to
+    end
+  end
+end
+
+
+########################################################################
+# Custom matchers...
+RSpec::Matchers.define :have_matching_element do |expected|
+  match do |actual|
+    actual.any? { |item| item =~ expected }
+  end
+end
+
+
+RSpec::Matchers.define :exit_with do |expected|
+  actual = nil
+  match do |block|
+    begin
+      block.call
+    rescue SystemExit => e
+      actual = e.status
+    end
+    actual and actual == expected
+  end
+  failure_message_for_should do |block|
+    "expected exit with code #{expected} but " +
+      (actual.nil? ? " exit was not called" : "we exited with #{actual} instead")
+  end
+  failure_message_for_should_not do |block|
+    "expected that exit would not be called with #{expected}"
+  end
+  description do
+    "expect exit with #{expected}"
+  end
+end
+
+
+RSpec::Matchers.define :have_printed do |expected|
+  match do |block|
+    $stderr = $stdout = StringIO.new
+
+    begin
+      block.call
+    ensure
+      $stdout.rewind
+      @actual = $stdout.read
+
+      $stdout = STDOUT
+      $stderr = STDERR
+    end
+
+    if @actual then
+      case expected
+      when String
+        @actual.include? expected
+      when Regexp
+        expected.match @actual
+      else
+        raise ArgumentError, "No idea how to match a #{@actual.class.name}"
+      end
+    end
+  end
+
+  failure_message_for_should do |actual|
+    if actual.nil? then
+      "expected #{expected.inspect}, but nothing was printed"
+    else
+      "expected #{expected.inspect} to be printed; got:\n#{actual}"
+    end
+  end
+
+  description do
+    "expect #{expected.inspect} to be printed"
+  end
+
+  diffable
+end
diff --git a/modules/stdlib/spec/lib/puppet_spec/verbose.rb b/modules/stdlib/spec/lib/puppet_spec/verbose.rb
new file mode 100755 (executable)
index 0000000..d9834f2
--- /dev/null
@@ -0,0 +1,9 @@
+# Support code for running stuff with warnings disabled.
+module Kernel
+  def with_verbose_disabled
+    verbose, $VERBOSE = $VERBOSE, nil
+    result = yield
+    $VERBOSE = verbose
+    return result
+  end
+end
diff --git a/modules/stdlib/spec/monkey_patches/alias_should_to_must.rb b/modules/stdlib/spec/monkey_patches/alias_should_to_must.rb
new file mode 100755 (executable)
index 0000000..1a11117
--- /dev/null
@@ -0,0 +1,8 @@
+require 'rspec'
+
+class Object
+  # This is necessary because the RAL has a 'should'
+  # method.
+  alias :must :should
+  alias :must_not :should_not
+end
diff --git a/modules/stdlib/spec/monkey_patches/publicize_methods.rb b/modules/stdlib/spec/monkey_patches/publicize_methods.rb
new file mode 100755 (executable)
index 0000000..b39e9c0
--- /dev/null
@@ -0,0 +1,11 @@
+# Some monkey-patching to allow us to test private methods.
+class Class
+    def publicize_methods(*methods)
+        saved_private_instance_methods = methods.empty? ? self.private_instance_methods : methods
+
+        self.class_eval { public(*saved_private_instance_methods) }
+        yield
+        self.class_eval { private(*saved_private_instance_methods) }
+    end
+end
+
diff --git a/modules/stdlib/spec/spec.opts b/modules/stdlib/spec/spec.opts
new file mode 100644 (file)
index 0000000..91cd642
--- /dev/null
@@ -0,0 +1,6 @@
+--format
+s
+--colour
+--loadby
+mtime
+--backtrace
diff --git a/modules/stdlib/spec/spec_helper.rb b/modules/stdlib/spec/spec_helper.rb
new file mode 100644 (file)
index 0000000..87aac34
--- /dev/null
@@ -0,0 +1,105 @@
+dir = File.expand_path(File.dirname(__FILE__))
+$LOAD_PATH.unshift File.join(dir, 'lib')
+
+p dir
+
+# Don't want puppet getting the command line arguments for rake or autotest
+ARGV.clear
+
+require 'puppet'
+require 'facter'
+require 'mocha'
+gem 'rspec', '>=2.0.0'
+require 'rspec/expectations'
+
+# So everyone else doesn't have to include this base constant.
+module PuppetSpec
+  FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR)
+end
+
+require 'pathname'
+require 'tmpdir'
+
+require 'puppet_spec/verbose'
+require 'puppet_spec/files'
+require 'puppet_spec/fixtures'
+require 'puppet_spec/matchers'
+require 'monkey_patches/alias_should_to_must'
+require 'monkey_patches/publicize_methods'
+
+# JJM Hack to make the stdlib tests run in Puppet 2.6 (See puppet commit cf183534)
+if not Puppet.constants.include? "Test" then
+  module Puppet::Test
+    class LogCollector
+      def initialize(logs)
+        @logs = logs
+      end
+
+      def <<(value)
+        @logs << value
+      end
+    end
+  end
+  Puppet::Util::Log.newdesttype :log_collector do
+    match "Puppet::Test::LogCollector"
+
+    def initialize(messages)
+      @messages = messages
+    end
+
+    def handle(msg)
+      @messages << msg
+    end
+  end
+end
+
+Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour|
+  require behaviour.relative_path_from(Pathname.new(dir))
+end
+
+RSpec.configure do |config|
+  include PuppetSpec::Fixtures
+
+  config.mock_with :mocha
+
+  config.before :each do
+    GC.disable
+
+    # these globals are set by Application
+    $puppet_application_mode = nil
+    $puppet_application_name = nil
+
+    # REVISIT: I think this conceals other bad tests, but I don't have time to
+    # fully diagnose those right now.  When you read this, please come tell me
+    # I suck for letting this float. --daniel 2011-04-21
+    Signal.stubs(:trap)
+
+    # Set the confdir and vardir to gibberish so that tests
+    # have to be correctly mocked.
+    Puppet[:confdir] = "/dev/null"
+    Puppet[:vardir] = "/dev/null"
+
+    # Avoid opening ports to the outside world
+    Puppet.settings[:bindaddress] = "127.0.0.1"
+
+    @logs = []
+    Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs))
+
+    @log_level = Puppet::Util::Log.level
+  end
+
+  config.after :each do
+    Puppet.settings.clear
+    Puppet::Node::Environment.clear
+    Puppet::Util::Storage.clear
+    Puppet::Util::ExecutionStub.reset if Puppet::Util.constants.include? "ExecutionStub"
+
+    PuppetSpec::Files.cleanup
+
+    @logs.clear
+    Puppet::Util::Log.close_all
+    Puppet::Util::Log.level = @log_level
+
+    GC.enable
+  end
+end
diff --git a/modules/stdlib/spec/unit/facter/root_home_spec.rb b/modules/stdlib/spec/unit/facter/root_home_spec.rb
new file mode 100644 (file)
index 0000000..8946d9d
--- /dev/null
@@ -0,0 +1,42 @@
+require 'spec_helper'
+require 'facter/root_home'
+
+describe Facter::Util::RootHome do
+  context "solaris" do
+    let(:root_ent) { "root:x:0:0:Super-User:/:/sbin/sh" }
+    let(:expected_root_home) { "/" }
+
+    it "should return /" do
+      Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
+      Facter::Util::RootHome.get_root_home.should == expected_root_home
+    end
+  end
+  context "linux" do
+    let(:root_ent) { "root:x:0:0:root:/root:/bin/bash" }
+    let(:expected_root_home) { "/root" }
+
+    it "should return /root" do
+      Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
+      Facter::Util::RootHome.get_root_home.should == expected_root_home
+    end
+  end
+  context "macosx" do
+    let(:root_ent) { "root:*:0:0:System Administrator:/var/root:/bin/sh" }
+    let(:expected_root_home) { "/var/root" }
+
+    it "should return /var/root" do
+      Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
+      Facter::Util::RootHome.get_root_home.should == expected_root_home
+    end
+  end
+  context "windows" do
+    let(:root_ent) { "FIXME TBD on Windows" }
+    let(:expected_root_home) { "FIXME TBD on Windows" }
+
+    it "should return FIXME TBD on windows" do
+      pending "FIXME: TBD on windows"
+      Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
+      Facter::Util::RootHome.get_root_home.should == expected_root_home
+    end
+  end
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/abs_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/abs_spec.rb
new file mode 100755 (executable)
index 0000000..65ba2e8
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the abs function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("abs").should == "function_abs"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_abs([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should convert a negative number into a positive" do
+    result = @scope.function_abs(["-34"])
+    result.should(eq(34))
+  end
+
+  it "should do nothing with a positive number" do
+    result = @scope.function_abs(["5678"])
+    result.should(eq(5678))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/bool2num_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/bool2num_spec.rb
new file mode 100755 (executable)
index 0000000..d5da18c
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the bool2num function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("bool2num").should == "function_bool2num"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_bool2num([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should convert true to 1" do
+    result = @scope.function_bool2num([true])
+    result.should(eq(1))
+  end
+
+  it "should convert false to 0" do
+    result = @scope.function_bool2num([false])
+    result.should(eq(0))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/capitalize_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/capitalize_spec.rb
new file mode 100755 (executable)
index 0000000..1c45821
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the capitalize function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("capitalize").should == "function_capitalize"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_capitalize([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should capitalize the beginning of a string" do
+    result = @scope.function_capitalize(["abc"])
+    result.should(eq("Abc"))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/chomp_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/chomp_spec.rb
new file mode 100755 (executable)
index 0000000..0592115
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the chomp function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("chomp").should == "function_chomp"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_chomp([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should chomp the end of a string" do
+    result = @scope.function_chomp(["abc\n"])
+    result.should(eq("abc"))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/chop_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/chop_spec.rb
new file mode 100755 (executable)
index 0000000..0c456a8
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the chop function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("chop").should == "function_chop"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_chop([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should chop the end of a string" do
+    result = @scope.function_chop(["asdf\n"])
+    result.should(eq("asdf"))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/delete_at_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/delete_at_spec.rb
new file mode 100755 (executable)
index 0000000..27db0c8
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the delete_at function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("delete_at").should == "function_delete_at"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_delete_at([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should delete an item at specified location from an array" do
+    result = @scope.function_delete_at([['a','b','c'],1])
+    result.should(eq(['a','c']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/delete_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/delete_spec.rb
new file mode 100755 (executable)
index 0000000..fab3230
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the delete function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("delete").should == "function_delete"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_delete([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should delete an item from an array" do
+    result = @scope.function_delete([['a','b','c'],'b'])
+    result.should(eq(['a','c']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/downcase_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/downcase_spec.rb
new file mode 100755 (executable)
index 0000000..0bccd5f
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the downcase function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("downcase").should == "function_downcase"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_downcase([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should downcase a string" do
+    result = @scope.function_downcase(["ASFD"])
+    result.should(eq("asfd"))
+  end
+
+  it "should do nothing to a string that is already downcase" do
+    result = @scope.function_downcase(["asdf asdf"])
+    result.should(eq("asdf asdf"))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/empty_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/empty_spec.rb
new file mode 100755 (executable)
index 0000000..cb0021f
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the empty function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("empty").should == "function_empty"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_empty([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return a true for an empty string" do
+    result = @scope.function_empty([''])
+    result.should(eq(true))
+  end
+
+  it "should return a false for a non-empty string" do
+    result = @scope.function_empty(['asdf'])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/flatten_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/flatten_spec.rb
new file mode 100755 (executable)
index 0000000..7bedeb2
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the flatten function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("flatten").should == "function_flatten"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_flatten([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should flatten a complex data structure" do
+    result = @scope.function_flatten([["a","b",["c",["d","e"],"f","g"]]])
+    result.should(eq(["a","b","c","d","e","f","g"]))
+  end
+
+  it "should do nothing to a structure that is already flat" do
+    result = @scope.function_flatten([["a","b","c","d"]])
+    result.should(eq(["a","b","c","d"]))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/getvar_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/getvar_spec.rb
new file mode 100644 (file)
index 0000000..16edd98
--- /dev/null
@@ -0,0 +1,53 @@
+require 'puppet'
+
+# We don't need this for the basic tests we're doing
+# require 'spec_helper'
+
+# Dan mentioned that Nick recommended the function method call
+# to return the string value for the test description.
+# this will not even try the test if the function cannot be
+# loaded.
+describe Puppet::Parser::Functions.function(:getvar) do
+
+  # Pulled from Dan's create_resources function
+  def get_scope
+    @topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    @topscope.parent = nil
+    @scope = Puppet::Parser::Scope.new
+    @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    @scope.parent = @topscope
+    @compiler = @scope.compiler
+  end
+
+  describe 'when calling getvar from puppet' do
+
+    it "should not compile when no arguments are passed" do
+      Puppet[:code] = 'getvar()'
+      get_scope
+      expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+    end
+    it "should not compile when too many arguments are passed" do
+      Puppet[:code] = 'getvar("foo::bar", "baz")'
+      get_scope
+      expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+    end
+
+    it "should lookup variables in other namespaces" do
+      pending "Puppet doesn't appear to think getvar is an rvalue function... BUG?"
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        class site::data { $foo = 'baz' }
+        include site::data
+        $foo = getvar("site::data::foo")
+        if $foo != 'baz' {
+          fail('getvar did not return what we expect')
+        }
+      ENDofPUPPETcode
+      get_scope
+      @scope.compiler.compile
+    end
+
+  end
+
+end
+
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/grep_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/grep_spec.rb
new file mode 100755 (executable)
index 0000000..b1f647c
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the grep function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("grep").should == "function_grep"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_grep([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should grep contents from an array" do
+    result = @scope.function_grep([["aaabbb","bbbccc","dddeee"], "bbb"])
+    result.should(eq(["aaabbb","bbbccc"]))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/has_key_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/has_key_spec.rb
new file mode 100644 (file)
index 0000000..d1dcd15
--- /dev/null
@@ -0,0 +1,46 @@
+require 'puppet'
+require 'mocha'
+describe Puppet::Parser::Functions.function(:has_key) do
+
+  # Pulled from Dan's create_resources function
+  # TODO - this should be moved to spec_helper since the
+  # logic is likely to be applied to multiple rspec files.
+  let(:compiler) {
+    topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    topscope.parent = nil
+    my_scope = Puppet::Parser::Scope.new
+    my_scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    my_scope.parent = topscope
+    compiler = my_scope.compiler
+  }
+  let(:scope) {
+    scope = Puppet::Parser::Scope.new
+    scope.stubs(:environment).returns(Puppet::Node::Environment.new('production'))
+    scope
+  }
+
+  describe 'when calling has_key from puppet' do
+    it "should not compile when no arguments are passed" do
+      Puppet[:code] = 'has_key()'
+      expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+    end
+    it "should not compile when 1 argument is passed" do
+      Puppet[:code] = "has_key('foo')"
+      expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+    end
+    it "should require the first value to be a Hash" do
+      Puppet[:code] = "has_key('foo', 'bar')"
+      expect { compiler.compile }.should raise_error(Puppet::ParseError, /expects the first argument to be a hash/)
+    end
+  end
+  describe 'when calling the function has_key from a scope instance' do
+    it 'should detect existing keys' do
+      scope.function_has_key([{'one' => 1}, 'one']).should be_true
+    end
+    it 'should detect existing keys' do
+      scope.function_has_key([{'one' => 1}, 'two']).should be_false
+    end
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/hash_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/hash_spec.rb
new file mode 100644 (file)
index 0000000..6d3d48c
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the hash function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("hash").should == "function_hash"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_hash([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should convert an array to a hash" do
+    result = @scope.function_hash([['a',1,'b',2,'c',3]])
+    result.should(eq({'a'=>1,'b'=>2,'c'=>3}))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_array_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_array_spec.rb
new file mode 100644 (file)
index 0000000..537595c
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_array function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_array").should == "function_is_array"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_array([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if passed an array" do
+    result = @scope.function_is_array([[1,2,3]])
+    result.should(eq(true))
+  end
+
+  it "should return false if passed a hash" do
+    result = @scope.function_is_array([{'a'=>1}])
+    result.should(eq(false))
+  end
+
+  it "should return false if passed a string" do
+    result = @scope.function_is_array(["asdf"])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_domain_name_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_domain_name_spec.rb
new file mode 100644 (file)
index 0000000..ec7c7f5
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_domain_name function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_domain_name").should == "function_is_domain_name"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_domain_name([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if a valid domain name" do
+    result = @scope.function_is_domain_name(["foo.bar.com"])
+    result.should(be_true)
+  end
+
+  it "should allow domain parts to start with numbers" do
+    result = @scope.function_is_domain_name(["3foo.2bar.com"])
+    result.should(be_true)
+  end
+
+  it "should allow domain to end with a dot" do
+    result = @scope.function_is_domain_name(["3foo.2bar.com."])
+    result.should(be_true)
+  end
+
+  it "should allow a single part domain" do
+    result = @scope.function_is_domain_name(["orange"])
+    result.should(be_true)
+  end
+
+  it "should return false if domain parts start with hyphens" do
+    result = @scope.function_is_domain_name(["-3foo.2bar.com"])
+    result.should(be_false)
+  end
+
+  it "should return true if domain contains hyphens" do
+    result = @scope.function_is_domain_name(["3foo-bar.2bar-fuzz.com"])
+    result.should(be_true)
+  end
+
+  it "should return false if domain name contains spaces" do
+    result = @scope.function_is_domain_name(["not valid"])
+    result.should(be_false)
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_float_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_float_spec.rb
new file mode 100644 (file)
index 0000000..55ba8cf
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_float function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_float").should == "function_is_float"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_float([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if a float" do
+    result = @scope.function_is_float(["0.12"])
+    result.should(eq(true))
+  end
+
+  it "should return false if a string" do
+    result = @scope.function_is_float(["asdf"])
+    result.should(eq(false))
+  end
+
+  it "should return false if an integer" do
+    result = @scope.function_is_float(["3"])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_hash_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_hash_spec.rb
new file mode 100644 (file)
index 0000000..94364f5
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_hash function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_hash").should == "function_is_hash"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_hash([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if passed a hash" do
+    result = @scope.function_is_hash([{"a"=>1,"b"=>2}])
+    result.should(eq(true))
+  end
+
+  it "should return false if passed an array" do
+    result = @scope.function_is_hash([["a","b"]])
+    result.should(eq(false))
+  end
+
+  it "should return false if passed a string" do
+    result = @scope.function_is_hash(["asdf"])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_integer_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_integer_spec.rb
new file mode 100644 (file)
index 0000000..faf6f2d
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_integer function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_integer").should == "function_is_integer"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_integer([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if an integer" do
+    result = @scope.function_is_integer(["3"])
+    result.should(eq(true))
+  end
+
+  it "should return false if a float" do
+    result = @scope.function_is_integer(["3.2"])
+    result.should(eq(false))
+  end
+
+  it "should return false if a string" do
+    result = @scope.function_is_integer(["asdf"])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_ip_address_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_ip_address_spec.rb
new file mode 100644 (file)
index 0000000..98ce828
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_ip_address function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_ip_address").should == "function_is_ip_address"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_ip_address([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if an IPv4 address" do
+    result = @scope.function_is_ip_address(["1.2.3.4"])
+    result.should(eq(true))
+  end
+
+  it "should return true if a full IPv6 address" do
+    result = @scope.function_is_ip_address(["fe80:0000:cd12:d123:e2f8:47ff:fe09:dd74"])
+    result.should(eq(true))
+  end
+
+  it "should return true if a compressed IPv6 address" do
+    result = @scope.function_is_ip_address(["fe00::1"])
+    result.should(eq(true))
+  end
+
+  it "should return false if not valid" do
+    result = @scope.function_is_ip_address(["asdf"])
+    result.should(eq(false))
+  end
+
+  it "should return false if IP octets out of range" do
+    result = @scope.function_is_ip_address(["1.1.1.300"])
+    result.should(eq(false))
+  end
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_mac_address_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_mac_address_spec.rb
new file mode 100644 (file)
index 0000000..c9b9637
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_mac_address function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_mac_address").should == "function_is_mac_address"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_mac_address([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if a valid mac address" do
+    result = @scope.function_is_mac_address(["00:a0:1f:12:7f:a0"])
+    result.should(eq(true))
+  end
+
+  it "should return false if octets are out of range" do
+    result = @scope.function_is_mac_address(["00:a0:1f:12:7f:g0"])
+    result.should(eq(false))
+  end
+
+  it "should return false if not valid" do
+    result = @scope.function_is_mac_address(["not valid"])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_numeric_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_numeric_spec.rb
new file mode 100644 (file)
index 0000000..2191b7b
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_numeric function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_numeric").should == "function_is_numeric"
+  end
+
+  it "should raise a ParseError if there is less than 1 argument" do
+    lambda { @scope.function_is_numeric([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if an integer" do
+    result = @scope.function_is_numeric(["3"])
+    result.should(eq(true))
+  end
+
+  it "should return true if a float" do
+    result = @scope.function_is_numeric(["3.2"])
+    result.should(eq(true))
+  end
+
+  it "should return false if a string" do
+    result = @scope.function_is_numeric(["asdf"])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/is_string_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/is_string_spec.rb
new file mode 100644 (file)
index 0000000..4f3f5fd
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_string function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("is_string").should == "function_is_string"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_is_string([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if a string" do
+    result = @scope.function_is_string(["asdf"])
+    result.should(eq(true))
+  end
+
+  it "should return false if an integer" do
+    result = @scope.function_is_string(["3"])
+    result.should(eq(false))
+  end
+
+  it "should return false if a float" do
+    result = @scope.function_is_string(["3.23"])
+    result.should(eq(false))
+  end
+
+  it "should return false if an array" do
+    result = @scope.function_is_string([["a","b","c"]])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/join_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/join_spec.rb
new file mode 100644 (file)
index 0000000..1b3dec8
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the join function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("join").should == "function_join"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_join([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should join an array into a string" do
+    result = @scope.function_join([["a","b","c"], ":"])
+    result.should(eq("a:b:c"))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/keys_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/keys_spec.rb
new file mode 100644 (file)
index 0000000..927be96
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the keys function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("keys").should == "function_keys"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_keys([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return an array of keys when given a hash" do
+    result = @scope.function_keys([{'a'=>1, 'b' => 2}])
+    result.should(eq(['a','b']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/lstrip_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/lstrip_spec.rb
new file mode 100644 (file)
index 0000000..ac331fa
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the lstrip function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("lstrip").should == "function_lstrip"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_lstrip([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should lstrip a string" do
+    result = @scope.function_lstrip(["  asdf"])
+    result.should(eq('asdf'))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/member_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/member_spec.rb
new file mode 100644 (file)
index 0000000..2cebc0d
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the member function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("member").should == "function_member"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_member([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if a member is in an array" do
+    result = @scope.function_member([["a","b","c"], "a"])
+    result.should(eq(true))
+  end  
+
+  it "should return false if a member is not in an array" do
+    result = @scope.function_member([["a","b","c"], "d"])
+    result.should(eq(false))
+  end  
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/merge_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/merge_spec.rb
new file mode 100644 (file)
index 0000000..71e1869
--- /dev/null
@@ -0,0 +1,54 @@
+require 'puppet'
+require 'mocha'
+describe Puppet::Parser::Functions.function(:merge) do
+
+  # Pulled from Dan's create_resources function
+  # TODO - these let statements should be moved somewhere
+  # where they can be resued
+  let(:compiler) {
+    topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    topscope.parent = nil
+    my_scope = Puppet::Parser::Scope.new
+    my_scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    my_scope.parent = topscope
+    compiler = my_scope.compiler
+  }
+  let(:scope) {
+    scope = Puppet::Parser::Scope.new
+    scope.stubs(:environment).returns(Puppet::Node::Environment.new('production'))
+    scope
+  }
+
+  describe 'when calling merge from puppet' do
+    it "should not compile when no arguments are passed" do
+      Puppet[:code] = 'merge()'
+      expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+    end
+    it "should not compile when 1 argument is passed" do
+      Puppet[:code] = "$my_hash={'one' => 1}\nmerge($my_hash)"
+      expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+    end
+  end
+  describe 'when calling merge on the scope instance' do
+    it 'should require all parameters are hashes' do
+      expect { new_hash = scope.function_merge([{}, '2'])}.should raise_error(Puppet::ParseError, /unexpected argument type String/)
+
+    end
+    it 'should be able to merge two hashes' do
+      new_hash = scope.function_merge([{'one' => '1', 'two' => '1'}, {'two' => '2', 'three' => '2'}])
+      new_hash['one'].should   == '1'
+      new_hash['two'].should   == '2'
+      new_hash['three'].should == '2'
+    end
+    it 'should merge multiple hashes' do
+      hash = scope.function_merge([{'one' => 1}, {'one' => '2'}, {'one' => '3'}])
+      hash['one'].should == '3'
+    end
+    it 'should accept empty hashes' do
+      scope.function_merge([{},{},{}]).should == {}
+    end
+
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/num2bool_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/num2bool_spec.rb
new file mode 100644 (file)
index 0000000..6585273
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the num2bool function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("num2bool").should == "function_num2bool"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_num2bool([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return true if 1" do
+    result = @scope.function_num2bool(["1"])
+    result.should(be_true)
+  end
+
+  it "should return false if 0" do
+    result = @scope.function_num2bool(["0"])
+    result.should(be_false)
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/parsejson_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/parsejson_spec.rb
new file mode 100644 (file)
index 0000000..26eea36
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the parsejson function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("parsejson").should == "function_parsejson"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_parsejson([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should convert JSON to a data structure" do
+    json = <<-EOS
+["aaa","bbb","ccc"]
+EOS
+    result = @scope.function_parsejson([json])
+    result.should(eq(['aaa','bbb','ccc']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/parseyaml_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/parseyaml_spec.rb
new file mode 100644 (file)
index 0000000..f9cb049
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the parseyaml function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("parseyaml").should == "function_parseyaml"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_parseyaml([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should convert YAML to a data structure" do
+    yaml = <<-EOS
+- aaa
+- bbb
+- ccc
+EOS
+    result = @scope.function_parseyaml([yaml])
+    result.should(eq(['aaa','bbb','ccc']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/prefix_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/prefix_spec.rb
new file mode 100644 (file)
index 0000000..a0cbcab
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the prefix function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("prefix").should == "function_prefix"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_prefix([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return a prefixed array" do
+    result = @scope.function_prefix([['a','b','c'], 'p'])
+    result.should(eq(['pa','pb','pc']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/range_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/range_spec.rb
new file mode 100644 (file)
index 0000000..8c2446a
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the range function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("range").should == "function_range"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_range([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return a letter range" do
+    result = @scope.function_range(["a","d"])
+    result.should(eq(['a','b','c','d']))
+  end
+
+  it "should return a number range" do
+    result = @scope.function_range(["1","4"])
+    result.should(eq([1,2,3,4]))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/reverse_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/reverse_spec.rb
new file mode 100644 (file)
index 0000000..4fa50e4
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the reverse function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("reverse").should == "function_reverse"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_reverse([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should reverse a string" do
+    result = @scope.function_reverse(["asdfghijkl"])
+    result.should(eq('lkjihgfdsa'))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/rstrip_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/rstrip_spec.rb
new file mode 100644 (file)
index 0000000..af8cc12
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the rstrip function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("rstrip").should == "function_rstrip"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_rstrip([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should rstrip a string" do
+    result = @scope.function_rstrip(["asdf  "])
+    result.should(eq('asdf'))
+  end
+
+  it "should rstrip each element in an array" do
+    result = @scope.function_rstrip([["a ","b ", "c "]])
+    result.should(eq(['a','b','c']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/shuffle_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/shuffle_spec.rb
new file mode 100644 (file)
index 0000000..f04fda5
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the shuffle function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("shuffle").should == "function_shuffle"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_shuffle([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should shuffle a string and the result should be the same size" do
+    result = @scope.function_shuffle(["asdf"])
+    result.size.should(eq(4))
+  end
+
+  it "should shuffle a string but the sorted contents should still be the same" do
+    result = @scope.function_shuffle(["adfs"])
+    result.split("").sort.join("").should(eq("adfs"))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/size_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/size_spec.rb
new file mode 100644 (file)
index 0000000..ccaa335
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the size function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("size").should == "function_size"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_size([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return the size of a string" do
+    result = @scope.function_size(["asdf"])
+    result.should(eq(4))
+  end
+
+  it "should return the size of an array" do
+    result = @scope.function_size([["a","b","c"]])
+    result.should(eq(3))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/sort_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/sort_spec.rb
new file mode 100644 (file)
index 0000000..fbe3073
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the sort function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("sort").should == "function_sort"
+  end
+
+  it "should raise a ParseError if there is not 1 arguments" do
+    lambda { @scope.function_sort(['','']) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should sort an array" do
+    result = @scope.function_sort([["a","c","b"]])
+    result.should(eq(['a','b','c']))
+  end
+
+  it "should sort a string" do
+    result = @scope.function_sort(["acb"])
+    result.should(eq('abc'))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/squeeze_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/squeeze_spec.rb
new file mode 100644 (file)
index 0000000..9355ad2
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the squeeze function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("squeeze").should == "function_squeeze"
+  end
+
+  it "should raise a ParseError if there is less than 2 arguments" do
+    lambda { @scope.function_squeeze([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should squeeze a string" do
+    result = @scope.function_squeeze(["aaabbbbcccc"])
+    result.should(eq('abc'))
+  end
+
+  it "should squeeze all elements in an array" do
+    result = @scope.function_squeeze([["aaabbbbcccc","dddfff"]])
+    result.should(eq(['abc','df']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/str2bool_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/str2bool_spec.rb
new file mode 100644 (file)
index 0000000..d7f0ac9
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the str2bool function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("str2bool").should == "function_str2bool"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_str2bool([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should convert string 'true' to true" do
+    result = @scope.function_str2bool(["true"])
+    result.should(eq(true))
+  end
+
+  it "should convert string 'undef' to false" do
+    result = @scope.function_str2bool(["undef"])
+    result.should(eq(false))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/strftime_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/strftime_spec.rb
new file mode 100644 (file)
index 0000000..f7a2cd9
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the strftime function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("strftime").should == "function_strftime"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_strftime([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "using %s should be higher then when I wrote this test" do
+    result = @scope.function_strftime(["%s"])
+    result.to_i.should(be > 1311953157)
+  end
+
+  it "using %s should be lower then 1.5 trillion" do
+    result = @scope.function_strftime(["%s"])
+    result.to_i.should(be < 1500000000)
+  end
+
+  it "should return a date when given %Y-%m-%d" do
+    result = @scope.function_strftime(["%Y-%m-%d"])
+    result.should =~ /^\d{4}-\d{2}-\d{2}$/
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/strip_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/strip_spec.rb
new file mode 100644 (file)
index 0000000..48a52dd
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the strip function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("strip").should == "function_strip"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_strip([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should strip a string" do
+    result = @scope.function_strip([" ab cd "])
+    result.should(eq('ab cd'))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/swapcase_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/swapcase_spec.rb
new file mode 100644 (file)
index 0000000..2686054
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the swapcase function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("swapcase").should == "function_swapcase"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_swapcase([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should swapcase a string" do
+    result = @scope.function_swapcase(["aaBBccDD"])
+    result.should(eq('AAbbCCdd'))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/time_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/time_spec.rb
new file mode 100644 (file)
index 0000000..666e8e0
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the time function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("time").should == "function_time"
+  end
+
+  it "should raise a ParseError if there is more than 2 arguments" do
+    lambda { @scope.function_time(['','']) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return a number" do
+    result = @scope.function_time([])
+    result.class.should(eq(Fixnum))
+  end
+
+  it "should be higher then when I wrote this test" do
+    result = @scope.function_time([])
+    result.should(be > 1311953157)
+  end
+
+  it "should be lower then 1.5 trillion" do
+    result = @scope.function_time([])
+    result.should(be < 1500000000)
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/type_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/type_spec.rb
new file mode 100644 (file)
index 0000000..e3c28ed
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the type function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("type").should == "function_type"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_type([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return string when given a string" do
+    result = @scope.function_type(["aaabbbbcccc"])
+    result.should(eq('string'))
+  end
+
+  it "should return array when given an array" do
+    result = @scope.function_type([["aaabbbbcccc","asdf"]])
+    result.should(eq('array'))
+  end
+
+  it "should return hash when given a hash" do
+    result = @scope.function_type([{"a"=>1,"b"=>2}])
+    result.should(eq('hash'))
+  end
+
+  it "should return integer when given an integer" do
+    result = @scope.function_type(["1"])
+    result.should(eq('integer'))
+  end
+
+  it "should return float when given a float" do
+    result = @scope.function_type(["1.34"])
+    result.should(eq('float'))
+  end
+
+  it "should return boolean when given a boolean" do
+    result = @scope.function_type([true])
+    result.should(eq('boolean'))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/unique_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/unique_spec.rb
new file mode 100644 (file)
index 0000000..627dc33
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the unique function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("unique").should == "function_unique"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_unique([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should remove duplicate elements in a string" do
+    result = @scope.function_unique(["aabbc"])
+    result.should(eq('abc'))
+  end
+
+  it "should remove duplicate elements in an array" do
+    result = @scope.function_unique([["a","a","b","b","c"]])
+    result.should(eq(['a','b','c']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/upcase_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/upcase_spec.rb
new file mode 100644 (file)
index 0000000..5d18846
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the upcase function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("upcase").should == "function_upcase"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_upcase([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should upcase a string" do
+    result = @scope.function_upcase(["abc"])
+    result.should(eq('ABC'))
+  end
+
+  it "should do nothing if a string is already upcase" do
+    result = @scope.function_upcase(["ABC"])
+    result.should(eq('ABC'))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/validate_array_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/validate_array_spec.rb
new file mode 100644 (file)
index 0000000..37ae09d
--- /dev/null
@@ -0,0 +1,63 @@
+require 'puppet'
+
+# We don't need this for the basic tests we're doing
+# require 'spec_helper'
+
+# Dan mentioned that Nick recommended the function method call
+# to return the string value for the test description.
+# this will not even try the test if the function cannot be
+# loaded.
+describe Puppet::Parser::Functions.function(:validate_array) do
+
+  # Pulled from Dan's create_resources function
+  def get_scope
+    @topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    @topscope.parent = nil
+    @scope = Puppet::Parser::Scope.new
+    @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    @scope.parent = @topscope
+    @compiler = @scope.compiler
+  end
+
+  describe 'when calling validate_array from puppet' do
+
+    %w{ true false }.each do |the_string|
+
+      it "should not compile when #{the_string} is a string" do
+        Puppet[:code] = "validate_array('#{the_string}')"
+        get_scope
+        expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/)
+      end
+
+      it "should not compile when #{the_string} is a bare word" do
+        Puppet[:code] = "validate_array(#{the_string})"
+        get_scope
+        expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/)
+      end
+
+    end
+
+    it "should compile when multiple array arguments are passed" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = [ ]
+        $bar = [ 'one', 'two' ]
+        validate_array($foo, $bar)
+      ENDofPUPPETcode
+      get_scope
+      @scope.compiler.compile
+    end
+
+    it "should not compile when an undef variable is passed" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = undef
+        validate_array($foo)
+      ENDofPUPPETcode
+      get_scope
+      expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/)
+    end
+
+  end
+
+end
+
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/validate_bool_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/validate_bool_spec.rb
new file mode 100644 (file)
index 0000000..e95c396
--- /dev/null
@@ -0,0 +1,76 @@
+require 'puppet'
+
+# We don't need this for the basic tests we're doing
+# require 'spec_helper'
+
+# Dan mentioned that Nick recommended the function method call
+# to return the string value for the test description.
+# this will not even try the test if the function cannot be
+# loaded.
+describe Puppet::Parser::Functions.function(:validate_bool) do
+
+  # Pulled from Dan's create_resources function
+  def get_scope
+    @topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    @topscope.parent = nil
+    @scope = Puppet::Parser::Scope.new
+    @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    @scope.parent = @topscope
+    @compiler = @scope.compiler
+  end
+
+  describe 'when calling validate_bool from puppet' do
+
+    %w{ true false }.each do |the_string|
+
+      it "should not compile when #{the_string} is a string" do
+        Puppet[:code] = "validate_bool('#{the_string}')"
+        get_scope
+        expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/)
+      end
+
+      it "should compile when #{the_string} is a bare word" do
+        Puppet[:code] = "validate_bool(#{the_string})"
+        get_scope
+        @scope.compiler.compile
+      end
+
+    end
+
+    it "should not compile when an arbitrary string is passed" do
+      Puppet[:code] = 'validate_bool("jeff and dan are awesome")'
+      get_scope
+      expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/)
+    end
+
+    it "should not compile when no arguments are passed" do
+      Puppet[:code] = 'validate_bool()'
+      get_scope
+      expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+    end
+
+    it "should compile when multiple boolean arguments are passed" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = true
+        $bar = false
+        validate_bool($foo, $bar, true, false)
+      ENDofPUPPETcode
+      get_scope
+      @scope.compiler.compile
+    end
+
+    it "should compile when multiple boolean arguments are passed" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = true
+        $bar = false
+        validate_bool($foo, $bar, true, false, 'jeff')
+      ENDofPUPPETcode
+      get_scope
+      expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/)
+    end
+
+  end
+
+end
+
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/validate_hash_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/validate_hash_spec.rb
new file mode 100644 (file)
index 0000000..8cc0b3d
--- /dev/null
@@ -0,0 +1,63 @@
+require 'puppet'
+
+# We don't need this for the basic tests we're doing
+# require 'spec_helper'
+
+# Dan mentioned that Nick recommended the function method call
+# to return the string value for the test description.
+# this will not even try the test if the function cannot be
+# loaded.
+describe Puppet::Parser::Functions.function(:validate_hash) do
+
+  # Pulled from Dan's create_resources function
+  def get_scope
+    @topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    @topscope.parent = nil
+    @scope = Puppet::Parser::Scope.new
+    @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    @scope.parent = @topscope
+    @compiler = @scope.compiler
+  end
+
+  describe 'when calling validate_hash from puppet' do
+
+    %w{ true false }.each do |the_string|
+
+      it "should not compile when #{the_string} is a string" do
+        Puppet[:code] = "validate_hash('#{the_string}')"
+        get_scope
+        expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/)
+      end
+
+      it "should not compile when #{the_string} is a bare word" do
+        Puppet[:code] = "validate_hash(#{the_string})"
+        get_scope
+        expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/)
+      end
+
+    end
+
+    it "should compile when multiple hash arguments are passed" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = {}
+        $bar = { 'one' => 'two' }
+        validate_hash($foo, $bar)
+      ENDofPUPPETcode
+      get_scope
+      @scope.compiler.compile
+    end
+
+    it "should not compile when an undef variable is passed" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = undef
+        validate_hash($foo)
+      ENDofPUPPETcode
+      get_scope
+      expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/)
+    end
+
+  end
+
+end
+
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/validate_string_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/validate_string_spec.rb
new file mode 100644 (file)
index 0000000..92392da
--- /dev/null
@@ -0,0 +1,83 @@
+require 'puppet'
+
+# We don't need this for the basic tests we're doing
+# require 'spec_helper'
+
+# Dan mentioned that Nick recommended the function method call
+# to return the string value for the test description.
+# this will not even try the test if the function cannot be
+# loaded.
+describe Puppet::Parser::Functions.function(:validate_string) do
+
+  # Pulled from Dan's create_resources function
+  def get_scope
+    @topscope = Puppet::Parser::Scope.new
+    # This is necessary so we don't try to use the compiler to discover our parent.
+    @topscope.parent = nil
+    @scope = Puppet::Parser::Scope.new
+    @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
+    @scope.parent = @topscope
+    @compiler = @scope.compiler
+  end
+
+  describe 'when calling validate_string from puppet' do
+
+    %w{ foo bar baz }.each do |the_string|
+
+      it "should compile when #{the_string} is a string" do
+        Puppet[:code] = "validate_string('#{the_string}')"
+        get_scope
+        @scope.compiler.compile
+      end
+
+      it "should compile when #{the_string} is a bare word" do
+        Puppet[:code] = "validate_string(#{the_string})"
+        get_scope
+        @scope.compiler.compile
+      end
+
+    end
+
+    %w{ true false }.each do |the_string|
+      it "should compile when #{the_string} is a string" do
+        Puppet[:code] = "validate_string('#{the_string}')"
+        get_scope
+        @scope.compiler.compile
+      end
+
+      it "should not compile when #{the_string} is a bare word" do
+        Puppet[:code] = "validate_string(#{the_string})"
+        get_scope
+        expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a string/)
+      end
+    end
+
+    it "should compile when multiple string arguments are passed" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = ''
+        $bar = 'two'
+        validate_string($foo, $bar)
+      ENDofPUPPETcode
+      get_scope
+      @scope.compiler.compile
+    end
+
+    it "should compile when an explicitly undef variable is passed (NOTE THIS MAY NOT BE DESIRABLE)" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        $foo = undef
+        validate_string($foo)
+      ENDofPUPPETcode
+      get_scope
+      @scope.compiler.compile
+    end
+
+    it "should compile when an undefined variable is passed (NOTE THIS MAY NOT BE DESIRABLE)" do
+      Puppet[:code] = <<-'ENDofPUPPETcode'
+        validate_string($foobarbazishouldnotexist)
+      ENDofPUPPETcode
+      get_scope
+      @scope.compiler.compile
+    end
+  end
+end
+
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/values_at_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/values_at_spec.rb
new file mode 100644 (file)
index 0000000..6c45316
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the values_at function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("values_at").should == "function_values_at"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_values_at([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should raise a ParseError if you try to use a range where stop is greater then start" do
+    lambda { @scope.function_values_at([['a','b'],["3-1"]]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return a value at from an array" do
+    result = @scope.function_values_at([['a','b','c'],"1"])
+    result.should(eq(['b']))
+  end
+
+  it "should return a value at from an array when passed a range" do
+    result = @scope.function_values_at([['a','b','c'],"0-1"])
+    result.should(eq(['a','b']))
+  end
+
+  it "should return chosen values from an array when passed number of indexes" do
+    result = @scope.function_values_at([['a','b','c'],["0","2"]])
+    result.should(eq(['a','c']))
+  end
+
+  it "should return chosen values from an array when passed ranges and multiple indexes" do
+    result = @scope.function_values_at([['a','b','c','d','e','f','g'],["0","2","4-5"]])
+    result.should(eq(['a','c','e','f']))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/values_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/values_spec.rb
new file mode 100644 (file)
index 0000000..f6eb5b6
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the values function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("values").should == "function_values"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_values([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should return values from a hash" do
+    result = @scope.function_values([{'a'=>'1','b'=>'2','c'=>'3'}])
+    result.should(eq(['1','2','3']))
+  end
+
+  it "should return values from a hash" do
+    lambda { @scope.function_values([['a','b','c']]) }.should( raise_error(Puppet::ParseError))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/parser/functions/zip_spec.rb b/modules/stdlib/spec/unit/puppet/parser/functions/zip_spec.rb
new file mode 100644 (file)
index 0000000..074f4df
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the zip function" do
+  before :all do
+    Puppet::Parser::Functions.autoloader.loadall
+  end
+
+  before :each do
+    @scope = Puppet::Parser::Scope.new
+  end
+
+  it "should exist" do
+    Puppet::Parser::Functions.function("zip").should == "function_zip"
+  end
+
+  it "should raise a ParseError if there is less than 1 arguments" do
+    lambda { @scope.function_zip([]) }.should( raise_error(Puppet::ParseError))
+  end
+
+  it "should be able to zip an array" do
+    result = @scope.function_zip([['1','2','3'],['4','5','6']])
+    result.should(eq([["1", "4"], ["2", "5"], ["3", "6"]]))
+  end
+
+end
diff --git a/modules/stdlib/spec/unit/puppet/provider/file_line/ruby_spec.rb b/modules/stdlib/spec/unit/puppet/provider/file_line/ruby_spec.rb
new file mode 100644 (file)
index 0000000..b03fc0e
--- /dev/null
@@ -0,0 +1,30 @@
+require 'puppet'
+require 'tempfile'
+provider_class = Puppet::Type.type(:file_line).provider(:ruby)
+describe provider_class do
+  before :each do
+    tmp = Tempfile.new('tmp')
+    @tmpfile = tmp.path
+    tmp.close!
+    @resource = Puppet::Type::File_line.new(
+      {:name => 'foo', :path => @tmpfile, :line => 'foo'}
+    )
+    @provider = provider_class.new(@resource)
+  end
+  it 'should detect if the line exists in the file' do
+    File.open(@tmpfile, 'w') do |fh|
+      fh.write('foo')
+    end
+    @provider.exists?.should be_true
+  end
+  it 'should detect if the line does not exist in the file' do
+    File.open(@tmpfile, 'w') do |fh|
+      fh.write('foo1')
+    end
+    @provider.exists?.should be_nil
+  end
+  it 'should append to an existing file when creating' do
+    @provider.create
+    File.read(@tmpfile).chomp.should == 'foo'
+  end
+end
diff --git a/modules/stdlib/spec/unit/puppet/type/anchor_spec.rb b/modules/stdlib/spec/unit/puppet/type/anchor_spec.rb
new file mode 100644 (file)
index 0000000..2030b83
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+
+require 'puppet'
+
+anchor = Puppet::Type.type(:anchor).new(:name => "ntp::begin")
+
+describe anchor do
+  it "should stringify normally" do
+    anchor.to_s.should == "Anchor[ntp::begin]"
+  end
+end
diff --git a/modules/stdlib/spec/unit/puppet/type/file_line_spec.rb b/modules/stdlib/spec/unit/puppet/type/file_line_spec.rb
new file mode 100644 (file)
index 0000000..7e07c06
--- /dev/null
@@ -0,0 +1,24 @@
+require 'puppet'
+require 'tempfile'
+describe Puppet::Type.type(:file_line) do
+  before :each do
+    @file_line = Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'line', :path => '/tmp/path')
+  end
+  it 'should accept a line and path' do
+    @file_line[:line] = 'my_line'
+    @file_line[:line].should == 'my_line'
+  end
+  it 'should accept posix filenames' do
+    @file_line[:path] = '/tmp/path'
+    @file_line[:path].should == '/tmp/path'
+  end
+  it 'should not accept unqualified path' do
+    expect { @file_line[:path] = 'file' }.should raise_error(Puppet::Error, /File paths must be fully qualified/)
+  end
+  it 'should require that a line is specified' do
+    expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.should raise_error(Puppet::Error, /Both line and path are required attributes/)
+  end
+  it 'should require that a file is specified' do
+    expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.should raise_error(Puppet::Error, /Both line and path are required attributes/)
+  end
+end
diff --git a/modules/stdlib/spec/watchr.rb b/modules/stdlib/spec/watchr.rb
new file mode 100644 (file)
index 0000000..885ef1d
--- /dev/null
@@ -0,0 +1,86 @@
+ENV['FOG_MOCK'] ||= 'true'
+ENV['AUTOTEST'] = 'true'
+ENV['WATCHR']   = '1'
+
+system 'clear'
+
+def growl(message)
+  growlnotify = `which growlnotify`.chomp
+  title = "Watchr Test Results"
+  image = case message
+  when /(\d+)\s+?(failure|error)/i
+    ($1.to_i == 0) ? "~/.watchr_images/passed.png" : "~/.watchr_images/failed.png"
+  else
+    '~/.watchr_images/unknown.png'
+  end
+  options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
+  system %(#{growlnotify} #{options} &)
+end
+
+def run(cmd)
+  puts(cmd)
+  `#{cmd}`
+end
+
+def run_spec_test(file)
+  if File.exist? file
+    result = run "rspec --format p --color #{file}"
+    growl result.split("\n").last
+    puts result
+  else
+    puts "FIXME: No test #{file} [#{Time.now}]"
+  end
+end
+
+def filter_rspec(data)
+  data.split("\n").find_all do |l|
+    l =~ /^(\d+)\s+exampl\w+.*?(\d+).*?failur\w+.*?(\d+).*?pending/
+  end.join("\n")
+end
+
+def run_all_tests
+  system('clear')
+  files = Dir.glob("spec/**/*_spec.rb").join(" ")
+  result = run "rspec #{files}"
+  growl_results = filter_rspec result
+  growl growl_results
+  puts result
+  puts "GROWL: #{growl_results}"
+end
+
+# Ctrl-\
+Signal.trap 'QUIT' do
+  puts " --- Running all tests ---\n\n"
+  run_all_tests
+end
+
+@interrupted = false
+
+# Ctrl-C
+Signal.trap 'INT' do
+  if @interrupted then
+    @wants_to_quit = true
+    abort("\n")
+  else
+    puts "Interrupt a second time to quit"
+    @interrupted = true
+    Kernel.sleep 1.5
+    # raise Interrupt, nil # let the run loop catch it
+    run_suite
+  end
+end
+
+def file2spec(file)
+  result = file.sub('lib/puppet/', 'spec/unit/puppet/').gsub(/\.rb$/, '_spec.rb')
+  result = file.sub('lib/facter/', 'spec/unit/facter/').gsub(/\.rb$/, '_spec.rb')
+end
+
+
+watch( 'spec/.*_spec\.rb' ) do |md|
+  #run_spec_test(md[0])
+  run_all_tests
+end
+watch( 'lib/.*\.rb' ) do |md|
+  # run_spec_test(file2spec(md[0]))
+  run_all_tests
+end
diff --git a/modules/stdlib/tests/file_line.pp b/modules/stdlib/tests/file_line.pp
new file mode 100644 (file)
index 0000000..eea693e
--- /dev/null
@@ -0,0 +1,9 @@
+# This is a simple smoke test
+# of the file_line resource type.
+file { '/tmp/dansfile':
+  ensure => present
+}->
+file_line { 'dans_line':
+  line => 'dan is awesome',
+  path => '/tmp/dansfile',
+}
diff --git a/modules/stdlib/tests/init.pp b/modules/stdlib/tests/init.pp
new file mode 100644 (file)
index 0000000..9675d83
--- /dev/null
@@ -0,0 +1 @@
+include stdlib