| % 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`
| => ""
lazy_backtick.rb:
| class LazyBacktick < String
| instance_methods.each {|m| undef_method(m) unless m =~ /^__/}
|
| def initialize(command)
| @command, @silence_stderr = command, false
| end
|
| def -@
| @swallow_stderr = true
| value
| end
|
| def method_missing(method, *arguments, &block)
| value.send(method, *arguments, &block)
| end
|
| private
| def value
| @value ||= 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 === `foo`" doesn't break. (It would be nice to have a mixin
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
Sorry, make that @silence_stderr.
On Windows, you could use 2>nul: instead of 2> /dev/null or
win32-open3 (see http://raa.ruby-lang.org/project/win32-open3/)
Regards,
Sean
I knew about win32-open3 but not about 2>:nul. Thanks for the tip Sean!
Sam
Regards,
Sean
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
--
Mauricio Fernandez
My mistake. I'm full of typos tonight. Thanks again.
Sam
Interesting, I didn't know that reopening STDERR would affect
subshells. It's more code but I think I prefer this approach.
Sam
> 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.
Hmm, what you've got here doesn't look quite like lazy evaluation,
exactly. More like Delegator, except way better.
Glad to be inspiring such cool things though!
-mental
> 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.
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 =~ /^__/ || m=='instance_eval'
}
extend BlankSlate::ClassMethods
}
end
end