summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-03-19 20:24:08 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2007-03-19 20:24:08 +0000
commit3d17685f9954b584cf84a6fe224b2513007108f0 (patch)
tree205402a6343fd6c667e984ca9a3874566e333244
parent290ad14f50dcb6e530e6f2624fe05d1c4cac3538 (diff)
downloadpuppet-3d17685f9954b584cf84a6fe224b2513007108f0.tar.gz
puppet-3d17685f9954b584cf84a6fe224b2513007108f0.tar.xz
puppet-3d17685f9954b584cf84a6fe224b2513007108f0.zip
Adding a "has_feature" method, so a provider can just declare that it has a given feature
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@2327 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r--lib/puppet/metatype/providers.rb6
-rw-r--r--lib/puppet/provider.rb13
-rw-r--r--lib/puppet/util/provider_features.rb55
-rwxr-xr-xtest/ral/manager/provider.rb74
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$