Fork me on GitHub

Links dump

I don't have time to write another big post so I have decided to post several interesting links.

You can use great Copy as RTF TextMate plugin by Dr. Nick If you want to insert highlighted code samples in you Keynote presentation. It allows you to copy code with highlighting from TextMate and paste it directly into the slides.

If you are using Ruby check out slides by Michael Klishin about Rspec patterns shmatterns. We are using all described techniques at Orwik.

Great blog post monoids in Haskell from A Neighborhood of Infinity. Describes Monoids and how to use them with Writer and State monads.

select * from depesz; is a very interesting blog about Postgresql RDBMS. It have posts about new Postgres features and useful tips.

Posted at 14PM on 11/29/09 | 0 comments | Filed Under: | read on

Ruby DSL and instance_eval

Showing Sunspot library to different people I have noticed their confusion about Sunspot search API. Sunspot provides the following API for search

search = Sunspot.search(Post) do
  keywords "Mark Twain"
end

And all rails developers try to do the following in the first place

class SearchController < Application
  def index
    @search = Sunspot.search(Post) do
      keywords params[:q]
    end
  end
end

Pretty obvious, huh? But they are facing the problem, cause this code throws an exception

 undefined method 'params' for <Sunspot::Query>

Some of them are trying to do the following:

def index
  query_string = params[:q]

  @search = Sunspot.search(Post) do
    keywords query_string
  end
end

And everything works as expected. At this place many of them are starting to understand what Sunspot uses instance_eval to provide this nice DSL.

instance_eval allows you to execute the block of the code in context of any object. In context means if you do

@object.instance_eval { puts self }

self in the block will be an @object itself.

Back to our sunspot problem. params in Rails is actually a method on ActiveController::Base so instance_eval on Suspot::Query object doesn't have it. The code with the local variable (2nd variant) is working because you have access to all variables deined in its lexical scope.

What to do with this "problem"? The idea was to catch the object in which the block was created and pass it to Query. Query is implementing method_missing with fallback to the caught object. Everything is working working as expected. But we have 2 new problems.

  • How to get the caller object?
  • What to do if the method is not found neither in Query nor in caller object?

I've found the answer to the first question inside the ruby Kernel#eval docs. Kernel#eval accepts the special object of class Binding which incapsulates the execution context at some place in the code (sounds like a continuation? yep) or objects of class Proc. (In Ruby 1.9 API has changed and Kernel#eval accepts only objects of class Binding).

Actualy blocks are the objects of class Proc (lambdas are Procs too). But I recommend to pass binding to keep compatibility with Ruby 1.9. Luckily for us there is a method Proc#binding which does the thing you expect. How to get required object from Proc and eval? Really simple:

eval 'self', block.binding

The second question is open for discussion.

Now we know enough to implement "smart" instance_eval which can try to find missing methods in context in which block was created.

def self.search_with_context(&blk)
  caller = eval('self', blk.binding)

  QueryWithContext.new(caller).tap do |query|
    query.instance_eval(&blk)
  end
end

Look in the sources on Github for full implementation.

Posted at 21PM on 11/12/09 | 0 comments | Filed Under: | read on

ZenTest autotest и Mac OS X Leopard.

Вернемся к используемым инструментам. Для запуска тестов и спек я снова начал активно использовать autotest. Отказаться от него пришлось из-за того, что для определения того, что какие-то файлы в рабочей папке обновились, он использовал polling. Т.е. с огромной скоростью снова и снова опрашивал файловую систему на предмет обновления файлов, что на медленном диске в ноутбуке здорово замедляло работу всех программ.

Но спасибо хорошим разработчикам из Apple, которые в леопарде добавили API для работы с файловой системой через события (FSEvents). Благодаря им и Свену Швину (Sven Schwyn), который написал расширение autotest-fsevent. Оно учит autotest использовать FSEvents вместо постоянного опроса файловой системы.

Чтобы активировать это полезный функционал вам понадоббится Mac OS X Leopard. Устанавливаете гем

sudo gem install autotest-fsevent

Затем добавляете в файл ~/.autotest

require 'autotest/fsevent'

И радуетесь вернувшейся производительности.

Прочитать больше можно в блоге Свена.

Posted at 19PM on 06/11/09 | 3 comments | Filed Under: | read on

Ruby loves PageRank

Довел до ума обещанный PageRank на Ruby. Забрать можно из моего гит репозитория. Код закомментирован, примеры использования в тестах. Тесты и идея взяты из этой статьи.

