Class: Puppet::Interface::Action

Inherits:
Object
  • Object
show all
Extended by:
DocGen
Includes:
FullDocs
Defined in:
lib/vendor/puppet/interface/action.rb

Instance Attribute Summary collapse

Attributes included from FullDocs

#copyright_owner, #copyright_years

Instance Method Summary collapse

Methods included from DocGen

attr_doc, strip_whitespace

Methods included from FullDocs

#author, #author=, #authors, #copyright, #munge_copyright_year, #short_description

Methods included from TinyDocs

#build_synopsis

Constructor Details

#initialize(face, name, attrs = {}) ⇒ Action

Returns a new instance of Action.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/vendor/puppet/interface/action.rb', line 9

def initialize(face, name, attrs = {})
  raise "#{name.inspect} is an invalid action name" unless name.to_s =~ /^[a-z]\w*$/
  @face    = face
  @name    = name.to_sym

  # The few bits of documentation we actually demand.  The default license
  # is a favour to our end users; if you happen to get that in a core face
  # report it as a bug, please. --daniel 2011-04-26
  @authors = []
  @license  = 'All Rights Reserved'

  attrs.each do |k, v| send("#{k}=", v) end

  # @options collects the added options in the order they're declared.
  # @options_hash collects the options keyed by alias for quick lookups.
  @options        = []
  @options_hash   = {}
  @when_rendering = {}
end

Instance Attribute Details

#defaultObject

Returns the value of attribute default.



42
43
44
# File 'lib/vendor/puppet/interface/action.rb', line 42

def default
  @default
end

#faceObject (readonly)

Returns the value of attribute face.



41
42
43
# File 'lib/vendor/puppet/interface/action.rb', line 41

def face
  @face
end

#nameObject (readonly)

Returns the value of attribute name.



40
41
42
# File 'lib/vendor/puppet/interface/action.rb', line 40

def name
  @name
end

#positional_arg_countObject (readonly)

We need to build an instance method as a wrapper, using normal code, to be able to expose argument defaulting between the caller and definer in the Ruby API. An extra method is, sadly, required for Ruby 1.8 to work since it doesn’t expose bind on a block.

Hopefully we can improve this when we finally shuffle off the last of Ruby 1.8 support, but that looks to be a few “enterprise” release eras away, so we are pretty stuck with this for now.

Patches to make this work more nicely with Ruby 1.9 using runtime version checking and all are welcome, provided that they don’t change anything outside this little ol’ bit of code and all.

Incidentally, we though about vendoring evil-ruby and actually adjusting the internal C structure implementation details under the hood to make this stuff work, because it would have been cleaner. Which gives you an idea how motivated we were to make this cleaner. Sorry. –daniel 2011-03-31



169
170
171
# File 'lib/vendor/puppet/interface/action.rb', line 169

def positional_arg_count
  @positional_arg_count
end

#render_asObject

Returns the value of attribute render_as.



109
110
111
# File 'lib/vendor/puppet/interface/action.rb', line 109

def render_as
  @render_as
end

#when_invokedObject

Returns the value of attribute when_invoked.



170
171
172
# File 'lib/vendor/puppet/interface/action.rb', line 170

def when_invoked
  @when_invoked
end

Instance Method Details

#__dup_and_rebind_to(to) ⇒ Object

This is not nice, but it is the easiest way to make us behave like the Ruby Method object rather than UnboundMethod. Duplication is vaguely annoying, but at least we are a shallow clone. –daniel 2011-04-12



32
33
34
35
36
# File 'lib/vendor/puppet/interface/action.rb', line 32

def __dup_and_rebind_to(to)
  bound_version = self.dup
  bound_version.instance_variable_set(:@face, to)
  return bound_version
end

#add_option(option) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/vendor/puppet/interface/action.rb', line 224

