Skip to content
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

Fix Ruby 3.0 failure from double splat operator #63

Closed

Conversation

justingaylor
Copy link

@justingaylor justingaylor commented Apr 2, 2022

Describe the change

This PR fixes a Ruby 3.0 failure (warning in Ruby 2.7) when using double splat operator/keyword params similar to this fix:
5f422f8

When using Ruby 3+ on tty, we'll encounter this error (in tty-command) trying to make a new app:

$ teletype new my_app      
/Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/tty-command-0.9.0/lib/tty/command.rb:54:in `initialize': wrong number of arguments (given 1, expected 0) (ArgumentError)
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/tty-0.10.0/lib/tty/cmd.rb:33:in `new'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/tty-0.10.0/lib/tty/cmd.rb:33:in `command'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/tty-0.10.0/lib/tty/commands/new.rb:46:in `initialize'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/tty-0.10.0/lib/tty/cli.rb:128:in `new'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/tty-0.10.0/lib/tty/cli.rb:128:in `new'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/thor-0.20.3/lib/thor/command.rb:27:in `run'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/thor-0.20.3/lib/thor.rb:387:in `dispatch'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/thor-0.20.3/lib/thor/base.rb:466:in `start'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/lib/ruby/gems/3.0.0/gems/tty-0.10.0/exe/teletype:14:in `<top (required)>'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/bin/teletype:25:in `load'
	from /Users/justin.gaylor/.asdf/installs/ruby/3.0.3/bin/teletype:25:in `<main>'

By fixing this issue in tty-command and bumping the version in tty, hopefully we'll be a step closer to being able to use tty with Ruby 3+. (There is a separate "*': negative argument (ArgumentError)"issue that happens intty` after this is fixed, so I will look into that after this gem gets fixed up.)

For further on the exact issue, read here.

Also, unit tests also were updated for a separate issue. When there is a space in the path to the checked out repo base, specs fail due to TTY::Command invoking ruby scripts in numerous places without shell escaping. This is fixed so specs will run for everybody.

Why are we doing this?

tty-command doesn't work on Ruby 3.0 or higher.

Benefits

We can more easily move tty-command (and thus the greater tty toolkit) forward to Ruby 3! 🚀

Drawbacks

None.

Requirements

  • Tests written & passing locally?
  • Code style checked?
  • Rebased with master branch?
  • Documentation updated?
  • Changelog updated?

spec/unit/input_spec.rb Outdated Show resolved Hide resolved
spec/unit/printers/pretty_spec.rb Outdated Show resolved Hide resolved
spec/unit/printers/pretty_spec.rb Outdated Show resolved Hide resolved
spec/unit/printers/pretty_spec.rb Outdated Show resolved Hide resolved
spec/unit/printers/pretty_spec.rb Outdated Show resolved Hide resolved
spec/unit/run_spec.rb Outdated Show resolved Hide resolved
spec/unit/run_spec.rb Outdated Show resolved Hide resolved
spec/unit/run_spec.rb Outdated Show resolved Hide resolved
spec/unit/run_spec.rb Outdated Show resolved Hide resolved
spec/unit/timeout_spec.rb Outdated Show resolved Hide resolved
@justingaylor justingaylor changed the title Fix double splat ruby3 Fix Ruby 3.0 failure from double splat operator Apr 2, 2022
lib/tty/command.rb Outdated Show resolved Hide resolved
@@ -161,10 +164,10 @@
lines.each { |line| line.gsub!(/\d+\.\d+(?= seconds)/, "x") }

