Filed under: ruby

Tutorial - Using Compass and SASS in a Java project

About six months ago, when I was still in Australia, my team decided that we needed to do a UX revamp for the application we were building. As part of that initiative, I suggested to start using Compass and SASS, which would simplify our CSS and make it more readable, alowing us to refactor everything that we would need and extract common stuff.

At that time, we tryied to find some Java library that could help us, with no success. We wanted to have a single jar with JRuby and all the gems that were needed and integrate everything with Ant. Today, for what I have searched, there is still no good solutions out there, so I have decided to share what we did.

Let me guide you through the required steps:

 

1 - Downloading JRuby

Just download the latest JRuby version and put into a place where you can modify it.

 

2 - Bundle pure-Ruby gem applications into an uber-jar

Here we followed this great tutorial, which explains each of the steps for creating our own jar. I have extracted the necessaries commands below and if you want more explanation about what is going on I suggest reading the post that I have mentioned.

java -jar jruby-complete-1.6.0.jar -S gem install -i ./compass compass
jar uf jruby-complete-1.6.0.jar -C compass .
java -jar jruby-complete-1.6.0.jar -S gem list

You can move the modified jar into the /lib folder.

 

3 - Creating Compass config files

a) create the /config/compass/compile.rb file

This file will have the ruby code that will be invoked by Ant and it's responsible for requiring all the dependencies and invoking compass. We also need to specify what is the command that we want compass to execute (we will have two possible commands: compile, which will convert *.sass files into *.css files and watch, which will watch a folder for modified content, and as soon as a .sass file is modified, the .css version of this file will be automatically created).

Dir.entries(ARGV[0]).each do |lib|
    $LOAD_PATH.unshift "#{ARGV[0]}/#{lib}/lib"
end
 
require 'rubygems' 
require 'compass'
require 'compass/exec'
 
command_line_class = Compass::Exec::Helpers.select_appropriate_command_line_ui [ARGV[1], ARGV[2], "-q"]
exit command_line_class.new([ARGV[1], ARGV[2], "-q"]).run!
 

b) create the /config/compass/config.rb

This file will have the properties required by Compass. Basically we need to specify where is the input folder, with all the *.sass files, and where is the output folder, with all the *.css files converted.

  # Require any additional compass plugins here.
 # Set this to the root of your project when deployed:
 http_path = "../../"
 css_dir = "../../src/main/webapp/css/"
 sass_dir = "../../src/main/webapp/sass"
 images_dir = "../../src/main/webapp/images"
 javascripts_dir = "../../src/main/webapp/javascripts"
 # To enable relative paths to assets via compass helper functions. Uncomment:
 # relative_assets = true
 

 

4. Now the last step is to integrate everything with Ant:

a) Loading JRuby into the claspath:

<path id="jruby.classpath">
    <fileset dir="lib/build">
        <include name="jruby*.jar"/>
    </fileset>
 </path>

 

b) Being able to invoke "ant compile.sass":

This will be basically used to convert *.sass files into *.css files and will be invoked automatically during the compile phase.

<target name="compile.sass">
     <java classname="org.jruby.Main" fork="true" failonerror="true" classpathref="jruby.classpath">
         <arg line="conf/compass/compile.rb ${basedir}/vendor/gems compile ${basedir}/conf/compass"/>
     </java>
 </target>
 

 

b) Being able to invoke "ant watch.sass":

This is very helpful in development mode as you can change the .sass file and verify the results just checking the browser.

<target name="watch.sass">
     <java classname="org.jruby.Main" fork="true" failonerror="true" classpathref="jruby.classpath">
         <arg line="conf/compass/compile.rb ${basedir}/vendor/gems watch ${basedir}/conf/compass"/>
     </java>
 </target>
 

 

c) Integrating with the compile phase:

<target name="compile.main" depends="setup-dependencies, compile.sass">
     <compile-folder folder="main" to="${main.classes.dir}" classpathref="main.dependencies"/>
</target>

 

 

If this was helpful or if you have any questions / suggestions, don't hesitate in writting a comment.

Utilizando cucumber para testar qualquer aplicação web

Há algum tempo venho utilizando o Cucumber em um cliente para testar aplicações web feitas em ASP e .NET. Nesse post, vou mostrar como configurar todo o ambiente, mas assumo que você já esteja familiarizado com Cucumber e Webrat. Além dessas duas bibliotecas, precisaremos ainda do Mechanize, uma gem capaz de automaticamente armazenar cookies, fazer redirects, enviar forms, etc; e tudo isso de forma integrada com o Webrat e Cucumber. Para chegar a solução atual, fiz uma pesquisa em diversos sites, mas mesmo a referência oficial do webrat não funcionava para mim, então acredito que esse post possa beneficiar mais pessoas. Antes de mais nada, é necessário instalarmos as gems que utilizaremos: sudo gem install cucumber webrat mechanize Para começar, vamos criar a estrutura de diretórios necessária: |teste |--features - onde ficarão nossas features |----step_definition - nossos webrat steps |----support - onde ficará nossos arquivos env.rb e paths.rb Vamos agora configurar nosso arquivo features/support/env.rb:
require 'webrat'

