Skip to content

Commit 3d17685

Browse files
author
luke
committed
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
1 parent 290ad14 commit 3d17685

File tree

4 files changed

+113
-35
lines changed

4 files changed

+113
-35
lines changed

Diff for: lib/puppet/metatype/providers.rb

+2-4
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,11 @@ def self.provide(name, options = {}, &block)
162162
:hash => @providers,
163163
:prefix => "Provider",
164164
:block => block,
165+
:include => feature_module,
166+
:extend => feature_module,
165167
:attributes => options
166168
)
167169

168-
# Add the feature module to both the instances and classes.
169-
provider.send(:include, feature_module)
170-
provider.send(:extend, feature_module)
171-
172170
return provider
173171
end
174172

Diff for: lib/puppet/provider.rb

+12-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ class << self
99
# Include the util module so we have access to things like 'binary'
1010
include Puppet::Util, Puppet::Util::Docs
1111
include Puppet::Util::Logging
12-
attr_accessor :name, :model
12+
attr_accessor :name
13+
attr_reader :model
1314
attr_writer :doc
1415
end
1516

@@ -139,6 +140,16 @@ def self.mkmodelmethods
139140
end
140141
end
141142

143+
# Add the feature module immediately, so its methods are available to the
144+
# providers.
145+
def self.model=(model)
146+
@model = model
147+
#if mod = model.feature_module
148+
# extend(mod)
149+
# include(mod)
150+
#end
151+
end
152+
142153
self.initvars
143154

144155
# Check whether this implementation is suitable for our platform.

Diff for: lib/puppet/util/provider_features.rb

+39-16
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,44 @@
11
# Provides feature definitions.
22
module Puppet::Util::ProviderFeatures
3+
4+
# The class that models the features and handles checking whether the features
5+
# are present.
36
class ProviderFeature
47
require 'puppet/util/methodhelper'
58
require 'puppet/util'
69
include Puppet::Util
710
include Puppet::Util::MethodHelper
811
attr_accessor :name, :docs, :methods
12+
13+
# Are all of the requirements met?
14+
def available?(obj)
15+
if self.methods and ! methods_available?(obj)
16+
return false
17+
end
18+
19+
true
20+
end
21+
922
def initialize(name, docs, hash)
1023
self.name = symbolize(name)
1124
self.docs = docs
1225
hash = symbolize_options(hash)
1326
set_options(hash)
1427
end
28+
29+
private
30+
31+
# Are all of the required methods available?
32+
def methods_available?(obj)
33+
methods.each do |m|
34+
if obj.is_a?(Class)
35+
return false unless obj.public_method_defined?(m)
36+
else
37+
return false unless obj.respond_to?(m)
38+
end
39+
end
40+
return true
41+
end
1542
end
1643

1744
# Define one or more features. At a minimum, features require a name
@@ -99,28 +126,24 @@ def feature_module
99126
@features.each do |name, feature|
100127
method = name.to_s + "?"
101128
@feature_module.send(:define_method, method) do
102-
set = nil
103-
feature.methods.each do |m|
104-
if is_a?(Class)
105-
unless public_method_defined?(m)
106-
set = false
107-
break
108-
end
109-
else
110-
unless respond_to?(m)
111-
set = false
112-
break
113-
end
114-
end
115-
end
116-
117-
if set.nil?
129+
if defined? @declared_features and @declared_features.include?(name)
130+
true
131+
elsif feature.available?(self)
118132
true
119133
else
120134
false
121135
end
122136
end
123137
end
138+
139+
# Allow the provider to declare that it has a given feature.
140+
@feature_module.send(:define_method, :has_features) do |*names|
141+
@declared_features ||= []
142+
names.each do |name|
143+
name = symbolize(name)
144+
@declared_features << name
145+
end
146+
end
124147
end
125148
@feature_module
126149
end

Diff for: test/ral/manager/provider.rb

+60-14
Original file line numberDiff line numberDiff line change
@@ -47,50 +47,58 @@ def test_provider_sorting
4747
assert_equal(should, type.allattrs.reject { |p| ! should.include?(p) },
4848
"Providify did not reorder parameters")
4949
end
50+
end
51+
52+
class TestProviderFeatures < Test::Unit::TestCase
53+
include PuppetTest
5054

