Архив автора за

06
Май
09

Демаршалинг Ruby данных в Erlang

Для меня стал сюрпризом тот факт, что Rails держит в сессионной cookie просто сериализованный хэш session. Я ожидал там увидеть обычный key=value, но тем не менее. Пришлось написать на Erlang распаковщик для Ruby Marshal. Умеет он совсем не много, работает только с самыми простыми типами данных, но вполне подходит для стандартной Rails cookie c user_id, например.

http://github.com/reversengineer/erlang-ruby-marshal/tree/master

Документации по этому вопросу не очень много, если кому будет интересно, то рекомендую начать со spec.ruby-doc.org и медитировать на реализацию вот здесь. Более свежий исходник можно посмотреть в репозитории.

16
Апр
09

Советы по Git

Совет #1

Возможно, вы уже успели заметить, что при работе с HTTP git весьма немногословен, особенно старые его версии. Например, в Debian Etch по умолчанию доступен git версии 1.4.*. Полагаю еще не все успели мигрировать на новый stable, Lenny. Думаю вам будет интересно узнать про одну переменную окружения, которая меня сильно выручает:

~$ GIT_CURL_VERBOSE=1 git clone http://example.com/repository.git

Увидев ее, git выдает verbose вывод от libcurl, чем удивительно облегчает процесс отладки удаленных репозиториев.

Совет #2

Если на удаленном репозитории используется HTTP Basic-Auth, то указать свой логин и пароль можно в файле ~/.netrc, в следующем формате:

machine example.com
login johndoe
password doepass

Только не забудьте про chmod 0600 на всякий случай.

Совет #3

Когда вы используете SSL для шифрования соединения с репозиторием git, бывают ситуации когда проверку сертификатов необходимо отключить. Это можно сделать двумя способами. Либо, как в первом совете, с помощью переменной окружения – GIT_SSL_NO_VERIFY. Либо с помощью .gitconfig:

[http]
sslVerify = false

14
Апр
09

Clojure в GAE/J

По этому поводу почитать можно тут.

13
Апр
09

Git с нуля

Обилие ссылок на github.com репозитории в повествовании о JRuby on Rails в AppEngine натолкнуло меня на мысль о том, что неплохо бы рассказать как пользоваться этим самым git. Я не буду вас мучить примерами с пустыми репозиториями. Давайте попробуем решить сугубо практическую задачу – внести небольшое изменение в библиотеку Bumble. Она и будет нашим учебным репозиторием. Скопировать удаленный репозиторий git можно с помощью команды clone:

~$ git clone git://github.com/olabini/bumble.git
Initialized empty Git repository in /home/engineer/bumble/.git/
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 5 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (5/5), done.

Git обладает очень простым и понятным интерфейсом работы с ветками. Плодить ветки в git репозитории под любые свои нужды – практика совершенно нормальная. Основная ветка репозитория называется master, получить список всех доступных вам веток можно командой branch:

~/bumble$ git branch
* master

Пока вам доступна одна ветка, master. Обратите внимание на “*” справа – так обозначена текущая ветка. Давайте сделаем свою ветку, перейдем в нее и приступим к изменениям кода:

~/bumble$ git branch filters
~/bumble$ git branch
filters
* master
~/bumble$ git checkout filters
Switched to branch "filters"

Добавим в Bumble::DS::Query обертку для методов add_filter в DataStore. В исходной версии Bumble есть возможно выбирать данные только с одним фильтром – EQUAL. Кроме него, есть еще четыре фильтра, работу с которыми мы добавим в Bumble, на примере метода all:

class Query
[:equal, :greater_than, :greater_than_or_equal, :less_than, :less_than_or_equal].each do |filter|
filter = filter.to_s
class_eval <<-END_EVAL
def add_filter_#{filter.sub('_than', '')}(name, value)
add_filter(name, DS::Query::FilterOperator::#{filter.upcase}, value)
end
END_EVAL
end
end

Теперь немного поправим метод all. Тут мы поменяем только разрабор параметра conditions, так что полный код метода я приводить не буду:

def all(conditions = {}, options = {})
q = DS::Query.new(self.name)
conditions.each do |k, v|
property_name = k.to_s
if v.is_a? Hash
v.each do |filter_op, value|
q = q.send "add_filter_#{filter_op}", property_name, value
end
else
q = q.add_filter(property_name, DS::Query::FilterOperator::EQUAL, v)
end
end
# some code below

Результаты своего труда можно увидеть с помощью команды diff. Попробуйте сами, заодно посмотрите man. Теперь нам нужно каким-то образом изменения в своей ветке зафиксировать, перенести в основную и пользоваться в своих проектах. Конечно, в git есть commit, но сам процесс несколько отличается от обычных систем контроля версий (я имею ввиду CVS, Subversion).

Сперва, вы должны добавить нужные файлы для commit командой add. Узнать имена этих файлов можно не только из diff, но командой status:

~/bumble$ git status
# On branch filters
# Changed but not updated:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: bumble/bumble.rb
#
no changes added to commit (use "git add" and/or "git commit -a")
~/bumble$ git add bumble/bumble.rb
~/bumble$ git commit -m 'new filters and all() refactored'
[filters]: created 300e887: "new filters and all() refactored"
1 files changed, 39 insertions(+), 21 deletions(-)

Номер ревизии, как впрочем и количество измененных строк у вас могут быть совсем другими. Теперь перенесем наши изменения в основную ветку:

~bumble/$ git checkout master
Switched to branch "master"
~bumble/$ git merge filters
Updating 96bdfc0..300e887
Fast forward
bumble/bumble.rb | 60 +++++++++++++++++++++++++++++++++++------------------
1 files changed, 39 insertions(+), 21 deletions(-)
~bumble/$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

Ну вот, надеюсь вы догадались, что переходить между ветками можно командой checkout, а перенести изменения – merge. В status вы видете, что ваш локальный репозиторий “опережает” основную ветку на удаленном сервере на один commit.

Конечно, рассмотренные выше примеры работы с git довольно примитивны. К сложным вопросам мы еще вернемся, а ответы к несложным я надеюсь читатель найдет в документации. Мне лишь хотелось вас заинтересовать.

12
Апр
09

JavaScript фреймворк Helma в GAE/J

Нашел интересную заметку у Roberto Saccon по поводу запуска Helma в GAE/J. Helma – это server-side фреймворк, написанный на Java. Языком для разработки выступает JavaScript, что делает этот фреймворк крайне интересным.

Мне кажется, GAE/J своим стартом дал дорогу многим интересным проектам, не только JRuby. Конечно все целиком зависит от задач, но Sinatra в GAE/J смотриться куда более органично, нежели Rails. А упор на BigTable должен поднять интерес к таким проектам как DataMapper. В ActiveRecord DataStore уже не влезет.

11
Апр
09

Запуск JRuby on Rails в Google AppEngine Java

Я не устоял перед соблазном и решил попробовать запустить JRuby on Rails в AppEngine. На этот шаг меня вдохновил целый ряд постов в разных блогах и мое повествование будет неполным без них:

По правде, до этого пользоваться JRuby мне приходилось только один раз, да и то, ради любопытства. Думаю многим JRuby знаком так же “хорошо”, поэтому начнем с самого начала. А для начала нам понадобиться свежий JRuby. Вытягиваем его из репозитория и собираем:

svn co http://svn.codehaus.org/jruby/trunk/jruby
cd jruby
ant && ant jar-complete

Использовать rake build тоже можно, но результатом его работы будет только собраный JRuby. А нам с вами нужен еще jruby-complete.jar, чуть позже мы вернемся к нему. Пока же для удобства пропишите себе путь к jruby/bin и продолжим – установим Rails и сделаем скелет приложения:

jruby -S gem install rails
jruby -S rails depot

Замораживаем все gems и удаляем в них тесты. Как я уже писал, GAE/J имеет ряд ограничений, в том числе и на число файлов. Их количество не должно привышать 1000 штук. Надеюсь, это временно ограничение. ActiveRecord нам тоже больше не нужен, на GAE/J применения ему нет, за компанию выбросим и ActionMailer с ActiveResource:

jruby -S rake rails:freeze:gems
rm -rf vendor/rails/actionpack/test/
rm -rf vendor/rails/activerecord/
rm -rf vendor/rails/actionmailer/
rm -rf vendor/rails/activeresource/

Поскольку от ActiveRecord, ActionMailer и ActiveResource мы избавились, будет разумным сразу поправить config/environment.rb:

environment.rb
config.frameworks -= [ :active_record, :active_resource, :action_mailer ]

Пока оставим Rails и займемся SDK для Google AppEngine Java. Для начала, вам следует скачать его с code.google.com, после разверните его в удобное для вас место и пропишите пути к скриптам в appengine-java-sdk/bin.

Из поставки GAE/J SDK нам понадобиться библиотека appengine-java-sdk/lib/impl/appengine-api.jar. Скопируйте ее в RAILS_ROOT/lib. Туда же нужно будет положить jruby-complete.jar из jruby/lib и jruby-jrack.jar. Последний можно найти в репозитории jruby-rack:

git clone git://github.com/nicksieger/jruby-rack.git
cd jruby-rack
jruby -S rake SKIP_SPECS=true

Поскольку jruby-complete.rb слишком большой для GAE/J, воспользуемся скриптом Ola Bini, позволяющим разбить его на две части – jruby-core.jar и ruby-stdlib.jar:

fix_libs.sh
#!/bin/sh
rm -rf jruby-core.jar
rm -rf ruby-stdlib.jar
rm -rf tmp_unpack
mkdir tmp_unpack
cd tmp_unpack
jar xf ../jruby-complete.jar
cd ..
mkdir jruby-core
mv tmp_unpack/org jruby-core/
mv tmp_unpack/com jruby-core/
mv tmp_unpack/jline jruby-core/
mv tmp_unpack/jay jruby-core/
mv tmp_unpack/jruby jruby-core/
cd jruby-core
jar cf ../jruby-core.jar .
cd ../tmp_unpack
jar cf ../ruby-stdlib.jar .
cd ..
rm -rf jruby-core
rm -rf tmp_unpack
rm -rf jruby-complete.jar

Этот скрипт можно найти в репозитории Ola Bini YARBL. Для замены ActiveRecord нужно будет установить Bumble из репозитория. Добавьте загрузку Bumble в environment.rb. В enviroments/session_store.rb отключите сессии. Готового решения для Rails 2.3.2 пока нет (узнать подробней об этом можно здесь). Пользоваться cookie для хранения сессий пока нельзя, нет обвязок для java.security и javax.crypto.

Библиотеки все собраны и для запуска нам осталось совсем немного. Установите warbler и сконфигурируйте его. Делать это надо в RAILS_ROOT и обратите внимание на коварство разработчиков – gem называется warbler, а скрипт warble:

jruby -S gem install warbler
jruby -S warble pluginize
jruby -S warble config

Конфигурация находиться в config/warble.rb:

warble.rb
config.includes = FileList["appengine-web.xml", "datastore-indexes.xml"]
config.webxml.jruby.min.runtimes = 1
config.webxml.jruby.max.runtimes = 2

Файлы appengine-web.xml и datastore-index.xml стандартные для приложений GAE/J. В первом доступна конфигурация приложения, во втором – индексы для DataStore. В нашем случае мы воспользуемся самым простыми вариантами этих двух файлов:

appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>depot</application>
<version>2</version>
<static-files />
<resource-files />
<sessions-enabled>true</sessions-enabled>
<system-properties>
<property name="jruby.management.enabled" value="false" />
<property name="os.arch" value="" />
<property name="jruby.compile.mode" value="JIT"/> <!-- JIT|FORCE|OFF -->
<property name="jruby.compile.fastest" value="true"/>
<property name="jruby.compile.frameless" value="true"/>
<property name="jruby.compile.positionless" value="true"/>
<property name="jruby.compile.threadless" value="false"/>
<property name="jruby.compile.fastops" value="false"/>
<property name="jruby.compile.fastcase" value="false"/>
<property name="jruby.compile.chainsize" value="500"/>
<property name="jruby.compile.lazyHandles" value="false"/>
<property name="jruby.compile.peephole" value="true"/>
</system-properties>
</appengine-web-app>

datastore-indexes.xml
<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="true">
</datastore-indexes>

Теперь можно попробовать запустить тестовый сервер GAE/J:

jruby -S warble
dev_appserver.sh tmp/war

Если все в порядке, то по адресу http://localhost:8080 вам будет доступен тестовый сервер GAE/J с вашим приложением.

11
Апр
09

Ограничения AppEngine

Nick Sieger в блоге рассказал о своих впечатлениях от работы с GAE/J. Там же упомянуты ряд ограничений для GAE/J:

  • No regular net/http, restclient, ActiveResource usage. Google has a URL fetch library, and has hooked up Java’s HttpURLConnection to it, but none of the Ruby URL-fetching libraries use it.
  • No ActiveRecord. ‘Nuff said. For some folks, that’s a welcome change, but wrapping your head around AppEngine’s BigTable-backed data store takes some thought. You just can’t view it like a SQL engine.
  • No RMagick/ImageScience/attachment_fu. No ImageVoodoo even (no javax.image APIs). Google has it’s own image manipulation API.
  • Startup/first request processing time is currently an issue. It’s not clear yet how long Google keeps JVMs warm, so if your application is idle, the first few hits to it return 500 errors. I can only assume Google has a plan to address this.
  • Crypto. Although java.security and javax.crypto APIs are apparently whitelisted, I haven’t had time to figure out how to leverage them. JRuby’s jruby-openssl gem does not work, which means things like digest aren’t available. That’s currently a blocker for Rails’ cookie session store.
  • 1000-files limit per application. In order to work around this, I ended up jarring up all the Rails gems when deploying a Rails application.

Что касается первого пункта, Bas Wilbers подготовил несложную библиотеку для работы с URL Fetch API в GAE/J. Найти ее вы можете на github.com: urlfetch-gae.

Вторая интересная библиотека Bas Wilbers – интерфейс к GAE/J MailService, pony-gae. Безусловно, начилие этих библиотек, а так же Beeu и Bumble от Ola Bini не решает всех текущих проблем, но запускать JRuby on Rails приложения это совсем не мешает.

10
Апр
09

Java в Google AppEngine

Наверное, про это не написал только ленивый. Так вот я ленивый, поэтому сообщу вам только сегодня – Google добавил поддержку Java в свой замечательный AppEngine. На практике, для не-Java-программиста это дает возможность использовать ряд языков доступных для JVM:

  • JRuby
  • Clojure
  • Scala
  • и еще кучу интересного вроде Rhino

К слову, реализация Java в GAE полноценная, по крайней мере если верить заявлениям Ola Bini. Он уже успел запустить там JRuby on Rails и попробовать собственную замену для ActiveRecord – Bumble. Его коллега Samuel Goebert сделал небольшое приложение на Sinatra и запустил его в Google AppEngine.

Пока свежих новостей нет, но результаты первых двух дней впечатляют. Для JRuby настал звездный час, впервые с момента своего рождения эта реализация Ruby стала реально востребованна. Такой вот неожиданностью стал запуск Java в GAE для Rails-сообщества.




Follow

Get every new post delivered to your Inbox.