Created
May 30, 2023 08:32
-
-
Save okuramasafumi/471b6f7ac05e161d10baa414fc95f828 to your computer and use it in GitHub Desktop.
RSpec documentation without executing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'syntax_tree' | |
class RSpecEnvironment | |
def initialize | |
@contexts = [] | |
@results = [] | |
end | |
def klass(k) | |
@contexts << k | |
end | |
def method(m) | |
@contexts << m | |
end | |
def context(c) | |
@contexts << c | |
end | |
alias describe context | |
def decontext | |
@contexts.pop | |
end | |
def it(i) | |
indendted_context = @contexts.map.with_index { |c, i| ' ' * i + c }.join("\n") | |
it_content = "#{' ' * @contexts.size}it #{i}" | |
@results << "#{indendted_context}\n#{it_content}" | |
end | |
def inspect | |
@results.join("\n") | |
end | |
end | |
class RSpecVisitor < SyntaxTree::Visitor | |
attr_reader :environment | |
def initialize | |
super | |
@environment = RSpecEnvironment.new | |
end | |
visit_methods do | |
def visit_command_call(node) | |
if node.receiver.child_nodes.first&.value == 'RSpec' && node.message.value == 'describe' | |
@environment.klass node.arguments.child_nodes.first.child_nodes.first.value | |
elsif node.receiver.message.value == 'expect' | |
subject = node.receiver.arguments.arguments.parts.first.value.value | |
predicate = node.arguments.parts.first.value.value | |
@environment.it "expect #{subject} to #{predicate}" | |
end | |
super | |
end | |
def visit_command(node) | |
name = node.child_nodes.first.value | |
if name == 'describe' || name == 'context' | |
str = node.arguments.child_nodes.first.parts.first.value | |
if str.start_with?('#') | |
@environment.method str | |
else | |
@environment.context str | |
end | |
elsif name == 'it' | |
str = node.arguments.child_nodes.first.parts.first.value | |
@environment.it str | |
end | |
super | |
if name == 'describe' || name == 'context' | |
@environment.decontext | |
end | |
end | |
end | |
end | |
visitor = RSpecVisitor.new | |
visitor.visit(SyntaxTree.parse(SyntaxTree.read('sample_spec.rb'))) | |
p visitor.environment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sample | |
#sample | |
with a context | |
it works | |
Sample | |
#sample | |
with a context | |
it expect true to be_truthy | |
Sample | |
#foo | |
some context | |
it expect true to be_truthy | |
Sample | |
#foo | |
outside context | |
inside context | |
it expect obj to be_falsey |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
RSpec.describe Sample do | |
describe '#sample' do | |
context 'with a context' do | |
subject { 'subject' } | |
let(:a) { 'a' } | |
let(:b) { 'b' } | |
it 'works' do | |
expect(true).to be_truthy | |
end | |
end | |
end | |
describe '#foo' do | |
subject { 1.abs } | |
context 'some context' do | |
subject { 'overridden subject' } | |
it do | |
expect(true).to be_truthy | |
end | |
end | |
context 'outside context' do | |
context 'inside context' do | |
let(:obj) { Object.new } | |
it do | |
expect(obj).to be_falsey | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment