mirror of
https://github.com/inspec/inspec
synced 2025-03-04 07:17:24 +00:00
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>
128 lines
4.8 KiB
Ruby
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
|