Showing only posts by William Morgan [.rss for this author]. See all posts.

“sudo gem install” considered harmful

Update 2010/10/02: see here for a real-life example.

If you habitually type sudo gem install on your development box, you are potentially exposing yourself to nasty behavior. If you have sudo gem install as part of your automated deploy process, you are begging for something tragic to happen.

Consider:

  1. A gem can execute arbitrary code at install time.1
  2. Anyone with the proper permissions on rubygems.org can publish a new version of a gem at any point. This code is not reviewed or audited by anyone before publication.
  3. gem install pulls in the latest version of any dependencies that it can, for the entire dependency graph.

All it takes is for one malicious or incompetent gem writer to do something wrong, even in a gem you don’t directly depend on, and sudo gem install will destroy your box.

Happily, rubygems work perfectly well in non-root mode. For local development, you can leave out the sudo and gems will be installed in your home directory. For production use, you should be running servers and apps as non-root users anyways.

Please, stop propagating the sudo gem install meme.

1 See http://github.com/wmorgan/killergem.

Whisper Fix

I just noticed that comments have been backlogged for a few months because the blog received a (spam) email with invalid UTF-8, which apparently in Ruby 1.9 causes String#=~ to throw the very generic ArgumentError.

I’ve caught the exception and, thanks to my high-tech mbox-based queueing system, we’re back on track. The hazards of a 1-person install base, I suppose.

Wall on Greatness

The very fact that it’s possible to write messy programs in Perl is also what makes it possible to write programs that are cleaner in Perl than they could ever be in a language that attempts to enforce cleanliness. The potential for greater good goes right along with the potential for greater evil. A little baby has little potential for good or evil, at least in the short term. A President of the United States has tremendous potential for both good and evil. — Larry Wall.

vim and git grep

[Update 2010-09-20: tweaked to run the grep on the git root instead of whatever directory the current file is in.]

After many months of screwing around with git.vim and fugitive.vim, I have finally found the perfect vim + git grep combination.

This incantation allows you to press <ctrl-x> twice on a symbol and have a minibuf pop up with all the occurrences of that symbol within the project. You can then jump to any occurrence by pressing enter on the corresponding line.

Place this in e.g. ~/.vim/plugin/git-grep.vim:

let g:gitgrepprg="git\\ grep\\ -n"
let g:gitroot="`git rev-parse --show-cdup`"

function! GitGrep(args)
    let grepprg_bak=&grepprg
    exec "set grepprg=" . g:gitgrepprg
    execute "silent! grep " . a:args . " " . g:gitroot
    botright copen
    let &grepprg=grepprg_bak
    exec "redraw!"
endfunction

func GitGrepWord()
  normal! "zyiw
  call GitGrep(getreg('z'))
endf
nmap <C-x><C-x> :call GitGrepWord()<CR>

Interview with Daniel Ellsberg

There’s a very interesting interview with Daniel Ellsberg, of Pentagon Papers fame, in the Economist. Some choice quotes:

“Obama has now prosecuted three people [for whistleblowing]. Two of whom are being prosecuted for acts carried out under George Bush and for which Bush chose not to prosecute[…]. So Obama’s famous position of not looking backward seems to apply only to crimes like torture or illegal warrantless surveillance. He’s given absolute amnesty to the officials of the Bush administration. But in the case of Thomas Drake, who told a reporter about a billion-and-half-dollar waste at the NSA, and in the case of Shamai Leibowitz, who says he exposed acts to a blogger that he regarded as illegal, Obama was willing to look backward and prosecute.”

“I think we can assume that those who don’t use Wikileaks’s technology to get the information out can be assured of prosecution. I have to assume that if I had now put out the Pentagon Papers as I did, using that now outmoded technology of Xerox, Obama would prosecute me to the full extent of the law.”

“A number of the acts undertaken against me, which were illegal at the time, forcing Nixon to obstruct justice by concealing them, have been made part of our explicit policy. Not just the warrantless wire-tapping, but the raid of my psychoanalyst’s office is now regarded as legal under the Patriot Act as a sneak-and-peek operation.”

“Nixon brought a dozen CIA assets […] with orders to incapacitate me totally. That was done covertly and was one of the factors that led to Nixon’s resignation. Obama has now announced, through his then-head of intelligence, Dennis Blair, that we have a list of those who can be assassinated by special-forces operators. And this president has even approved names of American citizens on that list. Now that’s an astonishing change, not in our covert policy—presidents have been involved in covert assassination plots repeatedly—but to announce that publicly as a supposedly legitimate policy. That negates the Magna Carta. It’s a kind of power that no king of England has asserted since John I.”

“[W]hen I said that Julian Assange is in some danger, others said that’s ridiculous, he’s too prominent, no president would do such a thing. Well, I’m not saying that it’s very likely, but I am saying that the chance of Julian Assange coming to harm from the US president should be zero, and it isn’t. To say that it’s ridiculous is simply unfounded. My own experience proves that. Because after all, I was as well-known at the time, when that assault was made, as Julian Assange is today.”