В кратце можно описать алгоритм так:

  1. Пусть у нас есть n страниц, на каждой из которых Ij ссылок. Мы хотим оценить некую "важность" страницы, с помощью которой можно было бы сказать, какая страница "авторитетнее", на основе количества ссылок на эту статью и "важности" страниц, с которых ведут ссылки. Важность и обзовем словом PageRank.
  2. Предположим, что если страница j ссылается на страницу i, то она отдает ей 1/|Ij| своей "важности".
  3. Составляем матрицу ссылок следующим образом: в клетке Si,j стоит число 1/|Ij|, если на j-ой странице есть ссылка на i-ую, 0 в противном случае.
  4. У нас получается квадратная матрица, в которой по диагонали стоят нули, а сумма всех чисел в столбце равняется единице.
  5. Чтобы посчитать "важность" каждой страницы необходимо найти собственный вектор V полученой матрицы H, соответствующий собственному значению 1. Vi — важность страницы i. Для этого воспользуемся простейшим итерационным методом.
  6. В данном решении возникают проблемы, типа висячей страницы, которая не ссылается ни на какие другие. Такая страница перетягивает на себя всю "важность" страниц, которые на нее ссылаются. Для этого мы интерпретируем H в вероятностном аспекте, о чем говорится в статье. Также в ней рассматриваются другие проблемы. Для понимания процесса рекомендую с ней ознакомится.

Комментарии и дополнения к коду приветствуются.

Posted at 19PM on 02/16/08 | 3 comments | Filed Under: | read on

Gruff на Mac OS X без RMagick

Для работы библиотеки Gruff нужен RMagick. Если вы пытались поставить RMagick на Mac OS X, то наверное представляете, насколько это сложный процесс. Но сегодня нашлось другое решение: использовать бридж Ruby/Cocoa и генерировать картинки с помощью встроенной в макось графической подсистемы.

  1. Для начала вам понадобится сам бридж. Для Mac OS X 10.4 брать на сайте. Рекомендую скачать и собрать руками, т.к. вы наверняка используете собственную версию руби (компилить с --enable-shared), а не из стандартной установки, а бинарники скомпилены для стандартной). Для Леопарда ничего качать на этом шаге не нужно, потому что Ruby/Cocoa уже стоит.
  2. Теперь вам понадобится библиоткеа отсюда, которую надо служить куда-нибудь, где руби ищет библиотеки, например в /usr/local/lib/ruby/ruby_site/1.8/. Обратите внимание, что в комментариях есть ссылка на обновленную версию.
  3. Можно ставить gruff через RubyGems или как вам удобно sudo gem install gruff
  4. Далее идем редактировать файл /usr/local/lib/ruby/gems/1.8/gems/gruff-0.2.9/lib/gruff/base.rb Меняем в нем require 'RMagick' На require 'CocoaMagick'

Вот и все. Gruff работает через какаву.

Posted at 15PM on 02/07/08 | 0 comments | Filed Under: | read on

autotest

Если вы пишете для своего кода на Ruby тесты либо спеки, то вам непременно пригодится autotest из гема ZenTest. Эта утилита запускается из корня проекта и следит за изменениями в тестах/спеках. Если таковые имеются, то она запускает только эти измененные файлы. За счет этого достигается скорость тестирования (прогонять переиодически кучу тестов — не быстрое занятие), и мы всегда знаем, когда у нас что-то сломалось.

Для этой утилиты существует плагин RedGreen, который подсвечивает зеленым или красным результаты прогона тестов, дабы одного взгляда хватило, чтобы увидеть ситуацию. Однако этот плагин не работает при тестирвоании спек, так как у них отличается формат вывода сообщения об ошибках. Если поместить следующий код в файл .autotest в вашем корневом каталоге или в каталоге с проектом, откуда запускаем тесты, то все будет работать как хочется.


  module Autotest::RedGreen
    BAR = "=" * 80

    Autotest.add_hook :ran_command do |at|
      # was     if at.results.last =~ /^.* (\d+) failures, (\d+) errors$/
      # changed because if we have pendings, output will look like "5 examples, 1 failure, 2 pending"
      # and this condition will not work
      if at.results.last =~ /^.* ((\d+) failures?|(\d+) errors?)/
        code = ($2 != "0" or (not $3.nil? && $3 != "0")) ? 31 : 32
        puts "\e[#{code}m#{BAR}\e[0m\n\n"
      end
    end
  end
Posted at 12PM on 01/11/08 | 0 comments | Filed Under: | read on

Rails 2.0 уже рядом

Вышла превью версия рельсов 2.0. Подробности позже

Posted at 05AM on 10/01/07 | 0 comments | Filed Under: | read on

About

Hi. My name is Dmitriy, i am a student from Vladivostok, Russia. This is my blog about web development and relative things.

I am interested in functional languages, especially Haskell and Common Lisp, Ruby, Ruby on Rails, Perl and other interesting topics. I don't like C plus plus, Java and Pascal.


Немного о

Привет. Меня зовут Дмитрий, я студент из Владивостока. Вы читаете мой блог о разработке сайтов и прочих подобных штуках.

Categories