Open simonhf opened 4 years ago
Just as a clarification, the intent here is to have --require file
and that just results in require "file"
being added to the evaluated code.
Right, sort of the crystal equivalent of the gcc force include command line option [1].
[1] https://stackoverflow.com/questions/3387453/include-header-files-using-command-line-option
Ruby has this too by doing ruby -roptparse
which does require "optparse"
at the beginning of the script.
I don't think we really need this, Crystal doesn't have many features geared towards one off command line usage, so this would cater to a usecase that's otherwise poorly supported and which other tools just will always solve better than Crystal.
Come to think of it, maybe the eval
option could be merged with the build
option? Instead of specifying the 'programfile' on the command line, then the 'source' could be optionally specified. Then all the same options could be used for eval as for build?
The proposed --require
option would then be added to just build
and would automatically work with eval
which would just be part of build
in the future?
For example, instead of:
$ crystal build -h | head -1
Usage: crystal build [options] [programfile] [--] [arguments]
$ crystal eval -h | head -1
Usage: crystal eval [options] [source]
The merged functionality would be:
$ crystal build -h | head -1
Usage: crystal build [options] [programfile]|[source] [--] [arguments]
Why should it matter for the build
option if the source code comes from a program file or from the command line?
This would be particularly useful if the crystal one liner via eval is using a module which relies on a build
time --define
...
What's the use case?
For build
I don't see how that would be useful. It makes sense to have all dependend code required from code, not from a CLI option.
For eval
, it's essentially
crystal eval --require "foo" 'Foo.hello_world'
# vs
crystal eval 'require "foo"; Foo.hello_world'
The latter is even shorter.
This would be particularly useful if the crystal one liner via eval is using a module which relies on a
build
time--define
...
What's a "build time --define"?
crystal eval --require "foo" 'Foo.hello_world' # vs crystal eval 'require "foo"; Foo.hello_world'
The latter is even shorter.
Yeah, but just like shell users short cut ls -al
to ll
, the former can be short cut too but not the latter. Let's say the short cut is cre
then the short cut would be the shortest, e.g.:
cre 'Foo.hello_world'
But I think require foo
maybe not the best example. It would be more like --require generic-eval-environment.cr
which would auto do boiler plate things that you might not want to type on the command line every time, e.g. STDOUT.flush_on_newline=true;
is a bit of a handful to type often :-)
This would be particularly useful if the crystal one liner via eval is using a module which relies on a
build
time--define
...What's a "build time --define"?
Let's you define a flag which can be used at compile time to e.g. make a debug build versus a release build, etc:
$ crystal build -h | egrep define
-D FLAG, --define FLAG Define a compile-time flag
... Crystal doesn't have many features geared towards one off command line usage, ...
Why do you say this, because AFAICT Crystal seems to have a really well functioning one liner capability via the eval
command line option, or? And although I understand it might have been created more for Crystal testing purposes, it seems to work really well for general purpose one liners, too. Some Crystal users appear to use eval
every day, while some virtually never use it. But if it works well for some people, why neglect it?
You can already have such a short cut with the current CLI state:
$ cre () {
crystal eval "require \"generic-eval-environment.cr\"; $0"
}
$ cre 'Foo.hello_world'
However, a benefit of external require would be that it does not mess up code locations in the user string.
Maybe as an alternative eval
could treat each CLI argument as an individual expression. Currently it just concatenates them with whitespace in between, so you can build a single Crystal expression from separate arguments (such as crystal eval puts \"foo\"
). I don't think that's particularly useful, though.
This would then allow to easily inject arbitrary code with shell aliases. That includes custom requires. And it's much more versatile than a --require
option. If you just want simple configuration settings for example, you can just inject STDOUT.flush_on_newline=true;
and don't need to have that in a file available to the compiler instance.
Thanks, and it works!
Even though I expected it not to work! I expected there to be some kind of conflict between the double quotes in the shell function wrapping $1
and the double quotes in the command line source code... but the shell seems to work its magic :-) The only thing that I don't know how to get is a verbatim copy of the Crystal command line actually run with all the correct quote escaping, etc.
$ echo 'puts %[- loaded |generic-eval-environment.cr| !]; STDOUT.flush_on_newline=true;' > generic-eval-environment.cr
$ cre () {
echo crystal eval "require \"./generic-eval-environment.cr\"; $1"
crystal eval "require \"./generic-eval-environment.cr\"; $1"
}
$ cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
crystal eval require "./generic-eval-environment.cr"; x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
- loaded |generic-eval-environment.cr| !
- a=ab b=cde // |$SHELL| !
I was fiddling around with a different way to cache the last 50 cre
builds and came up with this:
$ cat cre
#!/usr/bin/perl
use strict;
use Digest::SHA;
my $body = sprintf qq[STDOUT.flush_on_newline=true; ];
foreach my $arg (@ARGV) {
$body .= sprintf qq[%s], $arg;
}
my $path = sprintf qq[%s/.cre] , $ENV{HOME};
my $src = sprintf qq[%s/%s.cr], $path, Digest::SHA::sha256_hex($body);
my $exe = sprintf qq[%s.exe] , $src;
my $cmd = sprintf qq[crystal build -o %s %s 2>&1], $exe, $src;
if (not -e $exe) {
mkdir $path || die sprintf qq[ERROR: cannot create folder %s: $!], $path;
open(my $fd, '>', $src) || die sprintf qq[ERROR: cannot open file %s: $!], $src;
syswrite($fd, $body);
close $fd;
printf qq[- running: %s\n], $cmd if (exists $ENV{CRE_DEBUG});
print `$cmd`;
}
my $sorted_files_cmd = sprintf qq[ls -1rt %s 2>&1], $path;
printf qq[- running: %s\n], $sorted_files_cmd if (exists $ENV{CRE_DEBUG});
my @sorted_files = `$sorted_files_cmd`;
while (scalar @sorted_files > 100) {
my $temp_file_to_delete = sprintf qq[%s/%s], $path, shift @sorted_files;
chomp $temp_file_to_delete;
printf qq[- deleting oldest temp cache file: %s\n], $temp_file_to_delete if (exists $ENV{CRE_DEBUG});
unlink $temp_file_to_delete || die sprintf qq[ERROR: cannot delete oldest temp cache file %s: $!], $temp_file_to_delete;
}
printf qq[- running: %s\n], $exe if (exists $ENV{CRE_DEBUG});
system $exe;
$ chmod +x cre
$ rm -rf ~/.cre/
$ CRE_DEBUG=1 /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
- running: crystal build -o /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr 2>&1
- running: /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
- a=ab b=cde // |$SHELL| !
1.11user 0.28system 0:00.77elapsed 179%CPU (0avgtext+0avgdata 144456maxresident)k
0inputs+3064outputs (0major+60646minor)pagefaults 0swaps
$ CRE_DEBUG=1 /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
- running: /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
- a=ab b=cde // |$SHELL| !
0.03user 0.00system 0:00.02elapsed 176%CPU (0avgtext+0avgdata 6184maxresident)k
0inputs+0outputs (0major+923minor)pagefaults 0swaps
$ /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
- a=ab b=cde // |$SHELL| !
0.00user 0.02system 0:00.01elapsed 172%CPU (0avgtext+0avgdata 6204maxresident)k
0inputs+0outputs (0major+920minor)pagefaults 0swaps
$ wc --bytes ~/.cre/*
121 /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr
1559656 /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
$ cat ~/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr
STDOUT.flush_on_newline=true; x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
And then I was thinking.... Why use Perl to create the Crystal one liner wrapper script? Why not use Crystal? This would end up being my first ever Crystal script... so please be gentle with the comments, but all comments welcome! :-)
$ cat cre.cr
require "openssl"
sha256 = OpenSSL::Digest.new("sha256")
body = sprintf %[STDOUT.flush_on_newline=true;]
ARGV.each {|a| body += sprintf %[ %s], a}
path = sprintf "%s/.cache/cre" , ENV["HOME"]
src = sprintf "%s/%s.cr", path, sha256.update(body).hexdigest
exe = sprintf "%s.exe" , src
cmd = sprintf "crystal build --stats --progress -o %s %s 2>&1 > %s.log", exe, src, src
printf "- body=%s\n- path=%s\n- src=%s\n- exe=%s\n- cmd=%s\n", body, path, src, exe, cmd if ENV.has_key?("CRE_DEBUG")
if ! File.file?(exe)
Dir.mkdir(path) if ! File.directory?(path)
File.write(src, body)
printf "- running: %s\n", cmd if ENV.has_key?("CRE_DEBUG")
print `#{cmd}`
end
%w(cr cr.log cr.exe).each { |s|
sorted_files_cmd = sprintf "ls -1rt %s/*.%s 2>&1", path, s;
printf "- running: %s\n", sorted_files_cmd if ENV.has_key?("CRE_DEBUG")
sorted_files = `#{sorted_files_cmd}`.split
while sorted_files.size > 50
target_file = sorted_files.shift
printf "- deleting oldest temp cache file: %s\n", target_file if ENV.has_key?("CRE_DEBUG")
File.delete(target_file)
end
}
printf "- running: %s\n", exe if ENV.has_key?("CRE_DEBUG")
system exe;
$ crystal build cre.cr
$ rm -rf ~/.cre/
$ CRE_DEBUG=1 /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
- body=STDOUT.flush_on_newline=true; x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
- path=/home/simon/.cre
- src=/home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr
- exe=/home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
- cmd=crystal build -o /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr 2>&1
- running: crystal build -o /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr 2>&1
- running: ls -1rt /home/simon/.cre/*.cr 2>&1
- running: ls -1rt /home/simon/.cre/*.cr.exe 2>&1
- running: /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
- a=ab b=cde // |$SHELL| !
1.12user 0.32system 0:00.82elapsed 177%CPU (0avgtext+0avgdata 144544maxresident)k
0inputs+3064outputs (0major+61300minor)pagefaults 0swaps
$ CRE_DEBUG=1 /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
- body=STDOUT.flush_on_newline=true; x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
- path=/home/simon/.cre
- src=/home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr
- exe=/home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
- cmd=crystal build -o /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr 2>&1
- running: ls -1rt /home/simon/.cre/*.cr 2>&1
- running: ls -1rt /home/simon/.cre/*.cr.exe 2>&1
- running: /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
- a=ab b=cde // |$SHELL| !
0.00user 0.04system 0:00.02elapsed 235%CPU (0avgtext+0avgdata 6736maxresident)k
0inputs+0outputs (0major+1568minor)pagefaults 0swaps
$ /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
- a=ab b=cde // |$SHELL| !
0.00user 0.04system 0:00.02elapsed 250%CPU (0avgtext+0avgdata 6804maxresident)k
0inputs+0outputs (0major+1561minor)pagefaults 0swaps
$ wc --bytes ~/.cre/*
121 /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr
1559656 /home/simon/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr.exe
$ cat ~/.cre/9cddcf6d2334e104e06c4dd09514e61499e66b3c0bda5bdddb8e69ef322cc647.cr
STDOUT.flush_on_newline=true; x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
And some Crystal gurus helped me refine the script a little with extra Crystal features:
$ cat cre.cr
require "file_utils"
require "openssl"
require "log"; Log.setup_from_env # e.g. enable with CRYSTAL_LOG_LEVEL=DEBUG
CACHE_SIZE = 50
CACHE_PATH = File.expand_path("~/.cache/cre", home: true)
BOILER_PLATE = "STDOUT.flush_on_newline=true;"
body = "#{BOILER_PLATE} #{ARGV.join(' ')}"
path = "#{CACHE_PATH}/#{OpenSSL::Digest.new("sha256").update(body).hexdigest}/"
name = "one-liner.cr"
src = "#{path}#{name}"
log = "#{src}.log"
exe = "#{src}.exe"
cmd = "cd #{path} ; crystal build --stats --progress -o #{name}.exe #{name} 2>&1 > #{name}.log"
aged = sprintf "ls -1drt %s/* 2>&1", CACHE_PATH;
aged = "ls -1drt #{CACHE_PATH}/* 2>&1"
{% for v in %w[body path name src log exe cmd aged] %}; Log.debug { "#{{{v}}}=#{{{v.id}}}" }; {% end %}
Log.debug { "#{File.executable?(exe) ? "Reusing" : "Compiling"} file #{exe}" }
if ! File.executable?(exe)
Dir.mkdir_p(path)
File.write src, body
`#{cmd}`
Log.fatal { "Failed to build #{exe}" } if ! File.executable?(exe)
end
sorted_folders = `#{aged}`.split
while sorted_folders.size > CACHE_SIZE
target_folder = sorted_folders.shift
Log.debug { "Pruning cache folder: #{target_folder}" }
FileUtils.rm_rf(target_folder)
end
Log.debug { "Running #{exe}" }
Process.exec exe
$ crystal build cre.cr
$ rm -rf ~/.cache/cre/
$ CRYSTAL_LOG_LEVEL=DEBUG /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
D, [2020-05-28T23:47:27.444090000Z #66625] DEBUG -- cre:: body=STDOUT.flush_on_newline=true;x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
D, [2020-05-28T23:47:27.444172000Z #66625] DEBUG -- cre:: path=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/
D, [2020-05-28T23:47:27.444210000Z #66625] DEBUG -- cre:: name=one-liner.cr
D, [2020-05-28T23:47:27.444256000Z #66625] DEBUG -- cre:: src=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr
D, [2020-05-28T23:47:27.444295000Z #66625] DEBUG -- cre:: exe=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.exe
D, [2020-05-28T23:47:27.444358000Z #66625] DEBUG -- cre:: log=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.log
D, [2020-05-28T23:47:27.444403000Z #66625] DEBUG -- cre:: cmd=cd /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/ ; crystal build --stats --progress -o one-liner.cr.exe one-liner.cr 2>&1 > one-liner.cr.log
D, [2020-05-28T23:47:27.444454000Z #66625] DEBUG -- cre:: aged=ls -1drt /home/simon/.cache/cre/* 2>&1
D, [2020-05-28T23:47:27.444546000Z #66625] DEBUG -- cre:: Compiling file /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.exe
D, [2020-05-28T23:47:28.712664000Z #66625] DEBUG -- cre:: Running /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.exe
- a=ab b=cde // |$SHELL| !
2.28user 0.56system 0:01.28elapsed 220%CPU (0avgtext+0avgdata 144296maxresident)k
0inputs+13064outputs (0major+72963minor)pagefaults 0swaps
$ CRYSTAL_LOG_LEVEL=DEBUG /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
D, [2020-05-28T23:48:13.819790000Z #66718] DEBUG -- cre:: body=STDOUT.flush_on_newline=true;x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
D, [2020-05-28T23:48:13.819900000Z #66718] DEBUG -- cre:: path=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/
D, [2020-05-28T23:48:13.819988000Z #66718] DEBUG -- cre:: name=one-liner.cr
D, [2020-05-28T23:48:13.820039000Z #66718] DEBUG -- cre:: src=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr
D, [2020-05-28T23:48:13.820084000Z #66718] DEBUG -- cre:: exe=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.exe
D, [2020-05-28T23:48:13.820110000Z #66718] DEBUG -- cre:: log=/home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.log
D, [2020-05-28T23:48:13.820139000Z #66718] DEBUG -- cre:: cmd=cd /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/ ; crystal build --stats --progress -o one-liner.cr.exe one-liner.cr 2>&1 > one-liner.cr.log
D, [2020-05-28T23:48:13.820176000Z #66718] DEBUG -- cre:: aged=ls -1drt /home/simon/.cache/cre/* 2>&1
D, [2020-05-28T23:48:13.820201000Z #66718] DEBUG -- cre:: Reusing file /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.exe
D, [2020-05-28T23:48:13.830203000Z #66718] DEBUG -- cre:: Running /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.exe
- a=ab b=cde // |$SHELL| !
0.00user 0.03system 0:00.02elapsed 181%CPU (0avgtext+0avgdata 7108maxresident)k
0inputs+0outputs (0major+1130minor)pagefaults 0swaps
$ /usr/bin/time ./cre 'x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;'
- a=ab b=cde // |$SHELL| !
0.01user 0.01system 0:00.01elapsed 186%CPU (0avgtext+0avgdata 6996maxresident)k
0inputs+0outputs (0major+1118minor)pagefaults 0swaps
$ find ~/.cache/cre/* -type f | xargs wc --bytes
1559672 /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.exe
120 /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr
15203 /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr.log
$ cat /home/simon/.cache/cre/28fbe9a46fb80c1243764f41d92c8ba3862df2f8ac5bfa094a5fe586e3dd86d9/one-liner.cr
STDOUT.flush_on_newline=true;x = "abcdefg"; x =~ /(.*)(c.e).*/; _,a,b = $~; printf %[- a=%s b=%s // |$SHELL| !\n], a, b;
Instead of String.build I suggest you use string interpolation. Specially for a script.
@asterite Thanks for the tip. I changed it in the above comment and it looks shorter and more intentional revealing now.
Everything I learned so far about Crystal I dumped into some examples here: https://gist.github.com/simonhf/078f0874c622ef9b276fa58554fcd1fc
As mentioned in https://github.com/crystal-lang/crystal/issues/10947#issuecomment-880535124, if we want this capability for tools other than eval
then one way to do it is through a command line option:
$ crystal run -e 'require "big"' -e 'puts 10.to_big_r / 3'
10/3
$ crystal build -o a.out -e 'require "big"' -e 'puts 10.to_big_r / 3'
$ ./a.out
10/3
$ crystal i -e 'require "big"' -e 'puts 10.to_big_r / 3'
10/3
It would be great to have the
--prelude
option working foreval
as well asbuild
. Why?--prelude
instead ofrequire ...
means a shell short cut can be used too.Crystal version:
--prelude
option currently only forbuild
but noteval
: