Yarsh
Yet Another Ruby SHell is a mix of Ruby and standard Shell REPL. Priority is given to Ruby but if the variable or method is not found or if it is a syntax error, it will be passed to the default shell environment. It enable the best of both worlds, the power of ruby and the simplicity of the standard Shell.
This project was made just for fun, to remember the basis of Ruby and to discover new features. To provide a good user experience, it uses reline under the hood which already implement all we want for a REPL: History, completion, etc.
I wanted a simple version but already working version. If I have time, more features will come. For example, non interactive with a file as argument. I dream of a shell syntax we can do:
def install_rails
sudo apt update
sudo apt install ruby
gem install rails
end
install_rails
And this is now a reality: multi-line editing is supported, and shell commands work inside Ruby blocks, defs, and classes (see Multiline).
I developed this project half of the time offline, another part with the help of AI. It was a way for me to try to develop with AI. I used opencode with DeepSeek V4 Flash Free.
install
Run gem install yarsh
Usage
yarsh start the shell.
Features
Use it as a normal shell, except that you can use Ruby commands and methods. For example:
puts "Hello World! We can use Ruby or standard shell:"
Dir["**/*.rb"].each { |file| puts file }
puts "Or shell like:"
find . -name "*.rb" -print
For the moment, it display ruby evaluation results with pretty_print.
Special keyword for mixing
You can also mix both with the special keyword -->. It will pass to ruby the result of the shell command to use in Ruby. For example:
ls -al . --> lines.each { |file| puts file }
the result of the exectued shell command is ExecOutput a subclass of String with some extra methods. For the moment, it has:
#lines#words
You want to store the result of the ruby evaluation after a shell command? Use -->(varible_name). For example:
ls -al . -->(sorted) lines.sort {|a, b| a.length <=> b.length }
sorted.each { |file| puts "What ever you wanna do" }
Multiline
Multi-line input is supported: the REPL keeps reading while the buffer is
syntactically incomplete (missing end, unterminated string/heredoc/regexp,
trailing operator, ...) and submits when the syntax is complete or on an empty
line. Continuation lines get a > prompt.
The best part: you can mix Ruby and shell lines in the same block, def, or class:
def install_rails
sudo apt update
sudo apt install ruby
gem install rails
end
Dir['*.rb'].each do |f|
ls -l
puts "Processed: #{f}"
end
The whole buffer is evaluated in the shared REPL binding, so methods, variables, and shell side-effects persist between lines and across inputs. Shell lines are executed via the usual fallback (they are evaluated as Ruby first, then as a shell command). Heredoc bodies are kept verbatim:
x = <<~EOF
not evaluated, just a string
EOF
Known limitations:
- Pure-bash multiline (e.g. bash
if ...; then) is not supported; shell lines only work inside Ruby structures. - A Ruby expression that raises a real
NameErrorinside a block may be executed as a shell command instead of being reported.
Completion
For the moment, there is autocompletion for exectuables in PATH and for file and dir path for shell commands
Errors
$rberr are set for every catched Ruby error.
$sherr are set for every catched Shell error.
Configuration
You can create a file named config in ~/.yarsh. It is plain ruby, for now, you can define aliases for shell commands, define methods that will be available in the REPL, configure the prompt looks like and some logging. Here is an example file:
sh_alias 'ls', 'exa -l --icons=always'
sh_alias 'll', 'ls -a' # Will be expanded to exa -l --icons=always -a
configure do |c|
c.prompt = :powerline # To available prompt: :powerline or :basic
# Or define how your own logic for the prompt. Should return a string
c.prompt = Proc.new do
"hello> "
end
c.log_level = Logger::DEBUG # Lot of unuseful lines
end
# Will be available in the REPL once the related TODO is completed
def my_awsome_method
puts "Hello World"
end
Development
After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/facenord-sud/yarsh.