terça-feira, 30 de dezembro de 2014

Metaprogramming Ruby

I'm reading Metaprogramming Ruby 2: Program Like the Ruby Pros. I started to read it, because I guess that metaprogramming could make pieces of my code simpler, but I discovered that my problems are about abstractions. I just need better abstractions, nevertheless the concepts exposed in the book are very good and made me feel excited.

The first time I read about the Ruby object model I feel very impressed. Ruby is the first language that I learned with two concepts very new to me: dynamic typing and pure object oriented. So, understand how all the pieces fit together and get comfortable with the notion that everything is object, including classes, take some time to click.

I learn best by doing and now I'm experiencing an opportunity to apply metaprogramming (that I expect to blog in a near future). By doing and trying to understand what I was doing I can say that the Ruby object model clicked in my head, but one aspect that still confuses me a bit, and IMO isn't explained with great details in this book, is about method lookup.

How Ruby goes from the receiver of the calling to the location in the hierarchy of ancestors? One source of confusion was this picture:


I perceveid the object model in a very organized form: for each class, you have a singleton class and it's superclass is the singleton class of the class superclass. After you get it, it's not that complicated, but what I didn't perceived, was that in the middle of all this you can have modules!

This way, I was struggling in how I could add class methods to an existing class and also override some of it's methods. For example, for the following code:

module OneModule
  def my_method
    puts "OneModule.my_method"
  end
end

class MyClass
  class << self
    include OneModule
  end
end

How can I tweak my_method behavior? The first difficult that I had was map this code to the diagram above, since I didn't understand where the code was living.

After reading and re-reading the first chapters of Perrotta book, and tinkering with irb, I understand that it was going to the singleton class of MyClass.

This code provide insightful output:

p MyClass.ancestors
p MyClass.singleton_class.ancestors
p MyClass.methods(false) == MyClass.singleton_class.methods(false)
====
[MyClass, Object, Kernel, BasicObject]
[#, OneModule, #, #, Class, Module, Object, Kernel, BasicObject]
true

When you define a class method, it's stored in the singleton class. So if I would like to change a class method,  I have to change the singleton class, but this also puzzled me: how can I add it without removing the actual method?

From the output it's easy to see the solution, but it take me a while to realize that it was possible. I guess that the module methods where inserted in the singleton class, but the module is put as an ancestor of the singleton class.
With this knowledge in mind you can write the following:

module OtherModule
  def my_method
    puts "OtherModule.my_method"
    super
  end
end

class MyClass
  class << self
    include OtherModule
  end
end

p MyClass.my_method
p MyClass.singleton_class.ancestors
====
OtherModule.my_method
OneModule.my_method
[#, OtherModule, OneModule, #, #, Class, Module, Object, Kernel, BasicObject]

You can also call "super" in "OtherModule" and Ruby will chain the calls correctly.

After all, I still can't describe how method lookup works, and luckily someone blogged about it: Ruby's method lookup path, Part 1.

The algorithm can be resumed to the following:
  1. Methods defined in the object’s singleton class (i.e. the object itself)
  2. Modules mixed into the singleton class in reverse order of inclusion
  3. Methods defined by the object’s class
  4. Modules included into the object’s class in reverse order of inclusion
  5. Methods defined by the object’s superclass.
Armed with this, I'm by far better prepared to experiment and answer questions when they pop out. So nice, so good!

terça-feira, 16 de dezembro de 2014

Improved how to render coffeescript partial inside coffeescript template

Some time ago I googled trying to find a solution for render a coffeescript partial inside a coffeescript template in an attempt to DRY my coffeescript templates.

This led me to https://coderwall.com/p/i62phq/how-to-render-coffeescript-partial-inside-coffeescript-template. Initially I turn my nose for the syntax, but it solved my problem and wasn't that terrible so I stick with this.

After some time I need to debug my JS response and when I looked at the returned code I saw that I need a better solution:

(function() {
  (function() {
    $('.footer').html("<div class=\'btn-group\'>...<\/div>");
  }).call(this);
;}).call(this); 

As you use more partials and your code start to grow this mess only gets worst. After hitting my head around a bit I realized that what I need was to render plain coffeescript, so I renamed my partial to _partial.coffee.erb and it worked like a charm!

Now my show.js.coffee is:

<%= render 'footer.coffee' %>

And my _footer.coffee.erb is:

$('.footer').html("<%= j render 'my_footer_html_partial' %>")

And the response is:

(function() {
  $('.footer').html("<div class=\'btn-group\'>...<\/div>");
}).call(this);  

Cleaner, don't you think?

segunda-feira, 8 de dezembro de 2014

Setup wildcard subdomain with Bind

I found a good documentation about configuring a DNS server to use wildcard domains for development: http://superrb.com/blog/2012/09/24/how-to-set-up-bind-on-ubuntu-for-a-wildcard-development-domain

All went well in my setup, I just have to adapt some paths and made use of bind conventions described in arch wiki.

All well, except the fundamental: wildcard subdomain. After googling a bit and read some similar questions in stackoverflow this was my final configuration:

  • /etc/named.conf
zone "dev.com" {
        type master;
        file "dev.com.zone";
};

  •  /var/named/dev.com.zone
;
; BIND data file for local loopback interface
;
$TTL 14400
@ IN  SOA dev.com. root.dev.com. (
            2014110801   ; Serial
                 86400   ; Refresh
                  7200   ; Retry
               3600000   ; Expire
                 86400 ) ; Negative Cache TTL
;
@ IN  NS  dev.com.
@ IN  A 127.0.0.1
* IN  CNAME dev.com.
@ IN  AAAA  ::1
If you don't catch the difference, I changed the line: "* IN A 127.0.0.1" with "* IN CNAME dev.com.".

PS.: This is NOT a tutorial, so read the post  linked in the start to make this works as you expect, since there contains what more you need to configure.