class Puppet::Interface::Action

This represents an action that is attached to a face. Actions should be constructed by calling {Puppet::Interface::ActionManager#action}, which is available on {Puppet::Interface}, and then calling methods of {Puppet::Interface::ActionBuilder} in the supplied block. @api private

Attributes

default[RW]

Whether this is the default action for the face @return [Boolean] @api private

face[R]

The face this action is attached to @return [Puppet::Interface]

name[R]

The name of this action @return [Symbol]

positional_arg_count[R]

The arity of the action @return [Integer]

render_as[RW]

@api private @return [Symbol]

when_invoked[RW]

The block that is executed when the action is invoked @return [block]

Public Class Methods

new(face, name) click to toggle source

@api private

   # File lib/puppet/interface/action.rb
14 def initialize(face, name)
15   raise "#{name.inspect} is an invalid action name" unless name.to_s =~ /^[a-z]\w*$/
16   @face    = face
17   @name    = name.to_sym
18 
19   # The few bits of documentation we actually demand.  The default license
20   # is a favour to our end users; if you happen to get that in a core face
21   # report it as a bug, please. --daniel 2011-04-26
22   @authors = []
23   @license  = 'All Rights Reserved'
24 
25   # @options collects the added options in the order they're declared.
26   # @options_hash collects the options keyed by alias for quick lookups.
27   @options        = []
28   @display_global_options = []
29   @options_hash   = {}
30   @when_rendering = {}
31 end

Public Instance Methods

__dup_and_rebind_to(to) click to toggle source

@return [void] @api private

   # File lib/puppet/interface/action.rb
39 def __dup_and_rebind_to(to)
40   bound_version = self.dup
41   bound_version.instance_variable_set(:@face, to)
42   return bound_version
43 end
add_display_global_options(*args) click to toggle source
    # File lib/puppet/interface/action.rb
310 def add_display_global_options(*args)
311   @display_global_options ||= []
312   [args].flatten.each do |refopt|
313     unless Puppet.settings.include? refopt
314       #TRANSLATORS 'Puppet.settings' should not be translated
315       raise ArgumentError, _("Global option %{option} does not exist in Puppet.settings") % { option: refopt }
316     end
317     @display_global_options << refopt
318   end
319   @display_global_options.uniq!
320   @display_global_options
321 end
add_option(option) click to toggle source
    # File lib/puppet/interface/action.rb
278 def add_option(option)
279   option.aliases.each do |name|
280     conflict = get_option(name)
281     if conflict
282       raise ArgumentError, _("Option %{option} conflicts with existing option %{conflict}") %
283           { option: option, conflict: conflict }
284     else
285       conflict = @face.get_option(name)
286       if conflict
287         raise ArgumentError, _("Option %{option} conflicts with existing option %{conflict} on %{face}") %
288             { option: option, conflict: conflict, face: @face }
289       end
290     end
291   end
292 
293   @options << option.name
294 
295   option.aliases.each do |name|
296     @options_hash[name] = option
297   end
298 
299   option
300 end
default?() click to toggle source
   # File lib/puppet/interface/action.rb
59 def default?
60   !!@default
61 end
deprecate() click to toggle source

@api private @return [void]

    # File lib/puppet/interface/action.rb
151 def deprecate
152   @deprecated = true
153 end
deprecated?() click to toggle source

@api private @return [Boolean]

    # File lib/puppet/interface/action.rb
157 def deprecated?
158   @deprecated
159 end
display_global_option(*args)
display_global_options(*args) click to toggle source
    # File lib/puppet/interface/action.rb
323 def display_global_options(*args)
324   args ? add_display_global_options(args) : @display_global_options + @face.display_global_options
325 end
Also aliased as: display_global_option
get_option(name, with_inherited_options = true) click to toggle source
    # File lib/puppet/interface/action.rb
328 def get_option(name, with_inherited_options = true)
329   option = @options_hash[name.to_sym]
330   if option.nil? and with_inherited_options
331     option = @face.get_option(name)
332   end
333   option
334 end
option?(name) click to toggle source
    # File lib/puppet/interface/action.rb
302 def option?(name)
303   @options_hash.include? name.to_sym
304 end
options() click to toggle source
    # File lib/puppet/interface/action.rb
306 def options
307   @face.options + @options
308 end
render_as=(value) click to toggle source
    # File lib/puppet/interface/action.rb
145 def render_as=(value)
146   @render_as = value.to_sym
147 end
set_rendering_method_for(type, proc) click to toggle source

@api private

    # File lib/puppet/interface/action.rb
 92 def set_rendering_method_for(type, proc)
 93   unless proc.is_a? Proc
 94     msg = if proc.nil?
 95             #TRANSLATORS 'set_rendering_method_for' and 'Proc' should not be translated
 96             _("The second argument to set_rendering_method_for must be a Proc")
 97           else
 98             #TRANSLATORS 'set_rendering_method_for' and 'Proc' should not be translated
 99             _("The second argument to set_rendering_method_for must be a Proc, not %{class_name}") %
100                 { class_name: proc.class.name }
101           end
102     raise ArgumentError, msg
103   end
104 
105   if proc.arity != 1 and proc.arity != (@positional_arg_count + 1)
106     msg = if proc.arity < 0 then
107             #TRANSLATORS 'when_rendering', 'when_invoked' are method names and should not be translated
108             _("The when_rendering method for the %{face} face %{name} action takes either just one argument,"\
109                 " the result of when_invoked, or the result plus the %{arg_count} arguments passed to the"\
110                 " when_invoked block, not a variable number") %
111                 { face: @face.name, name: name, arg_count: @positional_arg_count }
112           else
113             #TRANSLATORS 'when_rendering', 'when_invoked' are method names and should not be translated
114             _("The when_rendering method for the %{face} face %{name} action takes either just one argument,"\
115                 " the result of when_invoked, or the result plus the %{arg_count} arguments passed to the"\
116                 " when_invoked block, not %{string}") %
117                 { face: @face.name, name: name, arg_count: @positional_arg_count, string: proc.arity.to_s }
118           end
119     raise ArgumentError, msg
120   end
121   unless type.is_a? Symbol
122     raise ArgumentError, _("The rendering format must be a symbol, not %{class_name}") % { class_name: type.class.name }
123   end
124   if @when_rendering.has_key? type then
125     raise ArgumentError, _("You can't define a rendering method for %{type} twice") % { type: type }
126   end
127   # Now, the ugly bit.  We add the method to our interface object, and
128   # retrieve it, to rotate through the dance of getting a suitable method
129   # object out of the whole process. --daniel 2011-04-18
130   @when_rendering[type] =
131     @face.__send__( :__add_method, __render_method_name_for(type), proc)
132 end
synopsis() click to toggle source
   # File lib/puppet/interface/action.rb
67 def synopsis
68   build_synopsis(@face.name, default? ? nil : name, arguments)
69 end
to_s() click to toggle source
   # File lib/puppet/interface/action.rb
45 def to_s() "#{@face}##{@name}" end
validate_and_clean(original) click to toggle source
    # File lib/puppet/interface/action.rb
336 def validate_and_clean(original)
337   # The final set of arguments; effectively a hand-rolled shallow copy of
338   # the original, which protects the caller from the surprises they might
339   # get if they passed us a hash and we mutated it...
340   result = {}
341 
342   # Check for multiple aliases for the same option, and canonicalize the
343   # name of the argument while we are about it.
344   overlap = Hash.new do |h, k| h[k] = [] end
345   unknown = []
346   original.keys.each do |name|
347     option = get_option(name)
348     if option
349       canonical = option.name
350       if result.has_key? canonical
351         overlap[canonical] << name
352       else
353         result[canonical] = original[name]
354       end
355     elsif Puppet.settings.include? name
356       result[name] = original[name]
357     else
358       unknown << name
359     end
360   end
361 
362   unless overlap.empty?
363     overlap_list = overlap.map {|k, v| "(#{k}, #{v.sort.join(', ')})" }.join(", ")
364     raise ArgumentError, _("Multiple aliases for the same option passed: %{overlap_list}") %
365         { overlap_list: overlap_list }
366   end
367 
368   unless unknown.empty?
369     unknown_list = unknown.sort.join(", ")
370     raise ArgumentError, _("Unknown options passed: %{unknown_list}") % { unknown_list: unknown_list }
371   end
372 
373   # Inject default arguments and check for missing mandating options.
374   missing = []
375   options.map {|x| get_option(x) }.each do |option|
376     name = option.name
377     next if result.has_key? name
378 
379     if option.has_default?
380       result[name] = option.default
381     elsif option.required?
382       missing << name
383     end
384   end
385 
386   unless missing.empty?
387     missing_list = missing.sort.join(', ')
388     raise ArgumentError, _("The following options are required: %{missing_list}") % { missing_list: missing_list }
389   end
390 
391   # All done.
392   return result
393 end
when_invoked=(block) click to toggle source
    # File lib/puppet/interface/action.rb
224   def when_invoked=(block)
225 
226     internal_name = "#{@name} implementation, required on Ruby 1.8".to_sym
227 
228     arity = @positional_arg_count = block.arity
229     if arity == 0 then
230       # This will never fire on 1.8.7, which treats no arguments as "*args",
231       # but will on 1.9.2, which treats it as "no arguments".  Which bites,
232       # because this just begs for us to wind up in the horrible situation
233       # where a 1.8 vs 1.9 error bites our end users. --daniel 2011-04-19
234       #TRANSLATORS 'when_invoked' should not be translated
235       raise ArgumentError, _("when_invoked requires at least one argument (options) for action %{name}") % { name: @name }
236     elsif arity > 0 then
237       range = Range.new(1, arity - 1)
238       decl = range.map { |x| "arg#{x}" } << "options = {}"
239       optn = ""
240       args = "[" + (range.map { |x| "arg#{x}" } << "options").join(", ") + "]"
241     else
242       range = Range.new(1, arity.abs - 1)
243       decl = range.map { |x| "arg#{x}" } << "*rest"
244       optn = "rest << {} unless rest.last.is_a?(Hash)"
245       if arity == -1 then
246         args = "rest"
247       else
248         args = "[" + range.map { |x| "arg#{x}" }.join(", ") + "] + rest"
249       end
250     end
251 
252     file    = __FILE__ + "+eval[wrapper]"
253     line    = __LINE__ + 2 # <== points to the same line as 'def' in the wrapper.
254     wrapper = <<WRAPPER
255 def #{@name}(#{decl.join(", ")})
256   #{optn}
257   args    = #{args}
258   action  = get_action(#{name.inspect})
259   args   << action.validate_and_clean(args.pop)
260   __invoke_decorations(:before, action, args, args.last)
261   rval = self.__send__(#{internal_name.inspect}, *args)
262   __invoke_decorations(:after, action, args, args.last)
263   return rval
264 end
265 WRAPPER
266 
267     if @face.is_a?(Class)
268       @face.class_eval do eval wrapper, nil, file, line end
269       @face.send(:define_method, internal_name, &block)
270       @when_invoked = @face.instance_method(name)
271     else
272       @face.instance_eval do eval wrapper, nil, file, line end
273       @face.meta_def(internal_name, &block)
274       @when_invoked = @face.method(name).unbind
275     end
276   end
when_rendering(type) click to toggle source

@api private

   # File lib/puppet/interface/action.rb
76 def when_rendering(type)
77   unless type.is_a? Symbol
78     raise ArgumentError, _("The rendering format must be a symbol, not %{class_name}") % { class_name: type.class.name }
79   end
80   # Do we have a rendering hook for this name?
81   return @when_rendering[type].bind(@face) if @when_rendering.has_key? type
82 
83   # How about by another name?
84   alt = type.to_s.sub(/^to_/, '').to_sym
85   return @when_rendering[alt].bind(@face) if @when_rendering.has_key? alt
86 
87   # Guess not, nothing to run.
88   return nil
89 end

Private Instance Methods

__add_method(name, proc) click to toggle source

@return [void] @api private

    # File lib/puppet/interface/action.rb
401 def __add_method(name, proc)
402   @face.__send__ :__add_method, name, proc
403 end
__render_method_name_for(type) click to toggle source

@return [void] @api private

    # File lib/puppet/interface/action.rb
136 def __render_method_name_for(type)
137   :"#{name}_when_rendering_#{type}"
138 end