Archive for July, 2007

Playing with Oniguruma

I’ve been busy reading Jeffrey Friedl’s Mastering Regular Expressions and getting a little sad that some of the coolest tricks available are not (yet) available in Ruby. Oniguruma, the regular expression engine coming in Ruby 2.0, is more feature-full and faster than what we have now, and makes whole swaths of Mastering Regular Expressions suddenly relevant. I hear it’s possible to recompile 1.8 to use Oniguruma instead, but I’m not quite ready for that.

I am ready for lookbehind and named captures, though. Thankfully, the Oniguruma gem is available to save me from trying to mess up my Ruby install.

The one unsettling thing about using the Oniguruma gem, though, is how they left String’s match method alone. It’s regexp.match(string) only for these things. Thankfully, that’s easily fixed:

class String

  def o_match(regexp)
    case regexp
    when Oniguruma::ORegexp
      regexp.match(self)
    else
      old_match(regexp)
    end
  end

  alias_method :old_match, :match
  alias_method :match, :o_match

end

Comments (2)

GuessMethod 0.0.5

GuessMethod, the aggressive spell checker for irb, can now be turned off!

Every once in a while, GuessMethod will get in the way. I’m trying to fix that, but in the meantime, you can just set GuessMethod::Options[:active] = false if you need it to leave everything alone for a little while. Just set it back to true when you want it back. This is handy for people (like me, now) who have require 'guessmethod' in their .irbrc (or config/environments/development.rb for Railsers).

And GuessMethod now includes/extends itself in Object when you require it. That happened in 0.0.4.

It’s been interesting to use GuessMethod regularly (especially considering I deemed it a bad idea). Sometimes I see it trying to handle calls I had no idea were being handled by an object’s method_missing.

Give it a shot if you haven’t already:

sudo gem install guessmethod

Comments

GuessMethod 0.0.3

Another release of GuessMethod, the aggressive spell checker for irb!

GuessMethod now handles constants as well, giving you the opportunity for even more non-fatal typos. Prepare for yourself for this magic:

003:0> Strin.tos
attention: replacing non-existant constant Strin with String for Object
attention: sending to_s instead of tos to String:Class
“String”

Enjoy!

Comments (1)

GuessMethod 0.0.2

I am pleased to announce the initial release of GuessMethod (as demonstrated earlier here).

GuessMethod is an aggressive spell checker for irb. It is not for production.

Get it:

sudo gem install guessmethod

Its sole requirement is HighLine.

Thanks to Dr. Nic for telling me to release it and for newgem.

Enjoy!

Comments (11)

An aggressive spellchecker for method calls

GuessMethod is probably a bad idea:

mvb:~ cms$ irb
001:0> load 'mm.rb'
true
002:0> class Object; include GuessMethod; end
Object
003:0> [’1′, ‘2′, ‘3′].mp {|x| x.toi}
attention: sending map instead of mp to [”1″, “2″, “3″]:Array
attention: sending to_i instead of toi to “1″:String
attention: sending to_i instead of toi to “2″:String
attention: sending to_i instead of toi to “3″:String
[1, 2, 3]
004:0> [’1′,’2′,’3′].mp {|x| x.to_}
attention: sending map instead of mp to [”1″, “2″, “3″]:Array
ambiguous method to_, possible matches to_a, to_i, to_s, to_f for “1″:String
NoMethodError: undefined method `to_’ for “1″:String
        from ./mm.rb:9:in `old_method_missing’
        from ./mm.rb:34:in `method_missing’
        from (irb):4
        from ./mm.rb:25:in `map’
        from ./mm.rb:25:in `send’
        from ./mm.rb:25:in `method_missing’
        from (irb):4
        from (irb):3
005:0> eixt
attention: sending exit instead of eixt to main:Object
13 seconds
mvb:~ cms$

It’s using the method_missing pre-handling trick I talked about earlier. It’s nasty. I’m not actually actively using this, but I’ve enjoyed toying around with it.

You can see after line 4 that the ambiguous ‘to_’ gets passed on to String’s method_missing, which would be cool if String had a method_missing that did something interesting. But this is a bad idea anyway. The whole thing is one giant bad idea.

Comments (4)

The least of them: minimum (and maximum) array values (plural!)

Every once in a while, I find myself wanting to do things like this:

017:0> %w(one two four six).find_all_min {|w| w.length}
["one", "two", "six"]
018:0> [3, 2, 1, 3, 1, 1, 3, 2].find_all_max
[3, 3, 3]

I want the values from an array that are the most (or least) of some property. And the array and property are arbitrary. Always.

I know I could just do something like:

009:0> array = %w(1 2 3 3)
["1", "2", "3", "3"]
010:0> max = array.map {|x| x.to_i}.max
3
011:0> array.find_all {|x| x.to_i == max}
["3", "3"]

But it looks clunky to me. What I really want are methods to do that for me, and I want methods that are a little more complicated, and generated via module_eval… and using a Proc. What I want, in short, is this:

module Enumerable
  [[’min‘,’-1‘], [’max‘,’1‘]].each do |name, comparator|

    module_eval %{
      def find_all_#{name}
        block = Proc.new do |object|
          block_given? ? yield(object) : object
        end

        self.inject([]) do |result, element|
          if result.empty?
            result << element
          else
            case block[element] <=> block[result.first]
            when 0
              result << element
            when #{comparator}
              [element]
            else
              result
            end
          end
        end
      end
    }
  end
