Archive for Ruby

Speeding up gem on OS X Leopard

Update: gem has changed for the better, and this is no longer necessary. Go ahead and gem update --system.

After upgrading to Leopard from Tiger, I noticed that certain network operations for some processes suddenly took forever. Most noticeably, when gem would update metadata. And I’m not the only one.

It’s not so bad anymore, and all I had to do was grab something from the standard library.

In gem (mine’s at /usr/local/bin/gem), add this line before any other code:

require 'resolv-replace'

Done. Seriously. gem will work much faster. Not as fast as you remember from Tiger, but getting there.

Discussions I’ve had suggest that Leopard isn’t caching DNS requests from certain processes, and letting Ruby handle that itself gets around this.

Update: Here’s the current state of my /usr/local/bin/gem:

#!/usr/local/bin/ruby
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++

require 'resolv-replace'

require 'rubygems'
require 'rubygems/gem_runner'

required_version = Gem::Requirement.new ">= 1.8.2"

unless required_version.satisfied_by? Gem::Version.new(RUBY_VERSION) then
  abort "Expected Ruby Version #{required_version}, was #{RUBY_VERSION}"
end

# We need to preserve the original ARGV to use for passing gem options
# to source gems.  If there is a -- in the line, strip all options after
# it...its for the source building process.
args = !ARGV.include?("--") ? ARGV.clone : ARGV[0...ARGV.index("--")]

Gem::GemRunner.new.run args

Comments (8)

You might be able to stop trying to call methods on nil

Correct me if I’m mistaken. Please.

The people behind andand, try, do_or_do_not, NilClass#method_missing, SafeNil, maybe, etc. seem to be trying to beautifully solve the problem of calling methods on objects that might be nil and not having Ruby complain about it. They might be chaining methods a lot or, when they check if an object is nil, they use the ternary conditional and (rightly) think it’s ugly.

As for these ternary conditional users, you can do this: @person.name if @person instead of @person ? @person.name : nil. It does what you need, looks great, and is highly readable.

Of course, that doesn’t help you if you’re chaining methods.

But (and this is what’s been on my mind), I suspect that all of these solutions value terseness over readability and flexibility. It’s a trade off I’m willing to make sometimes, but I think it’s unnecessary here.

For example, Reg Braithwaite’s example:

@phone = Location.find(:first, ...elided... ).andand.phone

We’re trying to get the phone number of a location, but maybe we won’t find the location. Seems normal on the surface. But these are the questions that run through my mind looking at this:

  1. All you need is the phone number?
  2. You’re sure you don’t need anything else from the Location object? (address, url, hours, etc.)
  3. It doesn’t mean anything if the location isn’t found?

I find it hard to believe that the answer to all these questions is “Yes”. I know this is example code, but it must be inspired from something, right?

I’d bet that instead of @phone = Location.find(:first, ...elided... ).andand.phone, later on you’d really wish you had this:

@location = Location.find(:first, ...elided... )

Maybe you’d discover your view (Reg’s example is ActiveResource-related, I’m running with that) needs more than just the phone number (who are you calling?). Or maybe you’d discover that if the location isn’t found, that that means something. Maybe you need to alert the user (unless @location ...).

It could be that I’m more hung up on this idea of meaning. The example for Ben’s maybe is:

if(customer && customer.order && customer.order.id==newest_customer_id)

I look at that and think: if there’s no customer, that means one thing; if there’s no order for the customer, that means something else; if the customer’s order’s id isn’t newest_customer_id, that means something else entirely; and if all these things are different, maybe they should be handled separately.

If you think about it that way, there’s no need to fiddle with nil or add methods to Object.

(I completely understand that this might just be an aesthetic difference, or that sometimes this apparent loss of flexibility is desirable, or that I might be wrong. Please narrow it down for me in the comments. Thanks.)

Comments (14)

A better try — chaining methods and nil

Of #try, #andand, and #do_or_do_not, the one I like best (and I don’t even like any of them that much, but that’s my next post) is #try.

What they are all basically for is chaining method calls when one of methods might return nil, resulting in a NoMethodError. Here’s Chris Wanstrath’s implementation:

