Lazy fun: Make unary minus silence stderr for backticks

S

Sam Stephenson

I was reading about mentalguy's lazy.rb and thought it'd be fun to use
lazy evaluation as a vehicle for adding new syntactic sugar to Ruby.=20
Here's one such example, which lets you prefix backticks with a unary
minus to silence stderr:

| % irb -r lazy_backtick
| irb(main):001:0> `hello`
| /opt/local/lib/ruby/1.8/irb/workspace.rb:81: command not found: hello
| =3D> ""
| irb(main):002:0> -`hello`
| =3D> ""

lazy_backtick.rb:

| class LazyBacktick < String
| instance_methods.each {|m| undef_method(m) unless m =3D~ /^__/}
|
| def initialize(command)
| @command, @silence_stderr =3D command, false
| end
|
| def -@
| @swallow_stderr =3D true
| value
| end
|
| def method_missing(method, *arguments, &block)
| value.send(method, *arguments, &block)
| end
|
| private
| def value
| @value ||=3D evaluate
| end
|
| def evaluate
| real_backtick "#@command#{' 2>/dev/null' if @silence_stderr}"
| end
| end
|
| module Kernel
| alias_method :real_backtick, :'`'
|
| def `(command)
| LazyBacktick.new(command)
| end
| end

Note that I'm using the same approach as BlankSlate to remove
LazyBacktick's methods, but inheriting from String instead -- this is
so "String =3D=3D=3D `foo`" doesn't break. (It would be nice to have a mixi=
n
alternative to BlankSlate.)

The way I'm silencing stderr is a bit, um, agile. Can it be made to
work in Ruby on Windows without loading an external library (since
open3 doesn't work there)?

Sam
 
S

Sean O'Halpin

I knew about win32-open3 but not about 2>:nul. Thanks for the tip Sean!
Be careful where you put the colon! It's 2>nul: not 2>:nul. Win/DOS
has a few pseudo-devices that use the same basic syntax as drive
letters (A:, C:) such as NUL:, CON: and AUX:

Regards,
Sean
 
M

Mauricio Fernández

The way I'm silencing stderr is a bit, um, agile. Can it be made to
work in Ruby on Windows without loading an external library (since
open3 doesn't work there)?

batsman@tux-chan:/tmp$ cat test.rb
require 'rbconfig'
def nostderr
old = STDERR.dup
# unsure about the next line
file = :):Config::CONFIG["arch"] =~ /dos|win32|mingw/) ? "NUL" : "/dev/null"
STDERR.reopen(file)
STDERR.sync = true # you want this so `hello3` still outputs something below...
yield
ensure
STDERR.reopen(old)
end

`hello`
nostderr { `hello2`; $stderr.puts "foo" }
`hello3`
batsman@tux-chan:/tmp$ ruby test.rb
test.rb:2: command not found: hello
test.rb:2: command not found: hello3
 
S

Sam Stephenson

Be careful where you put the colon! It's 2>nul: not 2>:nul. Win/DOS
has a few pseudo-devices that use the same basic syntax as drive
letters (A:, C:) such as NUL:, CON: and AUX:

My mistake. I'm full of typos tonight. Thanks again.

Sam
 
S

Sam Stephenson

batsman@tux-chan:/tmp$ cat test.rb
require 'rbconfig'
def nostderr
old =3D STDERR.dup
# unsure about the next line
file =3D :):Config::CONFIG["arch"] =3D~ /dos|win32|mingw/) ? "NUL" : "/= dev/null"
STDERR.reopen(file)
STDERR.sync =3D true # you want this so `hello3` still outputs somethi= ng below...
yield
ensure
STDERR.reopen(old)
end

`hello`
nostderr { `hello2`; $stderr.puts "foo" }
`hello3`
batsman@tux-chan:/tmp$ ruby test.rb
test.rb:2: command not found: hello
test.rb:2: command not found: hello3

Interesting, I didn't know that reopening STDERR would affect
subshells. It's more code but I think I prefer this approach.

Sam
 
F

Florian Groß

Sam said:
I was reading about mentalguy's lazy.rb and thought it'd be fun to use
lazy evaluation as a vehicle for adding new syntactic sugar to Ruby.
Here's one such example, which lets you prefix backticks with a unary
minus to silence stderr:

| % irb -r lazy_backtick
| irb(main):001:0> `hello`
| /opt/local/lib/ruby/1.8/irb/workspace.rb:81: command not found: hello
| => ""
| irb(main):002:0> -`hello`
| => ""

Nice hack, but here's a case that doesn't work and for that I don't have
a fix:

String.new(`echo foo`)

Which returns "" for me.

I guess you are better off not inheriting from String and letting the
String === test fail. Nowadays it's all about duck typing, anyway.
 
C

Caleb Clausen

(It would be nice to have a mixin alternative to BlankSlate.)

I hacked up a BlankSlate module for my own purposes. (This version doesn't
permenently remove any methods, just renames them to something.... unusual.=
)

Here it is:

module BlankSlate;
module ClassMethods
def restore(*names)
names.each{|name| alias_method name, "##{name}"}
end
def hide(*names)
names.each do|name|
undef_method name if instance_methods.include?(name.to_s)
end
end
end

def BlankSlate.included(othermod)
othermod.instance_eval {
instance_methods.each { |m|
alias_method "##{m}", m #archive m
undef_method m unless m =3D~ /^__/ || m=3D=3D'instance_eval'
}
extend BlankSlate::ClassMethods
}
end
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top