Rodrigo Flores's Corner

Kaizen - Ruby - Rails - Javascript - Computer Science

Book Review: Instant Nokogiri

| Comments

Disclaimer: I received a digital of this book for free from Packt Pub to review it. I’m not receiving any rewards by writing this review, and it contains my fair opinion. Here is the link to buy it.

Nokogiri is one of my favourite gems. I have used it alongside projects since I started developing applications with Ruby, some four years ago. As it is built upon LibXML2, a C library to deal with XML written in C, it has a nice performance and provides a beatiful API to deal with XML (and similar things like HTML). Even it requiring an extra effort to install (you have to compile the gem and install Libxml2 for that), I think it is worth it.

Powers’s book give you a nice overview of the library, what it is, how to install it and some basic usage, including a tutorial that will tell you how to do some page scraping using Nokogiri. It also will show you a summary of the main API methods that you will need to know to get some stuff done.

It is a kind of reading that I enjoy: a short book that goes right into the subject and tells you how to accomplish some task using a new tool, and it also may teach you some API usage that you didn’t know before. As the book name tells you, it is a knowledge shot that will provide you some basic knowledge about this tool, and even if you’re experienced with this library, you may learn a thing or two reading this book.

Ruby Patterns: Webservice Object

| Comments

This is a series about Ruby Patterns, which will explain some common uses of Ruby syntax. The second post is about a webservice based. I like to call it a pattern because it is very common and tends to repeat (on a not-duplicated way) on Service Oriented Architecture based applications. Of course, this code may be too sophisticated for such a small script like this, but it may be a good way to handle things on a more complex application.

So, you’re given the task to write a class that access a webservice and returns the info on it (e.g. the github repos for a given organization). A simplistic implemetation can be like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require 'faraday'
require 'json'

def retrieve_repos_for(org)
  connection = Faraday.new(:url => 'https://api.github.com') do |faraday|
    faraday.adapter  Faraday.default_adapter
  end

  response = JSON.parse(connection.get("/orgs/#{org}/repos").body)
  response
end

retrieve_repos_for('github').each do |repo|
  puts repo['clone_url']
end

Obviously, this is an example of a procedural implementation, so, let’s make it more object oriented.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
require 'faraday'
require 'json'

module Github
  class Organization
    def initialize(organization)
      @organization = organization
    end

    def repos
      connection = Faraday.new(:url => 'https://api.github.com') do |faraday|
        faraday.adapter  Faraday.default_adapter
      end

      response = JSON.parse(connection.get("/orgs/#{@organization}/repos").body)
      response
    end
  end
end

Github::Organization.new('github').repos.each do |repo|
  puts repo['clone_url']
end

Nice, we now have it inside a class. But we can extract some private methods here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
require 'faraday'
require 'json'

module Github
  class Organization
    def initialize(organization)
      @organization = organization
    end

    def repos
      response = JSON.parse(connection.get(repos_url).body)
      response
    end

    private

    def connection
      Faraday.new(:url => 'https://api.github.com') do |faraday|
        faraday.adapter  Faraday.default_adapter
      end
    end

    def repos_url
      "/orgs/#{@organization}/repos"
    end
  end
end

Github::Organization.new('github').repos.each do |repo|
  puts repo['clone_url']
end

Well, the public methods seems to be more concise now and we have extracted some methods that can be more easily reused. But there is a few flaws: if we call the repos method twice, it will make two requests, but this is easy to solve: just add some memoization.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
require 'faraday'
require 'json'

module Github
  class Organization
    def initialize(organization)
      @organization = organization
    end

    def repos
      @repos ||= JSON.parse(connection.get(repos_url).body)
    end

    private

    def connection
      Faraday.new(:url => 'https://api.github.com') do |faraday|
        faraday.adapter  Faraday.default_adapter
      end
    end

    def repos_url
      "/orgs/#{@organization}/repos"
    end
  end
end

Github::Organization.new('github').repos.each do |repo|
  puts repo['clone_url']
end

We’re almost done here. I’m not satisfied with the JSON.parse(connection.get(repos_url).body), it seems such a complex line. Let’s extract some methods here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
require 'faraday'
require 'json'

