poise 2.0.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.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.kitchen.travis.yml +9 -0
  4. data/.kitchen.yml +18 -0
  5. data/.rubocop.yml +2 -0
  6. data/.travis.yml +25 -0
  7. data/.yardopts +5 -0
  8. data/Berksfile +26 -0
  9. data/Berksfile.lock +10 -0
  10. data/CHANGELOG.md +58 -0
  11. data/Gemfile +32 -0
  12. data/LICENSE +202 -0
  13. data/README.md +198 -0
  14. data/Rakefile +17 -0
  15. data/lib/poise.rb +71 -0
  16. data/lib/poise/error.rb +24 -0
  17. data/lib/poise/helpers.rb +33 -0
  18. data/lib/poise/helpers/chefspec_matchers.rb +92 -0
  19. data/lib/poise/helpers/defined_in.rb +111 -0
  20. data/lib/poise/helpers/fused.rb +127 -0
  21. data/lib/poise/helpers/include_recipe.rb +62 -0
  22. data/lib/poise/helpers/inversion.rb +374 -0
  23. data/lib/poise/helpers/inversion/options_provider.rb +41 -0
  24. data/lib/poise/helpers/inversion/options_resource.rb +101 -0
  25. data/lib/poise/helpers/lazy_default.rb +62 -0
  26. data/lib/poise/helpers/lwrp_polyfill.rb +96 -0
  27. data/lib/poise/helpers/notifying_block.rb +78 -0
  28. data/lib/poise/helpers/option_collector.rb +117 -0
  29. data/lib/poise/helpers/resource_name.rb +99 -0
  30. data/lib/poise/helpers/subcontext_block.rb +58 -0
  31. data/lib/poise/helpers/subresources.rb +29 -0
  32. data/lib/poise/helpers/subresources/child.rb +217 -0
  33. data/lib/poise/helpers/subresources/container.rb +165 -0
  34. data/lib/poise/helpers/subresources/default_containers.rb +73 -0
  35. data/lib/poise/helpers/template_content.rb +165 -0
  36. data/lib/poise/provider.rb +55 -0
  37. data/lib/poise/resource.rb +75 -0
  38. data/lib/poise/subcontext.rb +27 -0
  39. data/lib/poise/subcontext/resource_collection.rb +56 -0
  40. data/lib/poise/subcontext/runner.rb +50 -0
  41. data/lib/poise/utils.rb +60 -0
  42. data/lib/poise/utils/resource_provider_mixin.rb +53 -0
  43. data/lib/poise/version.rb +20 -0
  44. data/poise.gemspec +38 -0
  45. data/test/cookbooks/poise_test/attributes/default.rb +17 -0
  46. data/test/cookbooks/poise_test/libraries/app.rb +43 -0
  47. data/test/cookbooks/poise_test/libraries/app_config.rb +46 -0
  48. data/test/cookbooks/poise_test/libraries/inversion.rb +67 -0
  49. data/test/cookbooks/poise_test/metadata.rb +18 -0
  50. data/test/cookbooks/poise_test/recipes/default.rb +25 -0
  51. data/test/cookbooks/poise_test/recipes/inversion.rb +42 -0
  52. data/test/gemfiles/chef-12.0.gemfile +18 -0
  53. data/test/gemfiles/chef-12.1.gemfile +18 -0
  54. data/test/gemfiles/chef-12.2.gemfile +18 -0
  55. data/test/gemfiles/chef-12.gemfile +18 -0
  56. data/test/gemfiles/master.gemfile +20 -0
  57. data/test/integration/default/serverspec/default_spec.rb +35 -0
  58. data/test/integration/default/serverspec/inversion_spec.rb +43 -0
  59. data/test/spec/helpers/chefspec_matchers_spec.rb +45 -0
  60. data/test/spec/helpers/defined_in_spec.rb +62 -0
  61. data/test/spec/helpers/fused_spec.rb +92 -0
  62. data/test/spec/helpers/include_recipe_spec.rb +34 -0
  63. data/test/spec/helpers/inversion/options_resource_spec.rb +212 -0
  64. data/test/spec/helpers/inversion_spec.rb +273 -0
  65. data/test/spec/helpers/lazy_default_spec.rb +74 -0
  66. data/test/spec/helpers/lwrp_polyfill_spec.rb +128 -0
  67. data/test/spec/helpers/notifying_block_spec.rb +87 -0
  68. data/test/spec/helpers/option_collector_spec.rb +82 -0
  69. data/test/spec/helpers/resource_name_spec.rb +39 -0
  70. data/test/spec/helpers/subcontext_block_spec.rb +94 -0
  71. data/test/spec/helpers/subresources/child_spec.rb +339 -0
  72. data/test/spec/helpers/subresources/container_spec.rb +175 -0
  73. data/test/spec/helpers/template_context_spec.rb +147 -0
  74. data/test/spec/poise_spec.rb +185 -0
  75. data/test/spec/provider_spec.rb +28 -0
  76. data/test/spec/resource_spec.rb +85 -0
  77. data/test/spec/spec_helper.rb +18 -0
  78. data/test/spec/utils/resource_provider_mixin_spec.rb +52 -0
  79. data/test/spec/utils_spec.rb +110 -0
  80. metadata +190 -0
@@ -0,0 +1,99 @@
1
+ #
2
+ # Copyright 2013-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 'chef/mixin/convert_to_class_name'
18
+
19
+
20
+ module Poise
21
+ module Helpers
22
+ # A resource mixin to automatically set @resource_name.
23
+ #
24
+ # @since 1.0.0
25
+ # @example
26
+ # class MyResource < Chef::Resource
27
+ # include Poise::Helpers::ResourceName
28
+ # provides(:my_resource)
29
+ # end
30
+ module ResourceName
31
+ def initialize(*args)
32
+ super
33
+ # If provides() was explicitly set, unconditionally set @resource_name.
34
+ # This helps when subclassing core Chef resources which set it
35
+ # themselves in #initialize.
36
+ if self.class.resource_name(false)
37
+ @resource_name = self.class.resource_name
38
+ else
39
+ @resource_name ||= self.class.resource_name
40
+ end
41
+ end
42
+
43
+ # @!classmethods
44
+ module ClassMethods
45
+ # Set the DSL name for the the resource class.
46
+ #
47
+ # @param name [Symbol] Name of the resource.
48
+ # @return [void]
49
+ # @example
50
+ # class MyResource < Chef::Resource
51
+ # include Poise::Resource::ResourceName
52
+ # provides(:my_resource)
53
+ # end
54
+ def provides(name)
55
+ # Patch self.constantize so this can cope with anonymous classes.
56
+ # This does require that the anonymous class define self.name though.
57
+ if self.name && respond_to?(:constantize)
58
+ old_constantize = instance_method(:constantize)
59
+ define_singleton_method(:constantize) do |const_name|
60
+ ( const_name == self.name ) ? self : old_constantize.bind(self).call(const_name)
61
+ end
62
+ end
63
+ # Store the name for later.
64
+ @provides_name = name
65
+ # Call the original if present. The defined? is for old Chef.
66
+ super if defined?(super)
67
+ end
68
+
69
+ # Retreive the DSL name for the resource class. If not set explicitly
70
+ # via {provides} this will try to auto-detect based on the class name.
71
+ #
72
+ # @param auto [Boolean] Try to auto-detect based on class name.
73
+ # @return [Symbol]
74
+ def resource_name(auto=true)
75
+ return @provides_name if @provides_name
76
+ @provides_name || if name && name.start_with?('Chef::Resource')
77
+ Chef::Mixin::ConvertToClassName.convert_to_snake_case(name, 'Chef::Resource').to_sym
78
+ elsif name
79
+ Chef::Mixin::ConvertToClassName.convert_to_snake_case(name.split('::').last).to_sym
80
+ end
81
+ end
82
+
83
+ # Used by Resource#to_text to find the human name for the resource.
84
+ #
85
+ # @api private
86
+ def dsl_name
87
+ resource_name.to_s
88
+ end
89
+
90
+ def included(klass)
91
+ super
92
+ klass.extend(ClassMethods)
93
+ end
94
+ end
95
+
96
+ extend ClassMethods
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,58 @@
1
+ #
2
+ # Copyright 2013-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 'poise/subcontext/resource_collection'
18
+
19
+
20
+ module Poise
21
+ module Helpers
22
+ # A provider mixin to help with creating subcontexts. Mostly for internal
23
+ # use within Poise.
24
+ #
25
+ # @since 1.0.0
26
+ module SubcontextBlock
27
+ private
28
+
29
+ def subcontext_block(parent_context=nil, &block)
30
+ # Setup a sub-run-context.
31
+ parent_context ||= @run_context
32
+ sub_run_context = parent_context.dup
33
+ sub_run_context.resource_collection = Poise::Subcontext::ResourceCollection.new(parent_context.resource_collection)
34
+
35
+ # Declare sub-resources within the sub-run-context. Since they
36
+ # are declared here, they do not pollute the parent run-context.
37
+ begin
38
+ outer_run_context = @run_context
39
+ @run_context = sub_run_context
40
+ instance_eval(&block)
41
+ ensure
42
+ @run_context = outer_run_context
43
+ end
44
+
45
+ # Return the inner context to do other things with
46
+ sub_run_context
47
+ end
48
+
49
+ def global_resource_collection
50
+ collection = @run_context.resource_collection
51
+ while collection.respond_to?(:parent) && collection.parent
52
+ collection = collection.parent
53
+ end
54
+ collection
55
+ end
56
+ end
57
+ end
58
+ end
@@ -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
+
18
+ module Poise
19
+ module Helpers
20
+ # Mixins and helpers for managing subresources, resources with a
21
+ # parent/child relationship.
22
+ #
23
+ # @since 2.0.0
24
+ module Subresources
25
+ autoload :Child, 'poise/helpers/subresources/child'
26
+ autoload :Container, 'poise/helpers/subresources/container'
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,217 @@
1
+ #
2
+ # Copyright 2013-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 'chef/resource'
18
+
19
+ require 'poise/error'
20
+ require 'poise/helpers/subresources/default_containers'
21
+
22
+
23
+ module Poise
24
+ module Helpers
25
+ module Subresources
26
+ # A resource mixin for child subresources.
27
+ #
28
+ # @since 1.0.0
29
+ module Child
30
+ # Little class used to fix up the display of subresources in #to_text.
31
+ # Without this you get the full parent resource shown for @parent et al.
32
+ # @api private
33
+ class ParentRef
34
+ attr_accessor :resource
35
+
36
+ def initialize(resource)
37
+ @resource = resource
38
+ end
39
+
40
+ def to_text
41
+ if @resource.nil?
42
+ 'nil'
43
+ else
44
+ @resource.to_s
45
+ end
46
+ end
47
+ end
48
+
49
+ # @overload parent()
50
+ # Get the parent resource for this child. This may be nil if the
51
+ # resource is set to parent_optional = true.
52
+ # @return [Chef::Resource, nil]
53
+ # @overload parent(val)
54
+ # Set the parent resource. The parent can be set as resource
55
+ # object, a string (either a bare resource name or a type[name]
56
+ # string), or a type:name hash.
57
+ # @param val [String, Hash, Chef::Resource] Parent resource to set.
58
+ # @return [Chef::Resource, nil]
59
+ def parent(val=nil)
60
+ _parent(:parent, self.class.parent_type, self.class.parent_optional, self.class.parent_auto, val)
61
+ end
62
+
63
+ # Register ourself with parents in case this is not a nested resource.
64
+ #
65
+ # @api private
66
+ def after_created
67
+ super
68
+ self.class.parent_attributes.each_key do |name|
69
+ parent = self.send(name)
70
+ parent.register_subresource(self) if parent
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ # Generic form of the parent getter/setter.
77
+ #
78
+ # @since 2.0.0
79
+ # @see #parent
80
+ def _parent(name, parent_type, parent_optional, parent_auto, val=nil)
81
+ # Allow using a DSL symbol as the parent type.
82
+ if parent_type.is_a?(Symbol)
83
+ parent_type = Chef::Resource.resource_for_node(parent_type, node)
84
+ end
85
+ # Grab the ivar for local use.
86
+ parent_ref = instance_variable_get(:"@#{name}")
87
+ if val
88
+ if val.is_a?(String) && !val.include?('[')
89
+ raise Poise::Error.new('Cannot use a string parent without defining a parent type') if parent_type == Chef::Resource
90
+ val = "#{parent_type.resource_name}[#{val}]"
91
+ end
92
+ if val.is_a?(String) || val.is_a?(Hash)
93
+ parent = @run_context.resource_collection.find(val)
94
+ else
95
+ parent = val
96
+ end
97
+ if !parent.is_a?(parent_type)
98
+ raise Poise::Error.new("Parent resource is not an instance of #{parent_type.name}: #{val.inspect}")
99
+ end
100
+ parent_ref = ParentRef.new(parent)
101
+ elsif !parent_ref
102
+ if parent_auto
103
+ # Automatic sibling lookup for sequential composition.
104
+ # Find the last instance of the parent class as the default parent.
105
+ # This is super flaky and should only be a last resort.
106
+ parent = Poise::Helpers::Subresources::DefaultContainers.find(parent_type, run_context)
107
+ end
108
+ # Can't find a valid parent, if it wasn't optional raise an error.
109
+ raise Poise::Error.new("No parent found for #{self}") unless parent || parent_optional
110
+ parent_ref = ParentRef.new(parent)
111
+ else
112
+ parent = parent_ref.resource
113
+ end
114
+ # Store the ivar back.
115
+ instance_variable_set(:"@#{name}", parent_ref)
116
+ # Return the actual resource.
117
+ parent
118
+ end
119
+
120
+ module ClassMethods
121
+ # @overload parent_type()
122
+ # Get the class of the default parent link on this resource.
123
+ # @return [Class, Symbol]
124
+ # @overload parent_type(type)
125
+ # Set the class of the default parent link on this resource.
126
+ # @param type [Class, Symbol] Class to set.
127
+ # @return [Class, Symbol]
128
+ def parent_type(type=nil)
129
+ if type
130
+ raise Poise::Error.new("Parent type must be a class, symbol, or true, got #{type.inspect}") unless type.is_a?(Class) || type.is_a?(Symbol) || type == true
131
+ @parent_type = type
132
+ end
133
+ @parent_type || (superclass.respond_to?(:parent_type) ? superclass.parent_type : Chef::Resource)
134
+ end
135
+
136
+ # @overload parent_optional()
137
+ # Get the optional mode for the default parent link on this resource.
138
+ # @return [Boolean]
139
+ # @overload parent_optional(val)
140
+ # Set the optional mode for the default parent link on this resource.
141
+ # @param val [Boolean] Mode to set.
142
+ # @return [Boolean]
143
+ def parent_optional(val=nil)
144
+ unless val.nil?
145
+ @parent_optional = val
146
+ end
147
+ if @parent_optional.nil?
148
+ superclass.respond_to?(:parent_optional) ? superclass.parent_optional : false
149
+ else
150
+ @parent_optional
151
+ end
152
+ end
153
+
154
+ # @overload parent_auto()
155
+ # Get the auto-detect mode for the default parent link on this resource.
156
+ # @return [Boolean]
157
+ # @overload parent_auto(val)
158
+ # Set the auto-detect mode for the default parent link on this resource.
159
+ # @param val [Boolean] Mode to set.
160
+ # @return [Boolean]
161
+ def parent_auto(val=nil)
162
+ unless val.nil?
163
+ @parent_auto = val
164
+ end
165
+ if @parent_auto.nil?
166
+ superclass.respond_to?(:parent_auto) ? superclass.parent_auto : true
167
+ else
168
+ @parent_auto
169
+ end
170
+ end
171
+
172
+ # Create a new kind of parent link.
173
+ #
174
+ # @since 2.0.0
175
+ # @param name [Symbol] Name of the relationship. This becomes a method
176
+ # name on the resource instance.
177
+ # @param type [Class] Class of the parent.
178
+ # @param optional [Boolean] If the parent is optional.
179
+ # @param auto [Boolean] If the parent is auto-detected.
180
+ # @return [void]
181
+ def parent_attribute(name, type: Chef::Resource, optional: false, auto: true)
182
+ name = :"parent_#{name}"
183
+ (@parent_attributes ||= {})[name] = type
184
+ define_method(name) do |val=nil|
185
+ _parent(name, type, optional, auto, val)
186
+ end
187
+ end
188
+
189
+ # Return the name of all parent relationships on this class.
190
+ #
191
+ # @since 2.0.0
192
+ # @return [Hash<Symbol, Class>]
193
+ def parent_attributes
194
+ {}.tap do |attrs|
195
+ # Grab superclass's attributes if possible.
196
+ attrs.update(superclass.parent_attributes) if superclass.respond_to?(:parent_attributes)
197
+ # Local default parent.
198
+ attrs[:parent] = parent_type
199
+ # Extra locally defined parents.
200
+ attrs.update(@parent_attributes) if @parent_attributes
201
+ # Remove anything with the type set to true.
202
+ attrs.reject! {|name, type| type == true }
203
+ end
204
+ end
205
+
206
+ # @api private
207
+ def included(klass)
208
+ super
209
+ klass.extend(ClassMethods)
210
+ end
211
+ end
212
+
213
+ extend ClassMethods
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,165 @@
1
+ #
2
+ # Copyright 2013-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 'chef/dsl/recipe'
18
+
19
+ require 'poise/helpers/subcontext_block'
20
+ require 'poise/helpers/subresources/default_containers'
21
+
22
+
23
+ module Poise
24
+ module Helpers
25
+ module Subresources
26
+ # A resource mixin for subresource containers.
27
+ #
28
+ # @since 1.0.0
29
+ module Container
30
+ # A resource collection that has much more condensed text output. This
31
+ # is used to show the value of @subresources during Chef's error formatting.
32
+ # @api private
33
+ class NoPrintingResourceCollection < Chef::ResourceCollection
34
+ def to_text
35
+ "[#{all_resources.map(&:to_s).join(', ')}]"
36
+ end
37
+ end
38
+
39
+ include SubcontextBlock
40
+ include Chef::DSL::Recipe
41
+
42
+ attr_reader :subresources
43
+
44
+ def initialize(*args)
45
+ super
46
+ @subresources = NoPrintingResourceCollection.new
47
+ end
48
+
49
+ def after_created
50
+ super
51
+ # Register
52
+ Poise::Helpers::Subresources::DefaultContainers.register!(self, run_context)
53
+ unless @subresources.empty?
54
+ Chef::Log.debug("[#{self}] Adding subresources to collection:")
55
+ # Because after_create is run before adding the container to the resource collection
56
+ # we need to jump through some hoops to get it swapped into place.
57
+ self_ = self
58
+ order_fixer = Chef::Resource::RubyBlock.new('subresource_order_fixer', @run_context)
59
+ order_fixer.block do
60
+ collection = self_.run_context.resource_collection
61
+ # Delete the current container resource from its current position.
62
+ collection.all_resources.delete(self_)
63
+ # Replace the order fixer with the container so it runs before all
64
+ # subresources.
65
+ collection.all_resources[collection.iterator.position] = self_
66
+ # Hack for Chef 11 to reset the resources_by_name position too.
67
+ # @todo Remove this when I drop support for Chef 11.
68
+ if resources_by_name = collection.instance_variable_get(:@resources_by_name)
69
+ resources_by_name[self_.to_s] = collection.iterator.position
70
+ end
71
+ # Step back so we re-run the "current" resource, which is now the
72
+ # container.
73
+ collection.iterator.skip_back
74
+ end
75
+ @run_context.resource_collection.insert(order_fixer)
76
+ @subresources.each do |r|
77
+ Chef::Log.debug(" * #{r}")
78
+ @run_context.resource_collection.insert(r)
79
+ end
80
+ end
81
+ end
82
+
83
+ def declare_resource(type, name, created_at=nil, &block)
84
+ Chef::Log.debug("[#{self}] Creating subresource from #{type}(#{name})")
85
+ self_ = self
86
+ # Used to break block context, non-local return from subcontext_block.
87
+ resource = []
88
+ # Grab the caller so we can make the subresource look like it comes from
89
+ # correct place.
90
+ created_at ||= caller[0]
91
+ # Run this inside a subcontext to avoid adding to the current resource collection.
92
+ # It will end up added later, indirected via @subresources to ensure ordering.
93
+ subcontext_block do
94
+ namespace = if self.class.container_namespace == true
95
+ # If the value is true, use the name of the container resource.
96
+ self.name
97
+ elsif self.class.container_namespace.is_a?(Proc)
98
+ instance_eval(&self.class.container_namespace)
99
+ else
100
+ self.class.container_namespace
101
+ end
102
+ sub_name = if name && !name.empty?
103
+ if namespace
104
+ "#{namespace}::#{name}"
105
+ else
106
+ name
107
+ end
108
+ else
109
+ # If you pass in nil or '', you just get the namespace or parent name.
110
+ namespace || self.name
111
+ end
112
+ resource << super(type, sub_name, created_at) do
113
+ # Apply the correct parent before anything else so it is available
114
+ # in after_created for the subresource.
115
+ parent(self_) if respond_to?(:parent)
116
+ # Run the resource block.
117
+ instance_exec(&block) if block
118
+ end
119
+ end
120
+ # Try and add to subresources. For normal subresources this is handled
121
+ # in the after_created.
122
+ register_subresource(resource.first) if resource.first
123
+ # Return whatever we have
124
+ resource.first
125
+ end
126
+
127
+ def register_subresource(resource)
128
+ subresources.lookup(resource)
129
+ rescue Chef::Exceptions::ResourceNotFound
130
+ Chef::Log.debug("[#{self}] Adding #{resource} to subresources")
131
+ subresources.insert(resource)
132
+ end
133
+
134
+ private
135
+
136
+ # Thanks Array.flatten, big help you are. Specifically the
137
+ # method_missing in the recipe DSL will make a flatten on an array of
138
+ # resources fail, so make this safe.
139
+ def to_ary
140
+ nil
141
+ end
142
+
143
+ # @!classmethods
144
+ module ClassMethods
145
+ def container_namespace(val=nil)
146
+ @container_namespace = val unless val.nil?
147
+ if @container_namespace.nil?
148
+ # Not set here, look at the superclass of true by default for backwards compat.
149
+ superclass.respond_to?(:container_namespace) ? superclass.container_namespace : true
150
+ else
151
+ @container_namespace
152
+ end
153
+ end
154
+
155
+ def included(klass)
156
+ super
157
+ klass.extend(ClassMethods)
158
+ end
159
+ end
160
+
161
+ extend ClassMethods
162
+ end
163
+ end
164
+ end
165
+ end