summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/face/certificate.rb28
-rw-r--r--lib/puppet/face/help.rb8
-rw-r--r--lib/puppet/face/indirector.rb15
-rw-r--r--lib/puppet/interface.rb39
-rw-r--r--lib/puppet/interface/action.rb39
-rw-r--r--lib/puppet/interface/option.rb47
-rw-r--r--lib/puppet/interface/option_builder.rb31
-rw-r--r--lib/puppet/interface/option_manager.rb4
-rwxr-xr-xspec/lib/puppet/face/basetest.rb1
-rwxr-xr-xspec/unit/application/indirection_base_spec.rb7
-rwxr-xr-xspec/unit/face/certificate_spec.rb9
-rwxr-xr-xspec/unit/face/help_spec.rb22
-rwxr-xr-xspec/unit/interface/action_builder_spec.rb9
-rwxr-xr-xspec/unit/interface/action_manager_spec.rb1
-rwxr-xr-xspec/unit/interface/action_spec.rb181
-rwxr-xr-xspec/unit/interface/face_collection_spec.rb4
-rwxr-xr-xspec/unit/interface/option_builder_spec.rb53
-rwxr-xr-xspec/unit/interface/option_spec.rb24
18 files changed, 437 insertions, 85 deletions
diff --git a/lib/puppet/face/certificate.rb b/lib/puppet/face/certificate.rb
index 77e80f099..4c2950fb3 100644
--- a/lib/puppet/face/certificate.rb
+++ b/lib/puppet/face/certificate.rb
@@ -2,24 +2,16 @@ require 'puppet/face/indirector'
require 'puppet/ssl/host'
Puppet::Face::Indirector.define(:certificate, '0.0.1') do
- # REVISIT: This should use a pre-invoke hook to run the common code that
- # needs to happen before we invoke any action; that would be much nicer than
- # the "please repeat yourself" stuff found in here right now.
- #
- # option "--ca-location LOCATION" do
- # type [:whatever, :location, :symbols]
- # hook :before do |value|
- # Puppet::SSL::Host.ca_location = value
- # end
- # end
- #
- # ...but should I pass the arguments as well?
- # --daniel 2011-04-05
- option "--ca-location LOCATION"
+ option "--ca-location LOCATION" do
+ before_action do |action, args, options|
+ Puppet::SSL::Host.ca_location = options[:ca_location].to_sym
+ end
+ end
action :generate do
+ summary "Generate a new Certificate Signing Request for HOST"
+
when_invoked do |name, options|
- Puppet::SSL::Host.ca_location = options[:ca_location].to_sym
host = Puppet::SSL::Host.new(name)
host.generate_certificate_request
host.certificate_request.class.indirection.save(host.certificate_request)
@@ -27,8 +19,9 @@ Puppet::Face::Indirector.define(:certificate, '0.0.1') do
end
action :list do
+ summary "List all Certificate Signing Requests"
+
when_invoked do |options|
- Puppet::SSL::Host.ca_location = options[:ca_location].to_sym
Puppet::SSL::Host.indirection.search("*", {
:for => :certificate_request,
}).map { |h| h.inspect }
@@ -36,8 +29,9 @@ Puppet::Face::Indirector.define(:certificate, '0.0.1') do
end
action :sign do
+ summary "Sign a Certificate Signing Request for HOST"
+
when_invoked do |name, options|
- Puppet::SSL::Host.ca_location = options[:ca_location].to_sym
host = Puppet::SSL::Host.new(name)
host.desired_state = 'signed'
Puppet::SSL::Host.indirection.save(host)
diff --git a/lib/puppet/face/help.rb b/lib/puppet/face/help.rb
index 8bd495f8a..099025583 100644
--- a/lib/puppet/face/help.rb
+++ b/lib/puppet/face/help.rb
@@ -20,6 +20,14 @@ Puppet::Face.define(:help, '0.0.1') do
# should rewrite this to use those. --daniel 2011-04-04
options = args.pop
if options.nil? or args.length > 2 then
+ if args.select { |x| x == 'help' } .length > 2 then
+ c = "\n !\"'),-./7:;<GIJLST\\_`abcdefhiklmnoprstuwx|}".split('')
+ i = <<'EOT' .to_i(36)
+2s7ytxy5vpj74kbab5xzf1ik2roinzlefaspjrzckiert5xbaxvwlku3a91w7y1rsdnenp51gwpulmnrp54nwdil36fjgjarab801y0r5a9nh1hdfgi99arn5c5t3zhxbvziu6wx5r1tb7lun7pro69nrxunqqixsh6qmmv0ms0i0yycqw3pystyzmiita0lpxynqsqkbjwadcx82n76wwpzbht8i8rgvqhqick8mk3cs3rvwdjookpgu0rxw4tcezned5sqz5x8z9vntyyz0s4h6hjhtwtbytsmmu7ltvdftaixc7fkt276sqm48ab4yv0ot9y26nz0xniy4pfl1x300lt6h9c8of49vf799ieuxwnoycsjlmtd4qntzit524j0tdn6n5ajmq3z10apjuhkzprvmu53z1gnacymnoforrz5mbqto062kckgw5463pxwzg8liglub4ubnr0dln1s6iy3ummxuhim7m5a7yedl3gyy6ow4qqtmsigv27lysooau24zpsccsvxddwygjprqpbwon7i9s1279m1fpinvva8mfh6bgmotrpxsh1c8rc83l3u0utf5i200yl7ui0ngcbcjyr4erzdee2tqk3fpjvb82t8xhncruhgn7j5dh2m914qzhb0gkoom47k6et7rp4tqjnrv0y2apk5qdl1x1hnbkkxup5ys6ip2ksmtpd3ipmrdtswxr5xwfiqtm60uyjr1v79irhnkrbbt4fwhgqjby1qflgwt9c1wpayzzucep6npgbn3f1k6cn4pug31u02wel4tald4hij8m5p49xr8u4ero1ucs5uht42o8nhpmpe7c7xf9t85i85m9m5kktgoqkgbu52gy5aoteyp8jkm3vri9fnkmwa5h60zt8otja72joxjb40p2rz2vp8f8q9nnggxt3x90pe5u4048ntyuha78q1oikhhpvw9j083yc3l00hz5ehv9c1au5gvctyapzprub289qruve9qsyuh75j04wzkemqw3uhisrfs92u1ahv2qlqxmorgob16c1vbqkxttkoyp2agkt0v5l7lec25p0jqun9y39k41h67aeb5ihiqsftxc9azmg31hc73dk8urlj88vgbmgt8yln9rchw60whgxvnv9zn6cxbr482svctswc5a07atj
+EOT
+ 607.times{i,x=i.divmod(1035);a,b=x.divmod(23);print(c[a]*b)}
+ raise ArgumentError, "Such panic is really not required."
+ end
raise ArgumentError, "help only takes two (optional) arguments, a face name, and an action"
end
diff --git a/lib/puppet/face/indirector.rb b/lib/puppet/face/indirector.rb
index f48611e4b..6c7708b51 100644
--- a/lib/puppet/face/indirector.rb
+++ b/lib/puppet/face/indirector.rb
@@ -5,6 +5,14 @@ class Puppet::Face::Indirector < Puppet::Face
option "--terminus TERMINUS" do
desc "REVISIT: You can select a terminus, which has some bigger effect
that we should describe in this file somehow."
+
+ before_action do |action, args, options|
+ set_terminus(options[:terminus])
+ end
+
+ after_action do |action, args, options|
+ indirection.reset_terminus_class
+ end
end
def self.indirections
@@ -17,7 +25,6 @@ that we should describe in this file somehow."
def call_indirection_method(method, *args)
options = args.last
- options.has_key?(:terminus) and set_terminus(options[:terminus])
begin
result = indirection.__send__(method, *args)
@@ -26,7 +33,6 @@ that we should describe in this file somehow."
raise "Could not call '#{method}' on '#{indirection_name}': #{detail}"
end
- indirection.reset_terminus_class
return result
end
@@ -49,16 +55,11 @@ that we should describe in this file somehow."
# Print the configuration for the current terminus class
action :info do
when_invoked do |*args|
- options = args.pop
- options.has_key?(:terminus) and set_terminus(options[:terminus])
-
if t = indirection.terminus_class
puts "Run mode '#{Puppet.run_mode.name}': #{t}"
else
$stderr.puts "No default terminus class for run mode '#{Puppet.run_mode.name}'"
end
-
- indirection.reset_terminus_class
end
end
diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb
index 6570ebe46..5e9355061 100644
--- a/lib/puppet/interface.rb
+++ b/lib/puppet/interface.rb
@@ -117,4 +117,43 @@ class Puppet::Interface
def to_s
"Puppet::Face[#{name.inspect}, #{version.inspect}]"
end
+
+ ########################################################################
+ # Action decoration, whee! You are not expected to care about this code,
+ # which exists to support face building and construction. I marked these
+ # private because the implementation is crude and ugly, and I don't yet know
+ # enough to work out how to make it clean.
+ #
+ # Once we have established that these methods will likely change radically,
+ # to be unrecognizable in the final outcome. At which point we will throw
+ # all this away, replace it with something nice, and work out if we should
+ # be making this visible to the outside world... --daniel 2011-04-14
+ private
+ def __invoke_decorations(type, action, passed_args = [], passed_options = {})
+ [:before, :after].member?(type) or fail "unknown decoration type #{type}"
+
+ # Collect the decoration methods matching our pass.
+ methods = action.options.select do |name|
+ passed_options.has_key? name
+ end.map do |name|
+ action.get_option(name).__decoration_name(type)
+ end
+
+ methods.each do |hook|
+ begin
+ respond_to? hook and self.__send__(hook, action, passed_args, passed_options)
+ rescue => e
+ Puppet.warning("invoking #{action} #{type} hook: #{e}")
+ end
+ end
+ end
+
+ def __decorate(type, name, proc)
+ meta_def(name, &proc)
+ method(name).unbind
+ end
+ def self.__decorate(type, name, proc)
+ define_method(name, proc)
+ instance_method(name)
+ end
end
diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb
index 3c18c2aaf..b94298963 100644
--- a/lib/puppet/interface/action.rb
+++ b/lib/puppet/interface/action.rb
@@ -7,8 +7,9 @@ class Puppet::Interface::Action
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
+
+ @options = {}
end
# This is not nice, but it is the easiest way to make us behave like the
@@ -84,11 +85,21 @@ class Puppet::Interface::Action
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"
+ wrapper = <<WRAPPER
+def #{@name}(*args, &block)
+ if args.last.is_a? Hash then
+ options = args.last
+ else
+ args << (options = {})
+ end
+
+ action = get_action(#{name.inspect})
+ __invoke_decorations(:before, action, args, options)
+ rval = self.__send__(#{internal_name.inspect}, *args)
+ __invoke_decorations(:after, action, args, options)
+ return rval
+end
+WRAPPER
if @face.is_a?(Class)
@face.class_eval do eval wrapper, nil, file, line end
@@ -123,7 +134,19 @@ class Puppet::Interface::Action
(@options.keys + @face.options).sort
end
- def get_option(name)
- @options[name.to_sym] || @face.get_option(name)
+ def get_option(name, with_inherited_options = true)
+ option = @options[name.to_sym]
+ if option.nil? and with_inherited_options
+ option = @face.get_option(name)
+ end
+ option
+ end
+
+ ########################################################################
+ # Support code for action decoration; see puppet/interface.rb for the gory
+ # details of why this is hidden away behind private. --daniel 2011-04-15
+ private
+ def __decorate(type, name, proc)
+ @face.__send__ :__decorate, type, name, proc
end
end
diff --git a/lib/puppet/interface/option.rb b/lib/puppet/interface/option.rb
index ccc2fbba7..2abcd4033 100644
--- a/lib/puppet/interface/option.rb
+++ b/lib/puppet/interface/option.rb
@@ -1,19 +1,6 @@
require 'puppet/interface'
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 = []
@@ -79,4 +66,38 @@ class Puppet::Interface::Option
raise "#{name.inspect} is an invalid option name" unless name.to_s =~ /^[a-z]\w*$/
name.to_sym
end
+
+
+ def takes_argument?
+ !!@argument
+ end
+ def optional_argument?
+ !!@optional_argument
+ end
+
+
+ attr_reader :parent, :name, :aliases, :optparse
+ attr_accessor :desc
+
+ attr_accessor :before_action
+ def before_action=(proc)
+ proc.is_a? Proc or raise ArgumentError, "before action hook for #{self} is a #{proc.class.name.inspect}, not a proc"
+ @before_action =
+ @parent.__send__(:__decorate, :before, __decoration_name(:before), proc)
+ end
+
+ attr_accessor :after_action
+ def after_action=(proc)
+ proc.is_a? Proc or raise ArgumentError, "after action hook for #{self} is a #{proc.class.name.inspect}, not a proc"
+ @after_action =
+ @parent.__send__(:__decorate, :after, __decoration_name(:after), proc)
+ end
+
+ def __decoration_name(type)
+ if @parent.is_a? Puppet::Interface::Action then
+ :"option #{name} from #{parent.name} #{type} decoration"
+ else
+ :"option #{name} #{type} decoration"
+ end
+ end
end
diff --git a/lib/puppet/interface/option_builder.rb b/lib/puppet/interface/option_builder.rb
index 2240b3e4a..d4e59a4df 100644
--- a/lib/puppet/interface/option_builder.rb
+++ b/lib/puppet/interface/option_builder.rb
@@ -17,9 +17,34 @@ class Puppet::Interface::OptionBuilder
# Metaprogram the simple DSL from the option class.
Puppet::Interface::Option.instance_methods.grep(/=$/).each do |setter|
- next if setter =~ /^=/ # special case, darn it...
+ next if setter =~ /^=/
+ dsl = setter.sub(/=$/, '')
- dsl = setter.to_s.sub(/=$/, '')
- define_method(dsl) do |value| @option.send(setter, value) end
+ unless self.class.methods.include?(dsl)
+ define_method(dsl) do |value| @option.send(setter, value) end
+ end
+ end
+
+ # Override some methods that deal in blocks, not objects.
+ def before_action(&block)
+ block or raise ArgumentError, "#{@option} before_action requires a block"
+ if @option.before_action
+ raise ArgumentError, "#{@option} already has a before_action set"
+ end
+ unless block.arity == 3 then
+ raise ArgumentError, "before_action takes three arguments, action, args, and options"
+ end
+ @option.before_action = block
+ end
+
+ def after_action(&block)
+ block or raise ArgumentError, "#{@option} after_action requires a block"
+ if @option.after_action
+ raise ArgumentError, "#{@option} already has a after_action set"
+ end
+ unless block.arity == 3 then
+ raise ArgumentError, "after_action takes three arguments, action, args, and options"
+ end
+ @option.after_action = block
end
end
diff --git a/lib/puppet/interface/option_manager.rb b/lib/puppet/interface/option_manager.rb
index 56df9760f..d42359c07 100644
--- a/lib/puppet/interface/option_manager.rb
+++ b/lib/puppet/interface/option_manager.rb
@@ -37,10 +37,10 @@ module Puppet::Interface::OptionManager
result.sort
end
- def get_option(name)
+ def get_option(name, with_inherited_options = true)
@options ||= {}
result = @options[name.to_sym]
- unless result then
+ if result.nil? and with_inherited_options then
if self.is_a?(Class) and superclass.respond_to?(:get_option)
result = superclass.get_option(name)
elsif self.class.respond_to?(:get_option)
diff --git a/spec/lib/puppet/face/basetest.rb b/spec/lib/puppet/face/basetest.rb
index 00616f74f..e935161ae 100755
--- a/spec/lib/puppet/face/basetest.rb
+++ b/spec/lib/puppet/face/basetest.rb
@@ -1 +1,2 @@
+require 'puppet/face'
Puppet::Face.define(:basetest, '0.0.1')
diff --git a/spec/unit/application/indirection_base_spec.rb b/spec/unit/application/indirection_base_spec.rb
index 63ab11eed..57740384a 100755
--- a/spec/unit/application/indirection_base_spec.rb
+++ b/spec/unit/application/indirection_base_spec.rb
@@ -23,12 +23,11 @@ describe Puppet::Application::IndirectionBase do
it "should accept a terminus command line option" do
# It would be nice not to have to stub this, but whatever... writing an
# entire indirection stack would cause us more grief. --daniel 2011-03-31
- terminus = mock("test indirection terminus")
+ terminus = stub_everything("test indirection terminus")
Puppet::Indirector::Indirection.expects(:instance).
- with(:testindirection).twice.returns()
+ with(:testindirection).returns(terminus)
- subject.command_line.
- instance_variable_set('@args', %w{--terminus foo save})
+ subject.command_line.instance_variable_set('@args', %w{--terminus foo save})
# Not a very nice thing. :(
$stderr.stubs(:puts)
diff --git a/spec/unit/face/certificate_spec.rb b/spec/unit/face/certificate_spec.rb
index dbcc888ad..b0bbf1af6 100755
--- a/spec/unit/face/certificate_spec.rb
+++ b/spec/unit/face/certificate_spec.rb
@@ -6,9 +6,14 @@ describe Puppet::Face[:certificate, '0.0.1'] do
end
it "should set the ca location when invoked" do
- pending "#6983: This is broken in the actual face..."
Puppet::SSL::Host.expects(:ca_location=).with(:foo)
Puppet::SSL::Host.indirection.expects(:save)
- subject.sign :ca_location => :foo
+ subject.sign "hello, friend", :ca_location => :foo
+ end
+
+ it "(#7059) should set the ca location when an inherited action is invoked" do
+ Puppet::SSL::Host.expects(:ca_location=).with(:foo)
+ subject.indirection.expects(:find)
+ subject.find "hello, friend", :ca_location => :foo
end
end
diff --git a/spec/unit/face/help_spec.rb b/spec/unit/face/help_spec.rb
index e67f29e07..b5205afd6 100755
--- a/spec/unit/face/help_spec.rb
+++ b/spec/unit/face/help_spec.rb
@@ -55,19 +55,23 @@ describe Puppet::Face[:help, '0.0.1'] do
end
end
- Puppet::Face.faces.each do |name|
- face = Puppet::Face[name, :current]
- summary = face.summary
+ it "should list all faces" do
+ Puppet::Face.faces.each do |name|
+ face = Puppet::Face[name, :current]
+ summary = face.summary
- it { should =~ %r{ #{name} } }
- it { should =~ %r{ #{name} +#{summary}} } if summary
+ subject.should =~ %r{ #{name} }
+ summary and subject.should =~ %r{ #{name} +#{summary}}
+ end
end
- Puppet::Face[:help, :current].legacy_applications.each do |appname|
- it { should =~ %r{ #{appname} } }
+ it "should list all legacy applications" do
+ Puppet::Face[:help, :current].legacy_applications.each do |appname|
+ subject.should =~ %r{ #{appname} }
- summary = Puppet::Face[:help, :current].horribly_extract_summary_from(appname)
- summary and it { should =~ %r{ #{summary}\b} }
+ summary = Puppet::Face[:help, :current].horribly_extract_summary_from(appname)
+ summary and subject.should =~ %r{ #{summary}\b}
+ end
end
end
diff --git a/spec/unit/interface/action_builder_spec.rb b/spec/unit/interface/action_builder_spec.rb
index 8f29c8a7b..aecaf198f 100755
--- a/spec/unit/interface/action_builder_spec.rb
+++ b/spec/unit/interface/action_builder_spec.rb
@@ -12,10 +12,11 @@ describe Puppet::Interface::ActionBuilder do
end
it "should define a method on the face which invokes the action" 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"
+ face = Puppet::Interface.new(:action_builder_test_interface, '0.0.1') do
+ action :foo do
+ when_invoked do
+ "invoked the method"
+ end
end
end
diff --git a/spec/unit/interface/action_manager_spec.rb b/spec/unit/interface/action_manager_spec.rb
index 387faa043..6a6c254d4 100755
--- a/spec/unit/interface/action_manager_spec.rb
+++ b/spec/unit/interface/action_manager_spec.rb
@@ -104,6 +104,7 @@ describe Puppet::Interface::ActionManager do
@klass = Class.new do
include Puppet::Interface::ActionManager
extend Puppet::Interface::ActionManager
+ def __invoke_decorations(*args) true end
end
@instance = @klass.new
end
diff --git a/spec/unit/interface/action_spec.rb b/spec/unit/interface/action_spec.rb
index 8c6782976..4be6a1c55 100755
--- a/spec/unit/interface/action_spec.rb
+++ b/spec/unit/interface/action_spec.rb
@@ -79,7 +79,7 @@ describe Puppet::Interface::Action do
end
it "should work when options are supplied" do
- options = face.bar :bar => "beer"
+ options = face.bar(:bar => "beer")
options.should == { :bar => "beer" }
end
end
@@ -169,4 +169,183 @@ describe Puppet::Interface::Action do
}.should raise_error ArgumentError, /Option foo conflicts with existing option foo/i
end
end
+
+ context "with action decorators" do
+ context "local only" do
+ let :face do
+ Puppet::Interface.new(:action_decorators, '0.0.1') do
+ action :bar do when_invoked do true end end
+ def report(arg) end
+ end
+ end
+
+ it "should call action before decorators" do
+ face.action(:baz) do
+ option "--baz" do
+ before_action do |action, args, options|
+ report(:action_option)
+ end
+ end
+ when_invoked do true end
+ end
+
+ face.expects(:report).with(:action_option)
+ face.baz :baz => true
+ end
+
+ it "should call action after decorators" do
+ face.action(:baz) do
+ option "--baz" do
+ after_action do |action, args, options|
+ report(:action_option)
+ end
+ end
+ when_invoked do true end
+ end
+
+ face.expects(:report).with(:action_option)
+ face.baz :baz => true
+ end
+
+ it "should call local before decorators" do
+ face.option "--foo FOO" do
+ before_action do |action, args, options|
+ report(:before)
+ end
+ end
+ face.expects(:report).with(:before)
+ face.bar({:foo => 12})
+ end
+
+ it "should call local after decorators" do
+ face.option "--foo FOO" do
+ after_action do |action, args, options| report(:after) end
+ end
+ face.expects(:report).with(:after)
+ face.bar({:foo => 12})
+ end
+
+ context "with inactive decorators" do
+ it "should not invoke a decorator if the options are empty" do
+ face.option "--foo FOO" do
+ before_action do |action, args, options|
+ report :before_action
+ end
+ end
+ face.expects(:report).never # I am testing the negative.
+ face.bar
+ end
+
+ context "with some decorators only" do
+ before :each do
+ face.option "--foo" do
+ before_action do |action, args, options| report :foo end
+ end
+ face.option "--bar" do
+ before_action do |action, args, options| report :bar end
+ end
+ end
+
+ it "should work with the foo option" do
+ face.expects(:report).with(:foo)
+ face.bar(:foo => true)
+ end
+
+ it "should work with the bar option" do
+ face.expects(:report).with(:bar)
+ face.bar(:bar => true)
+ end
+
+ it "should work with both options" do
+ face.expects(:report).with(:foo)
+ face.expects(:report).with(:bar)
+ face.bar(:foo => true, :bar => true)
+ end
+ end
+ end
+ end
+
+ context "with inherited decorators" do
+ let :parent do
+ parent = Class.new(Puppet::Interface)
+ parent.script :on_parent do :on_parent end
+ parent.define_method :report do |arg| arg end
+ parent
+ end
+
+ let :child do
+ child = parent.new(:inherited_decorators, '0.0.1') do
+ script :on_child do :on_child end
+ end
+ end
+
+ context "with a child decorator" do
+ subject do
+ child.option "--foo FOO" do
+ before_action do |action, args, options|
+ report(:child_before)
+ end
+ end
+ child.expects(:report).with(:child_before)
+ child
+ end
+
+ it "child actions should invoke the decorator" do
+ subject.on_child({:foo => true, :bar => true}).should == :on_child
+ end
+
+ it "parent actions should invoke the decorator" do
+ subject.on_parent({:foo => true, :bar => true}).should == :on_parent
+ end
+ end
+
+ context "with a parent decorator" do
+ subject do
+ parent.option "--foo FOO" do
+ before_action do |action, args, options|
+ report(:parent_before)
+ end
+ end
+ child.expects(:report).with(:parent_before)
+ child
+ end
+
+ it "child actions should invoke the decorator" do
+ subject.on_child({:foo => true, :bar => true}).should == :on_child
+ end
+
+ it "parent actions should invoke the decorator" do
+ subject.on_parent({:foo => true, :bar => true}).should == :on_parent
+ end
+ end
+
+ context "with child and parent decorators" do
+ subject do
+ parent.option "--foo FOO" do
+ before_action { |action, args, options| report(:parent_before) }
+ after_action { |action, args, options| report(:parent_after) }
+ end
+ child.option "--bar BAR" do
+ before_action { |action, args, options| report(:child_before) }
+ after_action { |action, args, options| report(:child_after) }
+ end
+
+ child.expects(:report).with(:child_before)
+ child.expects(:report).with(:parent_before)
+ child.expects(:report).with(:parent_after)
+ child.expects(:report).with(:child_after)
+
+ child
+ end
+
+ it "child actions should invoke all the decorator" do
+ subject.on_child({:foo => true, :bar => true}).should == :on_child
+ end
+
+ it "parent actions should invoke all the decorator" do
+ subject.on_parent({:foo => true, :bar => true}).should == :on_parent
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/interface/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb
index d1114dde7..f9498cbb8 100755
--- a/spec/unit/interface/face_collection_spec.rb
+++ b/spec/unit/interface/face_collection_spec.rb
@@ -24,10 +24,6 @@ describe Puppet::Interface::FaceCollection do
$".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
diff --git a/spec/unit/interface/option_builder_spec.rb b/spec/unit/interface/option_builder_spec.rb
index fae48324e..b32b316f6 100755
--- a/spec/unit/interface/option_builder_spec.rb
+++ b/spec/unit/interface/option_builder_spec.rb
@@ -8,22 +8,53 @@ describe Puppet::Interface::OptionBuilder do
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
+ 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
+ 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
- it "should support documentation declarations" do
- text = "this is the description"
+ context "before_action hook" do
+ it "should support a before_action hook" do
option = Puppet::Interface::OptionBuilder.build(face, "--foo") do
- desc text
+ before_action do |a,b,c| :whatever end
end
- option.should be_an_instance_of Puppet::Interface::Option
- option.desc.should == text
+ option.before_action.should be_an_instance_of UnboundMethod
+ end
+
+ it "should fail if the hook block takes too few arguments" do
+ expect do
+ Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ before_action do |one, two| true end
+ end
+ end.to raise_error ArgumentError, /takes three arguments/
+ end
+
+ it "should fail if the hook block takes too many arguments" do
+ expect do
+ Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ before_action do |one, two, three, four| true end
+ end
+ end.to raise_error ArgumentError, /takes three arguments/
+ end
+
+ it "should fail if the hook block takes a variable number of arguments" do
+ expect do
+ Puppet::Interface::OptionBuilder.build(face, "--foo") do
+ before_action do |*blah| true end
+ end
+ end.to raise_error ArgumentError, /takes three arguments/
end
end
end
diff --git a/spec/unit/interface/option_spec.rb b/spec/unit/interface/option_spec.rb
index 3bcd121e2..4c24dc940 100755
--- a/spec/unit/interface/option_spec.rb
+++ b/spec/unit/interface/option_spec.rb
@@ -72,4 +72,28 @@ describe Puppet::Interface::Option do
option.to_s.should == "foo-bar"
end
end
+
+ %w{before after}.each do |side|
+ describe "#{side} hooks" do
+ subject { Puppet::Interface::Option.new(face, "--foo") }
+ let :proc do Proc.new do :from_proc end end
+
+ it { should respond_to "#{side}_action" }
+ it { should respond_to "#{side}_action=" }
+
+ it "should set the #{side}_action hook" do
+ subject.send("#{side}_action").should be_nil
+ subject.send("#{side}_action=", proc)
+ subject.send("#{side}_action").should be_an_instance_of UnboundMethod
+ end
+
+ data = [1, "foo", :foo, Object.new, method(:hash), method(:hash).unbind]
+ data.each do |input|
+ it "should fail if a #{input.class} is added to the #{side} hooks" do
+ expect { subject.send("#{side}_action=", input) }.
+ to raise_error ArgumentError, /not a proc/
+ end
+ end
+ end
+ end
end