This summer I was selected with Josh Peek, Emilio Tagua and Nelson Crespo to work with Rails on Google Summer of Code (GSoC), which Nelson named as the Rails Summer Quartet.
Here, at Plataforma, we use a set of tools on our projects, which includes Inherited Resources, Remarkable and Formtastic. At some point, we were planning on creating generators for each of those tools but still they couldn’t play along. If I wanted a generator that uses all three projects, I needed to create a inherited_remarkable_formtastic generator which is not DRY at all.
For example, for those who wants to use Datamapper with Rspec, they need to call “ruby script/generate dm_rspec_model” instead of “ruby script/generate model”. Since Rails 3.0 is moving towards agnosticism, my GSoC proposal was exactly bring it to rails generators.
1. So, what about Thor?!
One day before the official coding period start, I was staring at this Thor post by Yehuda Katz. Thor is a rake replacement with support to options parsing:
class Speak < Thor desc "name", "the name to say hello to" method_options :loudly => false def hello(name) name.upcase! if options[:loudly] puts "Hello #{name}" end end
And then can be invoked as:
> thor speak:name jose Hello jose > thor speak:name jose –loudly Hello JOSE
At that point, I realized that a generator is nothing more than a scripting task (like rake or thor) with some extra methods which makes the creation and copy of files easy. Thor had several features which convinced me that it was the best solution to build generators on top of:
- It has a powerful options parser;
- Thor classes can be inherited and all tasks from the class are copied to the child;
- Thor classes are self contained. The example above can be invoked straight from your ruby code as Speak.new.hello(“jose”).
Then I was able to create a ROADMAP to Thor:
- Add actions like copy_file, template, empty_directory to Thor;
- Move all user input and output logic to its own class, so anyone can customize it;
- Extend even more Thor options parser to add support to hashes (as in Rails name:string age:integer on generators) and arrays;
- Add an invocation mechanism, so I can invoke one task from another Thor task.
2. An example
Let’s see an example on how you can create your own generators with Thor. For example, a generators that stubs out a new gem structure:
class NewgemGenerator < Thor::Group include Thor::Actions # Define arguments and options argument :name class_option :test_framework, :default => :test_unit def self.source_root File.dirname(__FILE__) end def create_lib_file create_file "#{name}/lib/#{name}.rb" do "class #{name.camelize}\nend" end end def create_test_file test = options[:test_framework] == "rspec" ? :spec : :test create_file "#{name}/#{test}/#{name}_#{test}.rb" end def copy_licence if yes? "Use MIT license?" # Make a copy of the MITLICENSE file at the source root copy_file "MITLICENSE", "#{name}/MITLICENSE" else say "Shame on you…", :red end end end
You can see from the example above that we are inheriting from Thor::Group and not Thor. In Thor, each method corresponds to a task, which can be invoked on its own. In Thor::Group, you invoke all tasks at once, in the order they are declared. This is interesting because you split your script/generator into several methods. It improves readability and allows anyone to inherit from your generator and change just one step in the process.
The next step, on lines 4 and 5, is to define arguments and options for the class. Arguments are required to be given right after the executable while options are given with switches. The newgem above can be invoked as:
newgem remarkable
And it will create two files: “remarkable/lib/remarkable.rb”, “remarkable/test/remarkable_test.rb” and prompt the user (with the use of the method yes?) if we wants to copy the MITLICENSE. If you want to change the test framework, you can give it as an option:
newgem remarkable --test-framework=rspecNow it generates “remarkable/lib/remarkable.rb” and “remarkable/spec/remarkable_spec.rb”.
The generation methods are kept into the Thor::Actions module, which is included on top of our class. It holds all the scripting methods, which are: copy_file, create_file, directory, empty_directory, get, inject_into_file and template. All those actions can be revoked, so Thor knows how to do and undo the process (like in script/generate and script/destroy).
Even more, some of Rails templates methods was moved to Thor, like: inside, run, run_ruby_script, gsub_file, append_file and prepend_file. So whenever creating scripts with Thor, those methods will be available to make your life easier.
Finally, all user iteration methods are handled by Thor::Shell classes by say, ask, yes? and no? methods. Thor ships with two Shell implementations: Basic and Color. If you mantain an IDE for Rails, you can build your own shell and make the user interaction through it.
3. What is more?
Thor is used as base in Rails::Generators, where Rails extend it to provide Rails specific functionalities, as hooks for ORM, Test framework and so on. This will be my talk subject on Rails Summit Latin America, 13th October, in São Paulo, Brazil.
If you can join us or not, be sure to grab our RSS feed and keep on checking, we will discuss about it here too.
Tags: generators, gsoc, rails, thor
Posted in English | 8 Comments »
Pergunta: Em uma frase, o que é a <plataforma/>?
Resposta: É uma consultoria em engenharia de software.
Pergunta: AH! Uma fábrica de software?
Resposta: NÃO!
Fábricas são locais que produzem commodities através de processos e modelos essencialmente estabelecidos no século XVIII. A atividade de desenvolvimento de softwares é muito mais recente e comprovadamente não se adequa aos modelos de produção industriais. Para ilustrar o cenário atual, pegamos os dados referentes à 2008 da The Standish Group (CHAOS Summary 2009, The Standish Group). De acordo com o levantamento feito por eles, 64% dos projetos de desenvolvimento de software atrasaram, ultrapassaram seus orçamentos, foram entregues parcialmente ou simplesmente foram cancelados.
Então, fica a pergunta: “O que está errado com a indústria de software?”
Sob a nossa ótica, o desenvolvimento de software deve ser tratado como uma prestação de serviços cujos principais ativos são as habilidades técnicas dos desenvolvedores e a capacidade gerencial que assegure que o projeto será entregue de acordo com as necessidades do cliente e executado sem desperdícios de tempo ou dinheiro.
Softwares não devem ser “fabricados” e desenvolvedores não são máquinas.
Desenvolver software é uma prestação de serviço feita por profissionais com talentos distintos e únicos.
Você contrataria uma “Fábrica de Planejamentos Estratégicos” ou uma Consultoria Estratégica?
O ponto em questão é esclarecer que existe uma carga conceitual pesada que justifica as limitações das “fábricas de software”. É fato que elas não atendem seus clientes como deveriam.
Dado o contexto, podemos concluir este post dizendo que não somos uma fábrica de software. Nós prestamos serviços de consultoria em engenharia de software. Nós realmente acreditamos que se enxergarmos o problema sob esta perspectiva entregaremos softwares funcionais, dentro do prazo, do orçamento e que gerem valor aos nossos clientes.
Bem, sobre o nosso blog… Ele será nosso canal de comunicação com pessoas que tiverem interesse em desenvolvimento de aplicativos web. Falaremos muito sobre Ruby, Ruby on Rails e engenharia de software em geral. Esperamos que gostem!
Abraços!
George, Hugo, José e Marcelo.
Tags: developer, plataforma, software, success
Posted in Português | Comments Off

All
English only
Em português apenas