expect(lines).to eq([
"[\e[32maaaaaa\e[0m] Running \e[33;1mruby #{non_zero_exit}\e[0m\n",
"[\e[32maaaaaa\e[0m] Running \e[33;1mruby #{escaped_path}\e[0m\n",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/IndentArray: Use 2 spaces for indentation in an array, relative to the first position after the preceding left parenthesis.

@@ -132,17 +134,18 @@
lines.each { |line| line.gsub!(/\d+\.\d+(?= seconds)/, "x") }

expect(lines).to eq([
"[\e[32maaaaaa\e[0m] Running \e[33;1mruby #{non_zero_exit}\e[0m\n",
"[\e[32maaaaaa\e[0m] Running \e[33;1mruby #{escaped_path}\e[0m\n",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/IndentArray: Use 2 spaces for indentation in an array, relative to the first position after the preceding left parenthesis.

@@ -109,16 +110,17 @@
lines.each { |line| line.gsub!(/\d+\.\d+(?= seconds)/, "x") }

expect(lines).to eq([
"[\e[32maaaaaa\e[0m] Running \e[33;1mruby #{zero_exit}\e[0m\n",
"[\e[32maaaaaa\e[0m] Running \e[33;1mruby #{escaped_path}\e[0m\n",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/IndentArray: Use 2 spaces for indentation in an array, relative to the first position after the preceding left parenthesis.

@@ -42,7 +43,7 @@
lines = output.readlines
lines.last.gsub!(/\d+\.\d+/, "x")
expect(lines).to eq([
"[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{phased_output}\e[0m\n",
"[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{escaped_path}\e[0m\n",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/IndentArray: Use 2 spaces for indentation in an array, relative to the first position after the preceding left parenthesis.

@@ -157,7 +159,7 @@
lines = output.readlines
lines.last.gsub!(/\d+\.\d+/, "x")
expect(lines).to eq([
"[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{phased_output}\e[0m\n",
"[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{escaped_path}\e[0m\n",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/IndentArray: Use 2 spaces for indentation in an array, relative to the first position after the preceding left parenthesis.


output.rewind
lines = output.readlines
lines.last.gsub!(/\d+\.\d+/, "x")
expect(lines).to eq([
"[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{non_zero_exit}\e[0m\n",
"[\e[32m#{uuid}\e[0m] Running \e[33;1mruby #{escaped_path}\e[0m\n",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/IndentArray: Use 2 spaces for indentation in an array, relative to the first position after the preceding left parenthesis.

@justingaylor
Copy link
Author

I can try to fix up those RuboCop violations, but I think that will retrigger the Metrics/LineLength: Line is too long. violations again.

Due to no shell escaping, when the file path contains spaces, local
tests fail with:

Failure/Error:
       expect {
         cmd.run("ruby #{cli}", input: infinite_input, timeout: 0.1)
       }.to raise_error(TTY::Command::TimeoutExceeded)

       expected TTY::Command::TimeoutExceeded, got #<TTY::Command::ExitError: Running `ruby /Volumes/1TB Seagate/src/tty-command/spec/fixtures/infinite_input` failed with
         exit status: 1
         stdout: Nothing written
         stderr: ruby: No such file or directory -- /Volumes/1TB (LoadError)
       > with backtrace:
         # ./lib/tty/command.rb:106:in `run'
         # ./spec/unit/timeout_spec.rb:33:in `block (3 levels) in <top (required)>'
         # ./spec/unit/timeout_spec.rb:32:in `block (2 levels) in <top (required)>'
     # ./spec/unit/timeout_spec.rb:32:in `block (2 levels) in <top (required)>'
wrong number of arguments (given 0, expected 1)
When TTY::Command.initialize uses the double splat operator, Ruby 3+
will fail this new test with the following error:

expected no Exception, got #<ArgumentError: wrong number of arguments (given 1, expected 0)> with backtrace:
         # ./lib/tty/command.rb:54:in `initialize'
         # ./spec/unit/command_spec.rb:5:in `new'
         # ./spec/unit/command_spec.rb:5:in `block (3 levels) in <top (required)>'
         # ./spec/unit/command_spec.rb:5:in `block (2 levels) in <top (required)>'
     # ./spec/unit/command_spec.rb:5:in `block (2 levels) in <top (required)>'
Copy link

@kigster kigster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems pretty straightforward.

Copy link

@jonatas jonatas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems legit. Trying locally I got the same issue and it seems a good alternative to fix it.

Copy link
Owner

@piotrmurach piotrmurach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Justin 👋

Thank you for looking into this issue and trying to resolve it. 🙏

Unfortunately, I don't believe we should be reverting to options hash. This change was done a long time ago and anyone who has used this gem should've already adjusted to using keywords. I see options hash as an antipattern. I no longer design my gems this way and wish tty-command to follow. Going forward, my preference is to use explicit keyword names and have Ruby on my side. Therefore I don't believe anything to be broken and thus need fixing on Ruby 3.0 as far as the initialisation goes.

As for the tty gem, it is broken in many ways. It is also not the way I wish to encourage building command-line applications. It was an early attempt and I'm working on overhauling the experience. First, I'll need to get other dependencies ready. What I'm trying to say is that we shouldn't worry about the impact on the tty.

Lastly, great find with escaping the path. However, I think we should fix it in the helper method to improve maintenance. I'd accept a PR specifically fixing only that if you have time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants