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_railsAnd 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.
Run gem install yarsh
yarsh start the shell.
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" -printFor the moment, it display ruby evaluation results with pretty_print.
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" }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
endDir['*.rb'].each do |f|
ls -l
puts "Processed: #{f}"
endThe 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
EOFKnown 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.
For the moment, there is autocompletion for exectuables in PATH and for file and dir path for shell commands
$rberr are set for every catched Ruby error.
$sherr are set for every catched Shell error.
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"
endAfter 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.
Bug reports and pull requests are welcome on GitHub at https://github.com/facenord-sud/yarsh.