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[R]

@api private @return [Symbol]

when_invoked[R]

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

Public Instance Methods

__dup_and_rebind_to(to) click to toggle source

@return [void] @api private

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

@api private @return [void]

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

@api private @return [Boolean]

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

@api private

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

@api private

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

Private Instance Methods

__add_method(name, proc) click to toggle source

@return [void] @api private

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

@return [void] @api private

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