Have you ever read about easyb? and about Grails? May be you answer yes to one or both previous questions, but this is the first time you will find them together I guarantee, at least in a plugin form.
This is the first post I’m writing about my latest toy project (at least for now it is only a toy project).
The project is hosted at GitHub, and any help will be very welcome since I do not work every day with Grails, but I did a presentation about grails in the last weekend and wanted to use BDD instead of the traditional GUnit based unit tests, I already use Easyb for some of my Java projects, then I wanted to make Easyb and Grails to work together.
It was not an easy task, because of some craziness of Grails class loader, but it is working fine now.
You can write a test with the easyb sintaxe, and the test will look line this:
scenario "Project creation", { given "A new project", { project = new Project() } when "the project name is supplied", { project.name = 'My test project' } and "there is no other project with that name", { validateproject = { project.validate().shouldBe true } } then "a new project must be created", { validateproject() project.save(flush:true).shouldNotBe null } } scenario "User association with a project", { given "Any existing project", { project = Project.findAll()[0] } when "a list of users is supplied", { users = [new User(login:'testUser1',password:'testUser1',email:'test1@test.com').save(),new User(login:'testUser2',password:'testUser2',email:'test2@test.com').save()] } then "the users must be associated with that project", { users.each{ ProjectMembership.link(it,project) } } }
You can even show it to your boss, because the output of this test is some thing like this:
Story: project management
scenario Project creation
given A new project
when the project name is supplied
when there is no other project with that name
then a new project must be createdscenario User association with a project
given Any existing project
when a list of users is supplied
then the users must be associated with that project
And the best part of it, is that you can use your tests as the specifications of your next grails project!
If you want to know more about the easyb sintax, take a look at the project site.
If you want to know more about grails, take a look at the project site.
If you want a new functionality in this plugin, I’ll probably accept all patches and push requests you send-me ![]()
And finally, if you want to install the plugin, download it from here and run:
grails install-plugin grails-easybtest-latest.zip
You will need to place the tests you write in the folder tests/behavior
And to run the tests, just type: grails easyb-test
Any doubts or suggestions leave a comment here ![]()
I hope it can be useful to others.
If you enjoyed this post, make sure you subscribe to my RSS feed!
Tags: easyb, easyb-test, grails, petproject, plugin, test
Following the sequence I started here, but changing the proposed order, let’s talk a little about Rails Generators.
Generators are one of the coolest things in Rails!
Of course you have already seem them, remember the first screencast you’ve seen about rails? Yes, that one where the guy wrote an entire CRUD application in two minutes …
Generators are a way to, generate code
But the generated code can be what you want, and rails already has a great support for writing generators, because it is already used in the rails core.
OK, but why would you want to write a generator?
Think about the project that is starting today, remember all that CRUD forms you’ll need to create, or that almost equal start point for every page of the application …
Now think about all the applications for your company …
Got it?
Ok, I agree that “scaffolding” a generic CRUD is not really useful, but if that scaffold is done following your company standards, it can improve a lot the development performance …
Now, I guess you are thinking: Good, generators seem cool, but stop the easy talk e show me the code!
So, let’s play a little …
Wi’ll start creating a new rails project: rails plugins102
Now from the project directory run: script\generate plugin my_generator
(if you think this is kind of a flash back, maybe you read my previous post about creating rails plugins
)
Now that you have already created your brand new plugin, let’s write some code!
To create a generator you need to create a generators directory inside your plugin’s directory, a directory with the name you want for your generator (for example test_gen), and a templates directory inside the previous one, for example, it will look like this:
Ok, you do not really need a plugin to create a generator, you can of course, place your brand new generator inside the following directories:
But I think that a plugin is the easiest way to do it, and it will be easier to deploy to your applications too.
Of course that a GEM would be a better way, because you can install only once per machine, and does not need it installed on the server, but I have never created a GEM before, so let’s stay with the plugin for a wile …
to start coding the generator, we’ll need to create a file named [generator_name]_generator.rb inside the generator’s directory, in my case, I’ve created the file: my_generator/generators/test_gen/test_gen_generator.rb
Now inside that file, create the class to define your generator, it must be named according to the file name, in my case TestGenGenerator, and this class must extend one of the base classes for Rails generators:
Rails::Generator::Base or Rails::Generator::NamedBase, I’ll use NamedBase (The base for the controller generator), and I’ll create a generator for a model and a migration, just to show how to do it …
The NamedBase is the perfect base class for generators that expect parameters in the form: Name [param1] [param2] …
For all the others, Base is a best start point …
The starting point for our code is:
1 2 3 4 5 6 7 | class TestGenGenerator < Rails::Generator::NamedBase def manifest record do |m| end end end |
In this class, all we need to do is to set up the generator’s manifest (more on this later) and to setup any local variables to be used by our templates (more on this later too).
with only this, we can already run: ruby script\generate test_gen asdas_dasda asd:ash (randon letters as parameters for now).
The NamedBase will automatically set up some variables for us, and the values for the given parameters will be:
of course this generator now will generate nothing, because our manifest is empty, so let’s build a simple example to see how it really works …
so, lets create inside the template directory, a directory called “dummy”, and a blank file called “log.log” inside of it and let’s change the manifest method to some thing like this:
1 2 3 4 5 | def manifest record do |m| m.file 'dummy/log.log', "log/#{file_path}.log" end end |
This code will tell the generator, to copy our newly created, blank file, to $APP_ROOT/log/asdas_dasda.log if we run the generator with the same parameters as before …
but just copying files from one place to another is not a very cool thing to be done, so let’s play a little with ERB, and let’s create a migration for our plugin, so we need to change again the manifest method as follow:
1 2 3 4 5 6 7 8 | def manifest @migration_name = "Create#{class_name}" @migration_action = "add" record do |m| m.file 'dummy/log.log', "log/#{file_path}.log" m.migration_template 'lib/mymigration.rb',"db/migrate", :migration_file_name => "create_#{file_path}" end end |
As you can see in the code, I’m telling the manifest that I have a template named mymigration.rb inside the directory lib in my templates directory, it will be processed and the result will be placed inside the directory “db/migrate” and will be called “000_create_asdas_dasda.rb” (the 000 will be replaced with the latest migration number plus one as the normal “generate migration” command do.
to be able to access the attributes migration_name and migration_action in the template, we need create the accessor methods for them, it is as easy as adding the following line to the TestGenGenerator class (outside the manifest method):
1 | attr_accessor :migration_name, :migration_action |
My migration template is the following:
1 2 3 4 5 6 7 8 9 10 11 | class <%= migration_name.underscore.camelize %> < ActiveRecord::Migration def self.up<% attributes.each do |attribute| %> <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end -%> <%- end %> end def self.down<% attributes.reverse.each do |attribute| %> <%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end -%> <%- end %> end end |
It is an ERB template that will generate a ruby file.
Now we have already a very cool working plugin, but what else can we do?
to answer this question, I’ll quote a little the documentation of the Rails::Generator::Commands::Create class, that means, what can you do within the manifest method:
I think that is it, you can ask more questions if you want, I’ll try to answer all, if any
for more resources on Rails generators you can follow this links:
http://wiki.rubyonrails.org/rails/pages/UnderstandingGenerators
http://www.aidanf.net/node/33
http://api.rubyonrails.org/classes/Rails/Generator/Base.html
http://api.rubyonrails.org/classes/Rails/Generator/NamedBase.html
http://api.rubyonrails.org/classes/Rails/Generator/Commands/Create.html
I hope this little step by step help some one!
The next one will be about writing tests for your plugins! and the fourth I have not started to think about yet
If you enjoyed this post, make sure you subscribe to my RSS feed!
One of the beauty of Ruby on Rails are the Plugins …
Ruby On Rails itself is already a great framework, but the combination of Rails plugins with the Ruby Open Classes is a killer feature!
This little combination enables you to create you own “tags” to be used in your views and layouts.
And it is really easy to create this kind of helper in Rails.
The non plugin way is to create a method in one of the Helper classes (the ones in app/helpers directory), for example, if all the forms in your application are inside a table, with one column for the label and one column for the real field, you can create a helper to simplify the code in your views like this:
The standard very simple form for the “Example” model we created for this example, in the application standards would be:
1 2 3 4 5 6 7 | <% form_for(@example) do |f| %> <table> <tr><td><label for="example_name">Name</label></td><td><%= f.text_field :name %></td></tr> <tr><td><label for="example_name">Url</label></td><td><%= f.text_field :url %></td></tr> <tr><td colspan="2"><%= f.submit "Update" %></td></tr> </table> <% end %> |
but if we edit the file app/application_helper.rb and add the following method there:
1 2 3 | def textfield label, object, property, options = {} %Q{<tr><td><label for="#{object.to_s}_#{property.to_s}">#{label}</label></td><td>#{text_field object, property, options}</td></tr>} end |
we could simplify a lot the code only with the help of this “helper”, the new form code would be like this:
1 2 3 4 5 6 7 | <% form_for(@example) do |f| %> <table> <%= textfield "Name", :example, :name %> <%= textfield "Url", :example, :url %> <tr><td colspan="2"><%= f.submit "Update" %></td></tr> </table> <% end %> |
for this little form, this is too much work for some less characters in the view, but if you think about your entire application it would help you a lot!
Now think bigger, this ugly table/form standard I’ve created is the standard for the entire company, all applications in the company follow this standard.
So all developers, always write the forms using the first option (the ugly one, with lots of HTML).
and one day, a new designer tells that you need to add one new class in the “TR” tag in all forms for all applications, and you start crying ![]()
Or you choose to use the second option (with the helper method) and just need to change one line of code for each application in the company!
Now you are a hero, right?
But if you are smarter than this? what about creating a plugin, that all applications can use, and define this tag inside the plugin?
That way you change only one line of code, test only once, and all applications will be fixed at the same time!
And as always with Rails, this is a lot easy to do!
Just follow this steps:
1 2 3 4 5 6 | # LifeSaver module LifeSaver def textfield label, object, property, options = {} %Q{<tr><td><label for=#{object.to_s}_#{property.to_s}>#{label}</label></td><td>#{text_field object, property, options}</td></tr>} end end |
1 2 | # Include hook code here ActionView::Base.send :include, LifeSaver |
Now you have just created your first Ruby On Rails plugin!
And yes, the code is the same as the one used in the application_helper.rb, the only trick here is in the init.rb file of the plugin, that line of code is including all methods of the module “LifeSaver” in the base class for all Rails views, the ActionView::Base class …
Now, if you did this, instead of just adding a helper method to each application, tell your boss how much time you have saved for the company with this little story here, and ask for a rise
I hope this little step by step help some one!
The next one will be about writing tests for your plugins, and the third one will talk about plugins with generators, the forth you’ll have to come back here to discover
If you enjoyed this post, make sure you subscribe to my RSS feed!
Tags: ActionView::Base, howto, plugin, rails, ruby, step-by-step