poise 2.2.3 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +0 -2
- data/lib/poise.rb +3 -1
- data/lib/poise/backports.rb +27 -0
- data/lib/poise/backports/not_passed.rb +52 -0
- data/lib/poise/helpers.rb +1 -0
- data/lib/poise/helpers/chefspec_matchers.rb +5 -1
- data/lib/poise/helpers/inversion.rb +36 -13
- data/lib/poise/helpers/option_collector.rb +15 -4
- data/lib/poise/helpers/resource_name.rb +1 -1
- data/lib/poise/helpers/resource_subclass.rb +81 -0
- data/lib/poise/helpers/subresources/child.rb +50 -9
- data/lib/poise/helpers/subresources/container.rb +33 -6
- data/lib/poise/resource.rb +3 -1
- data/lib/poise/subcontext/resource_collection.rb +20 -1
- data/lib/poise/utils.rb +79 -7
- data/lib/poise/utils/resource_provider_mixin.rb +2 -2
- data/lib/poise/version.rb +1 -1
- data/test/spec/backports/not_passed_spec.rb +29 -0
- data/test/spec/helpers/chefspec_matchers_spec.rb +17 -0
- data/test/spec/helpers/inversion_spec.rb +72 -0
- data/test/spec/helpers/lwrp_polyfill_spec.rb +9 -0
- data/test/spec/helpers/option_collector_spec.rb +66 -30
- data/test/spec/helpers/resource_name_spec.rb +15 -2
- data/test/spec/helpers/resource_subclass_spec.rb +97 -0
- data/test/spec/helpers/subresources/child_spec.rb +234 -2
- data/test/spec/helpers/subresources/container_spec.rb +37 -0
- data/test/spec/resource_spec.rb +31 -2
- data/test/spec/subcontext/resource_collection_spec.rb +99 -0
- data/test/spec/utils/resource_provider_mixin_spec.rb +22 -0
- data/test/spec/utils_spec.rb +187 -1
- metadata +11 -3
- data/Berksfile.lock +0 -10
@@ -48,8 +48,9 @@ module Poise
|
|
48
48
|
|
49
49
|
def after_created
|
50
50
|
super
|
51
|
-
# Register
|
52
|
-
Poise::Helpers::Subresources::DefaultContainers.register!(self, run_context)
|
51
|
+
# Register as a default container if needed.
|
52
|
+
Poise::Helpers::Subresources::DefaultContainers.register!(self, run_context) if self.class.container_default
|
53
|
+
# Add all internal subresources to the resource collection.
|
53
54
|
unless @subresources.empty?
|
54
55
|
Chef::Log.debug("[#{self}] Adding subresources to collection:")
|
55
56
|
# Because after_create is run before adding the container to the resource collection
|
@@ -113,8 +114,13 @@ module Poise
|
|
113
114
|
end
|
114
115
|
resource << super(type, sub_name, created_at) do
|
115
116
|
# Apply the correct parent before anything else so it is available
|
116
|
-
# in after_created for the subresource.
|
117
|
-
|
117
|
+
# in after_created for the subresource. It might raise
|
118
|
+
# NoMethodError is there isn't a real parent.
|
119
|
+
begin
|
120
|
+
parent(self_) if respond_to?(:parent)
|
121
|
+
rescue NoMethodError
|
122
|
+
# This space left intentionally blank.
|
123
|
+
end
|
118
124
|
# Run the resource block.
|
119
125
|
instance_exec(&block) if block
|
120
126
|
end
|
@@ -147,13 +153,34 @@ module Poise
|
|
147
153
|
def container_namespace(val=nil)
|
148
154
|
@container_namespace = val unless val.nil?
|
149
155
|
if @container_namespace.nil?
|
150
|
-
# Not set here, look at the superclass
|
151
|
-
|
156
|
+
# Not set here, look at the superclass or true by default for backwards compat.
|
157
|
+
Poise::Utils.ancestor_send(self, :container_namespace, default: true)
|
152
158
|
else
|
153
159
|
@container_namespace
|
154
160
|
end
|
155
161
|
end
|
156
162
|
|
163
|
+
# @overload container_default()
|
164
|
+
# Get the default mode for this resource. If false, this resource
|
165
|
+
# class will not be used for default container lookups. Defaults to
|
166
|
+
# true.
|
167
|
+
# @since 2.3.0
|
168
|
+
# @return [Boolean]
|
169
|
+
# @overload container_default(val)
|
170
|
+
# Set the default mode for this resource.
|
171
|
+
# @since 2.3.0
|
172
|
+
# @param val [Boolean] Default mode to set.
|
173
|
+
# @return [Boolean]
|
174
|
+
def container_default(val=nil)
|
175
|
+
@container_default = val unless val.nil?
|
176
|
+
if @container_default.nil?
|
177
|
+
# Not set here, look at the superclass or true by default for backwards compat.
|
178
|
+
Poise::Utils.ancestor_send(self, :container_default, default: true)
|
179
|
+
else
|
180
|
+
@container_default
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
157
184
|
def included(klass)
|
158
185
|
super
|
159
186
|
klass.extend(ClassMethods)
|
data/lib/poise/resource.rb
CHANGED
@@ -39,14 +39,16 @@ module Poise
|
|
39
39
|
include Poise::Helpers::OptionCollector
|
40
40
|
include Poise::Helpers::ResourceCloning
|
41
41
|
include Poise::Helpers::ResourceName
|
42
|
+
include Poise::Helpers::ResourceSubclass
|
42
43
|
include Poise::Helpers::TemplateContent
|
43
44
|
|
44
45
|
# @!classmethods
|
45
46
|
module ClassMethods
|
46
|
-
def poise_subresource_container(namespace=nil)
|
47
|
+
def poise_subresource_container(namespace=nil, default=nil)
|
47
48
|
include Poise::Helpers::Subresources::Container
|
48
49
|
# false is a valid value.
|
49
50
|
container_namespace(namespace) unless namespace.nil?
|
51
|
+
container_default(default) unless default.nil?
|
50
52
|
end
|
51
53
|
|
52
54
|
def poise_subresource(parent_type=nil, parent_optional=nil, parent_auto=nil)
|
@@ -40,7 +40,10 @@ module Poise
|
|
40
40
|
@parent.lookup(resource)
|
41
41
|
end
|
42
42
|
|
43
|
-
# Iterate
|
43
|
+
# Iterate over all resources, expanding parent context in order.
|
44
|
+
#
|
45
|
+
# @param block [Proc] Iteration block
|
46
|
+
# @return [void]
|
44
47
|
def recursive_each(&block)
|
45
48
|
if @parent
|
46
49
|
if @parent.respond_to?(:recursive_each)
|
@@ -51,6 +54,22 @@ module Poise
|
|
51
54
|
end
|
52
55
|
each(&block)
|
53
56
|
end
|
57
|
+
|
58
|
+
# Iterate over all resources in reverse order.
|
59
|
+
#
|
60
|
+
# @since 2.3.0
|
61
|
+
# @param block [Proc] Iteration block
|
62
|
+
# @return [void]
|
63
|
+
def reverse_recursive_each(&block)
|
64
|
+
reverse_each(&block)
|
65
|
+
if @parent
|
66
|
+
if @parent.respond_to?(:recursive_each)
|
67
|
+
@parent.reverse_recursive_each(&block)
|
68
|
+
else
|
69
|
+
@parent.reverse_each(&block)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
54
73
|
end
|
55
74
|
end
|
56
75
|
end
|
data/lib/poise/utils.rb
CHANGED
@@ -43,7 +43,6 @@ module Poise
|
|
43
43
|
if ver.respond_to?(:halite_root)
|
44
44
|
# The join is there because ../poise-ruby/lib starts with ../poise so
|
45
45
|
# we want a trailing /.
|
46
|
-
Chef::Log.debug("")
|
47
46
|
if filename.start_with?(File.join(ver.halite_root, ''))
|
48
47
|
Chef::Log.debug("[Poise] Found matching halite_root in #{name}: #{ver.halite_root.inspect}")
|
49
48
|
possibles[ver.halite_root] = name
|
@@ -53,7 +52,7 @@ module Poise
|
|
53
52
|
ver.segment_filenames(seg).each do |file|
|
54
53
|
# Put this behind an environment variable because it is verbose
|
55
54
|
# even for normal debugging-level output.
|
56
|
-
Chef::Log.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}") if ENV['POISE_DEBUG']
|
55
|
+
Chef::Log.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}") if ENV['POISE_DEBUG'] || run_context.node['POISE_DEBUG']
|
57
56
|
if file == filename
|
58
57
|
Chef::Log.debug("[Poise] Found matching #{seg} in #{name}: #{file.inspect}")
|
59
58
|
possibles[file] = name
|
@@ -70,14 +69,17 @@ module Poise
|
|
70
69
|
# Try to find an ancestor to call a method on.
|
71
70
|
#
|
72
71
|
# @since 2.2.3
|
72
|
+
# @since 2.3.0
|
73
|
+
# Added ignore parameter.
|
73
74
|
# @param obj [Object] Self from the caller.
|
74
75
|
# @param msg [Symbol] Method to try to call.
|
75
76
|
# @param args [Array<Object>] Method arguments.
|
76
77
|
# @param default [Object] Default return value if no valid ancestor exists.
|
78
|
+
# @param ignore [Array<Object>] Return value to ignore when scanning ancesors.
|
77
79
|
# @return [Object]
|
78
80
|
# @example
|
79
81
|
# val = @val || Poise::Utils.ancestor_send(self, :val)
|
80
|
-
def ancestor_send(obj, msg, *args, default: nil)
|
82
|
+
def ancestor_send(obj, msg, *args, default: nil, ignore: [default])
|
81
83
|
# Class is a subclass of Module, if we get something else use its class.
|
82
84
|
obj = obj.class unless obj.is_a?(Module)
|
83
85
|
ancestors = []
|
@@ -87,11 +89,81 @@ module Poise
|
|
87
89
|
end
|
88
90
|
# Make sure we don't check obj itself.
|
89
91
|
ancestors.concat(obj.ancestors.drop(1))
|
90
|
-
|
91
|
-
|
92
|
-
|
92
|
+
ancestors.each do |mod|
|
93
|
+
if mod.respond_to?(msg)
|
94
|
+
val = mod.send(msg, *args)
|
95
|
+
# If we get the default back, assume we should keep trying.
|
96
|
+
return val unless ignore.include?(val)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
# Nothing valid found, use the default.
|
100
|
+
default
|
101
|
+
end
|
102
|
+
|
103
|
+
# Create a helper to invoke a module with some parameters.
|
104
|
+
#
|
105
|
+
# @since 2.3.0
|
106
|
+
# @param mod [Module] The module to wrap.
|
107
|
+
# @param block [Proc] The module to implement to parameterization.
|
108
|
+
# @return [void]
|
109
|
+
# @example
|
110
|
+
# module MyMixin
|
111
|
+
# def self.my_mixin_name(name)
|
112
|
+
# # ...
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# Poise::Utils.parameterized_module(MyMixin) do |name|
|
117
|
+
# my_mixin_name(name)
|
118
|
+
# end
|
119
|
+
def parameterized_module(mod, &block)
|
120
|
+
raise Poise::Error.new("Cannot parameterize an anonymous module") unless mod.name && !mod.name.empty?
|
121
|
+
parent_name_parts = mod.name.split(/::/)
|
122
|
+
# Grab the last piece which will be the method name.
|
123
|
+
mod_name = parent_name_parts.pop
|
124
|
+
# Find the enclosing module or class object.
|
125
|
+
parent = parent_name_parts.inject(Object) {|memo, name| memo.const_get(name) }
|
126
|
+
# Object is a special case since we need #define_method instead.
|
127
|
+
method_type = if parent == Object
|
128
|
+
:define_method
|
93
129
|
else
|
94
|
-
|
130
|
+
:define_singleton_method
|
131
|
+
end
|
132
|
+
# Scoping hack.
|
133
|
+
self_ = self
|
134
|
+
# Construct the method.
|
135
|
+
parent.send(method_type, mod_name) do |*args|
|
136
|
+
self_.send(:check_block_arity!, block, args)
|
137
|
+
# Create a new anonymous module to be returned from the method.
|
138
|
+
Module.new do
|
139
|
+
# Fake the name.
|
140
|
+
define_singleton_method(:name) do
|
141
|
+
super() || mod.name
|
142
|
+
end
|
143
|
+
|
144
|
+
# When the stub module gets included, activate our behaviors.
|
145
|
+
define_singleton_method(:included) do |klass|
|
146
|
+
super(klass)
|
147
|
+
klass.send(:include, mod)
|
148
|
+
klass.instance_exec(*args, &block)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
# Check that the given arguments match the given block. This is needed
|
157
|
+
# because Ruby will nil-pad mismatched argspecs on blocks rather than error.
|
158
|
+
#
|
159
|
+
# @since 2.3.0
|
160
|
+
# @param block [Proc] Block to check.
|
161
|
+
# @param args [Array<Object>] Arguments to check.
|
162
|
+
# @return [void]
|
163
|
+
def check_block_arity!(block, args)
|
164
|
+
required_args = block.arity < 0 ? ~block.arity : block.arity
|
165
|
+
if args.length < required_args || (block.arity >= 0 && args.length > block.arity)
|
166
|
+
raise ArgumentError.new("wrong number of arguments (#{args.length} for #{required_args}#{block.arity < 0 ? '+' : ''})")
|
95
167
|
end
|
96
168
|
end
|
97
169
|
|
@@ -48,10 +48,10 @@ module Poise
|
|
48
48
|
# Cargo this .included to things which include us.
|
49
49
|
inner_klass.extend(mod)
|
50
50
|
# Dispatch to submodules, inner_klass is the most recent includer.
|
51
|
-
if inner_klass < Chef::Resource
|
51
|
+
if inner_klass < Chef::Resource || inner_klass.name.to_s.end_with?('::Resource')
|
52
52
|
# Use klass::Resource to look up relative to the original module.
|
53
53
|
inner_klass.class_exec { include klass::Resource }
|
54
|
-
elsif inner_klass < Chef::Provider
|
54
|
+
elsif inner_klass < Chef::Provider || inner_klass.name.to_s.end_with?('::Provider')
|
55
55
|
# As above, klass::Provider.
|
56
56
|
inner_klass.class_exec { include klass::Provider }
|
57
57
|
end
|
data/lib/poise/version.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2015, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'spec_helper'
|
18
|
+
|
19
|
+
describe Poise::Backports::NOT_PASSED do
|
20
|
+
it { is_expected.to be_truthy }
|
21
|
+
its(:to_s) { is_expected.to eq 'NOT_PASSED' }
|
22
|
+
its(:inspect) { is_expected.to eq 'NOT_PASSED' }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe Poise::NOT_PASSED do
|
26
|
+
it { is_expected.to be_truthy }
|
27
|
+
its(:to_s) { is_expected.to eq 'NOT_PASSED' }
|
28
|
+
its(:inspect) { is_expected.to eq 'NOT_PASSED' }
|
29
|
+
end
|
@@ -42,4 +42,21 @@ describe Poise::Helpers::ChefspecMatchers do
|
|
42
42
|
it { is_expected.to run_poise_other('test') }
|
43
43
|
it { expect(chef_run.poise_other('test')).to be_a Chef::Resource }
|
44
44
|
end # /context with an explicit name
|
45
|
+
|
46
|
+
context 'with a subclass' do
|
47
|
+
resource(:poise_test, auto: false, step_into: false) do
|
48
|
+
include described_class
|
49
|
+
provides(:poise_other)
|
50
|
+
actions(:run)
|
51
|
+
end
|
52
|
+
resource(:poise_sub, parent: :poise_test, auto: false, step_into: false) do
|
53
|
+
provides(:poise_sub)
|
54
|
+
end
|
55
|
+
recipe do
|
56
|
+
poise_sub 'test'
|
57
|
+
end
|
58
|
+
|
59
|
+
it { is_expected.to run_poise_sub('test') }
|
60
|
+
it { expect(chef_run.poise_sub('test')).to be_a Chef::Resource }
|
61
|
+
end # /context with a subclass
|
45
62
|
end
|
@@ -269,5 +269,77 @@ describe Poise::Helpers::Inversion do
|
|
269
269
|
end
|
270
270
|
end # /context with a provider
|
271
271
|
end # /describe .resolve_inversion_provider
|
272
|
+
|
273
|
+
describe 'provider resolution' do
|
274
|
+
before do
|
275
|
+
default_attributes['poise'] ||= {}
|
276
|
+
default_attributes['poise']['provider'] = 'auto'
|
277
|
+
end
|
278
|
+
resource(:poise_test_inversion, step_into: false) do
|
279
|
+
include Poise
|
280
|
+
provides(:poise_test_inversion)
|
281
|
+
end
|
282
|
+
provider(:poise_test_inversion) do
|
283
|
+
include described_class
|
284
|
+
inversion_resource(:poise_test_inversion)
|
285
|
+
inversion_attribute([])
|
286
|
+
provides(:inverted)
|
287
|
+
def self.provides_auto?(*args); true; end
|
288
|
+
end
|
289
|
+
provider(:poise_test_inversion_other, parent: :poise_test_inversion) do
|
290
|
+
provides(:other)
|
291
|
+
end
|
292
|
+
let(:test_resource) { nil }
|
293
|
+
subject { Chef::ProviderResolver.new(chef_run.node, test_resource, :run) }
|
294
|
+
|
295
|
+
context 'with an inversion resource' do
|
296
|
+
recipe(subject: false) do
|
297
|
+
poise_test_inversion 'test'
|
298
|
+
end
|
299
|
+
let(:test_resource) { chef_run.poise_test_inversion('test') }
|
300
|
+
|
301
|
+
its(:enabled_handlers) { is_expected.to eq [provider(:poise_test_inversion), provider(:poise_test_inversion_other)] }
|
302
|
+
its(:resolve) { is_expected.to eq provider(:poise_test_inversion) }
|
303
|
+
end # /context with an inversion resource
|
304
|
+
|
305
|
+
context 'with a resource that has no providers' do
|
306
|
+
resource(:poise_not_found, step_into: false)
|
307
|
+
recipe(subject: false) do
|
308
|
+
poise_not_found 'test'
|
309
|
+
end
|
310
|
+
let(:test_resource) { chef_run.find_resource(:poise_not_found, 'test') }
|
311
|
+
|
312
|
+
its(:enabled_handlers) { is_expected.to eq [] }
|
313
|
+
it { expect { subject.resolve }.to raise_error defined?(Chef::Exceptions::ProviderNotFound) ? Chef::Exceptions::ProviderNotFound : ArgumentError }
|
314
|
+
end # /context with a resource that has no providers
|
315
|
+
|
316
|
+
context 'with a subclassed resource' do
|
317
|
+
resource(:poise_inversion_sub, parent: :poise_test_inversion, step_into: false) do
|
318
|
+
provides(:poise_inversion_sub)
|
319
|
+
end
|
320
|
+
recipe(subject: false) do
|
321
|
+
poise_inversion_sub 'test'
|
322
|
+
end
|
323
|
+
let(:test_resource) { chef_run.find_resource(:poise_inversion_sub, 'test') }
|
324
|
+
|
325
|
+
its(:enabled_handlers) { is_expected.to eq [] }
|
326
|
+
it { expect { subject.resolve }.to raise_error defined?(Chef::Exceptions::ProviderNotFound) ? Chef::Exceptions::ProviderNotFound : ArgumentError }
|
327
|
+
end # /context with a subclassed resource
|
328
|
+
|
329
|
+
context 'with a subclassed resource using subclass_providers!' do
|
330
|
+
resource(:poise_inversion_subproviders, parent: :poise_test_inversion, step_into: false) do
|
331
|
+
include Poise::Helpers::ResourceSubclass
|
332
|
+
provides(:poise_inversion_subproviders)
|
333
|
+
subclass_providers!
|
334
|
+
end
|
335
|
+
recipe(subject: false) do
|
336
|
+
poise_inversion_subproviders 'test'
|
337
|
+
end
|
338
|
+
let(:test_resource) { chef_run.find_resource(:poise_inversion_subproviders, 'test') }
|
339
|
+
|
340
|
+
its(:enabled_handlers) { is_expected.to eq [provider(:poise_test_inversion), provider(:poise_test_inversion_other)] }
|
341
|
+
its(:resolve) { is_expected.to eq provider(:poise_test_inversion) }
|
342
|
+
end # /context with a subclassed resource using subclass_providers!
|
343
|
+
end # /describe provider resolution
|
272
344
|
end # /describe Poise::Helpers::Inversion::Provider
|
273
345
|
end
|
@@ -140,6 +140,15 @@ describe Poise::Helpers::LWRPPolyfill do
|
|
140
140
|
|
141
141
|
it { is_expected.to eq 'helper' }
|
142
142
|
end # /context with an intermediary class
|
143
|
+
|
144
|
+
context 'with no new_resource' do
|
145
|
+
provider(:poise_test, auto: false) do
|
146
|
+
include described_class
|
147
|
+
end
|
148
|
+
subject { provider(:poise_test).new(nil, nil).load_current_resource }
|
149
|
+
it { is_expected.to be_a Chef::Resource }
|
150
|
+
it { is_expected.to_not be_a resource(:poise_test) }
|
151
|
+
end # context with no new_resource
|
143
152
|
end # /describe load_current_resource override
|
144
153
|
|
145
154
|
describe 'Chef::DSL::Recipe include' do
|
@@ -78,49 +78,85 @@ describe Poise::Helpers::OptionCollector do
|
|
78
78
|
it { is_expected.to run_poise_test('test').with(options: {'one' => '1'}, value: 2) }
|
79
79
|
end # /context with a normal attribute too
|
80
80
|
|
81
|
-
context 'with
|
82
|
-
resource(:poise_test) do
|
83
|
-
include Poise::Helpers::LWRPPolyfill
|
84
|
-
include described_class
|
85
|
-
attribute(:options, option_collector: true, parser: proc {|val| parse(val) })
|
86
|
-
def parse(val)
|
87
|
-
{name: val}
|
88
|
-
end
|
89
|
-
end
|
81
|
+
context 'with an invalid key' do
|
90
82
|
recipe do
|
91
83
|
poise_test 'test' do
|
92
|
-
options
|
84
|
+
options do
|
85
|
+
one two
|
86
|
+
end
|
93
87
|
end
|
94
88
|
end
|
95
89
|
|
96
|
-
it {
|
97
|
-
end # /context with
|
90
|
+
it { expect { subject }.to raise_error NoMethodError }
|
91
|
+
end # /context with an invalid key
|
92
|
+
|
93
|
+
describe 'parser' do
|
94
|
+
context 'with a parser Proc' do
|
95
|
+
resource(:poise_test) do
|
96
|
+
include Poise::Helpers::LWRPPolyfill
|
97
|
+
include described_class
|
98
|
+
attribute(:options, option_collector: true, parser: proc {|val| parse(val) })
|
99
|
+
def parse(val)
|
100
|
+
{name: val}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
recipe do
|
104
|
+
poise_test 'test' do
|
105
|
+
options '1'
|
106
|
+
end
|
107
|
+
end
|
98
108
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
109
|
+
it { is_expected.to run_poise_test('test').with(options: {'name' => '1'}) }
|
110
|
+
end # /context with a parser Proc
|
111
|
+
|
112
|
+
context 'with a parser Symbol' do
|
113
|
+
resource(:poise_test) do
|
114
|
+
include Poise::Helpers::LWRPPolyfill
|
115
|
+
include described_class
|
116
|
+
attribute(:options, option_collector: true, parser: :parse)
|
117
|
+
def parse(val)
|
118
|
+
{name: val}
|
119
|
+
end
|
106
120
|
end
|
107
|
-
|
121
|
+
recipe do
|
122
|
+
poise_test 'test' do
|
123
|
+
options '1'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it { is_expected.to run_poise_test('test').with(options: {'name' => '1'}) }
|
128
|
+
end # /context with a parser Symbol
|
129
|
+
|
130
|
+
context 'with an invalid parser' do
|
131
|
+
it do
|
132
|
+
expect do
|
133
|
+
resource(:poise_test).send(:attribute, :options, option_collector: true, parser: 'invalid')
|
134
|
+
end.to raise_error(Poise::Error)
|
135
|
+
end
|
136
|
+
end # /context with an invalid parser
|
137
|
+
end # /describe parser
|
138
|
+
|
139
|
+
describe 'forced_keys' do
|
108
140
|
recipe do
|
109
141
|
poise_test 'test' do
|
110
|
-
options
|
142
|
+
options do
|
143
|
+
name 'foo'
|
144
|
+
end
|
111
145
|
end
|
112
146
|
end
|
113
147
|
|
114
|
-
|
115
|
-
|
148
|
+
context 'without forced_keys' do
|
149
|
+
it { is_expected.to run_poise_test('test').with(options: {}) }
|
150
|
+
end # /context without forced_keys
|
116
151
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
|
152
|
+
context 'with forced_keys' do
|
153
|
+
resource(:poise_test) do
|
154
|
+
include described_class
|
155
|
+
attribute(:options, option_collector: true, forced_keys: %i{name})
|
156
|
+
end
|
157
|
+
it { is_expected.to run_poise_test('test').with(options: {'name' => 'foo'}) }
|
158
|
+
end # /context with forced_keys
|
159
|
+
end # /describe forced_keys
|
124
160
|
|
125
161
|
# TODO: Write tests for mixed symbol/string data
|
126
162
|
end
|