diff options
| author | Daniel Pittman <daniel@puppetlabs.com> | 2011-04-18 13:29:47 -0700 |
|---|---|---|
| committer | Daniel Pittman <daniel@puppetlabs.com> | 2011-04-19 10:53:36 -0700 |
| commit | 86801b580101315706b1b02a00a36840eabd75cd (patch) | |
| tree | 9d0db179dabc6b113ff63965df0f01a2e2dadeb2 /lib/puppet/interface | |
| parent | be23b8423ba77a5935586e277bf543cd54b9dec7 (diff) | |
| download | puppet-86801b580101315706b1b02a00a36840eabd75cd.tar.gz puppet-86801b580101315706b1b02a00a36840eabd75cd.tar.xz puppet-86801b580101315706b1b02a00a36840eabd75cd.zip | |
(#7013) Support 'when_rendering' and 'render_as' in actions.
These define the API used by folks writing actions that supports their
rendering hooks. 'when_rendering' defines a helper method on the interface,
which runs the users code in their expected context.
'render_as' just sets the default rendering format; by default this is
:for_humans.
Reviewed-By: Max Martin <max@puppetlabs.com>
Diffstat (limited to 'lib/puppet/interface')
| -rw-r--r-- | lib/puppet/interface/action.rb | 57 | ||||
| -rw-r--r-- | lib/puppet/interface/action_builder.rb | 44 | ||||
| -rw-r--r-- | lib/puppet/interface/option.rb | 4 | ||||
| -rw-r--r-- | lib/puppet/interface/option_builder.rb | 2 |
4 files changed, 96 insertions, 11 deletions
diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index efe7b1f50..bdd42b197 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -10,6 +10,8 @@ class Puppet::Interface::Action attrs.each do |k, v| send("#{k}=", v) end @options = {} + @when_rendering = {} + @render_as = :for_humans end # This is not nice, but it is the easiest way to make us behave like the @@ -21,9 +23,9 @@ class Puppet::Interface::Action return bound_version end - attr_reader :name def to_s() "#{@face}##{@name}" end + attr_reader :name attr_accessor :default def default? !!@default @@ -31,6 +33,55 @@ class Puppet::Interface::Action attr_accessor :summary + + ######################################################################## + # Support for rendering formats and all. + def when_rendering(type) + unless type.is_a? Symbol + raise ArgumentError, "The rendering format must be a symbol, not #{type.class.name}" + end + @when_rendering[type] + end + def set_rendering_method_for(type, proc) + unless proc.is_a? Proc + msg = "The second argument to set_rendering_method_for must be a Proc" + msg += ", not #{proc.class.name}" unless proc.nil? + raise ArgumentError, msg + end + if proc.arity != 1 then + msg = "when_rendering methods take one argument, the result, not " + if proc.arity < 0 then + msg += "a variable number" + else + msg += proc.arity.to_s + end + raise ArgumentError, msg + end + unless type.is_a? Symbol + raise ArgumentError, "The rendering format must be a symbol, not #{type.class.name}" + end + if @when_rendering.has_key? type then + raise ArgumentError, "You can't define a rendering method for #{type} twice" + end + # Now, the ugly bit. We add the method to our interface object, and + # retrieve it, to rotate through the dance of getting a suitable method + # object out of the whole process. --daniel 2011-04-18 + @when_rendering[type] = + @face.__send__( :__add_method, __render_method_name_for(type), proc) + end + + def __render_method_name_for(type) + :"#{name}_when_rendering_#{type}" + end + private :__render_method_name_for + + + attr_accessor :render_as + def render_as=(value) + @render_as = value.to_sym + 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 @@ -161,7 +212,7 @@ WRAPPER # 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 + def __add_method(name, proc) + @face.__send__ :__add_method, name, proc end end diff --git a/lib/puppet/interface/action_builder.rb b/lib/puppet/interface/action_builder.rb index 639d8fc7f..2ffa38709 100644 --- a/lib/puppet/interface/action_builder.rb +++ b/lib/puppet/interface/action_builder.rb @@ -20,20 +20,54 @@ class Puppet::Interface::ActionBuilder # 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 when_rendering(type = nil, &block) + if type.nil? then # the default error message sucks --daniel 2011-04-18 + raise ArgumentError, 'You must give a rendering format to when_rendering' + end + if block.nil? then + raise ArgumentError, 'You must give a block to when_rendering' + end + @action.set_rendering_method_for(type, block) + end + def option(*declaration, &block) option = Puppet::Interface::OptionBuilder.build(@action, *declaration, &block) @action.add_option(option) end - def default - @action.default = true + def default(value = true) + @action.default = !!value + end + + def render_as(value = nil) + value.nil? and raise ArgumentError, "You must give a rendering format to render_as" + + formats = Puppet::Network::FormatHandler.formats << :for_humans + unless formats.include? value + raise ArgumentError, "#{value.inspect} is not a valid rendering format: #{formats.sort.join(", ")}" + end + + @action.render_as = value end - def summary(text) - @action.summary = text + # Metaprogram the simple DSL from the target class. + Puppet::Interface::Action.instance_methods.grep(/=$/).each do |setter| + next if setter =~ /^=/ + dsl = setter.sub(/=$/, '') + + unless private_instance_methods.include? dsl + # Using eval because the argument handling semantics are less awful than + # when we use the define_method/block version. The later warns on older + # Ruby versions if you pass the wrong number of arguments, but carries + # on, which is totally not what we want. --daniel 2011-04-18 + eval <<METHOD +def #{dsl}(value) + @action.#{dsl} = value +end +METHOD + end end end diff --git a/lib/puppet/interface/option.rb b/lib/puppet/interface/option.rb index 1971926d8..f4c56cb2c 100644 --- a/lib/puppet/interface/option.rb +++ b/lib/puppet/interface/option.rb @@ -84,14 +84,14 @@ class Puppet::Interface::Option 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) + @parent.__send__(:__add_method, __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) + @parent.__send__(:__add_method, __decoration_name(:after), proc) end def __decoration_name(type) diff --git a/lib/puppet/interface/option_builder.rb b/lib/puppet/interface/option_builder.rb index 7c2ab89de..8f358c222 100644 --- a/lib/puppet/interface/option_builder.rb +++ b/lib/puppet/interface/option_builder.rb @@ -20,7 +20,7 @@ class Puppet::Interface::OptionBuilder next if setter =~ /^=/ dsl = setter.sub(/=$/, '') - unless self.class.methods.include?(dsl) + unless private_instance_methods.include? dsl define_method(dsl) do |value| @option.send(setter, value) end end end |