def add_option(option)
  option.aliases.each do |name|
    if conflict = get_option(name) then
      raise ArgumentError, "Option #{option} conflicts with existing option #{conflict}"
    elsif conflict = @face.get_option(name) then
      raise ArgumentError, "Option #{option} conflicts with existing option #{conflict} on #{@face}"
    end
  end

  @options << option.name

  option.aliases.each do |name|
    @options_hash[name] = option
  end

  option
end

#default?Boolean

Returns:

  • (Boolean)


43
44
45
# File 'lib/vendor/puppet/interface/action.rb', line 43

def default?
  !!@default
end

#get_option(name, with_inherited_options = true) ⇒ Object



250
251
252
253
254
255
256
# File 'lib/vendor/puppet/interface/action.rb', line 250

def get_option(name, with_inherited_options = true)
  option = @options_hash[name.to_sym]
  if option.nil? and with_inherited_options
    option = @face.get_option(name)
  end
  option
end

#option?(name) ⇒ Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/vendor/puppet/interface/action.rb', line 242

def option?(name)
  @options_hash.include? name.to_sym
end

#optionsObject



246
247
248
# File 'lib/vendor/puppet/interface/action.rb', line 246

def options
  @face.options + @options
end

#set_rendering_method_for(type, proc) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/vendor/puppet/interface/action.rb', line 71

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 and proc.arity != (@positional_arg_count + 1)
    msg =  "the when_rendering method for the #{@face.name} face #{name} action "
    msg += "takes either just one argument, the result of when_invoked, "
    msg += "or the result plus the #{@positional_arg_count} arguments passed "
    msg += "to the when_invoked block, 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

#synopsisObject



51
52
53
# File 'lib/vendor/puppet/interface/action.rb', line 51

def synopsis
  build_synopsis(@face.name, default? ? nil : name, arguments)
end

#to_sObject



38
# File 'lib/vendor/puppet/interface/action.rb', line 38

def to_s() "#{@face}##{@name}" end

#validate_and_clean(original) ⇒ Object



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/vendor/puppet/interface/action.rb', line 258

def validate_and_clean(original)
  # The final set of arguments; effectively a hand-rolled shallow copy of
  # the original, which protects the caller from the surprises they might
  # get if they passed us a hash and we mutated it...
  result = {}

  # Check for multiple aliases for the same option, and canonicalize the
  # name of the argument while we are about it.
  overlap = Hash.new do |h, k| h[k] = [] end
  unknown = []
  original.keys.each do |name|
    if option = get_option(name) then
      canonical = option.name
      if result.has_key? canonical
        overlap[canonical] << name
      else
        result[canonical] = original[name]
      end
    elsif Puppet.settings.include? name
      result[name] = original[name]
    else
      unknown << name
    end
  end

  unless overlap.empty?
    msg = overlap.map {|k, v| "(#{k}, #{v.sort.join(', ')})" }.join(", ")
    raise ArgumentError, "Multiple aliases for the same option passed: #{msg}"
  end

  unless unknown.empty?
    msg = unknown.sort.join(", ")
    raise ArgumentError, "Unknown options passed: #{msg}"
  end

  # Inject default arguments and check for missing mandating options.
  missing = []
  options.map {|x| get_option(x) }.each do |option|
    name = option.name
    next if result.has_key? name

    if option.has_default?
      result[name] = option.default
    elsif option.required?
      missing << name
    end
  end

  unless missing.empty?
    msg = missing.sort.join(', ')
    raise ArgumentError, "The following options are required: #{msg}"
  end

  # All done.
  return result
end

#when_rendering(type) ⇒ Object

Support for rendering formats and all.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/vendor/puppet/interface/action.rb', line 57

def when_rendering(type)
  unless type.is_a? Symbol
    raise ArgumentError, "The rendering format must be a symbol, not #{type.class.name}"
  end
  # Do we have a rendering hook for this name?
  return @when_rendering[type].bind(@face) if @when_rendering.has_key? type

  # How about by another name?
  alt = type.to_s.sub(/^to_/, '').to_sym
  return @when_rendering[alt].bind(@face) if @when_rendering.has_key? alt

  # Guess not, nothing to run.
  return nil
end