end

It’s not the best way to handle this situation, but I’m on a metaprogramming diet, because that’s something I don’t have enough practice in. So I’m doing it more than I need to. I’m trying to get a feel of when a Proc is called for (har har). Given the way I’m doing the inject, I feel that the Proc is a good move. Maybe I’m wrong.

Comments

Safely overriding method_missing in a class that already has it

Today I’m making a ridiculous module. Pretty much all it does is override method_missing. There’s a big problem with that, though. What happens when the class you’re including the module in already has method_missing, and you don’t want to mess that up? After a few failed attempts, watching stack levels get too deep, and a little head-scratching, I made this:

module Hero

  def self.included(base)
    base.class_eval do
      unless method_defined? :method_missing
        def method_missing(meth, *args, &block); super; end
      end
      alias_method :old_method_missing, :method_missing
      alias_method :method_missing, :hero_method_missing
    end
  end

  def hero_method_missing(meth, *args, &block)
    if meth.to_s == hero
      Did I ever tell you you’re my #{meth}?
    else
      old_method_missing(meth, *args, &block)
    end
  end

end

There’s my trivial example. Hero is ready to be included in any class, method_missing defined or not. It’ll handle whenever you try to call a method named hero, and pass everything else on to whatever (the class’ original method_missing, or its parent’s method_missing). Now you can ruin ActiveRecord without totally ruining ActiveRecord!

The secret is defining method_missing in the class if it isn’t already, just super, so that the double alias_method is cool.

Take a look at it in action:

mvb:~ cms$ irb
001:0> load 'hero.rb'
true
002:0> class C;def method_missing(meth);"I'm fancy!";end;end
nil
003:0> C.new.hero
"I'm fancy!"
004:0> class C; include Hero; end
C
005:0> C.new.hero
"Did I ever tell you you're my hero?"
006:0> C.new.garbage!
"I'm fancy!"

I promise the actual use is more interesting, though possibly just as useless.

Comments (5)

Modifying regexes

I recently had a very long regular expression that I needed two versions of, one for anywhere and one for just the end of a line. Handled!

RE = /long with a (capture) or (two)/
RE_AT_END = Regexp.new(RE.source + $‘, RE.options)

This even works if the regular expression you’re modifying was created via something like Regexp.compile("(?i-mx:test)"), although it turns out a little ugly. In that case, I might (might) recommend:

Regexp.compile(RE.to_s.sub(/\)$/, $)‘))

Comments (1)

Modules included in a class

Someone over at comp.lang.ruby asked for a way to find out which modules had been included in a class. I guessed that the ancestors method (defined in the Module class) would be the key, and that Array’s select would be the… other key… Huh. Anyway, this does it (assuming a class C):

C.ancestors.select {|a| a.class == Module}

I even posted it as a solution. But what I should have looked closer, because there is exactly a method that does it, and it’s sort of obvious:

C.included_modules

Of course, I don’t know the Module methods by heart, and I had just assumed that he had already looked for something in the documentation.

Moral of the story: Never assume a person asking a question has even so much as tried anything out on irb or looked at the documentation.

Bonus moral: Matz names everything what you would name it (pretty much). You can guess at Ruby methods and get it right an awful lot.

Comments (1)

My .irbrc

I haven’t seen very many .irbrc files lying around on the internet. Examples, sure, I’ve seen examples, but nothing anyone would actually use. Maybe no one has taught me that things like .irbrc files are not interesting. I think they would be. I want to see more.

Here’s mine:

IRB_START_TIME = Time.now

ARGV.concat [ –readline ]

require pp
require rubygems
require duration
require wirble
require irb/completion
require irb/ext/save-history

IRB.conf[:PROMPT][:SHORT] = {
  :PROMPT_C=>”%03n:%i* “,
  :RETURN=>”%sn“,
  :PROMPT_I=>”%03n:%i> “,
  :PROMPT_N=>”%03n:%i> “,
  :PROMPT_S=>”%03n:%i%l 
}

IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = #{ENV[’HOME’]}/.irb-save-history
IRB.conf[:PROMPT_MODE] = :SHORT

Wirble.init(:skip_prompt => true, :skip_history => true)
Wirble.colorize

at_exit { puts Duration.new(Time.now - IRB_START_TIME) }

def clear
  print e[He[2J
end

A couple of notes:

  1. Wirble colorizes return values in irb, and does a pretty good job at it. It also changes the prompt and the behavior of irb’s history in ways I don’t like; the Wirble.init line takes care of those problems.
  2. I was always trying to clear the screen with clear. I had to make it happen on my own. If I could suppress the nil that gets displayed afterwards, I would.
  3. The short prompt I make there is sort of a halfway between the standard prompt irb(main)001:0> and the simple prompt >>. I want line numbers and indent levels! I want to know where I am.
  4. I also want to know when I am. So I set IRB_START_TIME and use the Duration gem and at_exit to tell me how long my irb sessions are. It is totally worthless, but I love it. It makes me feel productive. Have a look:
mvb:~ cms$ irb
001:0> "wait a minute"
wait a minute
002:0> exit
20 seconds
mvb:~ cms$

I couldn’t wait a full minute.

Comments (2)