module Github
  class Organization
    def initialize(organization)
      @organization = organization
    end

    def repos
      @repos ||= get(repos_url)
    end

    private

    def connection
      Faraday.new(:url => 'https://api.github.com') do |faraday|
        faraday.adapter  Faraday.default_adapter
      end
    end

    def get(url)
      JSON.parse(connection.get(url).body)
    end

    def repos_url
      "/orgs/#{@organization}/repos"
    end
  end
end

Github::Organization.new('github').repos.each do |repo|
  puts repo['clone_url']
end

The repos method seems simple enough now, and we have moved the parsing responsability to the get method. But we can get rid of it delegating to someone else to do that. There is a great gem called faraday-middleware that parses it for me, based on the content type header and returns a hash, so, let’s use it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
require 'faraday'
require 'faraday_middleware'

module Github
  class Organization
    def initialize(organization)
      @organization = organization
    end

    def repos
      @repos ||= get(repos_url)
    end

    private

    def connection
      @connection ||= Faraday.new(:url => 'https://api.github.com') do |faraday|
        faraday.adapter  Faraday.default_adapter
        faraday.response :json, :content_type => /\bjson$/
      end
    end

    def get(url)
      connection.get(url).body
    end

    def repos_url
      "/orgs/#{@organization}/repos"
    end
  end
end

I’ve also added a memoization on the connection (we don’t need to instantiate a new one every time).

Two days later, a new requirement: get the organization info and add it on the api. This implementation makes it really easy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
require 'faraday'
require 'faraday_middleware'

module Github
  class Organization
    def initialize(organization)
      @organization = organization
    end

    def repos
      @repos ||= get(repos_url)
    end

    def info
      @info ||= get(info_url)
    end

    private

    def connection
      @connection ||= Faraday.new(:url => 'https://api.github.com') do |faraday|
        faraday.adapter  Faraday.default_adapter
        faraday.response :json, :content_type => /\bjson$/
      end
    end

    def get(url)
      connection.get(url).body
    end

    def repos_url
      "/orgs/#{@organization}/repos"
    end

    def info_url
      "/orgs/#{@organization}"
    end
  end
end

org = Github::Organization.new('github')

puts org.info['name']
org.repos.each do |repo|
  puts repo['clone_url']
end

Neat! It is indeed really easy to add new endpoints support to our class. But I think it has a lot of responsability: it is dealing with the connection to the API. Let’s extract a new class that does that and refer to it on the client method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
require 'faraday'
require 'faraday_middleware'

module Github
  class Client
    def initialize
      @connection = Faraday.new(:url => 'https://api.github.com') do |faraday|
        faraday.adapter  Faraday.default_adapter
        faraday.response :json, :content_type => /\bjson$/
      end
    end

    def get(url)
      @connection.get(url).body
    end
  end

  class Organization
    def initialize(organization)
      @organization = organization
    end

    def repos
      @repos ||= client.get(repos_url)
    end

    def info
      @info ||= client.get(info_url)
    end

    private

    def client
      @client ||= Github::Client.new
    end

    def repos_url
      "/orgs/#{@organization}/repos"
    end

    def info_url
      "/orgs/#{@organization}"
    end
  end
end

org = Github::Organization.new('github')

puts org.info['name']
org.repos.each do |repo|
  puts repo['clone_url']
end

Now we have a pretty simple class, which I finally consider a final implementation, it splits the responsability to parse to another place and now I only have to specify the endpoints and get (or post/put/patch/delete) it. Another improvements may be to add a condition to do something when we have a 404 on an endpoint.

What about you ? Would you recommend another improvement ? Do you use something similar ?

Octopress and Capistrano

| Comments

To deploy your octopress blog with Capistrano, you should do these steps:

First, add capistrano gem to your Gemfile. Then, after running a bundle install, run bundle exec capify . (or bin/capify . if you use binstubs) to generate the Capistrano files.

After that, you should add a content like this to your config/deploy.rb file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Set this forward agent option to not have to add your server's ssh public key to your repository's host authorized keys
ssh_options[:forward_agent] = true
require "bundler/capistrano"

set :keep_releases, 5
set :scm, :git
set :scm_verbose, false

# Set your repository URL
set :repository, 'YOUR REPO HERE'

