Ruby Série #3 – Operador Splat

November 10, 2009 at 12:52 pm | In Ruby/Rails | Leave a Comment

Olá pessoal vamos para o terceiro post da série de Ruby, este post irá ser um pouco mais pequeno porque
irá tratar apenas de um operador, esse operador é o Splat.

O Operador Splat é usado quando queremos em uma atribução fazer com que vários valores de um array se tornem
rvalues, como por exemplo:

a, b, c, d = 10, 11, *[12,13]

Como da para se notar o que mudou foi o último rvalue sendo precedido por um *.

No Ruby 1.8 Arrays e Rangs podem ser splatted, ele também fornece um método to_ary que retorna um array de valores.

Também podemos fazer ao contrário, fazer um ivalue ter um *, quando isso acontece os rvlues extras são postos em um array e são atribuidos a tal valor.

x, *y = 1, 2, 3

Aqui x = 1 e y = [2,3]

OBS: No Ruby 1.9, você pode ter quantos splats quizer, para ver mais sobre Splat no 1.9 veja esse link:
http://ruby.about.com/od/newinruby191/qt/MultipleSplats.htm

Bom pessoal esse post foi rápito espero que deu para aprender algo com ele :D

Até o Mais.

Série Ruby #2 – Atribuições

November 6, 2009 at 2:36 pm | In Ruby/Rails | Leave a Comment

No último post foi visto como o Ruby trabalha com os 5 tipos de varíaveis, falamos bastante sobre atribuições também, então neste post iremos falar um pouco mais sobre isso.

Atribuições

Uma atribuição é um expressão que pode especificar um ou mais de um valor para uma dada varíavel ou mais corretamente
de um Ivalue.
IValue é um termo para indicar o que aparece antes de um operador de atribuição, por exemplo:

x = 10

Na expressão acima x é um ivalue e um rvalue que é 10.
No Ruby existem três tipos de expressões de atribuição, a mais simples vista acima e outras duas que vamos ver agora.

As atribuições abreviadas que são expressões que além de atualizar um valor ainda aplicam alguma matemática sobre o ivalue
certamente você já fez isso:

x *= 10

Também tempos as atribuições paralelas que são aquelas em que um rvalue é atribuido a n ivalues, por exemplo:

x, y, z = 10

Também é possivel tem n ivalues e n rvalues, assim:

x, y, z = 2, 4, 6

Aqui x recebe 2, t recebe 4 e z recebe 6.
O que um ivalue recebe como conteúdo é o valor ou array de valores que é à ela atribuido. Um operador de atribuição é righ-assiciative ou seja, a atribuição é avalidada da direita para a esquerda, com isso podemos fazer isso:

a = b = 4

Aqui b recebe 4 e a também recebe 4.

Efeitos colaterias – Idempotent.

Como vimos uma atribuição muda o estado de uma varíavel isso muda o estado de um programa por exemplo,
existem várias expressões que não tem efeitos colaterais algum, pois toda a vez que são avalidas irão retornar o mesmo valor ,por exemplo:

Dado um método para calcular a raiz quadrada de um número inteiro e positivo:

	def raiz(x)
	   return x * x
	end

Esse método não tem efeitos colaterais, esse tipo de expressão é chamado de idempotent, você pode
avaliar o método acima n vezes e ele sempre irá retornar o mesmo valor, já a seguinte expressão irá mudar a cada vez que for executada:

x += 1

Você pode ler mais sobre isso em: http://en.wikipedia.org/wiki/Idempotence
Bom pessoal, esse foi o segundo post da série Ruby. Até mais e Obrigado.

Série Ruby #1 – Varíaveis não inicializadas

November 3, 2009 at 2:01 am | In Programação, Ruby/Rails | 2 Comments

Varíaveis não inicializadas

cplx

Olá esse será o primeiro post de uma série que pretendo fazer falando sobre Ruby(A Linguagem)
Tentarei manter em posts pequenos com exemplos de código ou não,  não terá uma ordem do tipo: básico – intermediário – avançado, irei postando conforme eu achar melhor, ou se alguem vier a ler também gostaria de ouvir comentários sobre assuntos que poderiam serem abordados nos posts.

Para começar irei falar um pouco sobre “Varíaveis Não Inicializadas”. Então chega de bate papo e vamos ao post.

Se você já programa em alguma linguagem digamos assim mais conhecida como Java ou C sempre após a declaração de uma varíavel é recomendado que você à inicialize antes de fazer seu uso, uma das razões para se fazer isso é que pode acontecer de o local(na memória(1.a)) onde tal varíavel foi alocada já tenha sido usada por outra váriavel e posivelmente pode conter algum tipo de LIXO, então é uma boa prática inicializa-las.

1.a)

Básicamente falando a memória é vista pelo processador como uma tabela cada “entrada” desta tabela pode guardar um byte e cada entrada é referenciada pela sua posicão.

1 Byte é um conjunto de 8 bits pode representar um número de ate 255(na base 10).

Veja mais sobre essa matemática aqui.

Então no Ruby  em linhas gerais você sempre deve atribuir algum valor antes que de fato usar tal varíavel, mas como vamos ver existem alguns tipos de varíaveis no Ruby que não necessariamente precisam ser inicializadas.

Vejamos os tipos de váriaveis presentes no Ruby.

 - Varíaveis de Classe.
 - Varíaveis de instância.
 - Varíaveis globais.
 - Varíavies locais.

Varíaveis de Classe.

Sempre devem ter um valor atribuido antes de serem usadas, caso você à utilize sem inicializar irá receber um NameError, Como isso:

 class Class_Variable
puts @@var
 end

NameError: uninitialized class variable @@var in Class_Variable


Varíavies de Instância

Quando você tentar usar um varíiavel de instância sem ela ter sido devidamente inicializada o Ruby irá retornar um Nil, veja:

 def instance_variable
puts @name
 end

instance_variable

=> Nil
<pre>

Veja passando a opção -W para o comando Ruby em linha de comando, ele irá dar um aviso que você possue a varíavel não inicializada:

ruby -W teste.rb
teste.rb:2: warning: instance variable @x not initialized
nil

DICA: Sempre use a opção -W para testar seus código maiores, assim você pode verificar de forma fácil a presença desse tipo de coisa.


Varíaveis Globais.

Para esse tipo de varíavel vale a mesma regra que das de instância.

Varíaveis Locais.

Aqui temos que ter cuidado, em todos os outros tipos de varíaveis no Ruby temos um caractere de pontuação servindo como prefixo, isso quer dizer que as varíaveis locais se parecem com uma chamada de método, caso o Ruby “veja” uma atribuição para tal varíavel ele irá saber que se trata de uma varíavel e não de uma invocação de método, caso ele não ver, ele irá invocar o método, e caso o método não exista temos um NameError.

Por Exemplo se simplesmente fizermos isso:

 a
 NameError: undefined local variable or method `a' for main:Object
 from (irb):1
<pre>

Viram?

Então, a varíavel passa a existir apartir do momento em que ela recebe uma atribuição, e não necessita que a atribuição seja de fato executada, veja um exemplo:

 >> a = 0.0 if false
 => nil
 >> puts a
 nil

Bom pessoal é isso por hoje, espero que alguem leia isso :) .

Referencia: Livro – “A linguagem de Programação Ruby” – David Flanagan & Yukihiro Matsumoto.

Até Mais Pessoa e Orbrigado.

Pequena Intro BDD com Cucumber

October 22, 2009 at 10:28 pm | In Programação, Ruby/Rails, testing | Leave a Comment

Neste post vamos ver um pouco(bem pouco) sobre BDD ou Behavior Driven Development utilizando o Cucumber.

Aqui você ira escrever os testes antes de escrever

Primeiramente vamos começar criando uma “funcionalidade” para descrever qual o comportamente que queremos que nosso codigo tenha, isso é representado através de features, features são arquivos em pleno inglês ou português(sim tem como) para descrever o comportamente de um requesito, por exemplo.

Uma feature no cucumber tem seu esqueleto assim:

Feature: Be Awesome (Fazer alguam coisa, Responder alguma coisa, funcionalidade)

Senario: Delete products
   Given a list with 5 products
   When I select three items
   And I click delete
   Then I should see only 2 products

Ou no bom Português:

Cenário: Deletar produtos
 Dada uma lista com 5 produtos
  Quando eu selecionar três itens
 E eu clicar em excluir
 Então eu deveria ver apenas 2 produtos

Como você pode ver isso é facilmente compreendido por qualquer um, não precisa ser técnico nem nada para saber realmente o que o cenário faz.

Nosso pequeno exemplo:

Vamos criar um exemplo bem simples, nosso código irá ser uma calculadora, essa calculadora irá somente multiplicar(nosso cliente não sabe multiplicar ainda então…. :) ).

Com uma conversa de uns minutos com o cliente juntos criamos uma feature assim:

Feature: Multiplication Operation
   In order to to learn math
   As a math idiot
   I want multiply two numbers

Scenario: Add two numbers
   I initialize calculator with 10 and 10
   When I press go
   Then I should see 100

Scenario: Add two negative numbers
   Given I initialize calculator with -2 and -2
   When I press go
   Then I should see 4

Vamos começar executando nossa feature, inicialmente somente com o primeiro cenário, crie um arquivo chamado calculadora.feature e coloque o seguinte conteudo:

Feature: Multiplication Operation
   In order to to learn math
   As a math idiot
   I want multiply two numbers

Scenario: Add two numbers
   I initialize calculator with 10 and 10
   When I press go
   Then I should see 100

Agora vá até um terminal e execute:

cucumber calculadora.feature

Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculadora.feature:7
    When I press go                              # calculadora.feature:8
    Then I should see 100                        # calculadora.feature:9

1 scenario (1 undefined)
3 steps (3 undefined)
0m0.002s

You can implement step definitions for undefined steps with these snippets:

Given /^I initialize calculator with 10 and 10$/ do
  pending
end

When /^I press go$/ do
  pending
end

Then /^I should see 100$/ do
  pending
end

Bom, como vemos, temos 1 cenário que ainda não está definido, também tempos os três passos que também não estão definidos, logo abaixo o cucumber já nos da os passos para implementar, vamos copiar esse código e colocar dentro de um arquivo chamado calculadora_steps.rb, e então executar novamente nossa feature.

Rodando a feature iremos receber algo do tipo:

$ cucumber calculadora.feature
Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculador_steps.rb:1
      TODO (Cucumber::Pending)
      ./calculador_steps.rb:2:in `/^I initialize calculator with 10 and 10$/'
      calculadora.feature:7:in `Given I initialize calculator with 10 and 10'
    When I press go                              # calculador_steps.rb:5
    Then I should see 100                        # calculador_steps.rb:9

1 scenario (1 pending)
3 steps (2 skipped, 1 pending)
0m0.003s

Bom, vimos que ao pegar o código que o cucumber nos deu ele está usando o método pedding em todos os três passos, isso obviamente quer dizer que eles estão pendentes, vamos começar implementando o comportamento do primeiro passo, que é:

Given /^I initialize calculator with 10 and 10$/ do
  pending
end
[/sourcecode"]

Fazemos isso:

[sourcecode language="ruby"]
Given /^I initialize calculator with 10 and 10$/ do
  @c = Clac.new(x,y)
end

E rodamos nossa feature:

 cucumber calculadora.feature
Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculador_steps.rb:1
      uninitialized constant Calc (NameError)
      ./calculador_steps.rb:2:in `/^I initialize calculator with 10 and 10$/'
      calculadora.feature:7:in `Given I initialize calculator with 10 and 10'
    When I press go                              # calculador_steps.rb:5
    Then I should see 100                        # calculador_steps.rb:9

Failing Scenarios:
cucumber calculadora.feature:6 # Scenario: Add two numbers

1 scenario (1 failed)
3 steps (1 failed, 2 skipped)
0m0.003s

OPS, parece que não temos a classe calc, e de fato não temos, vamos cria-la, para isso, nesse caso, iremos escrever a classe no mesmo arquivo que temos nossos passos, isso não é uma boa prática, então não o faça, fiz aqui somente para fins de explicação :D .

Então no começo do arquivo calculadora_steps.rb iremos ter:

class Calc
	def initialize(x,y)
		@x =x
		@y = y
	end
end

Certamente isso irá fazer com que o teste passe, rodando a feature:

cucumber calculadora.feature
Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculador_steps.rb:8
      undefined local variable or method `x' for #<Object:0x8df61c> (NameError)
      ./calculador_steps.rb:9:in `/^I initialize calculator with 10 and 10$/'
      calculadora.feature:7:in `Given I initialize calculator with 10 and 10'
    When I press go                              # calculador_steps.rb:12
    Then I should see 100                        # calculador_steps.rb:16

Failing Scenarios:
cucumber calculadora.feature:6 # Scenario: Add two numbers

1 scenario (1 failed)
3 steps (1 failed, 2 skipped)
0m0.003s

E como diria Dave Thomas em Agile Web Development With Rails “…”, erro:

Ele está nos dizendo que a variavel x nao esta definida, vamos alterar um pouco nosso passo e no lugar do 10 and 10, vamos colocar um expresao regular, e passar para um bloco, assim:

Given /^I initialize calculator with (.*) and (.*)$/ do |x,y|
  @c = Calc.new(x.to_i, y.to_i)
end

Tambem utilizamos o metodo para converter os valores para inteiros, o to_i. E agora sim rodamos novamente nossa features, e esperamos que os testes passem.

cucumber calculadora.feature
Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculador_steps.rb:8
    When I press go                              # calculador_steps.rb:12
      TODO (Cucumber::Pending)
      ./calculador_steps.rb:13:in `/^I press go$/'
      calculadora.feature:8:in `When I press go'
    Then I should see 100                        # calculador_steps.rb:16

1 scenario (1 pending)
3 steps (1 skipped, 1 pending, 1 passed)
0m0.003s

E Bingo, passou! Vamos para o segundo passo:

When /^I press go$/ do
  @result = @c.go
end

Quermos o resultado do metodo go na variavel result, vamos executar a feature:

cucumber calculadora.feature
Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculador_steps.rb:8
    When I press go                              # calculador_steps.rb:12
      undefined method `go' for #<Calc:0x11c5358 @y=10, @x=10> (NoMethodError)
      ./calculador_steps.rb:13:in `/^I press go$/'
      calculadora.feature:8:in `When I press go'
    Then I should see 100                        # calculador_steps.rb:16

Failing Scenarios:
cucumber calculadora.feature:6 # Scenario: Add two numbers

1 scenario (1 failed)
3 steps (1 failed, 1 skipped, 1 passed)
0m0.003s

Olha, não temos ainda o metodo go, então vamos cirar-lo e fazer ele multiplicar os dois numeros.

def go
 @x * @y
end

E rodando mais um vez nossa feature, passou!

cucumber calculadora.feature
Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculador_steps.rb:11
    When I press go                              # calculador_steps.rb:15
    Then I should see 100                        # calculador_steps.rb:19
      TODO (Cucumber::Pending)
      ./calculador_steps.rb:20:in `/^I should see 100$/'
      calculadora.feature:9:in `Then I should see 100'

1 scenario (1 pending)
3 steps (1 pending, 2 passed)
0m0.003s

Vamos para o ultimo mas não menos importante passo, agora queremos verificar se o resultado da multiplicacao que esta na variavel @result eh igual ao que esperamos que seja, então vamos implementar.

Then /^I should see (.*)$/ do |result|
  @result.should == result.to_i
end

Aqui usamos o metodo should(deveria) para verificar se o resultado bate com o que definimos, se rodarmos o teste veremos que tudo passou.

cucumber calculadora.feature

Feature: Multiplication Operation
 In order to learn math
 As a math idiot
 I want to be told the multiply tow numbers

  Scenario: Add two numbers                      # calculadora.feature:6
    Given I initialize calculator with 10 and 10 # calculador_steps.rb:11
    When I press go                              # calculador_steps.rb:15
    Then I should see 100                        # calculador_steps.rb:19

1 scenario (1 passed)
3 steps (3 passed)
0m0.003s

Lega, tudo passou! Obviamente isso eh muito superficial, mas acredito que isso possa ser uma boa introducao de como isso funciona, também não vimos nada profundamente de como o cucumber funciona, acredito que não seja o objetivo desse post(e eu nao sei muito tambem :) ), Novamente recomendo a leitura dos textos sobre bdd e afims.

Também fiz um pequeno screencast demostrando o que foi postado aqui:

http://vimeo.com/7164228

Não deixe de ver o seguinte link:

http://en.wikipedia.org/wiki/Behavior_Driven_Development

Até mais pessoal e não deixem de comentar!

Rails for Kids 2009….

August 14, 2009 at 1:14 am | In Ruby/Rails | Leave a Comment

2929102250_a1ac31a20f

Irá sair no dia 12/09/2009 o Rails for Kids 2009,  se trata de uma série de palestras sobre assuntos relacionados com o mundo rails, as palestras irão ser mistradas por grandes nomes da comunidade Rails nacional e internacional, para participar do evento você deve fazer uma doação no  valor simbólico de R$ 30,00 , toda grana será destinada a Cotolengo de Mato Grosso do Sul. Para saber mais sobre a Cotolengo clique aqui.

Acesse o site Rails for Kids e de uma olhada nas palestras e palestrantes e realize sua inscrição.

Para se escrever clique nesse link.

É isso ai pessoal agente se encontra por lá… OPS, eh online tinha me esquecido :)

TDD + Ruby: Número de Fibonacci

June 15, 2009 at 3:34 am | In Ruby/Rails | Leave a Comment

Estou necessitado de escrever posts melhores, eu sei, mas enquanto isso, tava brincando aqui com TDD + Ruby, então resolvi fazer um código para gerar a sequencia de Fibonacci fazendo o uso de TDD.

Para quem ainda não sabe, o numero de fibonacci e uma sequencia de numero, que é gerada começando com 1 e em seguida somando os dois anteriores para se conhecer o próximo, na prática:

Começamos com 1, então o proximo numero será : 0 + 1 = 1, o seguinte será 1 + 1 = 2 … 2 +1 = 3 … e assim vai… essa sequencia é defenida como sendo recursiva, a formula é:

0d5cce25d67941bb4661afd52609d93c

Bom, o problema ta entendido(eu acho) rs.

Como vamos fazer o uso de TDD, vamos começar escrevendo nossos testes

Precisamos ter um método chamdo por exemplo fibo, esse método deve receber como argumento um inteiro, inicialmente se passarmos 0(zero) devemos ter como retorno 0(zero), entõa vamos criar o esqueleto do teste:


require "test/unit"

require "fibonacci.rb"

class Test < Test::Unit::TestCase
   def test_case_name

   end
end

Acima está o esquelete de um teste básico, na primeira linha fizemos a inclusão do framework de teste, no segundo require chamamos a nossa classe fibonacci(que ainda nao existe), e logo em seguida temos o primeiro método para teste, vamos mudar o nome dele e acresentar o comportamento que nossa classe fibonacci deve ter quando receber zero.

require "test/unit"
require "fibonacci.rb"
class TestFibonacci < Test::Unit::TestCase
	def test_fiboZero
		assert_equal(0, Fibonacci.seqfibo(0))
	end
end

Todo teste deve iniciar com o palavra test, logo em seguida vem nosso teste propriamente dito, é justamente o que falamos acima, se receber Zero, retorne Zero, vamos rodar nosso teste para ver o que acontece:

LoadError: no such file to load  fibonacci.rb

Ops, certamente teriamos um erro ai mesmo, pois ainda nao criamos nossa classe fibonacci, vamos cria-la,(sem nehum codigo ainda) e rodar novamente:

Ops, denov, so temos um arquivo e mais nada então recebemos o seguinte:


Started
E
Finished in 0.002 seconds.

1) Error:
test_fiboZero(TestFibonacci):
NameError: uninitialized constant TestFibonacci::Fibonacci
C:\Documents and Settings\casa\Desktop\Nova pasta\fibonacciTest:5:in `test_fiboZero’

1 tests, 0 assertions, 0 failures, 1 errors

Vamos criar essa classe, acresente o seguinte em fibonacci.rb:


class Fibonacci
    def self.seqfibo(num)
       return 0 if num == 0
    end
end

Bom, isso provavelmente irá fazer nosso teste passar, rodando recebemos o seguinte:

Started
.
Finished in 0.002 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

Legal, tudo passou, nosso primeiro caso esta feito, agora, podemos pensar em outro comportamento para nossa classe. . . .bom testamos com zero agora vamos tentar passar um(1) para o método e ver o que acontece, incluindo mais método para teste (poderia ser feito no mesmo método, mas vou separar aqui), nosso código de teste agora fica assim:


require "test/unit"
require "fibonacci.rb"
class TestFibonacci < Test::Unit::TestCase
    def test_fiboZero
       assert_equal(0, Fibonacci.seqfibo(0))
    end
    def test_fiboUm
       assert_equal(1, Fibonacci.seqfibo(1))
    end
end

a lógica dos teste aqui, nao mudou nada, vamos rodar para ver:

Started
F.
Finished in 0.033 seconds.

1) Failure:
test_fiboUm(TestFibonacci) [C:\Documents and Settings\casa\Desktop\Nova pasta\fibonacciTest:8]:
<1> expected but was
<nil>.

2 tests, 2 assertions, 1 failures, 0 errors

Bom, vimos ali que o teste esperava 1 mas retornou nil, vamos implementar essa lógica na nossa classe, agora temos isso:


class Fibonacci
    def self.seqfibo(num)
       return 0 if num == 0
      return 1 if num == 1
    end
end

