/lib/puppet/indirector/terminus.rb

https://github.com/nigelkersten/puppet-old · Ruby · 152 lines · 96 code · 31 blank · 25 comment · 8 complexity · 2147c62fcc0cf6460fca3402fdab8202 MD5 · raw file

  1. require 'puppet/indirector'
  2. require 'puppet/indirector/indirection'
  3. require 'puppet/util/instance_loader'
  4. # A simple class that can function as the base class for indirected types.
  5. class Puppet::Indirector::Terminus
  6. require 'puppet/util/docs'
  7. extend Puppet::Util::Docs
  8. class << self
  9. include Puppet::Util::InstanceLoader
  10. attr_accessor :name, :terminus_type
  11. attr_reader :abstract_terminus, :indirection
  12. # Are we an abstract terminus type, rather than an instance with an
  13. # associated indirection?
  14. def abstract_terminus?
  15. abstract_terminus
  16. end
  17. # Convert a constant to a short name.
  18. def const2name(const)
  19. const.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_" + i.downcase }.intern
  20. end
  21. # Look up the indirection if we were only provided a name.
  22. def indirection=(name)
  23. if name.is_a?(Puppet::Indirector::Indirection)
  24. @indirection = name
  25. elsif ind = Puppet::Indirector::Indirection.instance(name)
  26. @indirection = ind
  27. else
  28. raise ArgumentError, "Could not find indirection instance %s for %s" % [name, self.name]
  29. end
  30. end
  31. def indirection_name
  32. @indirection.name
  33. end
  34. # Register our subclass with the appropriate indirection.
  35. # This follows the convention that our terminus is named after the
  36. # indirection.
  37. def inherited(subclass)
  38. longname = subclass.to_s
  39. if longname =~ /#<Class/
  40. raise Puppet::DevError, "Terminus subclasses must have associated constants"
  41. end
  42. names = longname.split("::")
  43. # Convert everything to a lower-case symbol, converting camelcase to underscore word separation.
  44. name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_" + i.downcase }.intern
  45. subclass.name = name
  46. # Short-circuit the abstract types, which are those that directly subclass
  47. # the Terminus class.
  48. if self == Puppet::Indirector::Terminus
  49. subclass.mark_as_abstract_terminus
  50. return
  51. end
  52. # Set the terminus type to be the name of the abstract terminus type.
  53. # Yay, class/instance confusion.
  54. subclass.terminus_type = self.name
  55. # Our subclass is specifically associated with an indirection.
  56. raise("Invalid name %s" % longname) unless names.length > 0
  57. indirection_name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_" + i.downcase }.intern
  58. if indirection_name == "" or indirection_name.nil?
  59. raise Puppet::DevError, "Could not discern indirection model from class constant"
  60. end
  61. # This will throw an exception if the indirection instance cannot be found.
  62. # Do this last, because it also registers the terminus type with the indirection,
  63. # which needs the above information.
  64. subclass.indirection = indirection_name
  65. # And add this instance to the instance hash.
  66. Puppet::Indirector::Terminus.register_terminus_class(subclass)
  67. end
  68. # Mark that this instance is abstract.
  69. def mark_as_abstract_terminus
  70. @abstract_terminus = true
  71. end
  72. def model
  73. indirection.model
  74. end
  75. # Convert a short name to a constant.
  76. def name2const(name)
  77. name.to_s.capitalize.sub(/_(.)/) { |i| $1.upcase }
  78. end
  79. # Register a class, probably autoloaded.
  80. def register_terminus_class(klass)
  81. setup_instance_loading klass.indirection_name
  82. instance_hash(klass.indirection_name)[klass.name] = klass
  83. end
  84. # Return a terminus by name, using the autoloader.
  85. def terminus_class(indirection_name, terminus_type)
  86. setup_instance_loading indirection_name
  87. loaded_instance(indirection_name, terminus_type)
  88. end
  89. # Return all terminus classes for a given indirection.
  90. def terminus_classes(indirection_name)
  91. setup_instance_loading indirection_name
  92. # Load them all.
  93. instance_loader(indirection_name).loadall
  94. # And return the list of names.
  95. loaded_instances(indirection_name)
  96. end
  97. private
  98. def setup_instance_loading(type)
  99. unless instance_loading?(type)
  100. instance_load type, "puppet/indirector/%s" % type
  101. end
  102. end
  103. end
  104. def indirection
  105. self.class.indirection
  106. end
  107. def initialize
  108. if self.class.abstract_terminus?
  109. raise Puppet::DevError, "Cannot create instances of abstract terminus types"
  110. end
  111. end
  112. def model
  113. self.class.model
  114. end
  115. def name
  116. self.class.name
  117. end
  118. def terminus_type
  119. self.class.terminus_type
  120. end
  121. end