diff options
-rw-r--r-- | lib/puppet/metatype/providers.rb | 6 | ||||
-rw-r--r-- | lib/puppet/provider.rb | 13 | ||||
-rw-r--r-- | lib/puppet/util/provider_features.rb | 55 | ||||
-rwxr-xr-x | test/ral/manager/provider.rb | 74 |
4 files changed, 113 insertions, 35 deletions
diff --git a/lib/puppet/metatype/providers.rb b/lib/puppet/metatype/providers.rb index 98b5caf43..ed9c68ab6 100644 --- a/lib/puppet/metatype/providers.rb +++ b/lib/puppet/metatype/providers.rb @@ -162,13 +162,11 @@ class Puppet::Type :hash => @providers, :prefix => "Provider", :block => block, + :include => feature_module, + :extend => feature_module, :attributes => options ) - # Add the feature module to both the instances and classes. - provider.send(:include, feature_module) - provider.send(:extend, feature_module) - return provider end diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb index f5e45ba6d..d02868d86 100644 --- a/lib/puppet/provider.rb +++ b/lib/puppet/provider.rb @@ -9,7 +9,8 @@ class Puppet::Provider # Include the util module so we have access to things like 'binary' include Puppet::Util, Puppet::Util::Docs include Puppet::Util::Logging - attr_accessor :name, :model + attr_accessor :name + attr_reader :model attr_writer :doc end @@ -139,6 +140,16 @@ class Puppet::Provider end end + # Add the feature module immediately, so its methods are available to the + # providers. + def self.model=(model) + @model = model + #if mod = model.feature_module + # extend(mod) + # include(mod) + #end + end + self.initvars # Check whether this implementation is suitable for our platform. diff --git a/lib/puppet/util/provider_features.rb b/lib/puppet/util/provider_features.rb index fc59cc0b3..fbf2260dd 100644 --- a/lib/puppet/util/provider_features.rb +++ b/lib/puppet/util/provider_features.rb @@ -1,17 +1,44 @@ # Provides feature definitions. module Puppet::Util::ProviderFeatures + + # The class that models the features and handles checking whether the features + # are present. class ProviderFeature require 'puppet/util/methodhelper' require 'puppet/util' include Puppet::Util include Puppet::Util::MethodHelper attr_accessor :name, :docs, :methods + + # Are all of the requirements met? + def available?(obj) + if self.methods and ! methods_available?(obj) + return false + end + + true + end + def initialize(name, docs, hash) self.name = symbolize(name) self.docs = docs hash = symbolize_options(hash) set_options(hash) end + + private + + # Are all of the required methods available? + def methods_available?(obj) + methods.each do |m| + if obj.is_a?(Class) + return false unless obj.public_method_defined?(m) + else + return false unless obj.respond_to?(m) + end + end + return true + end end # Define one or more features. At a minimum, features require a name @@ -99,28 +126,24 @@ module Puppet::Util::ProviderFeatures @features.each do |name, feature| method = name.to_s + "?" @feature_module.send(:define_method, method) do - set = nil - feature.methods.each do |m| - if is_a?(Class) - unless public_method_defined?(m) - set = false - break - end - else - unless respond_to?(m) - set = false - break - end - end - end - - if set.nil? + if defined? @declared_features and @declared_features.include?(name) + true + elsif feature.available?(self) true else false end end end + + # Allow the provider to declare that it has a given feature. + @feature_module.send(:define_method, :has_features) do |*names| + @declared_features ||= [] + names.each do |name| + name = symbolize(name) + @declared_features << name + end + end end @feature_module end diff --git a/test/ral/manager/provider.rb b/test/ral/manager/provider.rb index 870c3134a..a314506c5 100755 --- a/test/ral/manager/provider.rb +++ b/test/ral/manager/provider.rb @@ -47,30 +47,38 @@ class TestTypeProviders < Test::Unit::TestCase assert_equal(should, type.allattrs.reject { |p| ! should.include?(p) }, "Providify did not reorder parameters") end +end + +class TestProviderFeatures < Test::Unit::TestCase + include PuppetTest - def test_features - type = Puppet::Type.newtype(:feature_test) do + def setup + super + @type = Puppet::Type.newtype(:feature_test) do newparam(:name) {} ensurable end cleanup { Puppet::Type.rmtype(:feature_test) } - features = {:numeric => [:one, :two], :alpha => [:a, :b]} + @features = {:numeric => [:one, :two], :alpha => [:a, :b]} - features.each do |name, methods| + @features.each do |name, methods| assert_nothing_raised("Could not define features") do - type.feature(name, "boo", :methods => methods) + @type.feature(name, "boo", :methods => methods) end end + end - providers = {:numbers => features[:numeric], :letters => features[:alpha]} - providers[:both] = features[:numeric] + features[:alpha] - providers[:mixed] = [:one, :b] - providers[:neither] = [:something, :else] + # Give them the basic run-through. + def test_method_features + @providers = {:numbers => @features[:numeric], :letters => @features[:alpha]} + @providers[:both] = @features[:numeric] + @features[:alpha] + @providers[:mixed] = [:one, :b] + @providers[:neither] = [:something, :else] - providers.each do |name, methods| + @providers.each do |name, methods| assert_nothing_raised("Could not create provider %s" % name) do - type.provide(name) do + @type.provide(name) do methods.each do |name| define_method(name) {} end @@ -78,11 +86,11 @@ class TestTypeProviders < Test::Unit::TestCase end end - model = type.create(:name => "foo") + model = @type.create(:name => "foo") {:numbers => [:numeric], :letters => [:alpha], :both => [:numeric, :alpha], :mixed => [], :neither => []}.each do |name, should| should.sort! { |a,b| a.to_s <=> b.to_s } - provider = type.provider(name) + provider = @type.provider(name) assert(provider, "Could not find provider %s" % name) assert_equal(should, provider.features, "Provider %s has incorrect features" % name) @@ -90,7 +98,7 @@ class TestTypeProviders < Test::Unit::TestCase inst = provider.new(model) # Make sure the boolean methods work on both the provider and # instance. - features.keys.each do |feature| + @features.keys.each do |feature| method = feature.to_s + "?" assert(inst.respond_to?(method), "No boolean instance method for %s on %s" % @@ -128,6 +136,44 @@ class TestTypeProviders < Test::Unit::TestCase "No features method defined for %s" % type.name) end end + + def test_has_feature + # Define a provider with nothing + provider = @type.provide(:nothing) {} + + assert(provider.respond_to?(:has_features), + "Provider did not get 'has_features' method added") + + # One with the numeric methods and nothing else + @type.provide(:numbers) do + define_method(:one) {} + define_method(:two) {} + end + + # Another with the numbers and a declaration + @type.provide(:both) do + define_method(:one) {} + define_method(:two) {} + + has_features :alpha + end + + # And just the declaration + @type.provide(:letters) do + has_features :alpha + end + + should = {:nothing => [], :both => [:numeric, :alpha], + :letters => [:alpha], :numbers => [:numeric]} + + should.each do |name, features| + provider = @type.provider(name) + assert(provider, "did not get provider named %s" % name) + features.sort! { |a,b| a.to_s <=> b.to_s } + assert_equal(features, provider.features, + "Got incorrect feature list for %s" % name) + end + end end # $Id$ |