Skip to content

Support Ruby 2.7.0 #148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
fail-fast: false
matrix:
ruby:
- '2.7'
- '2.7.0'
- '3.0'
- '3.1'
- head
Expand Down
17 changes: 13 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,17 @@ end

task default: :test

SOURCE_FILES =
FileList[%w[Gemfile Rakefile syntax_tree.gemspec lib/**/*.rb test/*.rb]]
configure = ->(task) do
task.source_files =
FileList[%w[Gemfile Rakefile syntax_tree.gemspec lib/**/*.rb test/*.rb]]

SyntaxTree::Rake::CheckTask.new { |t| t.source_files = SOURCE_FILES }
SyntaxTree::Rake::WriteTask.new { |t| t.source_files = SOURCE_FILES }
# Since Syntax Tree supports back to Ruby 2.7.0, we need to make sure that we
# format our code such that it's compatible with that version. This actually
# has very little effect on the output, the only change at the moment is that
# Ruby < 2.7.3 didn't allow a newline before the closing brace of a hash
# pattern.
task.target_ruby_version = Gem::Version.new("2.7.0")
end

SyntaxTree::Rake::CheckTask.new(&configure)
SyntaxTree::Rake::WriteTask.new(&configure)
35 changes: 22 additions & 13 deletions lib/syntax_tree/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@ def source
end
end

# An item of work that corresponds to a script content passed via the command line.
# An item of work that corresponds to a script content passed via the
# command line.
class ScriptItem
FILEPATH = :script

attr_reader :source

def initialize(source)
@source = source
end
Expand All @@ -68,10 +71,6 @@ def handler
def filepath
FILEPATH
end

def source
@source
end
end

# The parent action class for the CLI that implements the basics.
Expand Down Expand Up @@ -197,7 +196,7 @@ def run(item)

source = item.source
formatted = item.handler.format(source, options.print_width)
File.write(filepath, formatted) if FileItem === item
File.write(filepath, formatted) if item.filepath != :script

color = source == formatted ? Color.gray(filepath) : filepath
delta = ((Time.now - start) * 1000).round
Expand Down Expand Up @@ -259,13 +258,19 @@ def run(item)
# responsible for parsing the list and then returning the file paths at the
# end.
class Options
attr_reader :print_width, :scripts
attr_reader :plugins, :print_width, :scripts, :target_ruby_version

def initialize(print_width: DEFAULT_PRINT_WIDTH)
@plugins = []
@print_width = print_width
@scripts = []
@target_ruby_version = nil
end

# TODO: This function causes a couple of side-effects that I really don't
# like to have here. It mutates the global state by requiring the plugins,
# and mutates the global options hash by adding the target ruby version.
# That should be done on a config-by-config basis, not here.
def parse(arguments)
parser.parse!(arguments)
end
Expand All @@ -285,7 +290,8 @@ def parser
# require "syntax_tree/haml"
#
opts.on("--plugins=PLUGINS") do |plugins|
plugins.split(",").each { |plugin| require "syntax_tree/#{plugin}" }
@plugins = plugins.split(",")
@plugins.each { |plugin| require "syntax_tree/#{plugin}" }
end

# If there is a print width specified on the command line, then
Expand All @@ -296,8 +302,13 @@ def parser

# If there is a script specified on the command line, then parse
# it and add it to the list of scripts to run.
opts.on("-e SCRIPT") do |script|
@scripts << script
opts.on("-e SCRIPT") { |script| @scripts << script }

# If there is a target ruby version specified on the command line,
# parse that out and use it when formatting.
opts.on("--target-ruby-version=VERSION") do |version|
@target_ruby_version = Gem::Version.new(version)
Formatter::OPTIONS[:target_ruby_version] = @target_ruby_version
end
end
end
Expand Down Expand Up @@ -395,9 +406,7 @@ def run(argv)
queue << FileItem.new(filepath) if File.file?(filepath)
end
end
options.scripts.each do |script|
queue << ScriptItem.new(script)
end
options.scripts.each { |script| queue << ScriptItem.new(script) }
else
queue << ScriptItem.new($stdin.read)
end
Expand Down
12 changes: 9 additions & 3 deletions lib/syntax_tree/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ class Formatter < PrettierPrint
# Note that we're keeping this in a global-ish hash instead of just
# overriding methods on classes so that other plugins can reference this if
# necessary. For example, the RBS plugin references the quote style.
OPTIONS = { quote: "\"", trailing_comma: false }
OPTIONS = {
quote: "\"",
trailing_comma: false,
target_ruby_version: Gem::Version.new(RUBY_VERSION)
}

COMMENT_PRIORITY = 1
HEREDOC_PRIORITY = 2
Expand All @@ -23,14 +27,15 @@ class Formatter < PrettierPrint

# These options are overridden in plugins to we need to make sure they are
# available here.
attr_reader :quote, :trailing_comma
attr_reader :quote, :trailing_comma, :target_ruby_version
alias trailing_comma? trailing_comma

def initialize(
source,
*args,
quote: OPTIONS[:quote],
trailing_comma: OPTIONS[:trailing_comma]
trailing_comma: OPTIONS[:trailing_comma],
target_ruby_version: OPTIONS[:target_ruby_version]
)
super(*args)

Expand All @@ -40,6 +45,7 @@ def initialize(
# Memoizing these values per formatter to make access faster.
@quote = quote
@trailing_comma = trailing_comma
@target_ruby_version = target_ruby_version
end

def self.format(source, node)
Expand Down
15 changes: 9 additions & 6 deletions lib/syntax_tree/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2132,8 +2132,7 @@ def format(q)
in [
Paren[
contents: {
body: [ArrayLiteral[contents: { parts: [_, _, *] }] => array]
}
body: [ArrayLiteral[contents: { parts: [_, _, *] }] => array] }
]
]
# Here we have a single argument that is a set of parentheses wrapping
Expand Down Expand Up @@ -5116,8 +5115,13 @@ def format(q)
q.breakable
contents.call
end
q.breakable
q.text("}")

if q.target_ruby_version < Gem::Version.new("2.7.3")
q.text(" }")
else
q.breakable
q.text("}")
end
end
end
end
Expand Down Expand Up @@ -5204,8 +5208,7 @@ def call(q, node)
false
in {
statements: { body: [truthy] },
consequent: Else[statements: { body: [falsy] }]
}
consequent: Else[statements: { body: [falsy] }] }
ternaryable?(truthy) && ternaryable?(falsy)
else
false
Expand Down
13 changes: 12 additions & 1 deletion lib/syntax_tree/rake/check_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,22 @@ class CheckTask < ::Rake::TaskLib
# Defaults to 80.
attr_accessor :print_width

# The target Ruby version to use for formatting.
# Defaults to Gem::Version.new(RUBY_VERSION).
attr_accessor :target_ruby_version

def initialize(
name = :"stree:check",
source_files = ::Rake::FileList["lib/**/*.rb"],
plugins = [],
print_width = DEFAULT_PRINT_WIDTH
print_width = DEFAULT_PRINT_WIDTH,
target_ruby_version = Gem::Version.new(RUBY_VERSION)
)
@name = name
@source_files = source_files
@plugins = plugins
@print_width = print_width
@target_ruby_version = target_ruby_version

yield self if block_given?
define_task
Expand All @@ -64,10 +70,15 @@ def define_task
def run_task
arguments = ["check"]
arguments << "--plugins=#{plugins.join(",")}" if plugins.any?

if print_width != DEFAULT_PRINT_WIDTH
arguments << "--print-width=#{print_width}"
end

if target_ruby_version != Gem::Version.new(RUBY_VERSION)
arguments << "--target-ruby-version=#{target_ruby_version}"
end

SyntaxTree::CLI.run(arguments + Array(source_files))
end
end
Expand Down
13 changes: 12 additions & 1 deletion lib/syntax_tree/rake/write_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,22 @@ class WriteTask < ::Rake::TaskLib
# Defaults to 80.
attr_accessor :print_width

# The target Ruby version to use for formatting.
# Defaults to Gem::Version.new(RUBY_VERSION).
attr_accessor :target_ruby_version

def initialize(
name = :"stree:write",
source_files = ::Rake::FileList["lib/**/*.rb"],
plugins = [],
print_width = DEFAULT_PRINT_WIDTH
print_width = DEFAULT_PRINT_WIDTH,
target_ruby_version = Gem::Version.new(RUBY_VERSION)
)
@name = name
@source_files = source_files
@plugins = plugins
@print_width = print_width
@target_ruby_version = target_ruby_version

yield self if block_given?
define_task
Expand All @@ -64,10 +70,15 @@ def define_task
def run_task
arguments = ["write"]
arguments << "--plugins=#{plugins.join(",")}" if plugins.any?

if print_width != DEFAULT_PRINT_WIDTH
arguments << "--print-width=#{print_width}"
end

if target_ruby_version != Gem::Version.new(RUBY_VERSION)
arguments << "--target-ruby-version=#{target_ruby_version}"
end

SyntaxTree::CLI.run(arguments + Array(source_files))
end
end
Expand Down
2 changes: 1 addition & 1 deletion syntax_tree.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
.reject { |f| f.match(%r{^(test|spec|features)/}) }
end

spec.required_ruby_version = ">= 2.7.3"
spec.required_ruby_version = ">= 2.7.0"

spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
Expand Down
4 changes: 2 additions & 2 deletions test/cli_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,12 @@ def test_no_arguments_no_tty
end

def test_inline_script
stdio, = capture_io { SyntaxTree::CLI.run(["format", "-e", "1+1"]) }
stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1]) }
assert_equal("1 + 1\n", stdio)
end

def test_multiple_inline_scripts
stdio, = capture_io { SyntaxTree::CLI.run(["format", "-e", "1+1", "-e", "2+2"]) }
stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1 -e 2+2]) }
assert_equal("1 + 1\n2 + 2\n", stdio)
end

Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/args_forward.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%
% # >= 2.7.3
def foo(...)
bar(:baz, ...)
end
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/hshptn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
case foo
in **bar
end
%
% # >= 2.7.3
case foo
in {
foo:, # comment1
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def foo(*)
%
def foo(*rest)
end
%
% # >= 2.7.3
def foo(...)
end
%
Expand Down
20 changes: 11 additions & 9 deletions test/node_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,18 @@ def test_arg_star
end
end

def test_args_forward
source = <<~SOURCE
def get(...)
request(:GET, ...)
end
SOURCE
guard_version("2.7.3") do
def test_args_forward
source = <<~SOURCE
def get(...)
request(:GET, ...)
end
SOURCE

at = location(lines: 2..2, chars: 29..32)
assert_node(ArgsForward, source, at: at) do |node|
node.bodystmt.statements.body.first.arguments.arguments.parts.last
at = location(lines: 2..2, chars: 29..32)
assert_node(ArgsForward, source, at: at) do |node|
node.bodystmt.statements.body.first.arguments.arguments.parts.last
end
end
end

Expand Down
2 changes: 1 addition & 1 deletion test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def initialize
@called = nil
end

def method_missing(called, ...)
def method_missing(called, *, **)
@called = called
end
end
Expand Down