51-
def test_features
52-
type = Puppet::Type.newtype(:feature_test) do
55+
def setup
56+
super
57+
@type = Puppet::Type.newtype(:feature_test) do
5358
newparam(:name) {}
5459
ensurable
5560
end
5661
cleanup { Puppet::Type.rmtype(:feature_test) }
5762

58-
features = {:numeric => [:one, :two], :alpha => [:a, :b]}
63+
@features = {:numeric => [:one, :two], :alpha => [:a, :b]}
5964

60-
features.each do |name, methods|
65+
@features.each do |name, methods|
6166
assert_nothing_raised("Could not define features") do
62-
type.feature(name, "boo", :methods => methods)
67+
@type.feature(name, "boo", :methods => methods)
6368
end
6469
end
70+
end
6571

66-
providers = {:numbers => features[:numeric], :letters => features[:alpha]}
67-
providers[:both] = features[:numeric] + features[:alpha]
68-
providers[:mixed] = [:one, :b]
69-
providers[:neither] = [:something, :else]
72+
# Give them the basic run-through.
73+
def test_method_features
74+
@providers = {:numbers => @features[:numeric], :letters => @features[:alpha]}
75+
@providers[:both] = @features[:numeric] + @features[:alpha]
76+
@providers[:mixed] = [:one, :b]
77+
@providers[:neither] = [:something, :else]
7078

71-
providers.each do |name, methods|
79+
@providers.each do |name, methods|
7280
assert_nothing_raised("Could not create provider %s" % name) do
73-
type.provide(name) do
81+
@type.provide(name) do
7482
methods.each do |name|
7583
define_method(name) {}
7684
end
7785
end
7886
end
7987
end
8088

81-
model = type.create(:name => "foo")
89+
model = @type.create(:name => "foo")
8290
{:numbers => [:numeric], :letters => [:alpha], :both => [:numeric, :alpha],
8391
:mixed => [], :neither => []}.each do |name, should|
8492
should.sort! { |a,b| a.to_s <=> b.to_s }
85-
provider = type.provider(name)
93+
provider = @type.provider(name)
8694
assert(provider, "Could not find provider %s" % name)
8795
assert_equal(should, provider.features,
8896
"Provider %s has incorrect features" % name)
8997

9098
inst = provider.new(model)
9199
# Make sure the boolean methods work on both the provider and
92100
# instance.
93-
features.keys.each do |feature|
101+
@features.keys.each do |feature|
94102
method = feature.to_s + "?"
95103
assert(inst.respond_to?(method),
96104
"No boolean instance method for %s on %s" %
@@ -128,6 +136,44 @@ def test_features
128136
"No features method defined for %s" % type.name)
129137
end
130138
end
139+
140+
def test_has_feature
141+
# Define a provider with nothing
142+
provider = @type.provide(:nothing) {}
143+
144+
assert(provider.respond_to?(:has_features),
145+
"Provider did not get 'has_features' method added")
146+
147+
# One with the numeric methods and nothing else
148+
@type.provide(:numbers) do
149+
define_method(:one) {}
150+
define_method(:two) {}
151+
end
152+
153+
# Another with the numbers and a declaration
154+
@type.provide(:both) do
155+
define_method(:one) {}
156+
define_method(:two) {}
157+
158+
has_features :alpha
159+
end
160+
161+
# And just the declaration
162+
@type.provide(:letters) do
163+
has_features :alpha
164+
end
165+
166+
should = {:nothing => [], :both => [:numeric, :alpha],
167+
:letters => [:alpha], :numbers => [:numeric]}
168+
169+
should.each do |name, features|
170+
provider = @type.provider(name)
171+
assert(provider, "did not get provider named %s" % name)
172+
features.sort! { |a,b| a.to_s <=> b.to_s }
173+
assert_equal(features, provider.features,
174+
"Got incorrect feature list for %s" % name)
175+
end
176+
end
131177
end
132178

133179
# $Id$

0 commit comments

Comments
 (0)