Ruby module exclusion 5

Posted by yrashk

May be I am missing something (since I am not MRI hacker), but why there is no module exclusion functionality — i.e. you can extend object with module, but can’t reverse this operation? Any specific reason for this decision, do you know?

I’ve just sketched simplistic implementation for this kind of functionality and really wondering why there is no such stuff in MRI.

Again, am I missing something?

Ruby Tuesday, Oslo, Jun 26 2007

Posted by yrashk

I will be talking about Lilu (and may be about some other things as well) at Oslo’s Ruby Tuesday. Can’t wait to meet you all, Oslo Rubyists :)

Lilu 0.1.0 released and gemified

Posted by yrashk

I’ve released Lilu 0.1.0.

You can use it as plugin: svn://dev.railsware.com/lilu/lilu/tags/0.1.0 (or svn://dev.railsware.com/lilu/lilu/trunk for the latest version) or just install a ‘lilu’ gem (should be available through RubyForge mirrors soon).

I’m going to work on documentation and improvements soon.

ERB::Compiler Hack

Posted by yrashk

While trying to develop ERB -> Lilu convertor, I’ve found a funny trick for ERB::Compiler. Could be useful for somebody, but basically just a trick for fun:

1
2
3
c = ERB::Compiler.new nil
c.insert_cmd = "print %"
eval c.compile('<div id="1"><%= @hello %></div>')

returns

<div id="1">( @hello ).to_s</div>

P.S. Most probably, there will be no ERB -> Lilu convertor.

Lilu and Rails

Posted by yrashk

I’ve commited initial Rails support for Lilu. Now you can try to install a plugin (svn://dev.railsware.com/lilu/lilu/trunk) and use the following naming schema:

 app/
   layouts/
      application.html
      application.lilu
   views/
      blog/
       post.html
       post.lilu

Typical application.html should contain complete HTML mockup where some element content should be replaced with actual data:

1
2
3
4
5
6
7
8
9
10
<html>
  <head>
    <title>Hello world</title>
  </head>
  <body>
  <div id="main">
        Body goes here
  </div>
  </body>
</html>

application.lilu is pretty simple:


update('#main').with yield

or even


replace('#main').with yield

post.html could contain either full page with blog post or blog post design itself. in first case, you should prepend your post.lilu with something like use(’#post’).

1
2
3
4
<div id="post" class="post">
  <div id="title">Hello, world</div>
  <div id="text">I'm Lilu!</div>
</div>
1
2
3
4
5
# Uncomment this if you have full page design in your post.html
# use('#post')
update('#post').with :id => @post.id,
                     '#title' => { :id => "title-#{@post.id}", self => @post.title }, 
                     '#text' => { :id => "text-#{@post.id}", self => @post.text }

That’s it, first Lilu + Rails experience. The above code is just from my head (too lazy to check exactly this code right now), so it can contain some minor bugs.

And yes, current Lilu implementation most probably contains bugs and problems. It’s quite young—it’s only few days old. I hope it will be getting better and better each day. I’m working on this.

Some Lilu examples

Posted by yrashk

Before: this and this

I’ve posted some Lilu examples on project’s wiki. It looks pretty nice for me now and it actually seems to be implemented already!

Source code is not well polished yet, some specs are definitely missing yet, couple of thoughts and ideas are around

But anyway it was a short path from idea to something working.

Thinking more about views

Posted by yrashk

Russian translation is available.

I was thinking about how HTML should be defined in Rails app. There are plenty of ways to: erb, haml, markaby, etc. but I felt that I miss something.

Tonight I’ve conjured a bit in TextMate and here are some of my conclusions:

1. Whether do we want or not, but lots of projects lack of universal members and thus html is done by html coder and it is integrated into template by a developer.

2. Templates with some logic inside (if logged_in?, <%= ... %>, etc.) is a thing that I don’t like much. First of all, they are somewhat hard to read and they are not nice to preview without Rails running. Then, some developers tend to integrate much more complex logic into a template, like person age calculation. Then… ok, two subitems are enough for now.

Ok. Here is what I’ve hacked tonight, laying down with my macbookpro.

1. HTML template should remain untouched and should looks just fine when is opened with a browser.

2. Each view should have a descriptor that manipulates elements.

If elements are accessed with xpath or something like this, this mean that it will be much easier to code it after view spec (rspec), since all element paths are already coded there.

I’ve created a bit of hackish code and now it is possible to write such kind of descriptors:

1
2
3
4
5
6
7
8
9
10
11
at("#current-user") << 'John' 
at("#best-blogs/li").as_template do
  @blogs.each do |blog| 
    self['id'] = "blog-#{blog.id}"
    at("a") << blog.name 
    at("a")['href'] = blog.url
    append
  end
end
at("#hide-me").update { remove }
 

That’s for HTML code like:

1
2
3
4
5
6
7
8
9
10
11
<html>
 <head>
 </head>
 <body>
        Hello <div id="current-user">Guest</div>
        <ul id="best-blogs">
                <li id="best-blog-example"><a href="#">My blog</a></li>
        </ul>
        <div id="hide-me">Hello</div>
 </body>
</html>

Descriptor syntax is for sure far from being perfect and current implementation is pretty awful (Hpricot-based), but anyway it allows to generate this HTML pretty easily:

1
2
3
4
5
6
7
8
9
10
11
12
 <html>
 <head>
 </head>
 <body>
        Hello <div id="current-user">John</div>
        <ul id="best-blogs">
                <li id="blog-1"><a href="http://novemberain.com">Novemberain</a></li>
                <li id="blog-2"><a href="http://rashkovskii.com">yrashk</a></li>
        </ul>

 </body>
</html>

I want to play with implementation a bit more, since I like this idea. Let’s see what we can do.

Updated: Lilu markup, some ideas on verb based DSL instead of #at-based syntax

Erlang and Ruby: Make things easier!

Posted by yrashk

Russian translation on Novemberain.com

While experimenting with Erluby (Ruby in Erlang) I got a feeling that I do not want to write specs in Erlang. RSpec is finally much better than missingbdd/erlang and I pesonally think that Ruby is a more expressive language.

That’s why I’ve though about some kind of bridge between erlang and ruby. I’ve googled for it and found Rebar and even its “secret” sources. How it works? It’s basically a JSON server implemented in Erlang. That’s basically nice, though it seems to be a deep allpha version and it does not support some Erlang-specific types like pids.

And I’ve decided to think more about how to make it better. I’ve resulted in throwing Rebar off and toying with the following idea: Ruby sends Erlang code to Erlang server and Erlang server returns Ruby code.

I’ve hacked Rebar runner a bit and here is what I’ve got:

 
 -module(erluby_bridge).

-export([start/0, handle/1, loop/1]).

%% parse
eval_erlang_expr(Expr) ->
    {ok, Tokens, _} = erl_scan:string(Expr),
    {ok, [Form]} = erl_parse:parse_exprs(Tokens),
    {value, Result, _} = erl_eval:expr(Form,[]),
    {ok, Result}.
encode_to_ruby(E) when is_list(E) -> list_to_binary("'" ++ E ++ "'");
encode_to_ruby(E) when is_binary(E) -> encode_to_ruby(binary_to_list(E));
encode_to_ruby(E) when is_integer(E) -> list_to_binary(integer_to_list(E));
encode_to_ruby(E) when is_float(E) -> list_to_binary(float_to_list(E));
encode_to_ruby(E) when is_pid(E) -> list_to_binary("ErlPid.new('" ++ pid_to_list(E) ++ "')").
%% server
start() ->
  {ok, LSock} = gen_tcp:listen(9900, [binary, {packet, 0}, {active, false}]),
  Pid = spawn(erluby_bridge,loop,[LSock]),
  register(erluby_bridge, Pid),
  Pid.

loop(LSock) ->
  {ok, Sock} = gen_tcp:accept(LSock),
  spawn(erluby_bridge, handle, [Sock]),
  loop(LSock).

handle(Sock) ->
  % read the request from the socket
  {ok, Bin} = gen_tcp:recv(Sock, 0),

  % call the function
  try
    {ok, Return} = eval_erlang_expr(binary_to_list(Bin)),
    % send the response
    gen_tcp:send(Sock, encode_to_ruby(Return))
  catch
    error:Err ->
      Stack = lists:flatten(io_lib:fwrite("~p", [{Err, erlang:get_stacktrace()}])),
      gen_tcp:send(Sock, encode_to_ruby(Stack));
    _:Ouch ->
     io:format("~p~n!!!",[Ouch])
  end,

  ok = gen_tcp:close(Sock).

and on Ruby side:

 
require 'rubygems'
gem 'activesupport' 
require 'active_support'
class Object
  def to_erl
    to_s
  end
end
class String
  def to_erl
    '"' + to_s + '"'
  end
end
class ErlPid
  def initialize(binary)
    @binary = binary
  end
  def to_erl
    'list_to_pid("' + @binary + '")'
  end
  def to_s
   @binary
  end
end

class Symbol
  def to_erl
    "'#{to_s}'" 
  end
end

class Erluby
  def initialize(host, port=9900, mod="erlang")
    @host, @port, @mod = host, port, mod
  end
  def __invoke__(sym,*args)
    sym = sym.to_s
    if args.empty? and sym.camelize == sym
      Erluby.new(@host,@port, sym.tableize.singularize)
    else
      erl_expr = "#{@mod}:#{sym}(#{args.collect(&:to_erl).join(',')})." 
      sock = TCPSocket.new(@host,@port)
      sock.write(erl_expr)
      res = sock.gets
      eval(res)
    end
  end
  def __send_message__(pid,msg)
    self.Erlang.__invoke__("send",pid,msg)
  end
  def method_missing(sym,*args)
    __invoke__(sym,*args)
  end
end

All this stuff is far away from being polished (it’s very hackish) but it allows me to play with Erlang from Ruby. Something like:

 
@erluby = Erluby.new("127.0.0.1",9900)
puts @erluby.Base64.encode("havanagila")
puts @erluby.self
@erluby.__send_message__(:main,3) # unless whereis(main) == undefined
 

Ongoing improvements in Caches.rb

Posted by yrashk

I’ve spent few hours improving Caches.rb recently. While it is not still released (i.e. no official gem, only svn trunk), I’d like to disclose recent changes and share with my plans about it.

So, what’s done?

  • First of all, it was greatly refactored. The most significant change is that storages are not responsible for caching algorithms anymore. Each storage has only few (like 5) simple API methods that needs to be defined. You can look into the sources (svn://verbdev.com/rubylibs/caches.rb/trunk) to see how they are designed now. Please be aware that API method names are most likely to be changed very soon. I don’t like current naming scheme.
  • One more caching module added—Caches::Storage::Global, which stores cache in a global variable cache.
  • Then, I got rid of CachesConfig. If you need to specify a storage for your instance, just do instance_cache_storage StorageModule. CachesStorage::Instance is used by default (which stores cache in an object’s instance)
  • Caching static methods was requested by caches.rb users several times, so here you are:
 
 class SomeClass
   def self.static_method
    ...
   end
  class_caches :static_method
 end
 
You can also specify storage for static methods: class_cache_storage StorageModule
  • Since I was adding some Rails-specific behavior recently I’ve got some feedback on Rails-specific usage of Caches.rb. Apparently, if you cache static methods in your rails app and you’re running in development mode, your class is going to be reloaded by Rails and hence you will lose your changes. That’s why Caches::Storage::Global has appeared. So, now you can use the following pattern:
 
 class MyModel < ActiveRecord::Base
   def self.static_method
    ...
   end
  class_cache_storage Caches::Storage::Global 
  class_caches :static_method
 end
 
  • I’ve added experimental method caches? which should be used to check class whether it caches this or that method. I haven’t decided whether it makes any sense, so may be I will drop it.

Seems that it’s all.

Now, few words on my plans. I plan to:

  • perform a code cleanup, refactor it to the extent possible
  • invent a better naming schema for storage API (though I’m still not very satisfied with it)
  • improve specs, perform more tests
  • release new version
  • think about adding more sophisticated storage modules, like support for memcached.

Update: I’ve performed some refactoring and added memcached support (Caches::Storage::MemCached). Everything is available in svn trunk for testing purposes. I plan to release new official version (0.4.0) soon.

Just an Idea for Erlang

Posted by yrashk

I was using Erlang from time to time from 2000 or 2001. I’ve even done some commerical trading-related system in it. It’s definitely a good language for certain domains, and it has bright past and may be even brighter future. I was experimenting with some ideas in Erlang today, after long period of not using it and I should say that fairly speaking Erlang is far away from being a friendly language in terms of syntax.

What if Erlang could be considered a kind of “assembly” language for high-performance and distributed programming? What if we can use Lisp macro or Ruby metaprogramming capabilities to code generate Erlang? Taking in account the fact that Erlang code could be changed without a stop, why not generating source code on the fly and passing it to Erlang VM?

Ok, just as a nighty idea.

Common Lisp respond-to?

Posted by yrashk

Few days ago I’ve hacked a simplistic BDD for Common Lisp. I’m still having fun improving it. Here you are an improved respond-to? that supports generics much better.

 
  (defun respond-to? (o method &rest args)
  (restart-case
      (handler-bind ((undefined-function #'(lambda (c)
                         (declare (ignore c))
                         (invoke-restart 'no)))
             (simple-error #'(lambda (c)
                       (declare (ignore c))
                       (invoke-restart 'no))))
    (let ((sf (symbol-function method))
          (cpl (sb-pcl::class-precedence-list (class-of o))))
      (typecase sf
        (standard-generic-function
         (find t 
           (mapcar #'(lambda (klass)
                   (not (null
                     (find-method sf '() 
                          (cons klass
                            (mapcar #'(lambda (c) (declare (ignore c)) t) args)) nil))))
               cpl)))
        (function t))))
    (no (&optional v)
      nil)))
 

Though for non-generic functions there seems to be no way to check if actually object “responds” to function without actually evaluating it.

Anyway, it’s quite funny!

Thinking in Functional Ruby 6

Posted by yrashk

This article is a result of yesterday’s code review session I have done.

I have found that I don’t like the following code (well, a code like this):

def topmost_matches(str,limit=3)
  matches = []
  str.each(' ') do |word|
    word = word.strip.downcase
    matches << word if Entity.find_by_name(word)
  end
  return matches[0, limit] if matches.size > limit
  matches
end

Here is what we can do with this code to make it better:

Well, first of all, let’s simplify last two lines. Since if even matches.size is less than limit, matches[0,limit] will return the whole matches array. This means that we don’t need any kind of explicit condition:

  matches[0,limit]

Then, I really can’t say that the rest of the code is easy to read and understand. It is not readable, it is rather interpretable. And here we can use some Ruby power to do this stuff meach easier and nicer:

 str.split(/\s+/).         # here we split str by whitespace characters
      collect(&:downcase). # then we downcase each word
      select{|word| Entity.find_by_name(word)}[0,limit] 
                           # ...and finally we select that words
                           # that are found within Entities names

Also, it is pretty easy to add even a more complex functionality to this single functional “query”. For example, we also may want to sort results according Entities ratings, descending. No problem!

 str.split(/\s+/). 
      collect(&:downcase).
      select{|word| Entity.find_by_name(word)}.
      collect{|word| Entity.find_by_name(word)}. # collect respective Entities
      sort_by(&:rating).reverse.                 # sort them by rating, descending
      collect(&:name)[0,limit]                   # collect their names, and return topmost 
                                                 # of them

Of course, the above code is still a heaven for code reviewer, but it is out of this article’s scope.

Update: According to improvements proposed in comments, it could be even that easy:

 str.split(/\s+/). 
      collect(&:downcase).
      collect{|word| Entity.find_by_name(word)}.compact.
      sort_by(&:rating).reverse.               
      collect(&:name).first(limit)

Continuous Integration: Cerberus 13

Posted by yrashk

Jordan Arentsen said that he would like to read about Continuous Integration. With a great pleasure!

I would like to talk about Cerberus tool and how we apply it in particular. Cerberus is a great simple tool to perform rake tasks continuously on your project whenever it updates.

I will guide you through the setup.

  • First of all, make sure that your subversion client is at least at version 1.2. It will not work with earlier versions.
  • Setup an email alias for notifications, something like dev-foobar@foobar.com that will forward any email (except spam!) to your team.
  • Then, simply install Cerberus from a gem: gem install cerberus
  • Create a user for cerberus: adduser -m cerberus, passwd cerberus
  • Log in as a cerberus (or just use sudo -H -u cerberus as a prefix)
  • Assuming you have a project at file:///var/lib/svn/foobar/foobar/trunk just do
 
cerberus add file:///var/lib/svn/foobar/foobar/trunk  \
               APPLICATION_NAME=FooBar \
              RECIPIENTS=dev-foobar@foobar.com
 
  • Open /home/cerberus/.cerberus/config.yml and specify there such parameters:
 
publisher:
#  active: mail jabber rss campfire irc
  active: mail campfire # you may also use irc, jabber and rss,
                                     # which we are not using at the moment
  mail:
    sender: cerberus@foobar.com
    address: foobar.com
    port: 25
    domain: foobar.com
    #authentication: plain
    #user_name: someuser
    #password: somepassword
  campfire:
    url: http://cerberus@foobar.com:crbrs@foobar.campfirenow.com/room/58153
#  jabber:
#    jid: cerberus@gtalk.google.com
#    port: 5222
#    password: mypass
#    digest: false
#  irc:
#    nick: cerb
#    server: irc.freenode.net
#    channel: cerberus
#  rss:
#    file: /usr/www/rss.xml
builder:
  rake:
    task: db:migrate # we are also adding here 'spec spec_with_rcov ', since we use
                                # both RSpec and RCov
 
* Then, open /home/cerberus/.cerberus/config/FooBar.yml and edit it:
 
---
publisher:
  mail:
      recipients: dev-foobar@foobar.com
  # specify the rest publishers per project parameters here
scm: 
  type: svn
  url: file:///var/lib/svn/foobar/foobar/trunk
changeset_url: http://trac.foobar.com/changeset/  # If you have Trac (you should! :), integrate with it                                                                                  
 
  • You can override system-wide settings (/home/cerberus/.cerberus/config.yml) with project-wide settings (/home/cerberus/.cerberus/config/FooBar.yml), (I’d suggest to pay attention to at least builder: => rake:) (consider looking at a full list)
  • You can perform a test by typing cerberus build FooBar. It will email you about project setup.
* Now, add it to crontab to run it as frequently as you wish. It does not consumes much time if there was no fresh checkins in a repository, it only runs tests against your code if your repository was updated. We use to run Cerberus each 10 minutes:
 
*/10 * * * * cerberus buildall

  • You’re done!

Few more tips:

  • If you want Cerberus to rebuild FooBar from the scratch, simply rm -rf /home/cerberus/.cerberus/work/FooBar
  • I strongly recommend to generate RCov diagram each time Cerberus runs. Here is how you can integrate RCov with RSpec:

lib/tasks/rcov.task:


require 'rake'
require 'spec/rake/spectask'

Spec::Rake::SpecTask.new('spec_with_rcov') do |t|
    t.rcov = true
 end

  • To integrate it without RSpec, look here (not sure it is what you need exactly, however)
  • Then simply symlink generated coverage directory to some web-accessible (preferably httpauth protected)

I will try to talk more on a coverage analysis later. Now it’s too late (or too early, 4:45 AM)

Few Tips About How to Become a More Effective Developer

Posted by yrashk

Today I want to talk a bit about a topic that seemed to be quite trivial for me and people around, but I’ve found that some things that are trivial for us, aren’t obvious for everyone. So I want to share my thoughts about how to become a more effective developer. I do not pretend to be a guru in this area, it is just my own experience.

Planning

Planning is the first thing to think about if you want to become effective. No need to perform a prioritization or long-term planning. What you actually may need is the following path:

  • write down a list of tasks that you need to accomplish
  • pop those that could be completed in a matter of minutes and put them into ‘RightNow’ folder
  • then sort each task according to the milestone it relates to. If a task should be completed by tomorrow’s morning, then put it to ‘Today’ folder. If it should be done by the end of week, put it into ‘ThisWeek’ folder. If it should be done by the end of a month, put it to ‘ThisMonth’ folder and so on.

Simple enough. Few advices on tasks:

  • define them shortly and cleanly
  • be realistic on time consumation estimations

Execution

So, when you have a plan, you need to work properly with it. It is pretty easy to do:

  • first look into RightNow folder. If there is something to do, do it now. If it is empty, proceed to Today. And so on.
  • the rule of thumb is that you shoud not proceed with a next folder until your current folder is empty.
  • of course, you may need re-plan your tasks if some circumstances were changed. Pay attention to keep your plans up-to-date, that’s vital.

Source Code Management

Source code is the most important result of you work, so you need to manage it properly, aren’t you?

  • Use version control management system. It could be Subversion, Darcs, Git, whatever you like the most (Subversion is quite popular among Rails developers, and I will use it here for examples)
  • Check in your changes frequently. Why? First reason is that you will most likely avoid breaking own code. Once you’ve done task, check it in. Another reason is that if you’re working within a team, they surely would like to have all the code integrated as earlier as it is possible.
svn ci -m "Ticket #2: Improving code quality"
  • Keep your checkin messages descriptive. “another change”, “fixed bug” aren’t descriptive at all.

Example:

svn ci -m "Workaround for a defect #267"
  • Install something like a Trac. It will allow you to track your code changes and issues. It will simplify your life greatly.
  • If you’re working within a team, consider updating your repository (svn up) each few hours and reading others’ changesets at least once a day (in a morning). It will keep you up-to-date and you will not trap into a need to resolve a lot of source code conflicts.
  • Once you’ve trapped into a source code conflict (Subversion reports you about it with a ‘C’ tag for a file), resolve it ASAP. Merge changes outlined in a conflict file and then say svn resolve path/to/file

Source Code

Now, about source code itself.

  • Be lazy. Type less. If you are a happy TextMate user, press esc frequently to autocomplete your text. It will help you to avoid mispelled variable/method names.
  • Follow naming conventions. This is particulary easy with Rails, because it has already established common naming conventions. Ruby itself offers some conventions as well, like appending boolean methods with ?. Following naming conventions will simplify your life greatly, believe me.
  • Use descriptive names for your variables, methods, symbols, etc.
  • Write a code that should be readable, not interpretable. Anybody should be able to understand what your code does by just reading it as a subset of English with some mix with programming language constructs. If you need to interpret code in your brain to understand what it is doing, then it’s potentially a bad code. This is quite hard rule to follow, and it should not be applied to every and every bit of your code. But it’s important to not underestimate its value.
  • Shrink your code size. Avoid extra meaningless constructs. Use short forms of them.
Example: do_something if reasonable? instead of

if reasonable?
   do_something
end

  • Review your code before a checkin. If it smells bad even a bit, try to improve it.
  • Ask your colleague to spend 15 minutes reviewing your code.

Tests

It’s a large topic I will surely cover in some of my future. Let me outline few things:

  • Write test strictly before any implementation code. It will a) guarantee you’re implementing what you need exactly b) speed up your actual development significantly
  • Consider using RSpec. It allows you to write tests in a way that is much closer to English and it will also allow you to group your tests with ease:

context "Newly created Issue" do

 setup do
   @issue = Issue.new
 end

 specify "should have at least 2 questions" do
   @issue.should_have_at_least(2).questions
 end
end

  • Make sure your tests (or specifications in a RSpec terminology) are passing before each repository checkin.
  • Setup a continuous integration software like Cerberus. It will alert you if code becomes broken accidentally.
  • Consider generating RCov code coverage diagrams on a regular basis (let Cerberus do this!). This way you will be sure that your code is well covered by tests. Of course, RCov has to say nothing about how qualitative your tests coverage is, but it could say you whether you’re running each piece of your code by your tests or not. This is quite important.

TO BE CONTINUED: I would like to talk more on some tips, like Rails-specific ones, in the future posts. I’m going to add more details on an issues I’ve mentioned above, supply with more details. Stay tuned!

TO BE UPDATED: If I will find that I forgot to mention something important here, I will update this record.

P.S. Please advise me – may be the above issues are obvious for everyone and I should not write about them and save your and my time? :) I’m just not sure whether it have sense. If it has – then great!

We Are Hiring Internationally 0

Posted by yrashk

I’m happy to announce that Railsware is starting hiring internationally. We are obviously not requiring to relocate, we are just comfortable with telecommuting.

We’re building a networked team of decent Ruby on Rails developers. We’re looking for you.

We are fans of Rails. We like smart code. We like smart people. We like agile processes. We prefer to be an an edge.

If you’re interested to join a team of like-minded persons, then contact us at job@railsware.com. We are waiting for you!


Railsware is headquartered in Kiev, Ukraine, one of the top world outsourcing destinations.