Last active
December 9, 2017 17:27
-
-
Save JoshCheek/b31103fe4aab24f0d5cc650c442bddaa to your computer and use it in GitHub Desktop.
Backticks in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://twitter.com/yburyug/status/939517726846005248 | |
# It does execute it's arg in the shell | |
`echo hello` # => "hello\n" | |
# It doesn't work in your example b/c it is private | |
Object.new.` "echo world" rescue $! # => #<NoMethodError: private method ``' called for #<Object:0x007f8c900257c8>> | |
#`# fix the hilighting | |
# Lets make it public | |
public :` | |
# It's private, because it isn't intended as a method you call on other objects | |
# Like... the fact that I can now do this is pretty ridiculous | |
Object.new.` "echo world" # => "world\n" | |
123.` "echo hello | tr heo wod | sed s/l/r/" # => "world\n" | |
Object.` "ls" # => "program.rb\n" | |
#`# fix the hilighting | |
# So, why is it a method on every object, then? Because it comes from Kernel | |
method(:`).owner # => Kernel | |
# It's intended to be used like a set of latently available functionality, | |
# same as these other things we use like they're available from the language, | |
# without thinking too much about why | |
method(:require).owner # => Kernel | |
method(:puts).owner # => Kernel | |
method(:lambda).owner # => Kernel | |
method(:system).owner # => Kernel | |
# So by placing it in Kernel, it's available to the contexts we write code in, | |
# hence allowing us to do things like this: | |
`echo implicitly calling backticks on self` # => "implicitly calling backticks on self\n" | |
# And by making it private, the outside world can't see that it's part of our | |
# object, avoiding the confusion of what does it mean that I can call backticks | |
# on things like hashes and numbers. | |
# ----- Soooooooo, lets fuck with it! ----- | |
module Kernel | |
require 'shellwords' | |
def `(arg) | |
arg.shellsplit | |
.slice_before { |token| token == '|' } | |
.to_a | |
.each { |tokens| tokens.shift if tokens[0] == '|' } | |
.reduce([self, []]) { |(receiver, results), (message, *args)| | |
args.map! { |arg| arg=~/\A\d+\Z/ ? arg.to_i : arg } | |
result = receiver.send message, *args | |
[(result.clone rescue result), results<<result] | |
} | |
.last | |
end | |
end | |
`inspect | chars | join - | upcase` | |
# => ["main", ["m", "a", "i", "n"], "m-a-i-n", "M-A-I-N"] | |
# ALSO, fun fact: backticked heredocs | |
<<~`BASH` | |
itself | | |
inspect | | |
reverse | | |
delete i | | |
+ e | | |
split | | |
<< World | | |
<< greeting | | |
<< Hello | | |
each_slice 2 | to_h | |
BASH | |
# => [main, | |
# "main", | |
# "niam", | |
# "nam", | |
# "name", | |
# ["name"], | |
# ["name", "World"], | |
# ["name", "World", "greeting"], | |
# ["name", "World", "greeting", "Hello"], | |
# #<Enumerator: ...>, | |
# {"name"=>"World", "greeting"=>"Hello"}] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment