inspec/lib/inspec/rspec_extensions.rb
Ryan Davis 43f520b4a8 Merged Inspec::Plugins::Resource to Inspec::Resource.
This also removes Inspec::ResourceBehaviors and Inspec::ResourceDSL.

All class methods look like class methods.
All instance methods look like instance methods.

There is still too much clever going on with __register creating
another anonymous subclass, but I think I can work that out/down too.

Signed-off-by: Ryan Davis <zenspider@chef.io>
2020-02-03 14:41:37 -08:00

128 lines
4.8 KiB
Ruby

require "inspec/input_registry"
require "inspec/plugin/v2"
require "rspec/core/example_group"
require "inspec/input_dsl_helpers"
# Any additions to RSpec::Core::ExampleGroup (the RSpec class behind describe blocks) should go here.
module Inspec
# This module exists to intercept the method_missing *class* method on RSpec::Core::ExampleGroup
# and is part of support for DSL plugintypes
module DescribeDslLazyLoader
# Support for Describe DSL plugins
def method_missing(method_name, *arguments, &block)
begin
backend = metadata[:backend] # populated via Inspec::Runner#add_resource
resource = Inspec::DSL.method_missing_resource(backend, method_name, *arguments)
return resource if resource
rescue LoadError
# pass through
end
# Check to see if there is a describe_dsl plugin activator hook with the method name
registry = Inspec::Plugin::V2::Registry.instance
hook = registry.find_activators(plugin_type: :describe_dsl, activator_name: method_name).first
if hook
# OK, load the hook if it hasn't been already. We'll then know a module,
# which we can then inject into the context
hook.activate
# Inject the module's methods into the example group contexts.
# implementation_class is the field name, but this is actually a module.
# RSpec works by having these helper methods defined as class methods
# (see the definition of `let` as an example)
# So, we use extend to inject the new DSL methods.
RSpec::Core::ExampleGroup.extend(hook.implementation_class)
# We still haven't called the method we were looking for, so do so now.
send(method_name, *arguments, &block)
else
super
end
end
end
# This module exists to intercept the method_missing *instance* method on RSpec::Core::ExampleGroup
# and is part of support for DSL plugintypes
module TestDslLazyLoader
# Support for test DSL plugins
def method_missing(method_name, *arguments, &block)
# see if it is a resource first
begin
backend = inspec if respond_to?(:inspec) # backend not available??
resource = Inspec::DSL.method_missing_resource(backend, method_name, *arguments)
return resource if resource
rescue LoadError
# pass through
end
# Check to see if there is a test_dsl plugin activator hook with the method name
registry = Inspec::Plugin::V2::Registry.instance
hook = registry.find_activators(plugin_type: :test_dsl, activator_name: method_name).first
if hook
# OK, load the hook if it hasn't been already. We'll then know a module,
# which we can then inject into the context
hook.activate
# Inject the module's methods into the example group contexts.
# implementation_class is the field name, but this is actually a module.
# RSpec works by having these helper methods defined as instance methods.
# So, we use include to inject the new DSL methods.
RSpec::Core::ExampleGroup.include(hook.implementation_class)
# We still haven't called the method we were looking for, so do so now.
send(method_name, *arguments, &block)
else
super
end
end
end
end
class RSpec::Core::ExampleGroup
include Inspec::InputDslHelpers
# This DSL method allows us to access the values of inputs within InSpec tests
def input(input_name, options = {})
profile_id = self.class.metadata[:profile_id]
input_with_profile_id(profile_id, input_name, options)
end
define_example_method :input
def input_object(name)
Inspec::InputRegistry.find_or_register_input(name, self.class.metadata[:profile_id])
end
define_example_method :input_object
def attribute(name, options = {})
Inspec.deprecate(:attrs_dsl, "Input name: #{name}, Profile: #{self.class.metadata[:profile_id]}")
input(name, options)
end
define_example_method :attribute
# Here, we have to ensure our method_missing gets called prior
# to RSpec::Core::ExampleGroup.method_missing (the class method).
# So, we use prepend.
# Because it is a class method we're attempting to prepend, we must
# prepend against the singleton class.
singleton_class.prepend Inspec::DescribeDslLazyLoader
# Here, we have to ensure our method_missing gets called prior
# to RSpec::Core::ExampleGroup#method_missing (the instance method).
# So, we use prepend.
prepend Inspec::TestDslLazyLoader
end
class ResourceInspector < RSpec::Support::ObjectFormatter::BaseInspector
def self.can_inspect?(object)
Inspec::Resource === object
end
def inspect # do NOT use default inspect in rspec w/ resources
object.to_s
end
end
RSpec::Support::ObjectFormatter::INSPECTOR_CLASSES.unshift ResourceInspector