include Webrat::Methods
include Webrat::Matchers

Webrat.configure do |config|
  config.mode = :mechanize
end

World do
  Webrat::Session.new(Webrat::MechanizeAdapter.new)
end
Crie também o arquivo features/step_definitions/webrat_steps.rb, note que esse arquivo é o mesmo que é gerado quando você utiliza o cucumber em aplicações Rails, mas reproduzi na integra esse arquivo:
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))

# Commonly used webrat steps
# http://github.com/brynary/webrat

Given /^I am on (.+)$/ do |page_name|
  visit path_to(page_name)
end

When /^I go to (.+)$/ do |page_name|
  visit path_to(page_name)
end

When /^I press "([^\"]*)"$/ do |button|
  click_button(button)
end

When /^I follow "([^\"]*)"$/ do |link|
  click_link(link)
end

When /^I follow "([^\"]*)" within "([^\"]*)"$/ do |link, parent|
  click_link_within(parent, link)
end

When /^I fill in "([^\"]*)" with "([^\"]*)"$/ do |field, value|
  fill_in(field, :with => value)
end

When /^I fill in "([^\"]*)" for "([^\"]*)"$/ do |value, field|
  fill_in(field, :with => value)
end

When /^I fill in the following:$/ do |fields|
  fields.rows_hash.each do |name, value|
    When %{I fill in "#{name}" with "#{value}"}
  end
end

When /^I select "([^\"]*)" from "([^\"]*)"$/ do |value, field|
  select(value, :from => field)
end

When /^I select "([^\"]*)" as the date and time$/ do |time|
  select_datetime(time)
end

When /^I select "([^\"]*)" as the "([^\"]*)" date and time$/ do |datetime, datetime_label|
  select_datetime(datetime, :from => datetime_label)
end

When /^I select "([^\"]*)" as the time$/ do |time|
  select_time(time)
end

When /^I select "([^\"]*)" as the "([^\"]*)" time$/ do |time, time_label|
  select_time(time, :from => time_label)
end

When /^I select "([^\"]*)" as the date$/ do |date|
  select_date(date)
end

When /^I select "([^\"]*)" as the "([^\"]*)" date$/ do |date, date_label|
  select_date(date, :from => date_label)
end

When /^I check "([^\"]*)"$/ do |field|
  check(field)
end

When /^I uncheck "([^\"]*)"$/ do |field|
  uncheck(field)
end

When /^I choose "([^\"]*)"$/ do |field|
  choose(field)
end

When /^I attach the file at "([^\"]*)" to "([^\"]*)"$/ do |path, field|
  attach_file(field, path)
end

Then /^I should see "([^\"]*)"$/ do |text|
  response.should contain(text)
end

Then /^I should see \/([^\/]*)\/$/ do |regexp|
  regexp = Regexp.new(regexp)
  response.should contain(regexp)
end

Then /^I should not see "([^\"]*)"$/ do |text|
  response.should_not contain(text)
end

Then /^I should not see \/([^\/]*)\/$/ do |regexp|
  regexp = Regexp.new(regexp)
  response.should_not contain(regexp)
end

Then /^the "([^\"]*)" field should contain "([^\"]*)"$/ do |field, value|
  field_labeled(field).value.should =~ /#{value}/
end

Then /^the "([^\"]*)" field should not contain "([^\"]*)"$/ do |field, value|
  field_labeled(field).value.should_not =~ /#{value}/
end

Then /^the "([^\"]*)" checkbox should be checked$/ do |label|
  field_labeled(label).should be_checked
end

Then /^the "([^\"]*)" checkbox should not be checked$/ do |label|
  field_labeled(label).should_not be_checked
end

Then /^I should be on (.+)$/ do |page_name|
  URI.parse(current_url).path.should == path_to(page_name)
end

Then /^show me the page$/ do
  save_and_open_page
end
Ainda precisamos criar nosso arquivo /features/support/paths.rb, que será responsável pelo mapeamento dos sites que iremos testar:
module NavigationHelpers
  # Maps a name to a path. Used by the
  #
  #   When /^I go to (.+)$/ do |page_name|
  #
  # step definition in webrat_steps.rb
  #
  def path_to(page_name)
    case page_name

    when /google/                  # poderia ser minha_app
      'http://www.google.com'      # e http://localhost:8080/minha_app
    else
      raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
        "Now, go and add a mapping in #{__FILE__}"
    end
  end
end

World(NavigationHelpers)
Agora só falta criarmos nosso teste. Crie o arquivo features/teste.feature:
Feature: Testing
In order to value
As a role
I want feature

  Scenario: google
    Given I am on google
    When I fill in "q" with "java são paulo curso"
    And I press "Pesquisa Google"
    Then I should see "Caelum"
Agora basta executarmos nosso teste com o comando cucumber