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.

Lilu Markup

Posted by yrashk

Continuing this

First of all, I’ve configured project, you can find it here. Initial quick-n-dirty implementation (not completed yet) is commited.

Oleg Andreev and me are currently playing with making syntax better. One of the options we are playing with now is making it verb oriented.

I personally like the following way (experimental, from trunk and mind):

1
2
3
4
5
6
update("#some-data").with :id => "some-lilu-data", "a" => { :href => "/" } 
populate("#blog-example").for(:each,@blogs) do |blog| 
   mapping 'a' => {:href => blog.url}, :id => blog.blog_id 
end
move("#some-data").after("#some-div")
...

Verb based syntax looks to be more descriptive then that element-oriented syntax I’ve written about in my previous post.

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