Skip to content

Commit

Permalink
Merge pull request #407 from rspec/kwargs-class-exec
Browse files Browse the repository at this point in the history
Add helper for running class_exec with keywords when needed
  • Loading branch information
JonRowe committed May 2, 2020
1 parent fc45672 commit ca5db55
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
33 changes: 33 additions & 0 deletions lib/rspec/support/with_keywords_when_needed.rb
@@ -0,0 +1,33 @@
RSpec::Support.require_rspec_support("method_signature_verifier")

module RSpec
module Support
module WithKeywordsWhenNeeded
# This module adds keyword sensitive support for core ruby methods
# where we cannot use `ruby2_keywords` directly.

module_function

if RSpec::Support::RubyFeatures.kw_args_supported?
# Remove this in RSpec 4 in favour of explictly passed in kwargs where
# this is used. Works around a warning in Ruby 2.7

def class_exec(klass, *args, &block)
if MethodSignature.new(block).has_kw_args_in?(args)
binding.eval(<<-CODE, __FILE__, __LINE__)
kwargs = args.pop
klass.class_exec(*args, **kwargs, &block)
CODE
else
klass.class_exec(*args, &block)
end
end
ruby2_keywords :class_exec if respond_to?(:ruby2_keywords, true)
else
def class_exec(klass, *args, &block)
klass.class_exec(*args, &block)
end
end
end
end
end
48 changes: 48 additions & 0 deletions spec/rspec/support/with_keywords_when_needed_spec.rb
@@ -0,0 +1,48 @@
require 'rspec/support/with_keywords_when_needed'

module RSpec::Support
RSpec.describe "WithKeywordsWhenNeeded" do

describe ".class_exec" do
extend RubyFeatures

let(:klass) do
Class.new do
def self.check_argument(argument)
raise ArgumentError unless argument == 42
end
end
end

def run(klass, *args, &block)
WithKeywordsWhenNeeded.class_exec(klass, *args, &block)
end

it "will run a block without keyword arguments" do
run(klass, 42) { |arg| check_argument(arg) }
end

it "will run a block with a hash with out keyword arguments" do
run(klass, "value" => 42) { |arg| check_argument(arg["value"]) }
end

it "will run a block with optional keyword arguments when none are provided", :if => kw_args_supported? do
binding.eval(<<-CODE, __FILE__, __LINE__)
run(klass, 42) { |arg, val: nil| check_argument(arg) }
CODE
end

it "will run a block with optional keyword arguments when they are provided", :if => required_kw_args_supported? do
binding.eval(<<-CODE, __FILE__, __LINE__)
run(klass, val: 42) { |val: nil| check_argument(val) }
CODE
end

it "will run a block with required keyword arguments", :if => required_kw_args_supported? do
binding.eval(<<-CODE, __FILE__, __LINE__)
run(klass, val: 42) { |val:| check_argument(val) }
CODE
end
end
end
end

0 comments on commit ca5db55

Please sign in to comment.