<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">

 <title>avsej: developer's blog</title>
 
 <link href="http://avsej.net/" />
 <updated>2011-05-08T00:00:00-07:00</updated>
 <id>http://avsej.net/</id>
 <author>
   <name>Sergey Avseyev</name>
   <email>sergey.avseyev@gmail.com</email>
 </author>

 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/avsej" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="avsej" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
   <title>Обновление rake-тасков</title>
   <link href="http://avsej.net/2011/enhancing-rake-tasks/" />
   <updated>2011-05-08T00:00:00-07:00</updated>
   <id>http://avsej.net/2011/enhancing-rake-tasks/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://avsej.net/2011/enhancing-rake-tasks/"&gt;Обновление rake-тасков&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;В одном проекте мне понадобился &lt;a href="http://www.complang.org/ragel"&gt;ragel&lt;/a&gt; для разбора формул из TeX и, так как проект является гемом с нативной библиотекой, он должен ещё компилироваться при установке. Для облегчения сборки я использую &lt;a href="https://github.com/luislavena/rake-compiler"&gt;rake-compiler&lt;/a&gt;, который предоставляет набор тасков для сборки каждого расширения + таск &lt;code&gt;compile&lt;/code&gt;, что бы собрать все сразу. Проблема была в том, чтобы встроить в эту цепочку ещё один мини-таск, который бы генерировал парсер из ragel-исходника.&lt;/p&gt;

&lt;p&gt;Одни для этого &lt;a href="https://github.com/aslakhellesoy/gherkin/blob/master/tasks/ragel_task.rb#L13"&gt;создают отдельные таски&lt;/a&gt; как gherkin, а другие &amp;mdash; &lt;a href="https://github.com/defunkt/unicorn/blob/master/GNUmakefile#L58"&gt;используют gnu makefile&lt;/a&gt; как unicorn. Мне оба способа показались громоздкими, к тому же у меня уже есть таск &lt;code&gt;compile&lt;/code&gt; и заводить ещё один, который будет вызывать &lt;code&gt;ragel&lt;/code&gt;, а потом &lt;code&gt;compile&lt;/code&gt; было бы слишком. В &lt;a href="http://rake.rubyforge.org/classes/Rake/Task.html#M000112"&gt;документации rake&lt;/a&gt; нашлась отличный метод &lt;code&gt;Task#enhance&lt;/code&gt;, позволяющий добавить зависимости в уже существующий таск, но для меня этого было недостаточно, потому что, судя по коду, он добавляет таск в конец цепочки зависимостей, а мне нужно сгенерировать парсер &lt;em&gt;перед&lt;/em&gt; компиляцией. Выход нашёлся сразу же: использовать &lt;code&gt;Task#prerequisites&lt;/code&gt; (который ведёт себя как массив) и просто добавить мой мини-таск в самое начало. Ниже то, что получилось в итоге:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'rake/extensiontask'
Rake::ExtensionTask.new('expression_ext')
rule 'ext/expression_ext/parser.c' =&amp;gt; 'ext/expression_ext/parser.c.rl' do |task|
  sh %{ragel -C -o #{task.name} #{task.source}}
end
Rake::Task['compile'].prerequisites.unshift('ext/expression_ext/parser.c')
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Ссылки&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="http://www.complang.org/ragel"&gt;Ragel state machine compiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/luislavena/rake-compiler"&gt;rake-compiler&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/uoPCgi8rSnU" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>RSpec metadata trick</title>
   <link href="http://avsej.net/2011/rspec-metadata-trick/" />
   <updated>2011-03-11T00:00:00-08:00</updated>
   <id>http://avsej.net/2011/rspec-metadata-trick/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://avsej.net/2011/rspec-metadata-trick/"&gt;RSpec metadata trick&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;RSpec is absolutely flexible tool. One of its multitarget features is &lt;a href="https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/metadata.rb"&gt;metadata&lt;/a&gt;. The main purpose of this feature is filtering and groupping examples by given attributes. You can found a lot of examples in article &lt;a href="http://blog.davidchelimsky.net/2010/06/14/filtering-examples-in-rspec-2/"&gt;&amp;ldquo;Filtering examples in rspec-2&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recently I was faced with the need to test application behaviour depending on current subdomain. It was a group of examples so I need to use filters. Spec was similar to script below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;feature "On custom subdomain", :subdomain =&amp;gt; 'custom' do
  scenario "homepage should change colorscheme to blue and use custom logo" do
    ...
  end

  scenario "about us page should show custom contact info" do
    ...
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It also need to configure that filter in &lt;code&gt;spec_helper.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;RSpec.configure do |config|
  config.around(:each, :subdomain =&amp;gt; 'custom') do |example|
    Capybara.default_host = "custom.example.com"
    Capybara.current_session.reset!
    example.run
    Capybara.default_host = nil
    Capybara.current_session.reset!
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But what if we need to take into account particular subdomain name wich could be changed for another group. Here is that litle trick: RSpec hook conditions accept not only plain values. To solve our problem we need to change only two lines:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  config.around(:each, :subdomain =&amp;gt; /[\w-]+/) do |example|
    Capybara.default_host = "#{example.metadata[:subdomain]}.example.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code means that we looking for examples or example groups with key &lt;code&gt;:subdomain&lt;/code&gt; and value matching &lt;code&gt;/[\w-]+/&lt;/code&gt;. To see how it works let see &lt;code&gt;RSpec::Core::Metadata#apply_conditions&lt;/code&gt;. It has special handling for &lt;code&gt;Hash&lt;/code&gt;, &lt;code&gt;Regexp&lt;/code&gt;, &lt;code&gt;Proc&lt;/code&gt; and &lt;code&gt;Fixnum&lt;/code&gt;. So you can even use &lt;code&gt;:dup.to_proc&lt;/code&gt; as a filter condition.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/b4TvqBfOatM" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Калькулятор в XeLaTeX</title>
   <link href="http://avsej.net/2011/xelatex-calculator/" />
   <updated>2011-03-08T00:00:00-08:00</updated>
   <id>http://avsej.net/2011/xelatex-calculator/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://avsej.net/2011/xelatex-calculator/"&gt;Калькулятор в XeLaTeX&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;В течении ближайших нескольких месяцев я готовлюсь к защите диломного проекта. Один из разделов пояснительной записки называется &amp;ldquo;Технико-экономическое обоснование бла-бла-бла&amp;rdquo;. Там очень много всяких экономических формул, которые достаточно сильно связаны, но в общем расчёт представляет собой последовательную подстановку исходных значений в формулы. Обычно расчёт делают отдельно с помощью электронных таблиц, а потом переписывают значения в пояснительную записку. В реальности, при объёме раздела примерно 20 страниц и неизбежных исправлениях, возникает много монотонной переписывания, при котором легко допустить ошибку.&lt;/p&gt;

&lt;p&gt;Свою пояснительную записку я верстаю с помощью &lt;a href="http://en.wikipedia.org/wiki/XeTeX"&gt;XeLaTeX&lt;/a&gt;, для которого существует просто &lt;a href="http://www.ctan.org"&gt;огромное количество макропакетов&lt;/a&gt;. Xe(La)TeX полностью поддерживает синтаксис LaTeX плюс реализует очень хорошую поддержку системных шрифтов через &lt;a href="http://ctan.org/pkg/fontspec"&gt;fontspec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Я решил, что среди этого огромного количества пакетов должен быть хотябы один для расчётов внутри документа. И я не ошибся, почти сразу нашел пакет &lt;a href="http://www.ctan.org/tex-archive/macros/latex/contrib/fp/"&gt;fp&lt;/a&gt;. По ссылке можно прочитать достаточно подробное описание работы с ним, здесь я просто хочу показать минимальный рабочий пример, демонстрирующий его работу.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;\documentclass{article}
\usepackage{xunicode}
\usepackage{xltxtra}
\usepackage{graphicx}
\defaultfontfeatures{Mapping=tex-text}
\usepackage{polyglossia}
\setdefaultlanguage{english}

\usepackage{fp}

\begin{document}

\FPeval{x}{round((4 * sin(3 * 3.14)):2)}
\FPupn{y}{x 5 / 2 round}

$$ x = 4 \cdot sin(3\pi) = \x $$
$$ y = \frac{5}{x} = \frac{5}{\x} = \y $$

\end{document}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Этот код сгенерирует вот такой документ.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://files.avsej.net/assets/xelatex-calc.png" alt="Встроенные вычисления в XeLaTeX" /&gt;&lt;/p&gt;

&lt;p&gt;Как видно из примера, пакет &lt;a href="http://www.ctan.org/tex-archive/macros/latex/contrib/fp/"&gt;fp&lt;/a&gt; позволяет записывать вычисления как инфиксной, так и в постфиксной нотации. Надеюсь эта заметка вам пригодится.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/JVYz2QEpbVI" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Feature branch code reviews</title>
   <link href="http://avsej.net/links/2011/feature-branch-code-reviews/" />
   <updated>2011-02-18T00:00:00-08:00</updated>
   <id>http://avsej.net/links/2011/feature-branch-code-reviews/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://robots.thoughtbot.com/post/2831837714/feature-branch-code-reviews/"&gt;Feature branch code reviews&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;Great article about coding workflow from &lt;a href="http://thoughtbot.com/" title="Thoughbot"&gt;Thoughbot&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;  Here&amp;rsquo;s the flow. Read &lt;a href="http://blog.hasmanythrough.com/2008/12/18/agile-git-and-the-story-branch-pattern" title="Josh Susser's post"&gt;Josh Susser&amp;rsquo;s post&lt;/a&gt;. for the git commands.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Start a user story.&lt;/li&gt;
&lt;li&gt; Code the feature.&lt;/li&gt;
&lt;li&gt; Push the feature to a branch.&lt;/li&gt;
&lt;li&gt; A Github hook starts a CI build.&lt;/li&gt;
&lt;li&gt; A Github Campfire hook posts your work to Campfire.&lt;/li&gt;
&lt;li&gt; Click the link that’s in Campfire.&lt;/li&gt;
&lt;li&gt; Click the Github “Pull Request” button.&lt;/li&gt;
&lt;li&gt; It will smartly select all commits in your branch that are not in master.&lt;/li&gt;
&lt;li&gt; Create the pull request.&lt;/li&gt;
&lt;li&gt; Ask your team in Campfire for a review of the pull request.&lt;/li&gt;
&lt;li&gt; The team comments in-line, right on the code.&lt;/li&gt;
&lt;li&gt; Make the suggested changes.&lt;/li&gt;
&lt;li&gt; Merge into master.&lt;/li&gt;
&lt;li&gt; Push to master.&lt;/li&gt;
&lt;li&gt; CI runs again.&lt;/li&gt;
&lt;li&gt; Deploy to staging.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/pktd-1_oLfk" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>ruby 1.9.2 and rails 2.3 bootstrap</title>
   <link href="http://avsej.net/2010/ruby-192-rails-23-bootstrap/" />
   <updated>2010-11-07T00:00:00-07:00</updated>
   <id>http://avsej.net/2010/ruby-192-rails-23-bootstrap/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://avsej.net/2010/ruby-192-rails-23-bootstrap/"&gt;ruby 1.9.2 and rails 2.3 bootstrap&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;When I tried to launch console in rails 2.3.5 project with ruby 1.9.2 I&amp;rsquo;ve got nasty error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# ruby1.9.2 script/console
&amp;lt;internal:lib/rubygems/custom_require&amp;gt;:29:in `require': no such file to load -- script/../config/boot (LoadError)
  from &amp;lt;internal:lib/rubygems/custom_require&amp;gt;:29:in `require'
  from script/console:2:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lets look at this file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/env ruby
require File.dirname(__FILE__) + '/../config/boot'
require 'commands/console'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As ruby 1.9.2 changelog states &lt;code&gt;$: no longer includes the current directory, use require_relative&lt;/code&gt;
I tried this command but it failed too:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# ruby1.9.2 script/console
script/console:2:in `require_relative': no such file to load -- /root/code/ruby/testproject/script/config/boot (LoadError)
  from script/console:2:in `&amp;lt;main&amp;gt;'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So the solution was to expand path manually and then require it in usual way&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/env ruby
require File.expand_path(File.dirname(__FILE__) + '/../config/boot')
require 'commands/console'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This manipulations need to be applied for all scripts.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/kfiUI2a3cFA" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>CI: integrity with resque</title>
   <link href="http://avsej.net/2010/ci-integrity-with-resque/" />
   <updated>2010-09-30T00:00:00-07:00</updated>
   <id>http://avsej.net/2010/ci-integrity-with-resque/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://avsej.net/2010/ci-integrity-with-resque"&gt;CI: integrity with resque&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;Я думаю, что в каждой команде в процессе разработки рано или поздно встаёт вопрос о настройке &lt;a href="http://en.wikipedia.org/wiki/Continuous_Integration"&gt;continuous integration&lt;/a&gt;. Для руби-проектов существует много инструментов и по статистике &lt;a href="http://ruby-toolbox.com/categories/continuous_integration.html"&gt;ruby toolbox&lt;/a&gt; наибольшей популярностью пользуются &lt;a href="http://github.com/defunkt/cijoe"&gt;cjoe&lt;/a&gt;, &lt;a href="http://github.com/integrity/integrity"&gt;integrity&lt;/a&gt; и &lt;a href="http://github.com/thoughtworks/cruisecontrol.rb"&gt;cruisecontrol.rb&lt;/a&gt;. Раньше мы использовали cruisecontrol.rb, но на текущем проекте решили попробовать что-нибуть альтернативное, отчасти потому, что cruisecontrol.rb достаточно достаточно сложно настраивать, там отсутствуют web-hooks для github, а так же он периодически у нас зависал. Сначала я решил попробовать cijoe, который достаточно прост, но не подошел тем, что для каждого бранча нужно было поднимать отдельный экземпляр приложения, а CI у нас планировалось запускать на одном из development серверов.&lt;/p&gt;

&lt;p&gt;В итоге выбор пал на integrity. Посмотреть его в действии можно на &lt;a href="http://builder.integrityapp.com/"&gt;http://builder.integrityapp.com&lt;/a&gt;. Это простой в установке и использовании сервис. Написан на &lt;a href="http://www.sinatrarb.com/"&gt;sinatra&lt;/a&gt; и легко устанавливается в окружении, позволяющем запуск rack приложений. Внутри integrity очень простой, но в тоже время функциональный. Он предоставляет несколько механизмов уведомления: email, IRC, &lt;a href="http://campfirenow.com/"&gt;campfire&lt;/a&gt;, TCP, HTTP, &lt;a href="http://notifo.com/"&gt;notifo&lt;/a&gt; and &lt;a href="http://www.amqp.org"&gt;AMQP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Build можно запустить несколькими способами:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;сделать HTTP POST request по адресу &lt;code&gt;/:project/builds&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;настроить github &lt;a href="http://help.github.com/post-receive-hooks/"&gt;post receive hook&lt;/a&gt; на адрес &lt;code&gt;/github/:token&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;нажать кнопку &amp;ldquo;Fetch and build&amp;rdquo; на web-интерфейсе integrity;&lt;/li&gt;
&lt;li&gt;создать собственный скрипт и запускать его через cron. Этот способ зависит от того, какой builder вы используете.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;И, наконец, integrity позволяет механизм постановки в очередь и запуска заданий:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://github.com/integrity/integrity/blob/master/lib/integrity/threaded_builder.rb"&gt;threaded&lt;/a&gt; &amp;mdash; integrity создаёт пул потоков и запускает тесты параллельно. Я думаю тут нужно учитывать, что это зелёные потоки ruby, которые на самом деле запускаются в одном системном.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/integrity/integrity/blob/master/lib/integrity/delayed_builder.rb"&gt;delayed&lt;/a&gt; &amp;mdash; в этом случае, integrity использует &lt;a href="http://github.com/collectiveidea/delayed_job"&gt;delayed_job&lt;/a&gt; в качестве back-end. Для работы этого метода нужно включить &lt;a href="http://github.com/integrity/integrity/blob/81f46d7325e7244a847dadda46a6659cfbc826bb/Gemfile#L36"&gt;дополнительные зависимости в Gemfile&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/integrity/integrity/blob/master/lib/integrity/resque_builder.rb"&gt;resque&lt;/a&gt; &amp;mdash; этот метод я выбрал как наиболее безглючный и простой в настройке. &lt;a href="http://github.com/defunkt/resque"&gt;Resque&lt;/a&gt; &amp;mdash; это библиотека, написанная на ruby, для работы с фоновыми задачами. Resque использует &lt;a href="http://code.google.com/p/redis"&gt;redis&lt;/a&gt; в качестве хранилища, а так же предоставляет front-end на sinatra для мониторинга очередей.  Очереди в resque могут быть распределены между несколькими хостами. Подробнее можно прочитать в файле &lt;a href="http://github.com/defunkt/resque/blob/master//README.markdown"&gt;README из репозитория&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Настройка&lt;/h2&gt;

&lt;p&gt;Так как мы используем ubuntu на сервере, некоторые команды ниже могут быть специфичны для этой системы, но я
думаю будет не сложно найти аналогичные для вашей. Для начала нужно установить и настроить resque.&lt;/p&gt;

&lt;p&gt;Устанавливаем redis. При этом redis должен создать стартовый скрипт в &lt;code&gt;/etc/rc.*&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# apt-get install redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Далее устанавливаем resque:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# gem install resque
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Теперь настроим front-end для него. Мы используем nginx и passenger для запуска rack/rails приложений, так что дальше следует типичная настройка rack приложения для passenger (подробнее можно &lt;a href="http://www.modrails.com/documentation/Users%20guide%20Nginx.html#deploying_a_rack_app"&gt;прочитать в официальной документации&lt;/a&gt;).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# mkdir -p /home/deploy/resque/public
# mkdir -p /home/deploy/resque/tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Пример файла &lt;code&gt;/home/deploy/resque/config.ru&lt;/code&gt; можно взять в &lt;a href="http://github.com/defunkt/resque/blob/master/config.ru"&gt;репозитории resque&lt;/a&gt;. Мы используем такой:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'logger'

$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/lib')
require 'resque/server'

use Rack::ShowExceptions

Resque::Server.use Rack::Auth::Basic do |username, password|
  password == 'secret' &amp;amp;&amp;amp; username = 'admin'
end

run Resque::Server.new
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Тут вы можете защитить паролем ваш сервер. В nginx нужно добавить еще одну секцию &lt;code&gt;server&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  listen   80;
  server_name  resque.example.com;
  root /home/deploy/resque/public;
  passenger_enabled on;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;И после этого можно зайти на front-end в браузере и проверить, что всё ок.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://files.avsej.net/assets/resque.png" alt="Мониторинг очередей resque" /&gt;&lt;/p&gt;

&lt;p&gt;Дальше установим и настроим integrity:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# cd /home/deploy
# git clone git://github.com/integrity/integrity.git
# cd integrity
# mkdir -p tmp/pids
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Чтобы включить resque backend для integrity нужно раскоментировать соответствующую строку в &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem "resque"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Для nginx нужно добавить новую секцию &lt;code&gt;server&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  listen 80;
  error_log  logs/integrity.error.log info;
  server_name integrity.example.com;
  passenger_enabled on;
  root /home/deploy/integrity/public;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Мы используем следующий конфиг для integrity:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))

require ".bundle/environment"
require "integrity"
require "integrity/notifier/email"

Integrity.configure do |c|
  c.database = "sqlite3:integrity.db"
  c.directory = "builds"
  c.base_url = "http://integrity.example.com"
  c.log = "integrity.log"
  c.github_token = "YOUR_SECRET_GITHUB_TOKEN"
  c.build_all = true
  c.builder = :resque
  c.auto_branch = false
  c.username = "admin"
  c.password = "secret"
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Теперь осталось только запустить resque worker:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# rake resque:work
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Только скорее всего эта команда у вас не запустится, потому что в integrity есть &lt;a href="http://github.com/integrity/integrity/issues/#issue/86"&gt;небольшой баг&lt;/a&gt; в &lt;code&gt;Rakefile&lt;/code&gt; и, я надеюсь, что его скоро исправят. Если нет, то попробуйте вот этот патч:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;diff --git a/Rakefile b/Rakefile
index e384f82..4af7479 100644
--- a/Rakefile
+++ b/Rakefile
@@ -53,11 +53,11 @@ end

begin
  namespace :resque do
+    require "init"
    require "resque/tasks"

    desc "Start a Resque worker for Integrity"
    task :work do
-      require "init"
      ENV["QUEUE"] = "integrity"
      Rake::Task["resque:resque:work"].invoke
    end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;В github нужно добавить post-receive hook, чтобы тесты запускались каждый раз, когда кто-нибудь заливает новый код. Адрес должен быть в формате &lt;code&gt;http://username:password@integrity.example.com/github/:github_token&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ещё можно настроить &lt;a href="http://mmonit.com/monit"&gt;monit&lt;/a&gt; для мониторинга integrity workers. Пример конфигурации
