Archive for April, 2008

imenu for Ruby

Tuesday, April 22nd, 2008

If you use ruby-mode, you need to add

(imenu-add-to-menubar "iRuby")

to your .emacs right now.

This adds a menu to the menubar, titled “iRuby”, which lists all the classes and methods.  When you select one, it jumps to that point in the file. If you are a keyboard junkie, you can run M-x imenu and get keyboard completion on any of these.

The downsides of this are:

  • it doesn’t update automatically: you need to choose the “*Rescan*” menuitem
  • it does only simple regexp-based parsing, nests instead of putting more than 25 items in the menu, and various other slightly-annoying things

I started a project, iruby-mode, to be what I was looking for, but since I figured out a 1-line way to get me 85% or 90% of the way there, I have much less incentive to work on this.

ruby-mode.el regexp bug

Tuesday, April 22nd, 2008

ruby-mode.el has a nasty bug: sometimes it won’t recognize the end of a string, so you end up with half your file colored the weird string-color.  Of course, it’s very annoying.

Today, I discovered the cause of this: it happens when your string ends with a “?” and there’s a “‘” earlier in the string.  ruby-mode thinks the ?” is a character literal.  You know, that feature of Ruby which has been used exactly twice in the history of Ruby programming.  *facepalm*

The fix is easy, assuming you never use character literals: open up ruby-mode.el and scroll down to about line 1019:

	  ;; $' $" $` .... are variables
	  ;; ?' ?" ?` are ascii codes
	  ("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil))
	  ;; regexps
	  ("\\(^\\|[=(,~?:;]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)"

Comment out the line that ends (1 . nil)). Recompile the .elc, if you have such a file.

If anybody wants to come up with a fix for this that works for both string and character literals, be my guest. I’m not going to spend any time tweaking 15 lines of Emacs Lisp regexps for some feature I never use.

Thanks to Phil Hagelberg for inspiring me to fix this.

Challenge.find(:all, :conditions => ‘Mortal Kombat’)

Monday, April 21st, 2008

One database query enters the inner loop, and nothing ever leaves.

The challenge is never to use find(:all) for anything for an entire week. This way our database could grow without bounds, we could acquire 10,000 administrators, and our system would still scale. That and, instead of large svn commits each week or so, svn commits daily.

Rails bug?

Friday, April 18th, 2008

I discovered what looks like a bug with has_many :finder_sql.  The docs claim that if you supply :finder_sql and not :counter_sql, it makes the counter by replacing “SELECT * FROM …” with “SELECT COUNT(*) FROM …”.

This does not appear to work if your :finder_sql has a subquery.  To make up a fake example:

class User
    has_many :comments_not_mine,
        :class_name => 'Comment',
        :finder_sql => 'SELECT * FROM comments WHERE user_id != "#{id}" AND EXISTS (SELECT * FROM users)'
end

(The EXISTS part is silly, and just there to show a subquery.)

Now I can say user.comments_not_mine and it works fine, but user.comments_not_mine.count gives an error about the SQL "SELECT COUNT(*) FROM users)". It appears to be using a greedy regexp by mistake. (user.comments_not_mine.to_a.size works fine. It’s just the #count method it adds is trying to be clever, and failing.)

For the life of me, I can’t find it, so: dear lazyweb, please find the offending regexp, so I can write a patch.

Pseudo-English

Thursday, April 17th, 2008

So I came across a feature to implement whose description read “X% of the time, do Y”.  I thought for a second, and then wrote:

class Numeric
  def percent_of_the_time
    yield if rand(100) < self
  end
end

This works great: 15.percent_of_the_time {puts "hello, world"}.

(My unit testing friends are probably freaking out over monkey-patching core classes to be nondeterministic.  Good!)

Then I got to wondering: why can’t I do this in Lisp?  In Arc some things are callable which normally aren’t, but that seems a bit too much like magic to me, and I’m not sure it’s easily extensible to this case.

The problem with making something pseudo-English is that you need to put the noun first, and in Lisp the verb always comes first.

The solution is more obvious than I’d thought: use a library like curly-infix, and then just write a normal function.  Thus, in Lisp, it can be as simple as:

{15 percent-of-the-time (format t "hello, world")}

The only gotcha is that this looks suspiciously like a single-dispatch method call, but if you’re using CLOS generic functions, it’s not.

Ruby Iterators use Indices

Thursday, April 17th, 2008

Yes, they certainly do. Therefore if one tries to iterate through an array like this:

list = [0,1, 2, 3, 4, 5, 6, 7, 8, 9] ; list.each {|entry| list.delete(entry)}

an entry will be deleted and the index will be incremented, of course the index will now point one element too far, since the following elements move up in line. So it takes log n steps to delete a list this way, which is an odd thing to do but comes up during tests. Evidently there is a function Array.delete_if expressly for this purpose, or even Array.delete_all. Evidently I expected ActiveRecord to be behave differently (Model.find(:all).each do) but this was not a correct expectation. Arrays aren’t doubly-linked lists, Ruby isn’t Lisp, etc. Odd that it hadn’t come up before, this is very basic.

Fixed an evil bug; two things I learned

Monday, April 7th, 2008

1. link_to_remote’s :update parameter is the box to put the new object in, not the box to replace

2. If you stupidly have more than one element in your DOM with the same ID (see #1), and ask for it by ID, Firefox 2 takes the last one; Firefox 3, Safari, and Opera all take the first one.

Not knowing these facts can make debugging AJAX code in Rails seriously unfun.  It’s one thing when IE6 screws up your webpage, but when Firefox 2 doesn’t do what you want, it’s like it’s mocking you.

Database queries in Ruby

Sunday, April 6th, 2008

I just ran across Ambition, and it’s the coolest Ruby project I’ve seen in a while.

One of my complaints about Ruby has long been SQL. I’ve never quite been able to quite wrap my head around all of ActiveRecord’s query capabilities, so (unless I’m doing something trivial) I basically have to write an SQL query, and then port it to ActiveRecord. And then, what’s the point? Is a bunch of lines like “:joins => ‘LEFT OUTER JOIN foo ON foo.x_id = bar.id’” really an improvement over just writing straight SQL?

So, depending on how Ambition works, it could be either “even more useless than ActiveRecord” or “the coolest Ruby library ever”. If I still have to think in SQL and mentally convert that to Ambition, there’s no point. But if it can generate reasonable SQL queries for a wide spectrum of cases, given fairly natural Ruby code, this would be awesome.

Definitely a project to watch!