diff options
-rw-r--r-- | lib/puppet/face/certificate.rb | 28 | ||||
-rw-r--r-- | lib/puppet/face/help.rb | 8 | ||||
-rw-r--r-- | lib/puppet/face/indirector.rb | 15 | ||||
-rw-r--r-- | lib/puppet/interface.rb | 39 | ||||
-rw-r--r-- | lib/puppet/interface/action.rb | 39 | ||||
-rw-r--r-- | lib/puppet/interface/option.rb | 47 | ||||
-rw-r--r-- | lib/puppet/interface/option_builder.rb | 31 | ||||
-rw-r--r-- | lib/puppet/interface/option_manager.rb | 4 | ||||
-rwxr-xr-x | spec/lib/puppet/face/basetest.rb | 1 | ||||
-rwxr-xr-x | spec/unit/application/indirection_base_spec.rb | 7 | ||||
-rwxr-xr-x | spec/unit/face/certificate_spec.rb | 9 | ||||
-rwxr-xr-x | spec/unit/face/help_spec.rb | 22 | ||||
-rwxr-xr-x | spec/unit/interface/action_builder_spec.rb | 9 | ||||
-rwxr-xr-x | spec/unit/interface/action_manager_spec.rb | 1 | ||||
-rwxr-xr-x | spec/unit/interface/action_spec.rb | 181 | ||||
-rwxr-xr-x | spec/unit/interface/face_collection_spec.rb | 4 | ||||
-rwxr-xr-x | spec/unit/interface/option_builder_spec.rb | 53 | ||||
-rwxr-xr-x | spec/unit/interface/option_spec.rb | 24 |
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 |