# Set your application name
set :application, "YOUR APPLICATION NAME"
set :deploy_via, :remote_cache

# Set your machine user
set :user, 'YOUR SSH USER'

set :deploy_to, "/home/#{user}/apps/#{application}"
set :use_sudo, false

# Set your host, you can use the server IPs here if you don't have one yet
role :app, 'YOUR HOSTNAME', :primary => true

default_run_options[:pty] = true

namespace :octopress do
  task :generate, :roles => :app do
    run "cd #{release_path} && bundle exec rake generate"
  end
end

after 'deploy:update_code', 'deploy:cleanup'
after 'bundle:install', 'octopress:generate'

Now, you should add the group production to the development group on your Gemfile. Doing this, capistrano will be able to run octopress:generate on your server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
source "http://rubygems.org"

group :development, :production do
  gem 'rake', '~> 0.9'
  gem 'rack', '~> 1.4.1'
  gem 'jekyll', '~> 0.12'
  gem 'rdiscount', '~> 1.6.8'
  gem 'pygments.rb', '~> 0.3.4'
  gem 'RedCloth', '~> 4.2.9'
  gem 'haml', '~> 3.1.7'
  gem 'compass', '~> 0.12.2'
  gem 'sass-globbing', '~> 1.0.0'
  gem 'rubypants', '~> 0.2.0'
  gem 'rb-fsevent', '~> 0.9'
  gem 'stringex', '~> 1.4.0'
  gem 'liquid', '~> 2.3.0'
end

gem 'sinatra', '~> 1.3.5'
gem 'capistrano'

Finally, before doing the first cap deploy, do a git clone of your blog’s repository on the server (or try to connect through ssh to the repository server on your blog server), you will need to use the -A option on ssh command to forward your keys. This is needed because ssh asks for the fingerprint confirmation on the first ssh connection. As capistrano won’t do the ‘yes’ on the confirmation you should do it manually.

Doing this, you will be able to deploy your blog through capistrano. Do you have any tips on how to improve this capistrano recipe ? Please say them on the comments :).

Ruby Patterns: Method With Options

| Comments

This is a series about Ruby Patterns, which will explain some common uses of Ruby syntax. The first post is about methods with options.

Let’s start with an example where it can be useful. Suppose, you’re given an object and you should write a method that prints the object’s attributes in HTML. Also, you’ll also have to follow this other requirements:

  • You may specify the attributes that you want to show (by default you should show all of them);
  • You may specify the attributes that you don’t want to show (by default, you should show all of them, i.e. this list is empty);
  • You may specify the format: possible formats are :ordered_list, :unordered_list, :table (by default, present it as a :table);
  • You may specify the strftime format of the objects of Time type (default is :month/:day/:year :hour::minute :timezone in strftime format);
  • You may specify the strftime format of the objects of Date type (default is :month/:day/:year in strftime format);

So, given this requirements. Let’s write a function:

1
2
3
4
5
6
7
8
9
def object_to_html(object, only=nil, except=[], format=:table, time_format="%m/%d/%Y %H:%M %t", date_format="%m/%d/%Y")
  only ||= object.attributes - except

  if only - except != only
    fail "You can't put in except an attribute that you've put on only"
  end

  # Code that does what we proposed
end

Some examples of the usage of this function (and what someone will say after reading your code):

1
2
3
4
object_to_html(user) # Seems OK
object_to_html(user, nil, :encrypted_password) # What is this nil ?
object_to_html(user, [:email, :phone, :created_at], [], :ordered_list, "%d/%m/%Y %H:%M", "%d/%m/%Y") # WTF is this empty array ?
object_to_html(product, nil, [], :table, "%d/%m/%Y %H:%M", "%d/%m/%Y") # Gosh. My eyes are bleeding. Call an ambulance.

What a creepy code! If you want to change the last attribute, you will have to know all the default values of the other ones to be able to change it. You will also have to know (or constantly look at its implementation or documentation) the exactly order of the attributes. Also, if you decide to remove one attribute, you will have to find all the calls to this method and change it on all of them. Definitely, this is what I call ugly code: difficult to use and hard to maintain.

So, this pattern comes in handy: method with options!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def object_to_html(object, options={})
  default_options = {
    :format => :table,
    :only => nil,
    :except => [],
    :time_format => "%m/%d/%Y %H:%M %t",
    :date_format => "%m/%d/%Y"
  }

  options = options.reverse_merge(default_options)

  options[:only] ||= object.attributes - options[except]

  if options[:only] - options[:except] != options[:only]
    fail "You can't put in except an attribute that you've put on only"
  end

  # Code that does what we proposed (now it uses the options hash instead of local variables)
end

The same usage examples come along:

1
2
3
4
object_to_html(user)
object_to_html(user, :except => [:encrypted_password])
object_to_html(user, :only => [:email, :phone, :created_at], :format => :ordered_list, :time_format => "%d/%m/%Y %H:%M")
object_to_html(product, :time_format => "%d/%m/%Y %H:%M", :date_format => "%d/%m/%Y")

Now to the explanation of how this works: the Hash#reverse_merge! method does the key role here. It merges the two hashs (the one containing the default values with the one that was given as a parameter) and in case of the same key in both, it keeps the one that belongs to the Hash that received the method call (in our case, the one given as a parameter to the method). The method is called reverse_merge because the Hash#merge method solves the conflict in the opposite way: in case of the same key in both, it keeps the one that belongs to the hash given as argument on merge. We can easily use merge instead of reverse_merge if we write the line 10 this way:

1
options = default_options.merge(options)

And then the code would work the almost the same way: the only difference is that instead of accessing local variables we may access the arguments in the options hash, but this can be easily converted. Also, note that we’re adding a bang (!) so, it will modify the hash and do the merge on itself instead of not modifying and returning other instance of hash.

Also, if you want to enforce that one option is always given, you can do this:

1
2
3
4
5
begin
  options.fetch(:format)
rescue KeyError # Hash#fetch raises KeyError when a key is not found
  raise ArgumentError, "The :format option should be passed"
end

Doing this, you will treat a missing argument the same way Ruby does with the function calling. However, I’m not a big fan of this approach: I think that if an argument is mandatory, it should be passed as a regular argument and not on as a function.

This pattern is heavily used on famous Ruby libraries like Rails, Bundler or Devise and plays a big part on pretty DSLs like Rails routes or Gemfiles. So, IMO, you should use it wherever you find a need to include more than 2 or 3 arguments on a function. Also, it is possible to use this on Javascript: if you take a look at jQuery’s ajax function it works the same way: you can pass the url as the first argument and the other parameters (like callbacks, fallbacks, urls, etc) as an object.

A big disadvantage in doing this is that it is very difficult to know what is the default options, and even looking at your code, you may only understand what is the default behaviour passing through all the code (which is far from good). So, I suggest that you document the default parameters and what does they mean like Rails do in this example with the has_many method.

UPDATE: As Rafael França suggested, I’m not overriding the argument anymore. As hashes are passed as a reference, when you execute merge! you actually change the parameter outside the function as an undesirable side effect.

UPDATE II: Adam Meehan reminded me on the comments that Hash#reverse_merge is part of ActiveSupport and not part of Ruby standard library. To be able to use it, you will have to require activesupport/core_ext/hash.

Conference Speaker 101

| Comments

TLDR: Here I talk some of the things that helped me to present my first talk at a conference

Last year, I presented my first talk at RS on Rails, which is a Rails (and Ruby) conference which happens in Rio Grande do Sul at the south region of Brazil.

Before that, I never had given a 40 minute talk at a conference (I’ve only talked about 20 minutes at FISL 2008 on a short talk about Archlinux) and as a regular geek I’m shy and I don’t think I’m someone which masters the skills to delivery great talks like Steve Jobs.

This posts intends to tell you some tips that helped me to prepare my talk, how I rehearsed it and what I did on stage.

Content is king

If you’re not a well known speaker, people will not watch you unless you have something great to tell them, so spend some time thinking about nice things to talk and if a regular attendant will be able to watch it. I remember about going to an event where the speaker talked about Ruby’s meta programming and 90% of the attendants were doing their first steps on Ruby and Rails. The speaker was really a good speaker and taught really nice things, but clearly he missed the point talking about this on an event with that amount of newcomers. You should measure if the subject that you will talk is too basic or too advanced for the event.

Before writing any slides or sending any proposal, create a list of topics that you will talk about. Validate this with a colleague and see if he thinks that you had chosen well the topics. If you’re not secure about the topics and your colleague didn’t get the point of your talk, try to write a draft of the slides and present it to your colleagues in order to get some feedback. If you have friends that talked on events, you can get valuable feedback and discover what is worth talking and what isn’t.

Study about creating great slides

Every time I think about boring things, I remember a professor in college that used to give his lectures using power point slides. I remember that most of the students slept or played games on their mobile phones. You may say that students should pay attention on what professors say, but in our defense, I say that his lectures were really really boring. Obviously, even if he is a great researcher and knew a lot about the subject he was teaching, he lacks knowledge on presentation preparation to keep the audience focused.

Of course, lectures and talks are more than great slides. But in order to deliver a great talk, you should prepare beatiful slides.

But how do we prepare a good talk ? There is some resources that teaches you how to prepare great talks. Due to a friend recommendation, I’ve read Presentation Zen: Simple Ideas on Presentation Design and Delivery by Garr Reynolds before preparing the slides. This book tells you how to prepare and present a great talk and design great slides. I’ve also watched the talk Your Slides Suck by Shane Becker, that tells you how not write slides. Other resource that was published after my presentation is Zach Holman’s blog post about slide design which tells developers (that generally lack design skills) how to create beautiful and great slides.

Rehearse, rehearse, rehearse

When you’re writing slides, you probably know what to say on each slide. But, do you really know how to connect it to the previous and the next slide? Also, you know how to explain it clearly? As expected your answer is probably “no”. So, you should rehearse. Check if you’re saying what you need to say in your presentation time frame without having to hurry or skip any subject. Also, check if you can explain clearly every topic (if you’re afraid to forget something and your presentation software have this feature, write a note visible only to the speaker about what you’re supposed to talk). If you’re not secure, present it to your colleagues and get some feedback about your explanations or examples. When I wrote my talk, I present it at least 4 times to my colleagues at Plataformatec and every rehearsal I got valuable feedback about it. I also presented it to myself several times, and the last one was on the night before the event.

Also, ask a friend to play the devil’s advocate and find flaws on your talk.

Rehearsing is really important, but keep in mind that you’re rehearsing to practice what you will say, not exactly what you will say. Don’t try to memorize everything, because listening to someone reading (or saying something that has been memorized) is way boring of listening to someone telling a story (unless you’re an actor, which is probably not the case).

On the stage

When you’re on stage, you will probably get nervous with all that people watching you. I remember, while presenting a lightning talk on Ruby Conf Brazil, a moment when I forgot what to talk and, on stage, I saw the crowd looking at me, and I thought I would not be able to continue presenting. Fortunately, I quickly remembered what to say and continued my talk. Asking my friends later, they said that this moment took around a few seconds, but appeared to me that it took at least fifteen seconds.

You will probably get nervous, but if you have rehearsed it enough you will calm down and keep it going.

Adding UTF-8 Support to Rubies Compiled Through Ruby-build

| Comments

If I had to point one thing that gives me true headaches, I would certainly choose encodings. I have already spent a lot of time dealing with encoding problems and I usually get stressful when a have to deal with a new one (I think it is common sense to suppose that everyone would prefer spending time dealing with other things instead of encodings).

So, last week I was using irb and pry to prepare a small course about Ruby and I found out that I couldn’t input UTF-8 characters. When trying to insert a á I was getting this unicode character code:

Encoding problem

After a quick glance in some search results for irb utf-8 problem, I discovered that I was having this problem due to a Ruby compilation without Readline (which is a library with some useful functions for command lines).

Fixing this was really simple due to the possibility of passing options to include on Ruby compilation on ruby-build. So it was only a matter of executing this line to recompile and reinstalling Ruby with Readline support.

1
CONFIGURE_OPTS="--with-readline-dir=/usr/local/Cellar/readline/6.2.2" rbenv install 1.9.3-p194

Of course, if your readline dir is somewhere else, please put the correct directory instead of the one I put there.

After that, irb and pry started to accept UTF-8 characters.

Encoding problem solved

UPDATE: Fixed some grammar issues.