Pinker on Critical Thinking

[D]on’t rail at PowerPoint or Google. It’s not as if habits of deep reflection, thorough research and rigorous reasoning ever came naturally to people. They must be acquired in special institutions, which we call universities, and maintained with constant upkeep, which we call analysis, criticism and debate. They are not granted by propping a heavy encyclopedia on your lap, nor are they taken away by efficient access to information on the Internet.

— Steven Pinker

(or Twitter!)

Calculating string display width in Ruby

Most programmers are by now familiar with the difference between the number of bytes in a string and the number of characters. Depending on the string’s encoding, the relationship between these two measures can be either trivially computable or complicated and compute-heavy.

With the advent of Ruby 1.9, the Ruby world at last has this distinction formally encoded at the language level: String#bytesize is the number of bytes in the string, and String#length and String#size the number of characters.

But when you’re writing console applications, there’s a third measure you have to worry about: the width of the string on the display. ASCII characters take up one column when displayed on screen, but super-ASCII characters, such as Chinese, Japanese and Korean characters, can take up multiple columns. This display width is not trivially computable from the byte size of the character.

Finding the display width of a string is critical to any kind of console application that cares about the width of the screen, i.e. is not simply printing stuff and letting the terminal wrap. Personally, I’ve been needing it forever:

  1. Trollop needs it because it tries to format the help screen nicely.
  2. Sup needs it in a million places because it is a full-fledged console application and people use it for reading mail in all sorts of funny languages.

The actual mechanics of how to compute string width make for an interesting lesson in UNIX archaeology, but suffice it to say that I’ve travelled the path for you, with help from Tanaka Akira of pp fame, and I am happy to announce the release of the Ruby console gem.

The console gem currently provides these two methods:

  • Console.display_width: calculates the display width of a string
  • Console.display_slice: returns a substring according to display offset and display width parameters.

There is one horrible caveat outstanding, which is that I haven’t managed to get it to work on Ruby 1.8. Patches to this effect are most welcome, as are, of course, comments and suggestions.

Try it out!.

Trollop up to 8k downloads

UPDATE 2010-05-19: 12k downloads. Whoohoo!

I just noticed that Trollop 1.16.2 has over 8,000 downloads. That’s roughly an order of magnitude more than Sup. So, yay. Of course I suspect it’s largely thanks to the fact that it’s now a dependency of Cucumber. But I’ll take what I can get.

After all, it’s only been the best option parser for Ruby for three whole years.

Some people get it:

In my experience, OptionParser has been frustrating to use for several reasons, one of them being the poor documentation — hence your question. William Morgan, the author of Trollop, shows no mercy in his criticism (for example, see http://stackoverflow.com/questions/897630/ and http://trollop.rubyforge.org). I can’t dispute what he says.

And some people are merrily producing horrible alternatives.

Trollop 1.16.2 released

Trollop 1.16.2 has been out for a while now, but I realized I (heavens!) haven’t yet blogged about it.

Exciting features include:

  1. Scientific notation is now supported for floating-point arguments, thanks to Will Fitzgerald.
  2. Hoe dependency dropped. Finally.
  3. Some refactoring of the standard exception-handling logic, making it easier to customize Trollop’s behavior. For example, check this out:

opts = Trollop::with_standard_exception_handling p do
  p.parse ARGV
  raise Trollop::HelpNeeded if ARGV.empty? # show help screen
end

This example shows the help screen if there are no arguments. Previous to 1.16, this was difficult to do, since the standard exception-handling was baked into Trollop::options. The help message would automatically be displayed if -h was given, but programmatically invoking it on demand was difficult.

So I’ve refactored the standard exception handling into with_standard_exception_handling, and if you want fine-grained control, instead of calling Trollop::options, you now have the option to call Trollop#parse from within with_standard_exception_handling.

You don’t really need any of this stuff, of course, unless you’re really picky about how your exception-handling works. But hey, that’s why I wrote Trollop in the first place….

Simple breakpoints in Ruby

Sometimes it’s nice to have a simple breakpointing function that will dump you into an interactive session with all your local variables in place.

There are more sophisticated solutions for the world of multiple servers and daemonized code, but after some fighting with IRB, I find myself using this little snippet of code in many projects:

require 'irb'

module IRB
  def IRB.start_with_binding binding
    IRB.setup __FILE__
    w = WorkSpace.new binding
    irb = Irb.new w
    @CONF[:MAIN_CONTEXT] = irb.context
    irb.eval_input
  end
end

## call me like this: breakpoint binding
def breakpoint binding; IRB.start_with_binding binding end

As the comment states, you can invoke the breakpoint at any point by inserting a breakpoint binding statement anywhere in your code. Once that line is reached, you’ll be dumped into an IRB session with local variables intact. Quitting the session resumes execution.

Obviously with this method I’m having you pass in your binding explicitly. There are fancier tricks for capturing the binding of the caller (involving kernel trace functions and continuations), but I’m opting for the simpler solution here.

Works with Ruby 1.9, of course.

0 1 2 3 4 5 6 7  next