Rubish: A Unix shell written in pure Ruby(github.com) |
Rubish: A Unix shell written in pure Ruby(github.com) |
Just for fun, looking at code count as a rough measure of complexity.
rubish: 26,842
rc (plan9 shell): 5,888
To be fair, rubish does a lot more than rc. rc is pretty minimal.
rc source:
https://github.com/9front/9front/tree/front/sys/src/cmd/rc
Measures below:
$ wc -l `find . -name '*.rb'`
1124 ./rubish/execution_context.rb
43 ./rubish/frontend.rb
260 ./rubish/builtins/hash_directories.rb
510 ./rubish/builtins/echo_printf.rb
834 ./rubish/builtins/bind_readline.rb
182 ./rubish/builtins/directory_stack.rb
299 ./rubish/builtins/read.rb
324 ./rubish/builtins/trap.rb
129 ./rubish/builtins/arithmetic.rb
862 ./rubish/completion.rb
988 ./rubish/expansion.rb
431 ./rubish/completions/git.rb
114 ./rubish/completions/ssh.rb
530 ./rubish/completions/bash_helpers.rb
453 ./rubish/completions/help_parser.rb
167 ./rubish/ast.rb
46 ./rubish/frontend/tty.rb
1179 ./rubish/runtime.rb
127 ./rubish/lazy_loader.rb
63 ./rubish/data_define.rb
1163 ./rubish/runtime/command.rb
153 ./rubish/runtime/job.rb
7270 ./rubish/runtime/builtins.rb
306 ./rubish/config.rb
2442 ./rubish/repl.rb
1316 ./rubish/codegen.rb
1180 ./rubish/lexer.rb
742 ./rubish/history.rb
1169 ./rubish/parser.rb
67 ./rubish/startup_profiler.rb
848 ./rubish/prompt.rb
47 ./rubish/data/readline_config.rb
716 ./rubish/data/builtin_help.rb
251 ./rubish/data/shell_options.rb
53 ./rubish/data/completion_data.rb
5 ./rubish/version.rb
248 ./rubish/shell_state.rb
140 ./rubish/arithmetic.rb
61 ./rubish.rb
26842 total
rc: $ wc -l *.c *.h *.y
547 code.c
1173 exec.c
234 getflags.c
259 glob.c
240 havefork.c
137 here.c
301 io.c
436 lex.c
169 pcmd.c
78 pfnc.c
494 plan9.c
539 simple.c
74 subr.c
37 trap.c
190 tree.c
420 unix.c
109 var.c
85 exec.h
72 fns.h
7 getflags.h
28 io.h
167 rc.h
92 syn.y
5888 totalI would love to see more interpreted languages offer shells with native constructs for operating as daily drivers shells (not just REPLs). When I first started learning Ruby I used `rush`[0] as my main shell. Being immersed in the language, even if there were a few helpers for shell operations, really helped me reason better about Ruby and think in the language. `scsh`[1] was enlightening as well. Ultimately the ergonomics of both pushed me back to more conventional variant but they were really helpful learning mechanisms.
0: https://github.com/adamwiggins/rush 1: https://github.com/scheme/scsh
The "scripting" languages should of course not try to be slow, but people rarely use them for speed-reasons; they use these languages for gains in productivity and ease of writing code, adding features and so forth. That should be the primary focus point.
In the future we may no longer have such a speed penalty anyway.
A few years ago irb got a facelift, so rubish probably represents a more modern take on the shell concept. I tested it and it works too. I wonder how much the everything-is-an-object idea is extended here. Many years ago I learned avisynth + virtualdub and I always liked how they approached filtering. Ffmpeg is great, but I absolutely hate the filter system it uses and the ABSOLUTELY horrible syntax. The ffmpeg devs do not seem to know avisynth, or any alternatives here - so I want object manipulation with a convenient syntax at all times, not just for audio/video data but literally for any data. Naturally ruby would be a good fit by default, but I am unaware of many ruby developers even wanting to go that route. If there are still any ruby developers left that is - ruby has been tanking hard in the last few years, approaching extinction level, just like perl did before.
There has to be a better influx of new users; the old +50 years generation isn't going to keep languages alive really.
Edit: Also I forgot: the idea and implementation is fine, I just think we need much more of that in general. Ruby is kind of in a patchy patchwork situation. Where are the epic projects? Rails is also ancient already.
But, you can write an optimised pipe in ruby too. I actually did that, because I could not want to be bothered to be restricted via ruby's syntax for pipe-like operations.
Even aside from that, the original claim was about pipes versus method chaining. To me these are not orthogonal to one another; they are very similar. Just with the pipe focusing on tying together different programs and focusing on input-output functionality. Method chaining in ruby is a bit more flexible, we have blocks, and usually the methods chained occur in one class/object or the toplevel namespace (less frequently though, usually). Even the pipe comparison is not ideal, because traditional UNIX pipes don't support e. g. data manipulation via an object-oriented focus. And I want that (see avisynth, but extend the idea there via a) nicer syntax and b) data manipulation for EVERYTHING).
I don't see pipe as being exclusive over method chaining or reverse.
One interesting idea was to add |> elixir's pipe-like operator to ruby. I like that, but indeed, the net-gain in ruby is quite minimal since method-chaining + blocks already offer a ton of flexibility, so I am not sure how |> would fit into ruby 1:1. Still I like the idea, but anyone proposing |> needs to come up with really convincing ideas to matz here. Because people WILL ask what the real difference is to method chaining. Even fail-safe method chaining in ruby though I absolutely hate the syntax via ? there ... it reads like garbage to me. Example:
https://github.com/ruby/ruby/blob/trunk/test/ruby/test_threa...
t1&.kill&.join
(It has moved since then, so the above link no longer works,
been some years since I first saw it. Upon seeing it my brain
instantly cancelled any use of "&.", even though I understand
the rationale. It is just ugly to no ends. I still like the
|> syntax in Elixir though, even though I can not really see
what this should do in ruby.)