class Object
  ##
  #   @person ? @person.name : nil
  # vs
  #   @person.try(:name)
  def try(method)
    send method if respond_to? method
  end
end

It’s almost right!

First of all, I’d argue that if #try is trying to be better than something, it had better be better than @person.name if @person. That looks and reads so nicely I can scarcely see why it needs replacing. @person.name if @person is so obviously better than @person ? @person.name : nil that I hope people are using that before they start thinking about monkey patching Object (which I hear is destroying Ruby). Anyway, I’d fix the documentation first.

But I think the biggest problem with #try is that it’s not doing what it says it’s doing. It’s not a replacement for @person ? @person.name : nil. That’s certainly not what the method is doing. Here’s what I’d do:

class Object
  ##
  #   @person.name if @person
  # vs
  #   @person.try(:name)
  def try(method)
    self.send(method) if self
  end
end

See? Much clearer; it does what it says. Using respond_to? means that the original #try is about something else; it’s about whether or not an object responds to a message. This #try is about sending a message to an object unless it’s nil or false, which is closer to what the original use case was… right?

But then it occurred to me that the issue is nil, not nil or false. The problem isn’t getting false in the middle of method chains, it’s nil. So maybe what #try should really be is this:

class Object
  ##
  #   @person.name unless @person.nil?
  # vs
  #   @person.try(:name)
  def try(method)
    self.send(method) unless self.nil?
  end
end

I might even use that.

Comments (9)

Boy, what ISN’T destroying Ruby these days?

What else?

