hoodwink.d enhanced
RSS
2.0
XHTML
1.0

RedHanded

Thin Strand of Search-and-Replace Rails #

by why in inspect

If you’re playing with Rails and you want to better understand Ruby blocks, as well as method chaining, Matthew Bohnsack has a great one-liner, which boils to:

  Article.find_all.each { |a| a.body.gsub! \
    /src="\/(.*.(jpg|gif|png))/, 'src=\"http://bohnsack.com\1';
    a.save }

More like three or four lines, but still. He breaks it up, explains each part, with short paragraph-long lessons. I like how code like the above has the feeling of a sed recipe, but isn’t utterly cryptic.

said on

For me, the lack of parentheses in the gsub! call makes this harder to parse.

I prefer to drop parentheses when:
  • there’s no or only one argument
  • I want to pretend that it’s not a method call (when using some DSL ).
I also dislike things like
def somemeth bla, blerg, foo = 1, *bar

Anyway this is not a particularly enticing example of method chaining, is it?

said on
That looks like some ancient AR code ;) I rather like (newlines inserted to fit in the box):

Article.find(:all).each {|a| 
  a.update_attribute(:body, a.body.gsub())
}
Or if you were doing some operation you weren’t sure would be a success:

Article.find(:all).select {|a| 
  a unless a.update_attribute(:foo, 'bar')
}
Which would hand you any articles where the update failed.
said on

Woops, the ‘a unless’ part is not necessary. I should not reply before I’ve had my coffee :(

said on

Thanks for the linkage and the suggestions – update_attribute seems the way to go.

I was just geeked that I got it to work, not really knowing what I was doing. The statement I created was mostly a result of bouncing on the tab key in irb, picking methods that looked good, looking at their inspect output, and then repeating a few times until everything worked.

This seems an important part of the reason why Ruby and the Rails framework are so powerful. Lots of stuff works like you intuitively expect it to.

said on

If someone wants to explain yet another nifty piece of Ruby code: Quicksort by Tony Hoare at www.approximity.com/rubybuch2/node8_main.html . (I still cannot completely make out the data flow in this script, esp. the nested sorting issue, e.g. how & why [-1, -3.4, ...] would become [-3.4, -1, ...])

said on

def quicksort( xs ) return xs if xs.size <= 1 m = xs0 # Split-Element quicksort(xs.select { |i| i < m } ) + xs.select { |i| i == m } + quicksort(xs.select { |i| i > m } ) end

line by line:


  return xs if xs.size <= 1

If the size is 1 or 0, we just return the array; it’s already sorted


  m = xs[0]

Here we choose an arbitrary “pivot” element. This can be any element of the array. In this case we choose the first.


  quicksort(xs.select { |i| i < m } ) +
     xs.select { |i| i == m } +
     quicksort(xs.select{ |i| i > m } )

This is a little more complicated. First, let’s figure out what those selects do. The first one selects all elements less than the pivot. The second selects all elements equal to the pivot. The final one selects all elements greater than the pivot. Let’s modify this and use some temp variables.


  less = xs.select { |i| i < m }
  equal = xs.select { |i| i == m }
  more = xs.select { |i| i > m }

  quicksort( less ) + 
    equal + 
    quicksort( more ) )

In other words, we’re returning a list of all the elements less than the pivot, sorted, then all those equal, then all those greater, sorted. This is classic divide-and-conquer recursion. Quicksort is applied to ever smaller lists until we use it on lists of one or zero elements, and we hit the terminating condition.

OK, I’m not sure if that helped at all :)

said on

Oops, messed up the formatting on that first bit.


def quicksort( xs )
   return xs if xs.size <= 1
   m = xs[0] # Split-Element
   quicksort(xs.select { |i| i < m } ) +
     xs.select { |i| i == m } +
     quicksort(xs.select { |i| i > m } )
end

said on

Wow, thanks Matt for this ultra quick response! Great going!

said on

Hehe, it’s funny how this definition of quicksort is a direct translation of how one would write it in functional languages like Haskell. It’s one of the strengths of Ruby that it supports all programming styles (structured, object-oriented, functional, you name it) without ever having to resort to ugly hacks :) .

said on

To get a handle on the data flow you also can insert: puts i < m etc. or just after def quicksort(xs): puts xs.size; print xs; print ”\n”.

said on

The internal sorting of the array of numbers contained in the less and more temp variables is accomplished by the nested quicksort(xs.select…)functions. Each of these functions has the return-if condition but sets its own m=xs(0) pivot element! (The functions can be called nested because they are enclosed in def quicksort(xs)...end)

Comments are closed for this entry.