Exatamente igua ao anterior, agora não seria nada bom ficar acresentando todos essas asserts ai para testar cada um dos numero que esperamos obter,  para isso em nosso teste vamos criar um array de arrays contendo vários cassos de testes algo do tipo:

testes = [[0,0][1,1][2,1] . . .]

e logo interar por esse array passando esses valores para nosso teste, logo iremos ter um unico método, nossa classe teste fica +  – assim agora:


require "test/unit"
require "fibonacci.rb"
class TestFibonacci < Test::Unit::TestCase
    def test_fiboZero
       teste = [[0,0],[1,1],[2,2],[4,5],[3,2]]
       teste.each do |t|
          assert_equal(t[1], Fibonacci.seqfibo(t[0]))            
       end
    end
end

Bom, creie um array de array com alguns cassos, agora so falta implementar na classe fibonacci um funcao recursiva para fazer o calculo, então agora tempo:


class Fibonacci
     def self.seqfibo(num)
        return num unless num > 2
       seqfibo(num-1) + seqfibo(num-2)
   end

 #um metodo pra executar

   def execute
       for i in 1..10
          puts seqfibo(i)
       end 
  end
end

Agora rodamos o código de teste e recebemos:


Started
.
Finished in 0.002 seconds.

1 tests, 5 assertions, 0 failures, 0 errors

Bom, aqui acabamos nossa implementação, obviamente da para melhorar e fazer muitos outros teste, e melhorar o teste, e tudo mais, se alguem achar erros, ou quizer falar algo, porfavor deixe um comentário.

[Dica Rápida] Problema ao rodar Ruby no E-TextEditor

June 11, 2009 at 2:19 pm | In Ruby/Rails | 4 Comments

Se você é um usuário Windows e usa o E-textEditor e estiver tentando usar o comando ctrl+r para rodar seus codigos e está recebendo a seguinte mensagem:

ruby: no such file to load — ubygems (LoadError)
faça o seguinte para concertar esse problema:

1 – Baixe a ultima versao do RubyGems do site

2 – Descompacte-o dentro da sua pasta de usuario do Cygwin, no meu caso em:  C:\cygwin\home\edipo

3 – Abra o terminal do Cygwin e execute os seguintes comando:

$  unset RUBYOPT
$ ruby setup.rb

Pronto isso deve resolver.

Rails – Testando – Test::Unit – Parte 1

January 5, 2009 at 5:39 pm | In Ruby/Rails | Leave a Comment

testing

Olá, não sou um cara que sabe tudo sobre testes,( não sei quase nada :) , mas vejo a importância que eles tem no bom desenvolvimento, tendo isso em mente começei a estudar testes não escolhi um framework específico para fazer isso como o Rspec, ou algum outro, optei por escolher o framework que vem junto com o Rails que é o Test::Unit, então resolvi escrever aqui um pouco sobre isso e compartilhar, isso é algo simples, sendo que é o primeiro post de um série que eu acredito que será, então fazam bom proveito, e me desculpem os erros( deixem comentários).


1 – Começando: Criando um CRUD simples para os exemplo

Criei apenas um pequeno projeto rails como um CRUD normal para realizar algumas demos aqui, criei um modelo product, contendo o titulo do produto e a quantidade.

2 – Testes de Unidade.

Teste de Unidade são testes realizados nos models.

class ProductTest < Test::Unit::TestCase

ProductTeste é uma subclasse da classe  Test::Unit::TestCase que é onde fica o framework Test::Unit que esta pré-instalado com o rails.

require File.dirname(__FILE__) + '/../test_helper' 

class ProductTest < Test::Unit::TestCase 
  fixtures :products 

  # Replace this with your real tests. 
  def test_truth 
    assert true 
  end 
end 

aqui está o codigo que o rails gerou para nós, então: (veremos fixtures no proximo post)

fixtures :products 

Permite pré-pencher o banco de dados apenas com os dados de testes corretos e o método test_truth,
tudo que começa com test quer dizer que ele irá ser executado como teste pelo framework  a linha assert
true que é de fato o teste, mas o que ela simplesmente faz aqui é um teste se true é verdadeiro :)
______________________________________________________________

OBS 1: Definir um nome de teste como por exemplo:

	def teste_valide_empty_price
		# . . .
	end
isso gera um erro de sintaxe, pois testes devem começar com test e não teste
______________________________________________________________

Porque testar se true é verdaderiro?, Isso serve maior ou menos como um “verificador” para você se
assegurar que tudo está funcionando corretamente com o framework de testes. Bom você pode pensar o que
poderia dar errado mesmo antes de você começar a escrever os seus teste?

Bom tente executar então o teste de unidade:

Loaded suite test/unit/product_test
Started
EE
Finished in 0.014967 seconds.
1) Error:
test_truth(ProductTest):
Mysql::Error: Unknown database 'demo_test' 

2) Error:
test_truth(ProductTest):
Mysql::Error: Unknown database 'demo_test' 

1 tests, 0 assertions, 0 failures, 2 errors 

Viu?? Falhou, facilmente vimos que que ele não conseguiu localizar o banco de dados demo_test, e não
é de menos, não criamos esse banco ainda, como poderia achar?

mysql >> create database demo_test;

Agora rodando novamente o teste:

ruby test/unit/product_test.rb Loaded suite test/unit/product_test
Started
E
Finished in 0.599951 seconds. 

  1) Error:
test_truth(ProductTest):
ActiveRecord::StatementInvalid: Mysql::Error: Table 'demo_test.products' doesn't exist: DELETE FROM
products 

1 tests, 0 assertions, 0 failures, 1 errors 

E BUM, falhou de novo, agora vimos que a tebela não existe, então o rails tem uma tarefa rake que  faz isso:

rake db:test:prepare

Agora sim, rode novamente o teste e tudo deverá funcionar:

ruby test/unit/product_test.rb
Loaded suite test/unit/product_test
Started
.
Finished in 0.014913 seconds. 

1 tests, 1 assertions, 0 failures, 0 errors 

__________________________________________________________
Teste de Unidade são teste que testam models, o que testa uma acão em um controller são testes
funcionais, e o que testa o fluxo por um ou mais controllers são testes de integracão.
__________________________________________________________

o camando rake prenche o esquema de banco de dados igual a do de desevolvimento. 

Agora rodando o teste e vemos que tudo esta certo: 

ruby test/unit/product_test.rb
Loaded suite test/unit/product_test
Started
.
Finished in 0.017633 seconds. 

1 tests, 1 assertions, 0 failures, 0 errors

:) ok.

Agora que esta tudo OK, podemos começar a escrever uns pequenos testes.

O primeiro teste que vamos fazer é assegurar que esses dois campos não passem por um teste onde
seus atributos são vazios.

Como Fazer isso?

Caso um produto inválido( vazio ) seja criado, isso deve ser considerado inválido pelo nosso teste,
e por vez um erro deve ser associado ao campo em questão.

O rails possue um método chamado invalid? Para ver se o produto é valido, e usar o método invalid?
Para ver se existem erros associados a aquele atributo em questão.

Como dizemos para o teste se ele passou ou não ? A resposta para a pergunta são as assertivas(assert),
 elas informam ao framework o que esperamos ser verdade, caso for true nada ocorre, e se for false a
assert falha.

require File.dirname(__FILE__) + '/../test_helper' 

class ProductTest < Test::Unit::TestCase 
  fixtures :products 

  # Replace this with your real tests. 
  def test_truth 
    assert true 
  end 
  
  def test_invalid_empty 
     product = Product.new 
=>assert !product.valid? 
     assert product.errors.invalid?(:titulo) 
     assert product.errors.invalid?(:quantidade) 
  end 
end

Na linha em destaque, dizemos ao framework que  o modelo product não é valido, e usamos o método invalid?
Para verificar se contém algum erro asociado a tal atributo.
Tente executar esse teste e você irá ver que ele vai falhar, então vamos até o nosso model e coloquemos a
validação dos dois campos:

class Product < ActiveRecord::Base 
   validates_presence_of :titulo 
   validates_presence_of :quantidade 
end

Rode e teste e... passou, validação está certa.

Temos um campo chamado quantidade seria interessante que esse campo fosse maior que zero, entao eu me
faço a pergunta:

1 – Quantidade pode ser menor que 0? Não.

OBS 2: Essa dica de se fazer perguntas, é um jeito mais facil de descobrir como escrever seus testes,
ela foi dita pelo Tapájos, na excelente série sobre testes feita por ele.

  def test_quantidade_positiva 
  	   product = Product.new(:titulo => "TV LCD") 
  	   		                             
  	   product.quantidade = -1 
  	   assert !product.valid? 
  	   assert_equal "Should be at least 0", product.errors.on(:quantidade) 
  	   
  	   product.quantidade = 0 
  	   assert !product.valid? 
  	   assert_equal "Should be at least 0", product.errors.on(:quantidade) 
  	   
  	   product.quantidade = 1 
  	   assert product.valid? 
  end

Aqui há uma configuração de três possíveis valores que o campo quantidade pode receber, para ele ver
válido deve ter seu valor >  0, o que o teste faz é criar um novo produto, e configurar a quantidade em 0,
-1, e 1 respectivamente, os dois primeiros asserts são inválidos, pois os valores são 0 e -1, e o último
configurado como 1 dizemos que é valido.

Rode o teste, e BUM, falhou, não estamos fazendo a validacão correta para esse campo, entao no seu model
coloque algo do tipo:

protected 
   def validate 
      errors.add(:quantidade, "Deve ser maior que 0")  if quantidade.nil? || quantidade <= 0 
  end


Criei um método validate, com o conteúdo acima, ele é protected por que não pode ser chamado fora do
contesto do model.

Agora rode o teste novamente e... OK.

Vamos à mais um pergunta:

	A quantidade pode ser um valor quebrado(float)? - Não.

Então vamos ao teste, muito similar aos outros.

def test_inteiro_value
  	   product = Product.new(:titulo => "TV LCD",
  	                                        :quantidade => 1.2 )
  	   
  	   assert !product.valid?
  	   assert product.errors.invalid?(:quantidade)
end

Certo, sem problemas, rodando o teste vemos que o teste não passou, isso significa que temos uma falha
no nosso modelo de validação.

Vamos acresentar a seguinte validação:

	validates_numericality_of :quantidade, :o nly_integer => true

Aqui dizemos que estamos aceitado apenas numero inteiros, para o campo quantidade.

Bom, esse é o fim do primeiro post sobre Testes usando Test Unit, espero que tenha ficado claro,
obviamente isso foi muito superficial, mas creio que deu para dar uma compreendida e ver o quão
importante são os teste( e legal ). Esse post falamos apenas de testes de unidade, no próximo post,
continuaremos falando de testes de unidade.... é isso ai, espero comentários com críticas e sugestões,
abraço a todos.

Referências:

	Agil Development With Rails  - 2 (Livro)

Gerando arquivos PDF com Ruby(pdf/writer) – Parte 1.