которую мы используем &lt;code&gt;/etc/monit/conf.f/resque&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;check process resque_worker_integrity
  with pidfile /home/deploy/integrity/tmp/pids/resque_worker_integrity.pid
  start program = "/bin/sh -c 'cd /home/deploy/integrity; COUNT=1 QUEUE=integrity VERBOSE=1 nohup /opt/ruby-enterprise/bin/rake resque:work&amp;amp; &amp;gt; log/resque_worker_integrity.log &amp;amp;&amp;amp; echo $! &amp;gt; tmp/pids/resque_worker_integrity.pid'" as uid deploy and gid deploy
  stop program = "/bin/sh -c 'cd /home/deploy/integrity &amp;amp;&amp;amp; kill -s QUIT `cat tmp/pids/resque_worker_integrity.pid` &amp;amp;&amp;amp; rm -f tmp/pids/resque_worker_integrity.pid; exit 0;'"
  if totalmem is greater than 200 MB for 10 cycles then restart
  group resque_workers
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Теперь monit будет следить чтобы было запущено не более одного workers и будет перезапускать их, если
количество используемой памяти превышает 200 мегабайт. Если вы хотите использовать больше workers, то вам
нужно позаботиться чтобы ваш тестовый rake task учитывал одновременный запуск нескольких копий проекта
(использовал разные базы).&lt;/p&gt;