(Note: Charles Oliver Nutter is helping when he tells us that Thread#raise, Thread#kill, and timeout.rb are broken.)

Comments (7)

Pyre 0.3.0: Because Campfire doesn’t have an API (really)

I’ve released version 0.3.0 of Pyre, an alternative ruby library for interacting with Campfire from 37signals. Pyre now supports uploading files to a room! Observe:

require 'rubygems'
require 'pyre'  # it rhymes!

Pyre::Campfire.new('pyre') do |campfire|
  campfire.login('bot@seriouslyreal.com', '12345')
  campfire.room('Hot Chat') do |room|
    room.upload('/path/to/animated.gif')
    room.speak('What a cat!')
  end
end

Also, now there’s a contrib directory which will hold examples of things to do with Pyre. Currently, the only thing in there is a Subversion repository post-commit hook for putting really nice messages about commits into a Campfire room. It’s really nice. Out of the box they look like this:

cms commited revision 104
*************************
Fixed all spelling mistaeks in the README
*************************
U   pyre/trunk/README

I’m hoping to expand that contrib dir. I’m hoping people will help too.

Anyway, get it and use it.

sudo gem install pyre

Comments (2)

Pyre, an alternative library for Campfire

I’ve recently had reason to use 37signals’ Campfire, and thus a need for a Campfire bot. Tinder does a fine job, but I was running into issues (minor annoyances), so of course I decided to write my own library for interacting with Campfire.

And Pyre was born.

As of right now, you can log in, log out, join and leave rooms, speak and paste to rooms, and that’s it. But for something like a svn post-commit hook, that’s all you need. Pyre uses Mechanize (as opposed to Tinder’s ActiveSupport, Hpricot, and regular expressions combo) to deal with Campfire, so it was pretty easy to throw together.

Sample code? Here’s what the end of an svn post-commit hook might look like (after the message has been built):

Pyre::Campfire.new('subdomain', :ssl => true) do |campfire|
  campfire.login('bot@email', 'botpassword')
  campfire.room('Development') do |room|
    room.paste(message)
  end
end

Pretty straightforward.

For the most part I tried to stay close to Tinder’s interface so that porting to Pyre would be easy, but this block style is new (and, I think, nice).

I’ll be implementing listening in a room soon enough I wager.

So go ahead and get it!

sudo gem install pyre

Comments

MountainWest RubyConf

I finally ponied up the meager $100 for my spot at MountainWest RubyConf. Last year was good, and it looks like this year will be better. Pat Eyler says, “One of the sponsors has let me know that they’re planning something really special for attendees.” I’m looking forward to receiving this “special” mousepad. (It’s going to be a mousepad, right?)

If you need to harass me in person about how GuessMethod and CSSes aren’t suited for production, I’ll be wearing two hooded sweatshirts and a Baltimore Orioles cap. See you there.

Comments (1)

CSSes: a clean CSS slate for your Rails application

Update: CSSes is now a gem! No need to install the plugin for each app.

I’ve updated CSSes to handle a bunch more Rails HTML helpers, so your forms and images and links should all get the proper treatment and their own nicely alphabetized entries in the generated application.css file.

See it in action!

Say you have this view (though let it be known that CSSes scours your helpers, too):

<h1 id="pomp">The Grand Demonstration</h1>
<p class="wing">Super Mario Bros. 3 reference</p>
<%= image_tag('joy.png', :class => 'happy') %>
<%= link_to('Read', {:action => :read, :id => 4}, {:id => 'four'}) %>
<!-- and it works for form tags too -->

Do this:

script/generate csses

And look at that sweet generated application.css:

a {}
a:visited {}
a:hover {}
a:active {}
a#four {}
a#four:visited {}
a#four:hover {}
a#four:active {}
h1 {}
h1#pomp {}
img {}
img.happy {}
p {}
p.wing {}

Get it for yourself:

sudo gem install csses

Comments (4)

CSSes: gem to generate a CSS slate for Rails apps

I try to follow some good guidelines when developing a website. I separate content from style with CSS, for example, by judiciously using class and id attributes for html elements. Of course, I also usually leave the styling until the content has been mostly completed. The problem with that, though, is I end up with many views and many helpers that reference class and id attributes for elements I haven’t styled yet.

So I made CSSes. It searches helpers and views (you’re not putting style information in your controllers or models are you?) for references to html entities, and creates a bare-bones CSS file.

It has a few shortcomings. It doesn’t yet handle link_to* or image_tag or any of the form building methods, just raw referenced html. It’s only Rails 2.0.x friendly so far. It makes just one file, public/stylesheets/application.css, and you can’t control the name. If you use the < character in html attribute values, it will probably make a little noise. It doesn’t have any unit tests.

But! It was sure nice to run after working on a site for a while and finding this waiting for me:

body {}
div {}
div#author_bio {}
div#author_url {}
div#chapbook_exceprt {}
...
div.chapbook_links {}
div.poem_content {}
div.poem_links {}
...
h1 {}
h1#author_name {}
h1#chapbooks_header {}
...

Get it:

sudo gem install csses

Run it:

script/generate css

Any help at all would be greatly appreciated; it’s pretty raw. But I plan on making it more robust and more fun.

Update!: We’ve got tests, automatic anchor tag pseudo-classes, and basic link_to* and image_tag support (figuring out how to handle class and id attributes in rails helpers is a little trickier than I guessed at first). AND: it’s a gem now.

Comments (3)

Merry 1.9.0

According to Matz, Ruby 1.9.0 will be released today (relatively). The expected time is 3pm JST on 12/25, which is 1am EST on 12/25. I’ll be staying up until 11pm MST today (12/24) (where I am), hoping it gets released on time. All incompatibilities with 1.8.6 will be finalized, but it’s not as stable as hoped. Nonetheless, I’m jazzed. I’ve been playing with the 1.9.0 trunk, enjoying the changes and YARV’s speed.

Here’s the bash script I’ve been using to update my 1.9 install (taken mostly from one I saw somewhere, but can’t find now). I’ll probably be using it to keep tracking trunk.

#!/bin/bash
set -e

RUBY19_DIR=~/dev/ruby19

cd ${RUBY19_DIR}

svn up

VERSION=`grep 'RUBY_VERSION '   version.h | awk '{print $3}' | sed -e's/"//g'`
SUFFIX=`grep RUBY_RELEASE_CODE version.h | awk '{print $3}'`

echo "Building ${VERSION}-${SUFFIX}"
./configure --prefix=/usr/local --program-suffix=19 --with-readline-dir=/usr/local
make
sudo make install

exit 0

Comments (1)

« Previous entries · Next entries »