December 11, 2008 at 3:49 pm | In Ruby/Rails | 2 Comments

Olá, pessoal, uma forma de se gerar documentos PDF usando Ruby é utilizar o pdf-writer, é uma gem que pode ser usada tanto em Rails e Ruby, nessa primeira parte vamos conhecer o básico , criar alguns exemplos e ver como o negocio funciona, não iremos ver tudo da gem(é obvio) bem que para isso tem o manual no site(99 páginas em Inglês), nesse post não iremos interar com o Rails, somente Ruby.

1 – Instalação

Para instalar o pdf-writer temos dois caminhos, 1) Instalar via RubyGems(recomendo) e 2) Instalar manualmente usando o pacote. Recomendo via rubygems pois ele irá reconhecer as dependências que o pdf-writer tem, já a segunda você irá ter que instalar a dependencia, ou transaction-simple ou colors-tools.

Via RubyGems:

sudo gem install pdf-writer

Via “package”

wget http://rubyforge.org/frs/download.php/33972/pdf-writer.1.1.8.tar.gz
tar -xvzf pdf-writer.1.1.8.tar.gz
cd pdf_writer-1.1.8
sudo ruby setup.rb

agora instale o transaction-simple ou colors-tools da mesma forma.
Mas acho melhor a primeiro opção

2 – Criando um Exemplo Muito Simples.

Vamos criar um exemplo “Hello PDF::Writer” para não ficar “Hello World” , crie arquivo chamado teste_pdf1.pfd com o seguinte conteúdo:

require "rubygems"
require "pdf/writer"

pdf = PDF::Writer.new
pdf.text("Hello PDF::Writer", :font_size => 35)
pdf.save_as("file1.pdf")

Isto produz:

imagen1

Fizemos dois requires ali no começo, com rubygems e pdf/writer, após fizemos a chamada de PDF::Writer, logo depois “escrevemos” no documento  o texto “Hello PDF::Writer” e definimos o tamanho da fonte para 35 pontos, então por ultimo salvamos o documento como file1.pdf.

3 – Fontes e Posições.

Para configurar  o tipo de fonte usada você pode usar  pdf.select_font “Times-Roman” por exemplo, opções de posição , :left, :right, :absolute_left, :absolute_right, vamos a um exemplo:


require "rubygems"
require "pdf/writer"

pdf = PDF::Writer.new
pdf.select_font "Courier-BoldOblique"
pdf.text("Hello PDF::Writer", :font_size => 35, :left => 100)
pdf.save_as("file2.pdf")

Isto produz:

imagen2Justificações:
Com as seguinte quatro formas de justificação:

pdf.text("Hello Ruby!", :justification => :left)
pdf.text("Hello Ruby!", :justification => :right)
pdf.text(“Hello Ruby!", :justification => :center)
pdf.text("Hello Ruby", :justification => :full)

4 – Espaçamento entre Linhas

Você pode configurar o espaço entre determindas linhas do texto por exemplo:


require "rubygems"
require "pdf/writer"

pdf = PDF::Writer.new
pdf.select_font "Courier-BoldOblique"
pdf.text("Hello PDF::Writer", :font_size => 35, :left => 100)
pdf.text("Ola Mundo Cruel!", :font_size => 35, :left => 100, :spacing => 5)
pdf.save_as("file3.pdf")

imagen3


5 – Documento final

Para finalizar esse post vamos criar um “documento real” com um simples texto, usando o que vimos nesse post.


require "rubygems"
require "pdf/writer"

pdf = PDF::Writer.new

BODY = <<-'EOS'
Benjamin Franklin (January 17, 1706 [O.S. January 6, 1705]   April 17, 1790) was one of the Founding Fathers of the United States of America. A noted polymath, Franklin was a leading author and printer, satirist, political theorist, politician, scientist, inventor, civic activist, statesman, and diplomat. As a scientist, he was a major figure in the Enlightenment and the history of physics for his discoveries and theories regarding electricity. He invented the lightning rod, bifocals, the Franklin stove, a carriage odometer, and a musical instrument. He formed both the first public lending library in America and first fire department in Pennsylvania. He was an early proponent of colonial unity and as a political writer and activist he, more than anyone, invented the idea of an American nation[1] and as a diplomat during the American Revolution, he secured the French alliance that helped to make independence possible.
Franklin is credited as being foundational to the roots of American values and character, a marriage of the practical and democratic Puritan values of thrift, hard work, education, community spirit, self-governing institutions, and opposition to authoritarianism both political and religious, with the scientific and tolerant values of the Enlightenment. In the words of Henry Steele Commager, "In Franklin could be merged the virtues of Puritanism without its defects, the illumination of the Enlightenment without its heat."[2] To Walter Isaacson, this makes Franklin, "the most accomplished American of his age and the most influential in inventing the type of society America would become."
EOS

corpo = BODY.split($/).join(" ").squeeze(" ")

pdf.text("Benjamin Franklin", :font_size => 20, :justification => :center)
pdf.move_pointer(36)
pdf.text(corpo, :font_size => 12, :justification => :full)
pdf.move_pointer(50)
pdf.text("Fonte: Wikipedia", :font_size => 10, :left => 370)
pdf.save_as("final.pdf")

imagen4

Bom para começo é isso, logo irei postar algo mais sobre o pdf-writer, obviamente isso é muito mas muito básico.

Ruby – Hashes

December 7, 2008 at 4:25 pm | In Ruby/Rails | 3 Comments

Pequena Intro.

Hashes é uma coleção de pares (chave-valor), cada elemento da lista é um par, que contém uma chave que representa um valor. São semelhantes aos Arrays, porém se diferem desses por terem atribuição arbritária, chaves são qualquer tipo de objeto e não um int(inteiro) igual os Array.
Hashes em outra linguagem também são chamados de dicionários, e logo você vai ver porque ?.
Hashes tem valor padrão que é retornado se tentar acessar chaves que não existam, esse valor é nil.
Com essa pequena teoria sobre hashes em mente vamos fazer alguns exemplo, como sempre abra o IRB.

1 – Criando um hashe

h = {"choice"=>"escolha", "cloak"=>"capa", "stuffy"=>"abafado"}
=> {"stuffy"=>"abafado", "cloak"=>"capa", "choice"=>"escolha"}

Acima criamos um hashe simples contendo três palavras em inglês que suas traduções.
Bom como visto acima aqui não temos índices e sim chaves, vamos acessar as chaves desse hashe.
Antes vamos ver todos os métodos para manipulação de hashes, então usamos h.methods( onde h é o hashe que criamos a cima).

1.1 – Métodos

irb(main):003:0> h.methods
=> ["select", "[]=", "inspect", "each_value", "fetch", "clone", "values_at", "public_methods", "partition
", "display", "empty?", "instance_variable_defined?", "update", "shift", "to_yaml_properties", "equal?",
"freeze", "has_value?", "clear", "grep", "rehash", "to_yaml", "taguri", "indices", "methods", "respond_to
?", "reject", "each_key", "taguri=", "dup", "delete", "instance_variables", "yaml_initialize", "member?",
 "__id__", "find", "method", "eql?", "value?", "to_hash", "each_with_index", "id", "to_yaml_style", "inde
x", "collect", "singleton_methods", "send", "each_pair", "all?", "taint", "delete_if", "length", "entries
", "merge!", "frozen?", "instance_variable_get", "include?", "__send__", "instance_of?", "merge", "detect
", "to_a", "store", "zip", "type", "protected_methods", "instance_eval", "object_id", "map", "any?", "=="
, "values", "===", "size", "sort", "instance_variable_set", "default", "min", "kind_of?", "extend", "find
_all", "to_s", "default=", "default_proc", "key?", "each", "hash", "class", "reject!", "replace", "inject
", "tainted?", "keys", "=~", "private_methods", "invert", "nil?", "untaint", "sort_by", "has_key?", "max"
, "[]", "is_a?", "indexes"]
irb(main):004:0>

Veremos algo assim, uma grande lista de métodos que estão disponíveis para o uso, ali no meio(coloquei em negrito) temos o método Keys, ele nos mostra todas as chaves do nosso hashe, então vamos usá-lo.

1.2 – Chaves

h.keys
=> ["stuffy", "cloak", "choice"]

E está ai as três chaves que nosso hashe contém.

1.3 – Acessando Valores.

h["choice"]
=> "escolha"

Acho que não precisa explicar né ?

Temos outro método chamado values, como o primeiro que agente viu era chamado keys e você viu o que ele retornou, imagino que você já saiba o que este retorna:

h.values
=> ["abafado", "capa", "escolha"]

OHHHH, retornou os valores.

Com esses dois conceitos de keys e valeus em mente vamos fazer um loop para acessar todos os valores:

h.keys.each do |chave|
 puts "#{chave}  = #{h[chave]}"
end

stuffy  = abafado
cloak  = capa
choice  = escolha

2 – Adicionando novos elementos

Podemos adicionar novos elementos em um hashe, para isso temos dois métodos o merge e o merge!, listados na lista acima, vamos fazer dois exemplo usando os dois métodos é ver o que acontece.

numeros = {"1"=>"um","2"=>"dois","3"=>"tres"}
=> {"1"=>"um", "2"=>"dois", "3"=>"tres"}

Com merge

numeros.merge( {"4"=>"quatro"} )
=> {"1"=>"um", "2"=>"dois", "3"=>"tres", "4"=>"quatro"}
numeros
=> {"1"=>"um", "2"=>"dois", "3"=>"tres"}

Com merge!

numeros.merge!( {"4"=>"quatro"} )
=> {"1"=>"um", "2"=>"dois", "3"=>"tres", "4"=>"quatro"}
numeros
=> {"1"=>"um", "2"=>"dois", "3"=>"tres", "4"=>"quatro"}

Viu? Podemos concluir então que o primeiro método( merge ) não altera o hashe original, e o segundo já faz as alterações diretamente no original “gravando” as mudanças.

3 – Melhorando um pouco.

Esses exemplo acima, como você pode notar as chaves e os valores são representados com strings, isso não é bom, isso é feio, existe um tipo no ruby chamado symbol(símbolos), eles são representando com dois-pontos( : ) antes do nome, por exemplo :home.
Então vamos mudar nosso modo de criar hashe e usar symbols.

nums = {:um=>"1", :dois=>"2"}
=> {:um=>"1", :dois=>"2"}

Se você já andou mexendo com o Rails muito provavelmente você encontrou símbolos para tudo quanto é lado.
Então porque usar símbolos?
• São mais bonitos que Strings.
• O código fica melhor para ler
• Você economizara memória
• São usadas muito no Rails :)

Bom chegamos ao final, obviamente isso não é tudo, recomendo olhar a documentação do Ruby, e ir testando todos os métodos no IRB, novamente se alguém vier a ler isso e achar erros, me informe através dos comentários, ficaria feliz se quem ler esse post deixar um comentário dizendo o que achou.
Abraço a todos.

Next Page »

Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.