&lt;p&gt;Вот и всё, теперь можно зайти на &lt;code&gt;http://integrity.example.com&lt;/code&gt; и добавить ваш проект. Надеюсь эта статья
поможет вам. Спасибо.&lt;/p&gt;

&lt;h2&gt;Links&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="http://integrityapp.com"&gt;Домашняя страница integrity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/defunkt/cijoe"&gt;Репозиторий cijoe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/blog/542-introducing-resque"&gt;Статья &amp;ldquo;Introducing Resque&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://chriswanstrath.com/resque"&gt;Документация по resque&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mmonit.com/wiki/Monit/ConfigurationExamples"&gt;Примеры конфигураций monit&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/iETsrx2pgIw" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>Open file with gpicker and mlocate</title>
   <link href="http://avsej.net/2010/open-file-with-gpicker-and-mlocate/" />
   <updated>2010-09-08T00:00:00-07:00</updated>
   <id>http://avsej.net/2010/open-file-with-gpicker-and-mlocate/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://avsej.net/2010/open-file-with-gpicker-and-mlocate/"&gt;Open file with gpicker and mlocate&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://github.com/alk/gpicker"&gt;gpicker&lt;/a&gt; is a convenient tool for selecting files. Yesterday I remembered that it supports the gathering of data from the &lt;a href="http://carolina.mff.cuni.cz/~trmac/blog/mlocate"&gt;mlocate&lt;/a&gt; database and decided  to setup a convenient opening files from the mlocate database using gpicker and &lt;code&gt;gnome-open&lt;/code&gt;. To start you need to know where the base mlocate in your system. The path can be found on the man page &lt;a href="http://linux.die.net/man/1/locate"&gt;&lt;code&gt;locate(1)&lt;/code&gt;&lt;/a&gt; or via a call &lt;code&gt;locate -h&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ locate -h | grep "\.db"
      /var/lib/mlocate/mlocate.db)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is enough to bring all together:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gnome-open `gpicker -t mlocate --eat-prefix="" /var/lib/mlocate/mlocate.db`
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Option &lt;code&gt;--eat-prefix&lt;/code&gt; means strip prefix to make paths relative.&lt;/p&gt;

