diff --git a/lib/puppet/faces.rb b/lib/puppet/faces.rb index 07a745480..947eecf24 100644 --- a/lib/puppet/faces.rb +++ b/lib/puppet/faces.rb @@ -1,106 +1,12 @@ -require 'puppet' -require 'puppet/util/autoload' - -class Puppet::Faces - require 'puppet/faces/face_collection' - - require 'puppet/faces/action_manager' - include Puppet::Faces::ActionManager - extend Puppet::Faces::ActionManager - - require 'puppet/faces/option_manager' - include Puppet::Faces::OptionManager - extend Puppet::Faces::OptionManager - - include Puppet::Util - - class << self - # This is just so we can search for actions. We only use its - # list of directories to search. - # Can't we utilize an external autoloader, or simply use the $LOAD_PATH? -pvb - def autoloader - @autoloader ||= Puppet::Util::Autoload.new(:application, "puppet/faces") - end - - def faces - Puppet::Faces::FaceCollection.faces - end - - def face?(name, version) - Puppet::Faces::FaceCollection.face?(name, version) - end - - def register(instance) - Puppet::Faces::FaceCollection.register(instance) - end - - def define(name, version, &block) - if face?(name, version) - face = Puppet::Faces::FaceCollection[name, version] - else - face = self.new(name, version) - Puppet::Faces::FaceCollection.register(face) - # REVISIT: Shouldn't this be delayed until *after* we evaluate the - # current block, not done before? --daniel 2011-04-07 - face.load_actions - end - - face.instance_eval(&block) if block_given? - - return face - end - - alias :[] :define - end - - attr_accessor :default_format - - def set_default_format(format) - self.default_format = format.to_sym - end - - attr_accessor :type, :verb, :version, :arguments - attr_reader :name - - def initialize(name, version, &block) - unless Puppet::Faces::FaceCollection.validate_version(version) - raise ArgumentError, "Cannot create face #{name.inspect} with invalid version number '#{version}'!" - end - - @name = Puppet::Faces::FaceCollection.underscorize(name) - @version = version - @default_format = :pson - - instance_eval(&block) if block_given? - end - - # Try to find actions defined in other files. - def load_actions - path = "puppet/faces/#{name}" - - loaded = [] - [path, "#{name}@#{version}/#{path}"].each do |path| - Puppet::Faces.autoloader.search_directories.each do |dir| - fdir = ::File.join(dir, path) - next unless FileTest.directory?(fdir) - - Dir.chdir(fdir) do - Dir.glob("*.rb").each do |file| - aname = file.sub(/\.rb/, '') - if loaded.include?(aname) - Puppet.debug "Not loading duplicate action '#{aname}' for '#{name}' from '#{fdir}/#{file}'" - next - end - loaded << aname - Puppet.debug "Loading action '#{aname}' for '#{name}' from '#{fdir}/#{file}'" - require "#{Dir.pwd}/#{aname}" - end - end - end - end - end - - def to_s - "Puppet::Faces[#{name.inspect}, #{version.inspect}]" - end -end +# The public name of this feature is 'faces', but we have hidden all the +# plumbing over in the 'interfaces' namespace to make clear the distinction +# between the two. +# +# This file exists to ensure that the public name is usable without revealing +# the details of the implementation; you really only need go look at anything +# under Interfaces if you are looking to extend the implementation. +# +# It isn't hidden to gratuitously hide things, just to make it easier to +# separate out the interests people will have. --daniel 2011-04-07 +require 'puppet/interface' +Puppet::Faces = Puppet::Interface diff --git a/lib/puppet/faces.rb b/lib/puppet/interface.rb similarity index 72% copy from lib/puppet/faces.rb copy to lib/puppet/interface.rb index 07a745480..70484adfc 100644 --- a/lib/puppet/faces.rb +++ b/lib/puppet/interface.rb @@ -1,106 +1,106 @@ require 'puppet' require 'puppet/util/autoload' -class Puppet::Faces - require 'puppet/faces/face_collection' +class Puppet::Interface + require 'puppet/interface/face_collection' - require 'puppet/faces/action_manager' - include Puppet::Faces::ActionManager - extend Puppet::Faces::ActionManager + require 'puppet/interface/action_manager' + include Puppet::Interface::ActionManager + extend Puppet::Interface::ActionManager - require 'puppet/faces/option_manager' - include Puppet::Faces::OptionManager - extend Puppet::Faces::OptionManager + require 'puppet/interface/option_manager' + include Puppet::Interface::OptionManager + extend Puppet::Interface::OptionManager include Puppet::Util class << self # This is just so we can search for actions. We only use its # list of directories to search. # Can't we utilize an external autoloader, or simply use the $LOAD_PATH? -pvb def autoloader @autoloader ||= Puppet::Util::Autoload.new(:application, "puppet/faces") end def faces - Puppet::Faces::FaceCollection.faces + Puppet::Interface::FaceCollection.faces end def face?(name, version) - Puppet::Faces::FaceCollection.face?(name, version) + Puppet::Interface::FaceCollection.face?(name, version) end def register(instance) - Puppet::Faces::FaceCollection.register(instance) + Puppet::Interface::FaceCollection.register(instance) end def define(name, version, &block) if face?(name, version) - face = Puppet::Faces::FaceCollection[name, version] + face = Puppet::Interface::FaceCollection[name, version] else face = self.new(name, version) - Puppet::Faces::FaceCollection.register(face) + Puppet::Interface::FaceCollection.register(face) # REVISIT: Shouldn't this be delayed until *after* we evaluate the # current block, not done before? --daniel 2011-04-07 face.load_actions end face.instance_eval(&block) if block_given? return face end alias :[] :define end attr_accessor :default_format def set_default_format(format) self.default_format = format.to_sym end attr_accessor :type, :verb, :version, :arguments attr_reader :name def initialize(name, version, &block) - unless Puppet::Faces::FaceCollection.validate_version(version) + unless Puppet::Interface::FaceCollection.validate_version(version) raise ArgumentError, "Cannot create face #{name.inspect} with invalid version number '#{version}'!" end - @name = Puppet::Faces::FaceCollection.underscorize(name) + @name = Puppet::Interface::FaceCollection.underscorize(name) @version = version @default_format = :pson instance_eval(&block) if block_given? end # Try to find actions defined in other files. def load_actions path = "puppet/faces/#{name}" loaded = [] [path, "#{name}@#{version}/#{path}"].each do |path| - Puppet::Faces.autoloader.search_directories.each do |dir| + Puppet::Interface.autoloader.search_directories.each do |dir| fdir = ::File.join(dir, path) next unless FileTest.directory?(fdir) Dir.chdir(fdir) do Dir.glob("*.rb").each do |file| aname = file.sub(/\.rb/, '') if loaded.include?(aname) Puppet.debug "Not loading duplicate action '#{aname}' for '#{name}' from '#{fdir}/#{file}'" next end loaded << aname Puppet.debug "Loading action '#{aname}' for '#{name}' from '#{fdir}/#{file}'" require "#{Dir.pwd}/#{aname}" end end end end end def to_s "Puppet::Faces[#{name.inspect}, #{version.inspect}]" end end diff --git a/lib/puppet/faces/action.rb b/lib/puppet/interface/action.rb similarity index 97% rename from lib/puppet/faces/action.rb rename to lib/puppet/interface/action.rb index 58d2c6003..e4a37a1f7 100644 --- a/lib/puppet/faces/action.rb +++ b/lib/puppet/interface/action.rb @@ -1,119 +1,119 @@ # -*- coding: utf-8 -*- -require 'puppet/faces' -require 'puppet/faces/option' +require 'puppet/interface' +require 'puppet/interface/option' -class Puppet::Faces::Action +class Puppet::Interface::Action def initialize(face, name, attrs = {}) raise "#{name.inspect} is an invalid action name" unless name.to_s =~ /^[a-z]\w*$/ @face = face @name = name.to_sym @options = {} attrs.each do |k, v| send("#{k}=", v) end end attr_reader :name def to_s() "#{@face}##{@name}" end # Initially, this was defined to allow the @action.invoke pattern, which is # a very natural way to invoke behaviour given our introspection # capabilities. Heck, our initial plan was to have the faces delegate to # the action object for invocation and all. # # It turns out that we have a binding problem to solve: @face was bound to # the parent class, not the subclass instance, and we don't pass the # appropriate context or change the binding enough to make this work. # # We could hack around it, by either mandating that you pass the context in # to invoke, or try to get the binding right, but that has probably got # subtleties that we don't instantly think of – especially around threads. # # So, we are pulling this method for now, and will return it to life when we # have the time to resolve the problem. For now, you should replace... # # @action = @face.get_action(name) # @action.invoke(arg1, arg2, arg3) # # ...with... # # @action = @face.get_action(name) # @face.send(@action.name, arg1, arg2, arg3) # # I understand that is somewhat cumbersome, but it functions as desired. # --daniel 2011-03-31 # # PS: This code is left present, but commented, to support this chunk of # documentation, for the benefit of the reader. # # def invoke(*args, &block) # @face.send(name, *args, &block) # end def when_invoked=(block) # We need to build an instance method as a wrapper, using normal code, to # be able to expose argument defaulting between the caller and definer in # the Ruby API. An extra method is, sadly, required for Ruby 1.8 to work. # # In future this also gives us a place to hook in additional behaviour # such as calling out to the action instance to validate and coerce # parameters, which avoids any exciting context switching and all. # # Hopefully we can improve this when we finally shuffle off the last of # Ruby 1.8 support, but that looks to be a few "enterprise" release eras # away, so we are pretty stuck with this for now. # # Patches to make this work more nicely with Ruby 1.9 using runtime # version checking and all are welcome, but they can't actually help if # the results are not totally hidden away in here. # # Incidentally, we though about vendoring evil-ruby and actually adjusting # the internal C structure implementation details under the hood to make # this stuff work, because it would have been cleaner. Which gives you an # idea how motivated we were to make this cleaner. Sorry. --daniel 2011-03-31 internal_name = "#{@name} implementation, required on Ruby 1.8".to_sym file = __FILE__ + "+eval" line = __LINE__ + 1 wrapper = "def #{@name}(*args, &block) args << {} unless args.last.is_a? Hash args << block if block_given? self.__send__(#{internal_name.inspect}, *args) end" if @face.is_a?(Class) @face.class_eval do eval wrapper, nil, file, line end @face.define_method(internal_name, &block) else @face.instance_eval do eval wrapper, nil, file, line end @face.meta_def(internal_name, &block) end end def add_option(option) option.aliases.each do |name| if conflict = get_option(name) then raise ArgumentError, "Option #{option} conflicts with existing option #{conflict}" elsif conflict = @face.get_option(name) then raise ArgumentError, "Option #{option} conflicts with existing option #{conflict} on #{@face}" end end option.aliases.each do |name| @options[name] = option end option end def option?(name) @options.include? name.to_sym end def options (@options.keys + @face.options).sort end def get_option(name) @options[name.to_sym] || @face.get_option(name) end end diff --git a/lib/puppet/faces/action_builder.rb b/lib/puppet/interface/action_builder.rb similarity index 74% rename from lib/puppet/faces/action_builder.rb rename to lib/puppet/interface/action_builder.rb index a67068926..b08c3d023 100644 --- a/lib/puppet/faces/action_builder.rb +++ b/lib/puppet/interface/action_builder.rb @@ -1,31 +1,31 @@ -require 'puppet/faces' -require 'puppet/faces/action' +require 'puppet/interface' +require 'puppet/interface/action' -class Puppet::Faces::ActionBuilder +class Puppet::Interface::ActionBuilder attr_reader :action def self.build(face, name, &block) raise "Action #{name.inspect} must specify a block" unless block new(face, name, &block).action end private def initialize(face, name, &block) @face = face - @action = Puppet::Faces::Action.new(face, name) + @action = Puppet::Interface::Action.new(face, name) instance_eval(&block) end # Ideally the method we're defining here would be added to the action, and a # method on the face would defer to it, but we can't get scope correct, so # we stick with this. --daniel 2011-03-24 def when_invoked(&block) raise "when_invoked on an ActionBuilder with no corresponding Action" unless @action @action.when_invoked = block end def option(*declaration, &block) - option = Puppet::Faces::OptionBuilder.build(@action, *declaration, &block) + option = Puppet::Interface::OptionBuilder.build(@action, *declaration, &block) @action.add_option(option) end end diff --git a/lib/puppet/faces/action_manager.rb b/lib/puppet/interface/action_manager.rb similarity index 83% rename from lib/puppet/faces/action_manager.rb rename to lib/puppet/interface/action_manager.rb index 6c0036bd8..bb0e5bf57 100644 --- a/lib/puppet/faces/action_manager.rb +++ b/lib/puppet/interface/action_manager.rb @@ -1,49 +1,49 @@ -require 'puppet/faces/action_builder' +require 'puppet/interface/action_builder' -module Puppet::Faces::ActionManager +module Puppet::Interface::ActionManager # Declare that this app can take a specific action, and provide # the code to do so. def action(name, &block) @actions ||= {} raise "Action #{name} already defined for #{self}" if action?(name) - action = Puppet::Faces::ActionBuilder.build(self, name, &block) + action = Puppet::Interface::ActionBuilder.build(self, name, &block) @actions[action.name] = action end # This is the short-form of an action definition; it doesn't use the # builder, just creates the action directly from the block. def script(name, &block) @actions ||= {} raise "Action #{name} already defined for #{self}" if action?(name) - @actions[name] = Puppet::Faces::Action.new(self, name, :when_invoked => block) + @actions[name] = Puppet::Interface::Action.new(self, name, :when_invoked => block) end def actions @actions ||= {} result = @actions.keys if self.is_a?(Class) and superclass.respond_to?(:actions) result += superclass.actions elsif self.class.respond_to?(:actions) result += self.class.actions end result.sort end def get_action(name) @actions ||= {} result = @actions[name.to_sym] if result.nil? if self.is_a?(Class) and superclass.respond_to?(:get_action) result = superclass.get_action(name) elsif self.class.respond_to?(:get_action) result = self.class.get_action(name) end end return result end def action?(name) actions.include?(name.to_sym) end end diff --git a/lib/puppet/faces/face_collection.rb b/lib/puppet/interface/face_collection.rb similarity index 98% rename from lib/puppet/faces/face_collection.rb rename to lib/puppet/interface/face_collection.rb index e6ee709d6..9f7a499c2 100644 --- a/lib/puppet/faces/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -1,125 +1,125 @@ # -*- coding: utf-8 -*- -require 'puppet/faces' +require 'puppet/interface' -module Puppet::Faces::FaceCollection +module Puppet::Interface::FaceCollection SEMVER_VERSION = /^(\d+)\.(\d+)\.(\d+)([A-Za-z][0-9A-Za-z-]*|)$/ @faces = Hash.new { |hash, key| hash[key] = {} } def self.faces unless @loaded @loaded = true $LOAD_PATH.each do |dir| next unless FileTest.directory?(dir) Dir.chdir(dir) do # REVISIT: This is wrong!!!! We don't name files like that ever, # so we should no longer match things like this. Damnit!!! --daniel 2011-04-07 Dir.glob("puppet/faces/v*/*.rb").collect { |f| f.sub(/\.rb/, '') }.each do |file| iname = file.sub(/\.rb/, '') begin require iname rescue Exception => detail puts detail.backtrace if Puppet[:trace] raise "Could not load #{iname} from #{dir}/#{file}: #{detail}" end end end end end return @faces.keys end def self.validate_version(version) !!(SEMVER_VERSION =~ version.to_s) end def self.cmp_semver(a, b) a, b = [a, b].map do |x| parts = SEMVER_VERSION.match(x).to_a[1..4] parts[0..2] = parts[0..2].map { |e| e.to_i } parts end cmp = a[0..2] <=> b[0..2] if cmp == 0 cmp = a[3] <=> b[3] cmp = +1 if a[3].empty? && !b[3].empty? cmp = -1 if b[3].empty? && !a[3].empty? end cmp end def self.[](name, version) @faces[underscorize(name)][version] if face?(name, version) end def self.face?(name, version) name = underscorize(name) return true if @faces[name].has_key?(version) # We always load the current version file; the common case is that we have # the expected version and any compatibility versions in the same file, # the default. Which means that this is almost always the case. # # We use require to avoid executing the code multiple times, like any # other Ruby library that we might want to use. --daniel 2011-04-06 begin require "puppet/faces/#{name}" # If we wanted :current, we need to index to find that; direct version # requests just work™ as they go. --daniel 2011-04-06 if version == :current then # We need to find current out of this. This is the largest version # number that doesn't have a dedicated on-disk file present; those # represent "experimental" versions of faces, which we don't fully # support yet. # # We walk the versions from highest to lowest and take the first version # that is not defined in an explicitly versioned file on disk as the # current version. # # This constrains us to only ship experimental versions with *one* # version in the file, not multiple, but given you can't reliably load # them except by side-effect when you ignore that rule this seems safe # enough... # # Given those constraints, and that we are not going to ship a versioned # interface that is not :current in this release, we are going to leave # these thoughts in place, and just punt on the actual versioning. # # When we upgrade the core to support multiple versions we can solve the # problems then; as lazy as possible. # # We do support multiple versions in the same file, though, so we sort # versions here and return the last item in that set. # # --daniel 2011-04-06 latest_ver = @faces[name].keys.sort {|a, b| cmp_semver(a, b) }.last @faces[name][:current] = @faces[name][latest_ver] end rescue LoadError => e raise unless e.message =~ %r{-- puppet/faces/#{name}$} # ...guess we didn't find the file; return a much better problem. end # Now, either we have the version in our set of faces, or we didn't find # the version they were looking for. In the future we will support # loading versioned stuff from some look-aside part of the Ruby load path, # but we don't need that right now. # # So, this comment is a place-holder for that. --daniel 2011-04-06 return !! @faces[name].has_key?(version) end def self.register(face) @faces[underscorize(face.name)][face.version] = face end def self.underscorize(name) unless name.to_s =~ /^[-_a-z]+$/i then raise ArgumentError, "#{name.inspect} (#{name.class}) is not a valid face name" end name.to_s.downcase.split(/[-_]/).join('_').to_sym end end diff --git a/lib/puppet/faces/option.rb b/lib/puppet/interface/option.rb similarity index 97% rename from lib/puppet/faces/option.rb rename to lib/puppet/interface/option.rb index 7d3ed37ca..ccc2fbba7 100644 --- a/lib/puppet/faces/option.rb +++ b/lib/puppet/interface/option.rb @@ -1,82 +1,82 @@ -require 'puppet/faces' +require 'puppet/interface' -class Puppet::Faces::Option +class Puppet::Interface::Option attr_reader :parent attr_reader :name attr_reader :aliases attr_reader :optparse attr_accessor :desc def takes_argument? !!@argument end def optional_argument? !!@optional_argument end def initialize(parent, *declaration, &block) @parent = parent @optparse = [] # Collect and sort the arguments in the declaration. dups = {} declaration.each do |item| if item.is_a? String and item.to_s =~ /^-/ then unless item =~ /^-[a-z]\b/ or item =~ /^--[^-]/ then raise ArgumentError, "#{item.inspect}: long options need two dashes (--)" end @optparse << item # Duplicate checking... name = optparse_to_name(item) if dup = dups[name] then raise ArgumentError, "#{item.inspect}: duplicates existing alias #{dup.inspect} in #{@parent}" else dups[name] = item end else raise ArgumentError, "#{item.inspect} is not valid for an option argument" end end if @optparse.empty? then raise ArgumentError, "No option declarations found while building" end # Now, infer the name from the options; we prefer the first long option as # the name, rather than just the first option. @name = optparse_to_name(@optparse.find do |a| a =~ /^--/ end || @optparse.first) @aliases = @optparse.map { |o| optparse_to_name(o) } # Do we take an argument? If so, are we consistent about it, because # incoherence here makes our life super-difficult, and we can more easily # relax this rule later if we find a valid use case for it. --daniel 2011-03-30 @argument = @optparse.any? { |o| o =~ /[ =]/ } if @argument and not @optparse.all? { |o| o =~ /[ =]/ } then raise ArgumentError, "Option #{@name} is inconsistent about taking an argument" end # Is our argument optional? The rules about consistency apply here, also, # just like they do to taking arguments at all. --daniel 2011-03-30 @optional_argument = @optparse.any? { |o| o.include? "[" } if @optional_argument and not @optparse.all? { |o| o.include? "[" } then raise ArgumentError, "Option #{@name} is inconsistent about the argument being optional" end end # to_s and optparse_to_name are roughly mirrored, because they are used to # transform options to name symbols, and vice-versa. This isn't a full # bidirectional transformation though. --daniel 2011-04-07 def to_s @name.to_s.tr('_', '-') end def optparse_to_name(declaration) unless found = declaration.match(/^-+(?:\[no-\])?([^ =]+)/) then raise ArgumentError, "Can't find a name in the declaration #{declaration.inspect}" end name = found.captures.first.tr('-', '_') raise "#{name.inspect} is an invalid option name" unless name.to_s =~ /^[a-z]\w*$/ name.to_sym end end diff --git a/lib/puppet/faces/option_builder.rb b/lib/puppet/interface/option_builder.rb similarity index 69% rename from lib/puppet/faces/option_builder.rb rename to lib/puppet/interface/option_builder.rb index 0b6667546..83a1906b0 100644 --- a/lib/puppet/faces/option_builder.rb +++ b/lib/puppet/interface/option_builder.rb @@ -1,25 +1,25 @@ -require 'puppet/faces/option' +require 'puppet/interface/option' -class Puppet::Faces::OptionBuilder +class Puppet::Interface::OptionBuilder attr_reader :option def self.build(face, *declaration, &block) new(face, *declaration, &block).option end private def initialize(face, *declaration, &block) @face = face - @option = Puppet::Faces::Option.new(face, *declaration) + @option = Puppet::Interface::Option.new(face, *declaration) block and instance_eval(&block) @option end # Metaprogram the simple DSL from the option class. - Puppet::Faces::Option.instance_methods.grep(/=$/).each do |setter| + Puppet::Interface::Option.instance_methods.grep(/=$/).each do |setter| next if setter =~ /^=/ # special case, darn it... dsl = setter.sub(/=$/, '') define_method(dsl) do |value| @option.send(setter, value) end end end diff --git a/lib/puppet/faces/option_manager.rb b/lib/puppet/interface/option_manager.rb similarity index 89% rename from lib/puppet/faces/option_manager.rb rename to lib/puppet/interface/option_manager.rb index 02a73afc3..56df9760f 100644 --- a/lib/puppet/faces/option_manager.rb +++ b/lib/puppet/interface/option_manager.rb @@ -1,56 +1,56 @@ -require 'puppet/faces/option_builder' +require 'puppet/interface/option_builder' -module Puppet::Faces::OptionManager +module Puppet::Interface::OptionManager # Declare that this app can take a specific option, and provide # the code to do so. def option(*declaration, &block) - add_option Puppet::Faces::OptionBuilder.build(self, *declaration, &block) + add_option Puppet::Interface::OptionBuilder.build(self, *declaration, &block) end def add_option(option) option.aliases.each do |name| if conflict = get_option(name) then raise ArgumentError, "Option #{option} conflicts with existing option #{conflict}" end actions.each do |action| action = get_action(action) if conflict = action.get_option(name) then raise ArgumentError, "Option #{option} conflicts with existing option #{conflict} on #{action}" end end end option.aliases.each { |name| @options[name] = option } option end def options @options ||= {} result = @options.keys if self.is_a?(Class) and superclass.respond_to?(:options) result += superclass.options elsif self.class.respond_to?(:options) result += self.class.options end result.sort end def get_option(name) @options ||= {} result = @options[name.to_sym] unless result then if self.is_a?(Class) and superclass.respond_to?(:get_option) result = superclass.get_option(name) elsif self.class.respond_to?(:get_option) result = self.class.get_option(name) end end return result end def option?(name) options.include? name.to_sym end end diff --git a/spec/unit/faces/catalog_spec.rb b/spec/unit/faces/catalog_spec.rb index 7621a864a..71972194a 100755 --- a/spec/unit/faces/catalog_spec.rb +++ b/spec/unit/faces/catalog_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:catalog, '0.0.1'] do + it "should actually have some testing..." end diff --git a/spec/unit/faces/certificate_request_spec.rb b/spec/unit/faces/certificate_request_spec.rb index 637ea8c38..1a71a8379 100755 --- a/spec/unit/faces/certificate_request_spec.rb +++ b/spec/unit/faces/certificate_request_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:certificate_request, '0.0.1'] do + it "should actually have some tests..." end diff --git a/spec/unit/faces/certificate_revocation_list_spec.rb b/spec/unit/faces/certificate_revocation_list_spec.rb index e319b18e2..4f41edef6 100755 --- a/spec/unit/faces/certificate_revocation_list_spec.rb +++ b/spec/unit/faces/certificate_revocation_list_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:certificate_revocation_list, '0.0.1'] do + it "should actually have some tests..." end diff --git a/spec/unit/faces/file_spec.rb b/spec/unit/faces/file_spec.rb index aafa88ce0..fcb52c67e 100755 --- a/spec/unit/faces/file_spec.rb +++ b/spec/unit/faces/file_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:file, '0.0.1'] do + it "should actually have some tests..." end diff --git a/spec/unit/faces/key_spec.rb b/spec/unit/faces/key_spec.rb index 70d4a52c1..9b7a58706 100755 --- a/spec/unit/faces/key_spec.rb +++ b/spec/unit/faces/key_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:key, '0.0.1'] do + it "should actually have some tests..." end diff --git a/spec/unit/faces/option_builder_spec.rb b/spec/unit/faces/option_builder_spec.rb deleted file mode 100644 index 9296ba7b6..000000000 --- a/spec/unit/faces/option_builder_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'puppet/faces/option_builder' - -describe Puppet::Faces::OptionBuilder do - let :face do Puppet::Faces.new(:option_builder_testing, '0.0.1') end - - it "should be able to construct an option without a block" do - Puppet::Faces::OptionBuilder.build(face, "--foo"). - should be_an_instance_of Puppet::Faces::Option - end - - describe "when using the DSL block" do - it "should work with an empty block" do - option = Puppet::Faces::OptionBuilder.build(face, "--foo") do - # This block deliberately left blank. - end - - option.should be_an_instance_of Puppet::Faces::Option - end - - it "should support documentation declarations" do - text = "this is the description" - option = Puppet::Faces::OptionBuilder.build(face, "--foo") do - desc text - end - option.should be_an_instance_of Puppet::Faces::Option - option.desc.should == text - end - end -end diff --git a/spec/unit/faces/report_spec.rb b/spec/unit/faces/report_spec.rb index f7a67349c..30897d5e7 100755 --- a/spec/unit/faces/report_spec.rb +++ b/spec/unit/faces/report_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:report, '0.0.1'] do + it "should actually have some tests..." end diff --git a/spec/unit/faces/resource_spec.rb b/spec/unit/faces/resource_spec.rb index 0b4b24882..e3f2e1c62 100755 --- a/spec/unit/faces/resource_spec.rb +++ b/spec/unit/faces/resource_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:resource, '0.0.1'] do + it "should actually have some tests..." end diff --git a/spec/unit/faces/resource_type_spec.rb b/spec/unit/faces/resource_type_spec.rb index 157066f2d..fcbf07520 100755 --- a/spec/unit/faces/resource_type_spec.rb +++ b/spec/unit/faces/resource_type_spec.rb @@ -1,6 +1,3 @@ -#!/usr/bin/env ruby - -require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') - describe Puppet::Faces[:resource_type, '0.0.1'] do + it "should actually have some tests..." end diff --git a/spec/unit/faces/action_builder_spec.rb b/spec/unit/interface/action_builder_spec.rb similarity index 60% rename from spec/unit/faces/action_builder_spec.rb rename to spec/unit/interface/action_builder_spec.rb index 5c8b98849..ae9cc83d4 100755 --- a/spec/unit/faces/action_builder_spec.rb +++ b/spec/unit/interface/action_builder_spec.rb @@ -1,59 +1,59 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') -require 'puppet/faces/action_builder' +require 'puppet/interface/action_builder' -describe Puppet::Faces::ActionBuilder do +describe Puppet::Interface::ActionBuilder do describe "::build" do it "should build an action" do - action = Puppet::Faces::ActionBuilder.build(nil, :foo) do + action = Puppet::Interface::ActionBuilder.build(nil, :foo) do end - action.should be_a(Puppet::Faces::Action) + action.should be_a(Puppet::Interface::Action) action.name.should == :foo end it "should define a method on the face which invokes the action" do - face = Puppet::Faces.new(:action_builder_test_faces, '0.0.1') - action = Puppet::Faces::ActionBuilder.build(face, :foo) do + face = Puppet::Interface.new(:action_builder_test_interface, '0.0.1') + action = Puppet::Interface::ActionBuilder.build(face, :foo) do when_invoked do "invoked the method" end end face.foo.should == "invoked the method" end it "should require a block" do - expect { Puppet::Faces::ActionBuilder.build(nil, :foo) }. + expect { Puppet::Interface::ActionBuilder.build(nil, :foo) }. should raise_error("Action :foo must specify a block") end describe "when handling options" do - let :face do Puppet::Faces.new(:option_handling, '0.0.1') end + let :face do Puppet::Interface.new(:option_handling, '0.0.1') end it "should have a #option DSL function" do method = nil - Puppet::Faces::ActionBuilder.build(face, :foo) do + Puppet::Interface::ActionBuilder.build(face, :foo) do method = self.method(:option) end method.should be end it "should define an option without a block" do - action = Puppet::Faces::ActionBuilder.build(face, :foo) do + action = Puppet::Interface::ActionBuilder.build(face, :foo) do option "--bar" end action.should be_option :bar end it "should accept an empty block" do - action = Puppet::Faces::ActionBuilder.build(face, :foo) do + action = Puppet::Interface::ActionBuilder.build(face, :foo) do option "--bar" do # This space left deliberately blank. end end action.should be_option :bar end end end end diff --git a/spec/unit/faces/action_manager_spec.rb b/spec/unit/interface/action_manager_spec.rb similarity index 93% rename from spec/unit/faces/action_manager_spec.rb rename to spec/unit/interface/action_manager_spec.rb index 61d1c1df5..50bea5f89 100755 --- a/spec/unit/faces/action_manager_spec.rb +++ b/spec/unit/interface/action_manager_spec.rb @@ -1,233 +1,233 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') -# This is entirely an internal class for Faces, so we have to load it instead of our class. -require 'puppet/faces' +# This is entirely an internal class for Interface, so we have to load it instead of our class. +require 'puppet/interface' class ActionManagerTester - include Puppet::Faces::ActionManager + include Puppet::Interface::ActionManager end -describe Puppet::Faces::ActionManager do +describe Puppet::Interface::ActionManager do subject { ActionManagerTester.new } describe "when included in a class" do it "should be able to define an action" do subject.action(:foo) do when_invoked { "something "} end end it "should be able to define a 'script' style action" do subject.script :bar do "a bar is where beer is found" end end it "should be able to list defined actions" do subject.action(:foo) do when_invoked { "something" } end subject.action(:bar) do when_invoked { "something" } end subject.actions.should =~ [:foo, :bar] end it "should list 'script' actions" do subject.script :foo do "foo" end subject.actions.should =~ [:foo] end it "should list both script and normal actions" do subject.action :foo do when_invoked do "foo" end end subject.script :bar do "a bar is where beer is found" end subject.actions.should =~ [:foo, :bar] end it "should be able to indicate when an action is defined" do subject.action(:foo) do when_invoked { "something" } end subject.should be_action(:foo) end it "should indicate an action is defined for script actions" do subject.script :foo do "foo" end subject.should be_action :foo end it "should correctly treat action names specified as strings" do subject.action(:foo) do when_invoked { "something" } end subject.should be_action("foo") end end describe "when used to extend a class" do - subject { Class.new.extend(Puppet::Faces::ActionManager) } + subject { Class.new.extend(Puppet::Interface::ActionManager) } it "should be able to define an action" do subject.action(:foo) do when_invoked { "something "} end end it "should be able to list defined actions" do subject.action(:foo) do when_invoked { "something" } end subject.action(:bar) do when_invoked { "something" } end subject.actions.should include(:bar) subject.actions.should include(:foo) end it "should be able to indicate when an action is defined" do subject.action(:foo) { "something" } subject.should be_action(:foo) end end describe "when used both at the class and instance level" do before do @klass = Class.new do - include Puppet::Faces::ActionManager - extend Puppet::Faces::ActionManager + include Puppet::Interface::ActionManager + extend Puppet::Interface::ActionManager end @instance = @klass.new end it "should be able to define an action at the class level" do @klass.action(:foo) do when_invoked { "something "} end end it "should create an instance method when an action is defined at the class level" do @klass.action(:foo) do when_invoked { "something" } end @instance.foo.should == "something" end it "should be able to define an action at the instance level" do @instance.action(:foo) do when_invoked { "something "} end end it "should create an instance method when an action is defined at the instance level" do @instance.action(:foo) do when_invoked { "something" } end @instance.foo.should == "something" end it "should be able to list actions defined at the class level" do @klass.action(:foo) do when_invoked { "something" } end @klass.action(:bar) do when_invoked { "something" } end @klass.actions.should include(:bar) @klass.actions.should include(:foo) end it "should be able to list actions defined at the instance level" do @instance.action(:foo) do when_invoked { "something" } end @instance.action(:bar) do when_invoked { "something" } end @instance.actions.should include(:bar) @instance.actions.should include(:foo) end it "should be able to list actions defined at both instance and class level" do @klass.action(:foo) do when_invoked { "something" } end @instance.action(:bar) do when_invoked { "something" } end @instance.actions.should include(:bar) @instance.actions.should include(:foo) end it "should be able to indicate when an action is defined at the class level" do @klass.action(:foo) do when_invoked { "something" } end @instance.should be_action(:foo) end it "should be able to indicate when an action is defined at the instance level" do @klass.action(:foo) do when_invoked { "something" } end @instance.should be_action(:foo) end it "should list actions defined in superclasses" do @subclass = Class.new(@klass) @instance = @subclass.new @klass.action(:parent) do when_invoked { "a" } end @subclass.action(:sub) do when_invoked { "a" } end @instance.action(:instance) do when_invoked { "a" } end @instance.should be_action(:parent) @instance.should be_action(:sub) @instance.should be_action(:instance) end it "should create an instance method when an action is defined in a superclass" do @subclass = Class.new(@klass) @instance = @subclass.new @klass.action(:foo) do when_invoked { "something" } end @instance.foo.should == "something" end end describe "#get_action" do let :parent_class do - parent_class = Class.new(Puppet::Faces) + parent_class = Class.new(Puppet::Interface) parent_class.action(:foo) {} parent_class end it "should check that we can find inherited actions when we are a class" do Class.new(parent_class).get_action(:foo).name.should == :foo end it "should check that we can find inherited actions when we are an instance" do instance = parent_class.new(:foo, '0.0.0') instance.get_action(:foo).name.should == :foo end end end diff --git a/spec/unit/faces/action_spec.rb b/spec/unit/interface/action_spec.rb similarity index 82% rename from spec/unit/faces/action_spec.rb rename to spec/unit/interface/action_spec.rb index c087744b1..4801a3cc8 100755 --- a/spec/unit/faces/action_spec.rb +++ b/spec/unit/interface/action_spec.rb @@ -1,173 +1,173 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') -require 'puppet/faces/action' +require 'puppet/interface/action' -describe Puppet::Faces::Action do +describe Puppet::Interface::Action do describe "when validating the action name" do [nil, '', 'foo bar', '-foobar'].each do |input| it "should treat #{input.inspect} as an invalid name" do - expect { Puppet::Faces::Action.new(nil, input) }. + expect { Puppet::Interface::Action.new(nil, input) }. should raise_error(/is an invalid action name/) end end end describe "when invoking" do it "should be able to call other actions on the same object" do - face = Puppet::Faces.new(:my_face, '0.0.1') do + face = Puppet::Interface.new(:my_face, '0.0.1') do action(:foo) do when_invoked { 25 } end action(:bar) do when_invoked { "the value of foo is '#{foo}'" } end end face.foo.should == 25 face.bar.should == "the value of foo is '25'" end # bar is a class action calling a class action # quux is a class action calling an instance action # baz is an instance action calling a class action # qux is an instance action calling an instance action it "should be able to call other actions on the same object when defined on a class" do - class Puppet::Faces::MyFacesBaseClass < Puppet::Faces + class Puppet::Interface::MyInterfaceBaseClass < Puppet::Interface action(:foo) do when_invoked { 25 } end action(:bar) do when_invoked { "the value of foo is '#{foo}'" } end action(:quux) do when_invoked { "qux told me #{qux}" } end end - face = Puppet::Faces::MyFacesBaseClass.new(:my_inherited_face, '0.0.1') do + face = Puppet::Interface::MyInterfaceBaseClass.new(:my_inherited_face, '0.0.1') do action(:baz) do when_invoked { "the value of foo in baz is '#{foo}'" } end action(:qux) do when_invoked { baz } end end face.foo.should == 25 face.bar.should == "the value of foo is '25'" face.quux.should == "qux told me the value of foo in baz is '25'" face.baz.should == "the value of foo in baz is '25'" face.qux.should == "the value of foo in baz is '25'" end context "when calling the Ruby API" do let :face do - Puppet::Faces.new(:ruby_api, '1.0.0') do + Puppet::Interface.new(:ruby_api, '1.0.0') do action :bar do when_invoked do |options| options end end end end it "should work when no options are supplied" do options = face.bar options.should == {} end it "should work when options are supplied" do options = face.bar :bar => "beer" options.should == { :bar => "beer" } end end end describe "with action-level options" do it "should support options with an empty block" do - face = Puppet::Faces.new(:action_level_options, '0.0.1') do + face = Puppet::Interface.new(:action_level_options, '0.0.1') do action :foo do option "--bar" do # this line left deliberately blank end end end face.should_not be_option :bar face.get_action(:foo).should be_option :bar end it "should return only action level options when there are no face options" do - face = Puppet::Faces.new(:action_level_options, '0.0.1') do + face = Puppet::Interface.new(:action_level_options, '0.0.1') do action :foo do option "--bar" end end face.get_action(:foo).options.should =~ [:bar] end describe "with both face and action options" do let :face do - Puppet::Faces.new(:action_level_options, '0.0.1') do + Puppet::Interface.new(:action_level_options, '0.0.1') do action :foo do option "--bar" end action :baz do option "--bim" end option "--quux" end end it "should return combined face and action options" do face.get_action(:foo).options.should =~ [:bar, :quux] end it "should fetch options that the face inherited" do - parent = Class.new(Puppet::Faces) + parent = Class.new(Puppet::Interface) parent.option "--foo" child = parent.new(:inherited_options, '0.0.1') do option "--bar" action :action do option "--baz" end end action = child.get_action(:action) action.should be [:baz, :bar, :foo].each do |name| - action.get_option(name).should be_an_instance_of Puppet::Faces::Option + action.get_option(name).should be_an_instance_of Puppet::Interface::Option end end it "should get an action option when asked" do face.get_action(:foo).get_option(:bar). - should be_an_instance_of Puppet::Faces::Option + should be_an_instance_of Puppet::Interface::Option end it "should get a face option when asked" do face.get_action(:foo).get_option(:quux). - should be_an_instance_of Puppet::Faces::Option + should be_an_instance_of Puppet::Interface::Option end it "should return options only for this action" do face.get_action(:baz).options.should =~ [:bim, :quux] end end it_should_behave_like "things that declare options" do def add_options_to(&block) - face = Puppet::Faces.new(:with_options, '0.0.1') do + face = Puppet::Interface.new(:with_options, '0.0.1') do action(:foo, &block) end face.get_action(:foo) end end it "should fail when a face option duplicates an action option" do expect { - Puppet::Faces.new(:action_level_options, '0.0.1') do + Puppet::Interface.new(:action_level_options, '0.0.1') do option "--foo" action :bar do option "--foo" end end }.should raise_error ArgumentError, /Option foo conflicts with existing option foo/i end end end diff --git a/spec/unit/faces/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb similarity index 96% rename from spec/unit/faces/face_collection_spec.rb rename to spec/unit/interface/face_collection_spec.rb index 30147a548..de6d29cee 100755 --- a/spec/unit/faces/face_collection_spec.rb +++ b/spec/unit/interface/face_collection_spec.rb @@ -1,184 +1,184 @@ #!/usr/bin/env ruby require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') require 'tmpdir' -describe Puppet::Faces::FaceCollection do +describe Puppet::Interface::FaceCollection do # To avoid cross-pollution we have to save and restore both the hash - # containing all the faces data, and the array used by require. Restoring + # containing all the interface data, and the array used by require. Restoring # both means that we don't leak side-effects across the code. --daniel 2011-04-06 before :each do - @original_faces = subject.instance_variable_get("@faces").dup + @original_faces = subject.instance_variable_get("@faces").dup @original_required = $".dup subject.instance_variable_get("@faces").clear end after :each do subject.instance_variable_set("@faces", @original_faces) $".clear ; @original_required.each do |item| $" << item end end describe "::faces" do it "REVISIT: should have some tests here, if we describe it" end describe "::validate_version" do it 'should permit three number versions' do subject.validate_version('10.10.10').should == true end it 'should permit versions with appended descriptions' do subject.validate_version('10.10.10beta').should == true end it 'should not permit versions with more than three numbers' do subject.validate_version('1.2.3.4').should == false end it 'should not permit versions with only two numbers' do subject.validate_version('10.10').should == false end it 'should not permit versions with only one number' do subject.validate_version('123').should == false end it 'should not permit versions with text in any position but at the end' do subject.validate_version('v1.1.1').should == false end end describe "::[]" do before :each do subject.instance_variable_get("@faces")[:foo]['0.0.1'] = 10 end before :each do @dir = Dir.mktmpdir @lib = FileUtils.mkdir_p(File.join @dir, 'puppet', 'faces') $LOAD_PATH.push(@dir) end after :each do FileUtils.remove_entry_secure @dir $LOAD_PATH.pop end it "should return the faces with the given name" do subject["foo", '0.0.1'].should == 10 end it "should attempt to load the faces if it isn't found" do subject.expects(:require).with('puppet/faces/bar') subject["bar", '0.0.1'] end it "should attempt to load the default faces for the specified version :current" do subject.expects(:require).never # except... subject.expects(:require).with('puppet/faces/fozzie') subject['fozzie', :current] end end describe "::face?" do before :each do subject.instance_variable_get("@faces")[:foo]['0.0.1'] = 10 end it "should return true if the faces specified is registered" do subject.face?("foo", '0.0.1').should == true end it "should attempt to require the faces if it is not registered" do subject.expects(:require).with do |file| subject.instance_variable_get("@faces")[:bar]['0.0.1'] = true file == 'puppet/faces/bar' end subject.face?("bar", '0.0.1').should == true end it "should return true if requiring the faces registered it" do subject.stubs(:require).with do subject.instance_variable_get("@faces")[:bar]['0.0.1'] = 20 end end it "should return false if the faces is not registered" do subject.stubs(:require).returns(true) subject.face?("bar", '0.0.1').should be_false end it "should return false if the faces file itself is missing" do subject.stubs(:require). raises(LoadError, 'no such file to load -- puppet/faces/bar') subject.face?("bar", '0.0.1').should be_false end it "should register the version loaded by `:current` as `:current`" do subject.expects(:require).with do |file| subject.instance_variable_get("@faces")[:huzzah]['2.0.1'] = :huzzah_faces file == 'puppet/faces/huzzah' end subject.face?("huzzah", :current) subject.instance_variable_get("@faces")[:huzzah][:current].should == :huzzah_faces end context "with something on disk" do before :each do write_scratch_faces :huzzah do |fh| fh.puts < {'0.0.1' => faces}} end end describe "::underscorize" do faulty = [1, "#foo", "$bar", "sturm und drang", :"sturm und drang"] valid = { "Foo" => :foo, :Foo => :foo, "foo_bar" => :foo_bar, :foo_bar => :foo_bar, "foo-bar" => :foo_bar, :"foo-bar" => :foo_bar, } valid.each do |input, expect| it "should map #{input.inspect} to #{expect.inspect}" do result = subject.underscorize(input) result.should == expect end end faulty.each do |input| it "should fail when presented with #{input.inspect} (#{input.class})" do expect { subject.underscorize(input) }. should raise_error ArgumentError, /not a valid face name/ end end end end diff --git a/spec/unit/interface/option_builder_spec.rb b/spec/unit/interface/option_builder_spec.rb new file mode 100644 index 000000000..fae48324e --- /dev/null +++ b/spec/unit/interface/option_builder_spec.rb @@ -0,0 +1,29 @@ +require 'puppet/interface/option_builder' + +describe Puppet::Interface::OptionBuilder do + let :face do Puppet::Interface.new(:option_builder_testing, '0.0.1') end + + it "should be able to construct an option without a block" do + Puppet::Interface::OptionBuilder.build(face, "--foo"). + should be_an_instance_of Puppet::Interface::Option + end + + describe "when using the DSL block" do + it "should work with an empty block" do + option = Puppet::Interface::OptionBuilder.build(face, "--foo") do + # This block deliberately left blank. + end + + option.should be_an_instance_of Puppet::Interface::Option + end + + it "should support documentation declarations" do + text = "this is the description" + option = Puppet::Interface::OptionBuilder.build(face, "--foo") do + desc text + end + option.should be_an_instance_of Puppet::Interface::Option + option.desc.should == text + end + end +end diff --git a/spec/unit/faces/option_spec.rb b/spec/unit/interface/option_spec.rb similarity index 67% rename from spec/unit/faces/option_spec.rb rename to spec/unit/interface/option_spec.rb index a28fef087..3bcd121e2 100644 --- a/spec/unit/faces/option_spec.rb +++ b/spec/unit/interface/option_spec.rb @@ -1,75 +1,75 @@ -require 'puppet/faces/option' +require 'puppet/interface/option' -describe Puppet::Faces::Option do - let :face do Puppet::Faces.new(:option_testing, '0.0.1') end +describe Puppet::Interface::Option do + let :face do Puppet::Interface.new(:option_testing, '0.0.1') end describe "#optparse_to_name" do ["", "=BAR", " BAR", "=bar", " bar"].each do |postfix| { "--foo" => :foo, "-f" => :f }.each do |base, expect| input = base + postfix it "should map #{input.inspect} to #{expect.inspect}" do - option = Puppet::Faces::Option.new(face, input) + option = Puppet::Interface::Option.new(face, input) option.name.should == expect end end end [:foo, 12, nil, {}, []].each do |input| it "should fail sensible when given #{input.inspect}" do - expect { Puppet::Faces::Option.new(face, input) }. + expect { Puppet::Interface::Option.new(face, input) }. should raise_error ArgumentError, /is not valid for an option argument/ end end ["-foo", "-foo=BAR", "-foo BAR"].each do |input| it "should fail with a single dash for long option #{input.inspect}" do - expect { Puppet::Faces::Option.new(face, input) }. + expect { Puppet::Interface::Option.new(face, input) }. should raise_error ArgumentError, /long options need two dashes \(--\)/ end end end it "requires a face when created" do - expect { Puppet::Faces::Option.new }. + expect { Puppet::Interface::Option.new }. should raise_error ArgumentError, /wrong number of arguments/ end it "also requires some declaration arguments when created" do - expect { Puppet::Faces::Option.new(face) }. + expect { Puppet::Interface::Option.new(face) }. should raise_error ArgumentError, /No option declarations found/ end it "should infer the name from an optparse string" do - option = Puppet::Faces::Option.new(face, "--foo") + option = Puppet::Interface::Option.new(face, "--foo") option.name.should == :foo end it "should infer the name when multiple optparse string are given" do - option = Puppet::Faces::Option.new(face, "--foo", "-f") + option = Puppet::Interface::Option.new(face, "--foo", "-f") option.name.should == :foo end it "should prefer the first long option name over a short option name" do - option = Puppet::Faces::Option.new(face, "-f", "--foo") + option = Puppet::Interface::Option.new(face, "-f", "--foo") option.name.should == :foo end it "should create an instance when given a face and name" do - Puppet::Faces::Option.new(face, "--foo"). - should be_instance_of Puppet::Faces::Option + Puppet::Interface::Option.new(face, "--foo"). + should be_instance_of Puppet::Interface::Option end describe "#to_s" do it "should transform a symbol into a string" do - option = Puppet::Faces::Option.new(face, "--foo") + option = Puppet::Interface::Option.new(face, "--foo") option.name.should == :foo option.to_s.should == "foo" end it "should use - rather than _ to separate words in strings but not symbols" do - option = Puppet::Faces::Option.new(face, "--foo-bar") + option = Puppet::Interface::Option.new(face, "--foo-bar") option.name.should == :foo_bar option.to_s.should == "foo-bar" end end end diff --git a/spec/unit/faces_spec.rb b/spec/unit/interface_spec.rb similarity index 59% rename from spec/unit/faces_spec.rb rename to spec/unit/interface_spec.rb index 586abd6b5..afcf95dcf 100755 --- a/spec/unit/faces_spec.rb +++ b/spec/unit/interface_spec.rb @@ -1,145 +1,146 @@ -#!/usr/bin/env ruby +require 'puppet/faces' +require 'puppet/interface' -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') +describe Puppet::Interface do + subject { Puppet::Interface } -describe Puppet::Faces do before :all do - @faces = Puppet::Faces::FaceCollection.instance_variable_get("@faces").dup + @faces = Puppet::Interface::FaceCollection.instance_variable_get("@faces").dup end before :each do - Puppet::Faces::FaceCollection.instance_variable_get("@faces").clear + Puppet::Interface::FaceCollection.instance_variable_get("@faces").clear end after :all do - Puppet::Faces::FaceCollection.instance_variable_set("@faces", @faces) + Puppet::Interface::FaceCollection.instance_variable_set("@faces", @faces) end describe "#define" do it "should register the face" do - face = Puppet::Faces.define(:face_test_register, '0.0.1') - face.should == Puppet::Faces[:face_test_register, '0.0.1'] + face = subject.define(:face_test_register, '0.0.1') + face.should == subject[:face_test_register, '0.0.1'] end it "should load actions" do - Puppet::Faces.any_instance.expects(:load_actions) - Puppet::Faces.define(:face_test_load_actions, '0.0.1') + subject.any_instance.expects(:load_actions) + subject.define(:face_test_load_actions, '0.0.1') end it "should require a version number" do - expect { Puppet::Faces.define(:no_version) }.should raise_error ArgumentError + expect { subject.define(:no_version) }.should raise_error ArgumentError end end describe "#initialize" do it "should require a version number" do - expect { Puppet::Faces.new(:no_version) }.should raise_error ArgumentError + expect { subject.new(:no_version) }.should raise_error ArgumentError end it "should require a valid version number" do - expect { Puppet::Faces.new(:bad_version, 'Rasins') }. + expect { subject.new(:bad_version, 'Rasins') }. should raise_error ArgumentError end it "should instance-eval any provided block" do - face = Puppet::Faces.new(:face_test_block, '0.0.1') do + face = subject.new(:face_test_block, '0.0.1') do action(:something) do when_invoked { "foo" } end end face.something.should == "foo" end end it "should have a name" do - Puppet::Faces.new(:me, '0.0.1').name.should == :me + subject.new(:me, '0.0.1').name.should == :me end it "should stringify with its own name" do - Puppet::Faces.new(:me, '0.0.1').to_s.should =~ /\bme\b/ + subject.new(:me, '0.0.1').to_s.should =~ /\bme\b/ end it "should allow overriding of the default format" do - face = Puppet::Faces.new(:me, '0.0.1') + face = subject.new(:me, '0.0.1') face.set_default_format :foo face.default_format.should == :foo end it "should default to :pson for its format" do - Puppet::Faces.new(:me, '0.0.1').default_format.should == :pson + subject.new(:me, '0.0.1').default_format.should == :pson end # Why? it "should create a class-level autoloader" do - Puppet::Faces.autoloader.should be_instance_of(Puppet::Util::Autoload) + subject.autoloader.should be_instance_of(Puppet::Util::Autoload) end it "should try to require faces that are not known" do - Puppet::Faces::FaceCollection.expects(:require).with "puppet/faces/foo" - Puppet::Faces[:foo, '0.0.1'] + subject::FaceCollection.expects(:require).with "puppet/faces/foo" + subject[:foo, '0.0.1'] end it "should be able to load all actions in all search paths" it_should_behave_like "things that declare options" do def add_options_to(&block) - Puppet::Faces.new(:with_options, '0.0.1', &block) + subject.new(:with_options, '0.0.1', &block) end end describe "with face-level options" do it "should not return any action-level options" do - face = Puppet::Faces.new(:with_options, '0.0.1') do + face = subject.new(:with_options, '0.0.1') do option "--foo" option "--bar" action :baz do option "--quux" end end face.options.should =~ [:foo, :bar] end it "should fail when a face option duplicates an action option" do expect { - Puppet::Faces.new(:action_level_options, '0.0.1') do + subject.new(:action_level_options, '0.0.1') do action :bar do option "--foo" end option "--foo" end }.should raise_error ArgumentError, /Option foo conflicts with existing option foo on/i end it "should work when two actions have the same option" do - face = Puppet::Faces.new(:with_options, '0.0.1') do + face = subject.new(:with_options, '0.0.1') do action :foo do option "--quux" end action :bar do option "--quux" end end face.get_action(:foo).options.should =~ [:quux] face.get_action(:bar).options.should =~ [:quux] end end describe "with inherited options" do let :face do - parent = Class.new(Puppet::Faces) + parent = Class.new(subject) parent.option("--inherited") face = parent.new(:example, '0.2.1') face.option("--local") face end describe "#options" do it "should list inherited options" do face.options.should =~ [:inherited, :local] end end describe "#get_option" do it "should return an inherited option object" do - face.get_option(:inherited).should be_an_instance_of Puppet::Faces::Option + face.get_option(:inherited).should be_an_instance_of subject::Option end end end end