UPDATE II: I’ve put a better picture for the solution

Why We Should Choose Stack Overflow Instead of Mailing Lists for Open Source Support

| Comments

This is a very opinionated blog post about why we should use Stack Overflow instead of mailing lists for open source support. This post doesn’t reflects the opinion of the company that I work for and I also didn’t receive any kind of benefit from Stack Exchange or its partners. As you may notice, I’m not an english native speaker, so if you find an gramatical or any error that may be related with a bad explanation, please provide some feedback in the commentaries. I will correct/explain better it as soon as I can.

In the past few months, I spent some time answering some questions about Devise on Stack Overflow and I found out that it is an awesome web application to ask and answer questions regarding open source projects (and everything else). I also try to follow some mailing lists of my favoured projects, but I realized how open source support works better on Stack Overflow than on Mailing Lists.

But firstly, what is Stack Overflow?

Stack Overflow is a free (as in free beer) Q & A website about programming, so if you have a doubt, uncertainty, problem or question about a library, framework or programming language, you can ask it there and there is a good chance for you to get an answer about it. It was the first site of Stack Exchange, a collection of 76 sites about a lot of subjects including System Administration, Cooking, Startups, Gaming, Sci Fi, Firearms and a lot of other websites about a lot of stuff.

But why is it so famous? Well, It is not a simple Q & A website. Given a question and a answer, you can give a +1 to the answer if it is useful or a -1 otherwise. You can also accept an answer for a question you asked, that is, you believes that a given answer was correct or solved the problem that you had. You can also assign a tag to your question, and some people who follow that tag may be able to answer it. You can also attribute a bounty for questions users find relevant but hasn’t received any good answers (and this bounties are basically points, which I will explain later on this text). Besides this, you can comment on questions and answers to ask more information about it, without having to pollute the answers with this. Needless to say that if your question doesn’t fit with the question policy it will be closed without mercy.

It also doesn’t have a “Big Brother” team that moderates questions: all questions are moderated by the community. But not all members can moderate questions: when contributing with questions or answers you may receive points, and depending of the number of points that you have, you gain some trust and some “power” become available for you. In the beginning you can only ask and answer questions but after some points you can edit questions and answers, assign bounties, comment on questions or answer and even moderate questions and answers. You can also earn badges, based on goals. In summary, you earn trust and power through desert. Ask wise questions and provide great answers and you gain power. Promote or post spam, off-topic or flamewars and you will be banned.

Well, IMHO, I find it awesome. A lot of questions get answered in reward of points and badges that can make a lot of people (including recruiters) hear your name. This number of points, also appear besides your name on every question that you answer, which provides you more credibility. It is nothing more than a “gamificated” and improved internet forum that works.

But what about Mailing Lists? Mailing lists exists in a long time and became very popular with Yahoo groups and Google groups among other famous options. They’re very easy to use (just a matter of sending and replying to e-mails) but they do lack of a good search tool (it is not easy to find a question about something with only a naïve text field search) and usually have problems with off-topic discussions and , spam and flamewars. Ok, this is a human problem, but well moderated communities tend to have less problems with that matter. Also, e-mails aren’t a good place to discuss about code: the lack of a source code formatting turns very difficult to read it. The moderations is also difficult: you can’t remove an e-mail after it was received by the list, so irrelevant or off-topic questions may get more repudiating replies and attention than well founded questions about topics that really matter. Although they’re not great for support, they’re great to ask opinions and provide discussions and even announce new versions.

So, I’m not suggestions that we should stop using discussion lists. I’m only suggesting that we may reduce its scope to not accept (or accept and recommend posting it on Stack Overflow next time) support questions (some open source software already have two lists to avoid questions being asked on the development mailing list, which may be used for discussions about the development of the software, e.g. MongoDB-user and MongoDB development for support question), so it is only a matter of encourage users to send questions to Stack Overflow instead of posting on the support list.

To summarize, we have two options: one that seems to be outdated and its search only based on full-text search, without giving relevance to the content (as tags do), and not easily moderated. And another that provides support to source code formatting, tag assignment (and tags may have more relevance than words on a text) and that can be easily moderated. Other great advantage: we may sort the answers by the sum of all scores, so the answer that gets the biggest number of +1 (and is probably more useful than the others), will appear first. In contrast, there isn’t anyway to say that an answer solves your problem on a mailing list without having to send a message and the mail thread starts to get difficult to read.