&lt;p&gt;It remains only to set up a hotkey in metacity (e.g. via &lt;a href="http://linux.die.net/man/1/gconftool-2"&gt;gconftool-2(1)&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gconftool-2 --search-key-regex run_command_\\d+
  /apps/metacity/global_keybindings/run_command_1 = &amp;lt;Super&amp;gt;c
  /apps/metacity/global_keybindings/run_command_2 = &amp;lt;Super&amp;gt;f
  /apps/metacity/global_keybindings/run_command_3 = &amp;lt;Super&amp;gt;s
  /apps/metacity/global_keybindings/run_command_4 = &amp;lt;Super&amp;gt;x
  /apps/metacity/global_keybindings/run_command_5 = &amp;lt;Super&amp;gt;d
  /apps/metacity/global_keybindings/run_command_6 = &amp;lt;Super&amp;gt;v
  /apps/metacity/global_keybindings/run_command_7 = &amp;lt;Super&amp;gt;a
  /apps/metacity/global_keybindings/run_command_8 = disabled
  /apps/metacity/global_keybindings/run_command_10 = disabled
  /apps/metacity/global_keybindings/run_command_11 = disabled
  /apps/metacity/global_keybindings/run_command_12 = disabled
  /apps/metacity/global_keybindings/run_command_9 = disabled
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Choose free number and assign it to the command and hot-key.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gconftool-2 --type string --set /apps/metacity/global_keybindings/run_command_10 '&amp;lt;Super&amp;gt;g'
$ gconftool-2 --type string --set /apps/metacity/keybinding_commands/command_10 'sh -c "gnome-open `gpicker -t mlocate --eat-prefix="" /var/lib/mlocate/mlocate.db`"'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src="http://files.avsej.net/assets/gpicker-mlocate.png" alt="Pick files with gpicker, mlocate and gnome-open" /&gt;&lt;/p&gt;

&lt;p&gt;Also you can create local mlocate database for particular directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ updatedb -o mlocate.db -U .
$ gpicker -t mlocate mlocate.db
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To use mlocate you need to install gpicker 2.1 (&lt;a href="http://download.savannah.gnu.org/releases/gpicker/gpicker-2.1.tar.gz"&gt;tarball&lt;/a&gt;, &lt;a href="http://download.savannah.gnu.org/releases/gpicker/gpicker_2.1-1_i386.deb"&gt;deb-i386&lt;/a&gt;, &lt;a href="http://download.savannah.gnu.org/releases/gpicker/gpicker_2.1-1_amd64.deb"&gt;deb-amd64&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Links&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="http://github.com/alk/gpicker"&gt;gpicker repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://download.savannah.gnu.org/releases/gpicker"&gt;gpicker releases&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/GMZt6qt1i5Q" height="1" width="1"/&gt;</content>
 </entry>
 
 <entry>
   <title>github + jekyll = blog</title>
   <link href="http://avsej.net/2010/github-jekyll-blog/" />
   <updated>2010-08-22T00:00:00-07:00</updated>
   <id>http://avsej.net/2010/github-jekyll-blog/</id>
   <author>
       <name>Sergey Avseyev</name>
       <email>sergey.avseyev@gmail.com</email>
   </author>
   <content type="html">&lt;h1&gt;&lt;a href="http://avsej.net/2010/github-jekyll-blog/"&gt;github + jekyll = blog&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;Пару месяцев назад я начал пользоваться сервисом &lt;a href="http://pages.github.com"&gt;github pages&lt;/a&gt;. Мне очень понравилась идея хранить сайт в репозитории. До последнего момента я использовал его только как визитку и для &lt;a href="http://openid.net/specs/openid-authentication-1_1.html#delegating_authentication"&gt;делегации OpenID&lt;/a&gt;. Тогда я узнал, что содержимое страницы парсится с помощью &lt;a href="http://github.com/mojombo/jekyll"&gt;jekyll&lt;/a&gt;, но, к сожалению, тогда у меня не было достаточно времени чтобы посмотреть на него, да и задачи как-то не стояло. А вчера я прочитал в buzz анонс блога &lt;a href="http://www.sablog.me/post/981470427/hello-world"&gt;Виталика Куликова&lt;/a&gt;, который он открыл на tumblr.  Если честно, он мне не очень понравился, наверное, из-за кривоватой темы, и я вспомнил про jekyll. Этот пост собственно посвящен моим экспериментам с ним.&lt;/p&gt;

&lt;p&gt;Итак, для меня в блоге важно наличие всего нескольких вещей и полностью отсутствие всего остального:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;удобный язык разметки. Jekyll поддерживает &lt;a href="http://redcloth.org/textile"&gt;textile&lt;/a&gt; и &lt;a href="http://daringfireball.net/projects/markdown"&gt;markdown&lt;/a&gt;, кроме этого любой html-документ является валидным документом для jekyll.&lt;/li&gt;
&lt;li&gt;подстветка синтаксиса. Jekyll реализует её с помощью &lt;a href="http://pygments.org"&gt;pygments&lt;/a&gt; кроме того всегда можно использовать &lt;a href="http://gist.github.com"&gt;gist&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;простое, надежное и удобное хранилище для статей. &lt;a href="http://git-scm.com" title="&amp;quot;the stupid content tracker&amp;quot;"&gt;git&lt;/a&gt; для этого идеально подходит.&lt;/li&gt;
&lt;li&gt;генерация atom/rss. С jekyll это делать достаточно легко благодаря &lt;a href="http://www.liquidmarkup.org"&gt;liquid&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;надёжный хостинг. Я считаю что github будет достаточно надежным хостингом для этого блога, тем более, что он полностью статический и его очень легко кешировать.&lt;/li&gt;
&lt;li&gt;и, наконец, комментарии в блоге. Я думаю, что для этого я буду использовать &lt;a href="http://disqus.com"&gt;disqus&lt;/a&gt;, как и Виталик. И, если там исправят наконец &lt;a href="http://getsatisfaction.com/disqus/topics/cant_log_in_with_openid-1j9j8"&gt;баг с OpenID&lt;/a&gt;, то будет вообще супер.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;На последок несколько отрывков кода, чтобы проверить подстветку.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class GreaterClass
  def initialize(username)
    @username = username
  end

  def hello
    puts("Hello, #{@username}!")
  end
end
GreaterClass.new(ENV['USERNAME']).send(:hello)

$ USERNAME=world ruby hello.rb
Hello, world!
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Ссылки&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="http://github.com/mojombo/jekyll/"&gt;репозиторий jekyll&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://tom.preston-werner.com/"&gt;Tom Preston-Werner, автор jekyll и cofounder of github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html"&gt;статья &amp;ldquo;Blogging Like a Hacker&amp;rdquo;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/avsej/avsej.github.com/raw/master/_posts/2010-08-22-github-jekyll-blog.markdown"&gt;исходный код этой статьи&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;img src="http://feeds.feedburner.com/~r/avsej/~4/s77IBvsBORI" height="1" width="1"/&gt;</content>
 </entry>
 

</feed>

