Skip to content

Commit

Permalink
Make it possible to include/prepend shared modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Jul 22, 2024
1 parent be47581 commit 239d645
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 30 deletions.
46 changes: 31 additions & 15 deletions lib/sus/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,38 +76,54 @@ def each(&block)
end
end

def before(&block)
# Include an around method to the context class, that invokes the given block before running the test.
#
# Before hooks are called in the reverse order they are defined, in other words the last defined before hook is called first.
#
# @parameter hook [Proc] The block to execute before each test.
def before(&hook)
wrapper = Module.new

wrapper.define_method(:before) do
super()
instance_exec(&block)
wrapper.define_method(:around) do |&block|
instance_exec(&hook)
super(&block)
end

self.include(wrapper)
end

def after(&block)
# Include an around method to the context class, that invokes the given block after running the test.
#
# After hooks are called in the order they are defined, in other words the last defined after hook is called last.
#
# @parameter hook [Proc] The block to execute after each test. An `error` argument is passed if the test failed with an exception.
def after(&hook)
wrapper = Module.new

wrapper.define_method(:after) do
instance_exec(&block)
super()
wrapper.define_method(:around) do |&block|
error = nil

super(&block)
rescue => error
raise
ensure
instance_exec(error, &hook)
end

self.include(wrapper)
end

# Add an around hook to the context class.
#
# Around hooks are called in the reverse order they are defined.
#
# The top level `around` implementation invokes before and after hooks.
#
# @paremeter block [Proc] The block to execute around each test.
def around(&block)
wrapper = Module.new

wrapper.define_method(:around) do
call_super = proc do
super()
end

instance_exec(call_super, &block)
end
wrapper.define_method(:around, &block)

self.include(wrapper)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/sus/include_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

module Sus
module Context
def include_context(shared, ...)
shared.included(self, ...)
def include_context(shared, *arguments, **options)
self.class_exec(*arguments, **options, &shared.block)
end
end
end
10 changes: 7 additions & 3 deletions lib/sus/shared.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@ module Shared
attr_accessor :block

def self.build(name, block)
base = Class.new
base = Module.new
base.extend(Shared)
base.name = name
base.block = block

return base
end

def included(base, *arguments, **options)
base.class_exec(*arguments, **options, &self.block)
def included(base)
base.class_exec(&self.block)
end

def prepended(base)
base.class_exec(&self.block)
end
end

Expand Down
28 changes: 18 additions & 10 deletions test/sus/include_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,46 @@
# Released under the MIT License.
# Copyright, 2023, by Samuel Williams.

AThing = Sus::Shared("a thing") do |key, value: 42|
AContextWithArguments = Sus::Shared("a context with arguments") do |key, value: 42|
let(:a_thing) {{key => value}}

end

AContextWithHooks = Sus::Shared("a context with hooks") do
before do
$stderr.puts "before: #{self}"
events << :shared_before
end

after do
$stderr.puts "after: #{self}"
events << :shared_after
end

around do |block|
$stderr.puts "around: #{self}"
block.call
around do |&block|
events << :shared_around_before
super(&block)
end
end

describe Sus::Context do
with '.include_context' do
with "a shared context with an option" do
include_context AContextWithArguments, :key, value: 42

it "can include a shared context with arguments" do
expect(a_thing).to be == {:key => 42}
end
end

with "a shared context with arguments" do
let(:events) {Array.new}
include_context AThing, :key, value: 42

include AContextWithHooks

before do
events << :example_before
end

it "can include a shared context" do
expect(a_thing).to be == {:key => 42}
expect(events).to be == [:shared_before, :example_before]
expect(events).to be == [:example_before, :shared_around_before, :shared_before]
end
end
end
Expand Down

0 comments on commit 239d645

Please sign in to comment.