So. here is an idea: why don’t we stop using it for support and only use it for discussion or announcements? OK, users may not like this at first and we may think about a smoothly transition, but in long term, we may have better resources to find questions and to follow a tag and answer questions about it.

What do you think about this? Would you use it for your open source project support?

EDIT: Fixed some broken links

Rails Documentation

| Comments

As a Rails developer, I frequently have to check some definitions or get some help about a method or class on the api documentation. In my first months as a Rails developer, I used the official documention, but after some months I discovered other alternatives, which I preferred over the official documentation.

But firstly, what’s wrong with the official documentation ?

Some days before Rails 3.1 release, the official documentation was redesigned and it became so much better than it was, I liked the navigation sidebar, where you can find a method or a class easily. But (and this is IMHO) I still find it very unpleasant to read. However, as an official documentation, it is updated by the same time that the code is released and I expect it to have documentation for “edge-ish” Rails features (there is also a version which is synchronized with rails master branch).

But what are the options ? There is two options that I found out to be great. The first one is Rails Searchable API Doc and the second one is Apidock. There is also another options like RailsBrain which seems to be abandoned (the latest Rails version there is 2.3.2) or to import the documentation into the OSX dictionary which I have not tried it yet.

Rails Searchable API Doc

Rails Searchable API Doc is the documentation I currently use when I develop Ruby on Rails applications. It has a nice look and also have the cool sidebar (by the way, the new design of Rails official documentation uses this engine, but with different colors). It also allows adding the Ruby language documentation and another popular libraries documentations as well. So, as a developer that most of the time uses Ruby, Rails, RSpec and Nokogiri, the possibility of adding this other documentations on the same window is great. Other cool option is the possibility of selecting the documentation for a minor version, so you can select the documentation for Rails 2.3.x, Ruby 1.8.x and Nokogiri 1.3.x. Besides this, we can download the full documentation (including generating a custom package of documentation) to access it locally (if you have a mac, you can use Fluid to setup an App with the documentation. Ok, you can do the same with the Rails documentation, but it is not easy as this. If you like this alternative and you also uses jQuery you can use a similar version to check the library’s documentation.

However, there is some points you should consider when using railsapi documentation: it is not updated as the official one (the current version is 3.1.3 but Rails api is still on 3.0.8rc1, one minor version behind). Other problem resulting of the possibility of adding many libraries, is that the results of a search can show you some irrelevant results, as you can see in the image above.

example with merge

If you want to access enumerable#merge (which is probably the most popular between these results) you will have to look for results that aren’t what you want.

Api Dock

I used Api Dock a lot, but as I prefer an offline based version of a documentation, I choose Rails Searchable API Doc. But, there is some really nice reasons try Api Dock out.

First of all, it allows people to make comments to make the documentation more comprehensible (there is a nice example on has and belongs to many documentation) and it also allows other people to thank who wrote the commentary. Besides this, it gives you a nice look about a class/method among Rails versions, so you can see the point where something has been added or removed. It also lists some related methods whose documentation can be useful. It is also more updated than Rails Searchable API Doc, as of the time of writing this post, it is on version v3.1.0. It also shows the current status of the documentation, if it is extensive or there is only a few lines of explanation.

One shortcoming of Api Dock is that it is not open source, so you can’t generate it on your computer and access it locally, although it is free (as in free beer) to use. It is also only available for three projects: Ruby, Rails and RSpec and they can’t be accessed simultaneously (which can be bad if you like to see several documentations together but the search results doesn’t shows a lot of irrelevant results).

What about you? What documentation do you use? Have you tried these three I mentioned? Do you want to recommend me another documentation ?

Hello World - This Is My New Blog

| Comments

Hi, my name is Rodrigo Flores and this is my new blog.

I used Octopress, a blog engine based on Jekyll to build it and Heroku to host it. Both are simple to set up and well documented, so I was able to put it into production in a few hours (I also made some changes on the layouts to adapt it to what I wanted)

So, this is it. I hope you enjoy the content :)