diff --git a/.rubocop.yml b/.rubocop.yml index c0892d8a..27efc39a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -46,6 +46,9 @@ Naming/MethodParameterName: Naming/RescuedExceptionsVariableName: PreferredName: error +Style/CaseEquality: + Enabled: false + Style/ExplicitBlockArgument: Enabled: false diff --git a/Rakefile b/Rakefile index 6de81bd8..4973d45e 100644 --- a/Rakefile +++ b/Rakefile @@ -7,13 +7,7 @@ require "syntax_tree/rake_tasks" Rake::TestTask.new(:test) do |t| t.libs << "test" t.libs << "lib" - test_files = FileList["test/**/*_test.rb"] - if RUBY_ENGINE == "truffleruby" - # language_server.rb uses pattern matching - test_files -= FileList["test/language_server/*_test.rb"] - test_files -= FileList["test/language_server_test.rb"] - end - t.test_files = test_files + t.test_files = FileList["test/**/*_test.rb"] end task default: :test diff --git a/lib/syntax_tree/cli.rb b/lib/syntax_tree/cli.rb index 518b58a6..62e8ab68 100644 --- a/lib/syntax_tree/cli.rb +++ b/lib/syntax_tree/cli.rb @@ -193,8 +193,8 @@ def run(item) class Expr < Action def run(item) program = item.handler.parse(item.source) - if Program === program and expressions = program.statements.body and - expressions.size == 1 + + if (expressions = program.statements.body) && expressions.size == 1 puts expressions.first.construct_keys else warn("The input to `stree expr` must be a single expression.") diff --git a/lib/syntax_tree/language_server.rb b/lib/syntax_tree/language_server.rb index d2714b5c..c2265c32 100644 --- a/lib/syntax_tree/language_server.rb +++ b/lib/syntax_tree/language_server.rb @@ -13,6 +13,50 @@ module SyntaxTree # stree lsp # class LanguageServer + # This is a small module that effectively mirrors pattern matching. We're + # using it so that we can support truffleruby without having to ignore the + # language server. + module Request + # Represents a hash pattern. + class Shape + attr_reader :values + + def initialize(values) + @values = values + end + + def ===(other) + values.all? do |key, value| + value == :any ? other.key?(key) : value === other[key] + end + end + end + + # Represents an array pattern. + class Tuple + attr_reader :values + + def initialize(values) + @values = values + end + + def ===(other) + values.each_with_index.all? { |value, index| value === other[index] } + end + end + + def self.[](value) + case value + when Array + Tuple.new(value.map { |child| self[child] }) + when Hash + Shape.new(value.transform_values { |child| self[child] }) + else + value + end + end + end + attr_reader :input, :output, :print_width def initialize( @@ -39,30 +83,33 @@ def run # stree-ignore case request - in { method: "initialize", id: } + when Request[method: "initialize", id: :any] store.clear - write(id: id, result: { capabilities: capabilities }) - in { method: "initialized" } + write(id: request[:id], result: { capabilities: capabilities }) + when Request[method: "initialized"] # ignored - in { method: "shutdown" } # tolerate missing ID to be a good citizen + when Request[method: "shutdown"] # tolerate missing ID to be a good citizen store.clear write(id: request[:id], result: {}) return - in { method: "textDocument/didChange", params: { textDocument: { uri: }, contentChanges: [{ text: }, *] } } - store[uri] = text - in { method: "textDocument/didOpen", params: { textDocument: { uri:, text: } } } - store[uri] = text - in { method: "textDocument/didClose", params: { textDocument: { uri: } } } - store.delete(uri) - in { method: "textDocument/formatting", id:, params: { textDocument: { uri: } } } + when Request[method: "textDocument/didChange", params: { textDocument: { uri: :any }, contentChanges: [{ text: :any }] }] + store[request.dig(:params, :textDocument, :uri)] = request.dig(:params, :contentChanges, 0, :text) + when Request[method: "textDocument/didOpen", params: { textDocument: { uri: :any, text: :any } }] + store[request.dig(:params, :textDocument, :uri)] = request.dig(:params, :textDocument, :text) + when Request[method: "textDocument/didClose", params: { textDocument: { uri: :any } }] + store.delete(request.dig(:params, :textDocument, :uri)) + when Request[method: "textDocument/formatting", id: :any, params: { textDocument: { uri: :any } }] + uri = request.dig(:params, :textDocument, :uri) contents = store[uri] - write(id: id, result: contents ? format(contents, uri.split(".").last) : nil) - in { method: "textDocument/inlayHint", id:, params: { textDocument: { uri: } } } + write(id: request[:id], result: contents ? format(contents, uri.split(".").last) : nil) + when Request[method: "textDocument/inlayHint", id: :any, params: { textDocument: { uri: :any } }] + uri = request.dig(:params, :textDocument, :uri) contents = store[uri] - write(id: id, result: contents ? inlay_hints(contents) : nil) - in { method: "syntaxTree/visualizing", id:, params: { textDocument: { uri: } } } - write(id: id, result: PP.pp(SyntaxTree.parse(store[uri]), +"")) - in { method: %r{\$/.+} } + write(id: request[:id], result: contents ? inlay_hints(contents) : nil) + when Request[method: "syntaxTree/visualizing", id: :any, params: { textDocument: { uri: :any } }] + uri = request.dig(:params, :textDocument, :uri) + write(id: request[:id], result: PP.pp(SyntaxTree.parse(store[uri]), +"")) + when Request[method: %r{\$/.+}] # ignored else raise ArgumentError, "Unhandled: #{request}" diff --git a/lib/syntax_tree/language_server/inlay_hints.rb b/lib/syntax_tree/language_server/inlay_hints.rb index 12c10230..dfd63b8d 100644 --- a/lib/syntax_tree/language_server/inlay_hints.rb +++ b/lib/syntax_tree/language_server/inlay_hints.rb @@ -69,11 +69,10 @@ def visit_assign(node) # def visit_binary(node) case stack[-2] - in Assign | OpAssign + when Assign, OpAssign parentheses(node.location) - in Binary[operator: operator] if operator != node.operator - parentheses(node.location) - else + when Binary + parentheses(node.location) if stack[-2].operator != node.operator end super @@ -91,9 +90,8 @@ def visit_binary(node) # def visit_if_op(node) case stack[-2] - in Assign | Binary | IfOp | OpAssign + when Assign, Binary, IfOp, OpAssign parentheses(node.location) - else end super diff --git a/lib/syntax_tree/pattern.rb b/lib/syntax_tree/pattern.rb index c612c4ea..439d573f 100644 --- a/lib/syntax_tree/pattern.rb +++ b/lib/syntax_tree/pattern.rb @@ -75,103 +75,212 @@ def compile private + # Shortcut for combining two procs into one that returns true if both return + # true. def combine_and(left, right) - ->(node) { left.call(node) && right.call(node) } + ->(other) { left.call(other) && right.call(other) } end + # Shortcut for combining two procs into one that returns true if either + # returns true. def combine_or(left, right) - ->(node) { left.call(node) || right.call(node) } + ->(other) { left.call(other) || right.call(other) } end - def compile_node(root) - if AryPtn === root and root.rest.nil? and root.posts.empty? - constant = root.constant - compiled_constant = compile_node(constant) if constant + # Raise an error because the given node is not supported. + def compile_error(node) + raise CompilationError, PP.pp(node, +"").chomp + end - preprocessed = root.requireds.map { |required| compile_node(required) } + # There are a couple of nodes (string literals, dynamic symbols, and regexp) + # that contain list of parts. This can include plain string content, + # interpolated expressions, and interpolated variables. We only support + # plain string content, so this method will extract out the plain string + # content if it is the only element in the list. + def extract_string(node) + parts = node.parts - compiled_requireds = ->(node) do - deconstructed = node.deconstruct + if parts.length == 1 && (part = parts.first) && part.is_a?(TStringContent) + part.value + end + end - deconstructed.length == preprocessed.length && - preprocessed - .zip(deconstructed) - .all? { |(matcher, value)| matcher.call(value) } - end + # in [foo, bar, baz] + def compile_aryptn(node) + compile_error(node) if !node.rest.nil? || node.posts.any? - if compiled_constant - combine_and(compiled_constant, compiled_requireds) - else - compiled_requireds - end - elsif Binary === root and root.operator == :| - combine_or(compile_node(root.left), compile_node(root.right)) - elsif Const === root and SyntaxTree.const_defined?(root.value) - clazz = SyntaxTree.const_get(root.value) - - ->(node) { node.is_a?(clazz) } - elsif Const === root and Object.const_defined?(root.value) - clazz = Object.const_get(root.value) - - ->(node) { node.is_a?(clazz) } - elsif ConstPathRef === root and VarRef === root.parent and - Const === root.parent.value and - root.parent.value.value == "SyntaxTree" - compile_node(root.constant) - elsif DynaSymbol === root and root.parts.empty? + constant = node.constant + compiled_constant = compile_node(constant) if constant + + preprocessed = node.requireds.map { |required| compile_node(required) } + + compiled_requireds = ->(other) do + deconstructed = other.deconstruct + + deconstructed.length == preprocessed.length && + preprocessed + .zip(deconstructed) + .all? { |(matcher, value)| matcher.call(value) } + end + + if compiled_constant + combine_and(compiled_constant, compiled_requireds) + else + compiled_requireds + end + end + + # in foo | bar + def compile_binary(node) + compile_error(node) if node.operator != :| + + combine_or(compile_node(node.left), compile_node(node.right)) + end + + # in Ident + # in String + def compile_const(node) + value = node.value + + if SyntaxTree.const_defined?(value) + clazz = SyntaxTree.const_get(value) + + ->(other) { clazz === other } + elsif Object.const_defined?(value) + clazz = Object.const_get(value) + + ->(other) { clazz === other } + else + compile_error(node) + end + end + + # in SyntaxTree::Ident + def compile_const_path_ref(node) + parent = node.parent + compile_error(node) if !parent.is_a?(VarRef) || !parent.value.is_a?(Const) + + if parent.value.value == "SyntaxTree" + compile_node(node.constant) + else + compile_error(node) + end + end + + # in :"" + # in :"foo" + def compile_dyna_symbol(node) + if node.parts.empty? symbol = :"" - ->(node) { node == symbol } - elsif DynaSymbol === root and parts = root.parts and parts.size == 1 and - TStringContent === parts[0] - symbol = parts[0].value.to_sym - - ->(node) { node == symbol } - elsif HshPtn === root and root.keyword_rest.nil? - compiled_constant = compile_node(root.constant) - - preprocessed = - root.keywords.to_h do |keyword, value| - unless keyword.is_a?(Label) - raise CompilationError, PP.pp(root, +"").chomp - end - [keyword.value.chomp(":").to_sym, compile_node(value)] - end - - compiled_keywords = ->(node) do - deconstructed = node.deconstruct_keys(preprocessed.keys) - - preprocessed.all? do |keyword, matcher| - matcher.call(deconstructed[keyword]) - end + ->(other) { symbol === other } + elsif (value = extract_string(node)) + symbol = value.to_sym + + ->(other) { symbol === other } + else + compile_error(root) + end + end + + # in Ident[value: String] + # in { value: String } + def compile_hshptn(node) + compile_error(node) unless node.keyword_rest.nil? + compiled_constant = compile_node(node.constant) if node.constant + + preprocessed = + node.keywords.to_h do |keyword, value| + compile_error(node) unless keyword.is_a?(Label) + [keyword.value.chomp(":").to_sym, compile_node(value)] end - if compiled_constant - combine_and(compiled_constant, compiled_keywords) - else - compiled_keywords + compiled_keywords = ->(other) do + deconstructed = other.deconstruct_keys(preprocessed.keys) + + preprocessed.all? do |keyword, matcher| + matcher.call(deconstructed[keyword]) end - elsif RegexpLiteral === root and parts = root.parts and - parts.size == 1 and TStringContent === parts[0] - regexp = /#{parts[0].value}/ - - ->(attribute) { regexp.match?(attribute) } - elsif StringLiteral === root and root.parts.empty? - ->(attribute) { attribute == "" } - elsif StringLiteral === root and parts = root.parts and - parts.size == 1 and TStringContent === parts[0] - value = parts[0].value - ->(attribute) { attribute == value } - elsif SymbolLiteral === root - symbol = root.value.value.to_sym - - ->(attribute) { attribute == symbol } - elsif VarRef === root and Const === root.value - compile_node(root.value) - elsif VarRef === root and Kw === root.value and root.value.value.nil? - ->(attribute) { attribute.nil? } + end + + if compiled_constant + combine_and(compiled_constant, compiled_keywords) + else + compiled_keywords + end + end + + # in /foo/ + def compile_regexp_literal(node) + if (value = extract_string(node)) + regexp = /#{value}/ + + ->(attribute) { regexp === attribute } + else + compile_error(node) + end + end + + # in "" + # in "foo" + def compile_string_literal(node) + if node.parts.empty? + ->(attribute) { "" === attribute } + elsif (value = extract_string(node)) + ->(attribute) { value === attribute } + else + compile_error(node) + end + end + + # in :+ + # in :foo + def compile_symbol_literal(node) + symbol = node.value.value.to_sym + + ->(attribute) { symbol === attribute } + end + + # in Foo + # in nil + def compile_var_ref(node) + value = node.value + + if value.is_a?(Const) + compile_node(value) + elsif value.is_a?(Kw) && value.value.nil? + ->(attribute) { nil === attribute } + else + compile_error(node) + end + end + + # Compile any kind of node. Dispatch out to the individual compilation + # methods based on the type of node. + def compile_node(node) + case node + when AryPtn + compile_aryptn(node) + when Binary + compile_binary(node) + when Const + compile_const(node) + when ConstPathRef + compile_const_path_ref(node) + when DynaSymbol + compile_dyna_symbol(node) + when HshPtn + compile_hshptn(node) + when RegexpLiteral + compile_regexp_literal(node) + when StringLiteral + compile_string_literal(node) + when SymbolLiteral + compile_symbol_literal(node) + when VarRef + compile_var_ref(node) else - raise CompilationError, PP.pp(root, +"").chomp + compile_error(node) end end end diff --git a/lib/syntax_tree/rake/task.rb b/lib/syntax_tree/rake/task.rb index ea228e8f..e9a20433 100644 --- a/lib/syntax_tree/rake/task.rb +++ b/lib/syntax_tree/rake/task.rb @@ -78,7 +78,7 @@ def run_task arguments << "--ignore-files=#{ignore_files}" if ignore_files != "" - SyntaxTree::CLI.run(arguments + Array(source_files)) + abort if SyntaxTree::CLI.run(arguments + Array(source_files)) != 0 end end end diff --git a/test/cli_test.rb b/test/cli_test.rb index b5316d7f..c00fb338 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -173,7 +173,6 @@ def test_plugins def test_language_server prev_stdin = $stdin prev_stdout = $stdout - skip unless SUPPORTS_PATTERN_MATCHING request = { method: "shutdown" }.merge(jsonrpc: "2.0").to_json $stdin = diff --git a/test/idempotency_test.rb b/test/idempotency_test.rb index 76116572..32d9d196 100644 --- a/test/idempotency_test.rb +++ b/test/idempotency_test.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -return unless ENV["CI"] and RUBY_ENGINE != "truffleruby" +return if !ENV["CI"] || RUBY_ENGINE == "truffleruby" require_relative "test_helper" module SyntaxTree diff --git a/test/language_server_test.rb b/test/language_server_test.rb index 466bf737..8e1ed9a7 100644 --- a/test/language_server_test.rb +++ b/test/language_server_test.rb @@ -4,6 +4,7 @@ require "syntax_tree/language_server" module SyntaxTree + # stree-ignore class LanguageServerTest < Minitest::Test class Initialize < Struct.new(:id) def to_hash @@ -21,12 +22,7 @@ class TextDocumentDidOpen < Struct.new(:uri, :text) def to_hash { method: "textDocument/didOpen", - params: { - textDocument: { - uri: uri, - text: text - } - } + params: { textDocument: { uri: uri, text: text } } } end end @@ -36,9 +32,7 @@ def to_hash { method: "textDocument/didChange", params: { - textDocument: { - uri: uri - }, + textDocument: { uri: uri }, contentChanges: [{ text: text }] } } @@ -49,11 +43,7 @@ class TextDocumentDidClose < Struct.new(:uri) def to_hash { method: "textDocument/didClose", - params: { - textDocument: { - uri: uri - } - } + params: { textDocument: { uri: uri } } } end end @@ -63,11 +53,7 @@ def to_hash { method: "textDocument/formatting", id: id, - params: { - textDocument: { - uri: uri - } - } + params: { textDocument: { uri: uri } } } end end @@ -77,11 +63,7 @@ def to_hash { method: "textDocument/inlayHint", id: id, - params: { - textDocument: { - uri: uri - } - } + params: { textDocument: { uri: uri } } } end end @@ -91,75 +73,71 @@ def to_hash { method: "syntaxTree/visualizing", id: id, - params: { - textDocument: { - uri: uri - } - } + params: { textDocument: { uri: uri } } } end end def test_formatting - messages = [ + responses = run_server([ Initialize.new(1), TextDocumentDidOpen.new("file:///path/to/file.rb", "class Foo; end"), TextDocumentDidChange.new("file:///path/to/file.rb", "class Bar; end"), TextDocumentFormatting.new(2, "file:///path/to/file.rb"), TextDocumentDidClose.new("file:///path/to/file.rb"), Shutdown.new(3) - ] - - case run_server(messages) - in [ - { id: 1, result: { capabilities: Hash } }, - { id: 2, result: [{ newText: new_text }] }, - { id: 3, result: {} } - ] - assert_equal("class Bar\nend\n", new_text) - end + ]) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: [{ newText: :any }] }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) + assert_equal("class Bar\nend\n", responses.dig(1, :result, 0, :newText)) end def test_formatting_failure - messages = [ + responses = run_server([ Initialize.new(1), TextDocumentDidOpen.new("file:///path/to/file.rb", "<>"), TextDocumentFormatting.new(2, "file:///path/to/file.rb"), Shutdown.new(3) - ] - - case run_server(messages) - in [ - { id: 1, result: { capabilities: Hash } }, - { id: 2, result: }, - { id: 3, result: {} } - ] - assert_nil(result) - end + ]) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: :any }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) + assert_nil(responses.dig(1, :result)) end def test_formatting_print_width contents = "#{"a" * 40} + #{"b" * 40}\n" - messages = [ + responses = run_server([ Initialize.new(1), TextDocumentDidOpen.new("file:///path/to/file.rb", contents), TextDocumentFormatting.new(2, "file:///path/to/file.rb"), TextDocumentDidClose.new("file:///path/to/file.rb"), Shutdown.new(3) - ] - - case run_server(messages, print_width: 100) - in [ - { id: 1, result: { capabilities: Hash } }, - { id: 2, result: [{ newText: new_text }] }, - { id: 3, result: {} } - ] - assert_equal(contents, new_text) - end + ], print_width: 100) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: [{ newText: :any }] }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) + assert_equal(contents, responses.dig(1, :result, 0, :newText)) end def test_inlay_hint - messages = [ + responses = run_server([ Initialize.new(1), TextDocumentDidOpen.new("file:///path/to/file.rb", <<~RUBY), begin @@ -169,37 +147,37 @@ def test_inlay_hint RUBY TextDocumentInlayHint.new(2, "file:///path/to/file.rb"), Shutdown.new(3) - ] - - case run_server(messages) - in [ - { id: 1, result: { capabilities: Hash } }, - { id: 2, result: hints }, - { id: 3, result: {} } - ] - assert_equal(3, hints.length) - end + ]) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: :any }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) + assert_equal(3, responses.dig(1, :result).size) end def test_visualizing - messages = [ + responses = run_server([ Initialize.new(1), TextDocumentDidOpen.new("file:///path/to/file.rb", "1 + 2"), SyntaxTreeVisualizing.new(2, "file:///path/to/file.rb"), Shutdown.new(3) - ] - - case run_server(messages) - in [ - { id: 1, result: { capabilities: Hash } }, - { id: 2, result: }, - { id: 3, result: {} } - ] - assert_equal( - "(program (statements ((binary (int \"1\") + (int \"2\")))))\n", - result - ) - end + ]) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: :any }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) + assert_equal( + "(program (statements ((binary (int \"1\") + (int \"2\")))))\n", + responses.dig(1, :result) + ) end def test_reading_file @@ -207,20 +185,20 @@ def test_reading_file file.write("class Foo; end") file.rewind - messages = [ + responses = run_server([ Initialize.new(1), TextDocumentFormatting.new(2, "file://#{file.path}"), Shutdown.new(3) - ] - - case run_server(messages) - in [ - { id: 1, result: { capabilities: Hash } }, - { id: 2, result: [{ newText: new_text }] }, - { id: 3, result: {} } - ] - assert_equal("class Foo\nend\n", new_text) - end + ]) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: [{ newText: :any }] }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) + assert_equal("class Foo\nend\n", responses.dig(1, :result, 0, :newText)) end end @@ -231,29 +209,30 @@ def test_bogus_request end def test_clean_shutdown - messages = [Initialize.new(1), Shutdown.new(2)] + responses = run_server([Initialize.new(1), Shutdown.new(2)]) - case run_server(messages) - in [{ id: 1, result: { capabilities: Hash } }, { id: 2, result: {} }] - assert_equal(true, true) - end + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: {} } + ]] + + assert_operator(shape, :===, responses) end def test_file_that_does_not_exist - messages = [ + responses = run_server([ Initialize.new(1), TextDocumentFormatting.new(2, "file:///path/to/file.rb"), Shutdown.new(3) - ] - - case run_server(messages) - in [ - { id: 1, result: { capabilities: Hash } }, - { id: 2, result: nil }, - { id: 3, result: {} } - ] - assert_equal(true, true) - end + ]) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: :any }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) end private @@ -281,6 +260,7 @@ def run_server(messages, print_width: DEFAULT_PRINT_WIDTH) output: output, print_width: print_width ).run + read(output.tap(&:rewind)) end end diff --git a/test/rake_test.rb b/test/rake_test.rb index 57364859..bd315cc6 100644 --- a/test/rake_test.rb +++ b/test/rake_test.rb @@ -6,30 +6,36 @@ module SyntaxTree module Rake class CheckTaskTest < Minitest::Test - Invoke = Struct.new(:args) + Invocation = Struct.new(:args) def test_check_task source_files = "{app,config,lib}/**/*.rb" CheckTask.new { |t| t.source_files = source_files } - invoke = nil - SyntaxTree::CLI.stub(:run, ->(args) { invoke = Invoke.new(args) }) do - ::Rake::Task["stree:check"].invoke - end - - assert_equal(["check", source_files], invoke.args) + invocation = invoke("stree:check") + assert_equal(["check", source_files], invocation.args) end def test_write_task source_files = "{app,config,lib}/**/*.rb" WriteTask.new { |t| t.source_files = source_files } - invoke = nil - SyntaxTree::CLI.stub(:run, ->(args) { invoke = Invoke.new(args) }) do - ::Rake::Task["stree:write"].invoke - end + invocation = invoke("stree:write") + assert_equal(["write", source_files], invocation.args) + end - assert_equal(["write", source_files], invoke.args) + private + + def invoke(task_name) + invocation = nil + stub = ->(args) { invocation = Invocation.new(args) } + + begin + SyntaxTree::CLI.stub(:run, stub) { ::Rake::Task[task_name].invoke } + flunk + rescue SystemExit + invocation + end end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index c421d8ee..c46022ae 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -17,8 +17,6 @@ require "pp" require "minitest/autorun" -SUPPORTS_PATTERN_MATCHING = RUBY_ENGINE != "truffleruby" - module SyntaxTree module Assertions class Recorder @@ -69,7 +67,7 @@ def assert_syntax_tree(node) refute_includes(json, "#<") assert_equal(type, JSON.parse(json)["type"]) - if SUPPORTS_PATTERN_MATCHING + if RUBY_ENGINE != "truffleruby" # Get a match expression from the node, then assert that it can in fact # match the node. # rubocop:disable all