Ruby on Rails – Ruby 2.0 – Rails 4.0



Ruby on Rails – Ruby 2.0 – Rails 4.0

0 0


ruby-tutorial

Ruby Tutorial - Unipac Contagem (Pós Engenharia Software)

On Github jlucasps / ruby-tutorial

Ruby on Rails

Ruby 2.0

Rails 4.0

João Lucas Pereira de Santana

Apresentação

João Lucas Pereira de Santana

Agenda

  • Linguagem Ruby
  • Ruby on Rails full stack
  • Ferramentas e ambiente
  • Aplicação Básicas
  • Deploy na Heroku

Linguagem Ruby

Yukihiro “Matz” Matsumoto

Ruby on Rails - Origem

Open source desde 2004

David Heinemeier Hansson (DHH)

Rails Core Team

Maio/2014

Linguagem Ruby

  • Interpretada
  • Orientada a Objetos
    • Tudo é objeto
    • Operações são chamadas de métodos em algum objeto
  • Tipagem Dinâmica
    • Objetos possuem tipos
    • Variáveis não possuem tipos

Linguagem Ruby

  • Dinâmica
    • Adicionar / modificar código em tempo de execução (metaprogramação)
    • Inspecionar e analisar objetos (reflection)

Interpretada

Abrir o console e digitar:
jlucasps@lotus:~/Projects/ruby$ irb-ruby-2.0.0-p353
> 2 + 7
 => 9 
> "Joao Lucas".capitalize
 => "Joao lucas" 
> "Joao Lucas".upcase
 => "JOAO LUCAS" 
> 
          

Interpretada

Criar o arquivo today.rb com o seguinte conteúdo
t = Time.now
puts "Hoje é dia #{ t.strftime( '%m/%d/%Y' ) }."
print "Hora atual: #{ t.strftime(' %I:%M%p' ) }. "
puts "Tenha uma boa semana!"
          
Em seguida, execute o arquivo utilizando o interpretador:
jlucasps@lotus:~/Projects/ruby$ ruby today.rb 
Hoje é dia 05/14/2014.
Hora atual:  02:30AM. Tenha uma boa semana!
jlucasps@lotus:~/Projects/ruby$
          

Orientada a Objetos

Digitar no interpretador:
jlucasps@lotus:~/Projects/ruby$ irb-ruby-2.0.0-p353
> class Book; end
 => nil
          
> Book.new.class
 => Book 
> Book.new.object_id
 => 7256240
          
> Book.class
 => Class 
> Book.object_id
 => 7359560
          
Classes também são objetos!

Orientada a Objetos

Criar o arquivo book.rb com o seguinte conteúdo:
class Book

    def initialize(title)
        @title = title
    end

    def title
        @title
    end

end
          

Orientada a Objetos

Abrir o interpretador e importar o arquivo book.rb
jlucasps@elrond:~/Projects/ruby$ irb
> require './book'
 => true 
> book = Book.new "Eloquent Ruby"
 => #<Book:0x0000000173e870 @title="Eloquent Ruby"> 
> book.title
 => "Eloquent Ruby" 
> book.send(:title)
 => "Eloquent Ruby" 
>
            
Chamadas de métodos em objetos

Orientada a Objetos

Ainda no interpretador
> 2.send(:+, 2)
 => 4 
> arr = [:a, :b, :c]
 => [:a, :b, :c] 
> arr.send(:[]=, 3, :d)
 => :d 
> arr
 => [:a, :b, :c, :d] 
> 
> arr << :e
 => [:a, :b, :c, :d, :e] 
            
Até mesmo operações são métodos

Orientada a Objetos

Mais métodos
> x = 3
 => 3 
> if ( x.send( :==, 3 ) )
>   puts "X é igual a 3"
> end
X é igual a 3
 => nil 
            

Orientada a Objetos

Funções (métodos) criadas no interpretador
> def sum(a, b)
>   a + b
> end
 => nil 
> sum( 3, 4 )
 => 7 
> self.send(:sum, 5, 6)
 => 11 
            

Tipagem Dinâmica

> def my_func(a, b, c)
>   res = a
>   puts res.class				
>   # ...
>   res = b
>   puts res.class
>   # more code here ...
>   res = c
>   puts res.class
> end
 => nil 
> my_func("v1", :v2, 3)
String
Symbol
Fixnum
 => nil 
>
            
Variável armazena objetos de qualquer tipo

Tipagem Dinâmica

> def other_func(d, e)
>   res = d
>   puts res.object_id
>   # more code here ...
>   res = e
>   puts res.object_id
> end
 => nil 
> other_func(:d, ['e'])
373928
11939060
 => nil 
            
Objetos e identificadores

Metaprogramming

Códigos criados/modificados em tempo de execução
class Book

    def initialize(title)
        @title = title
    end

    def title
        @title
    end

    def title=(title)
        @title = title
    end
end
            

Metaprogramming

É o mesmo que:
class Book

    attr_accessor :title

    def initialize(title)
        @title = title
    end

end
            
jlucasps@elrond:~/Projects/ruby$ irb
> require './book'
 => true 
> book = Book.new( "Eloquent Ruby" )
 => #<Book:0x000000015d3b20 @title="Eloquent Ruby"> 
> book.title
 => "Eloquent Ruby" 
> 
            

Reflection

jlucasps@elrond:~/Projects/ruby$ irb
> require './book'
 => true 
> book = Book.new ( "Eloquent Ruby" )
 => #<Book:0x0000000138a288 @title="Eloquent Ruby"> 
> book.respond_to?(:title)
 => true 
> book.respond_to?(:content)
 => false
            
Inspecionando objetos

Reflection

> require './book'
 => true 
> book = Book.new "Eloquent Ruby"
 => #<Book:0x00000002845330 @title="Eloquent Ruby"> 
> book.methods
 => [:title, :title=, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>,
      :class, :singleton_class, :clone, :dup, :taint, :tainted?,
      :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?,
      :to_s, :inspect, :methods, :singleton_methods, :protected_methods,
      :private_methods, :public_methods, :instance_variables,
      :instance_variable_get, :instance_variable_set,
      :instance_variable_defined?, :remove_instance_variable,
      :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send,
      :respond_to?, :extend, :display, :method, :public_method,
      :define_singleton_method, :object_id, :to_enum, :enum_for,
      :==, :equal?, :!, :!=, :instance_eval, :instance_exec,
      :__send__, :__id__] 
>
          

Ruby code conventions

Nome das classes UpperCamelCase
class Magazine
  # ...
end
          
Métodos e variáveis usam snake_case
def number_of_pages 
  # some code here ...
end
def is_web_magazine?
  # more code ...
end
def change_folder!
  # code code code ...
end
          

Variáveis

Constantes
class Magazine
  MAX_PAGES = 30
end
          
Variáveis de instância
class Magazine
  def initialize
    @max_pages = 30 # instance variable
  end
end
          
Variáveis de classe
class Magazine
  @@max_pages = 30 # class variable
  def initialize
    # ...
  end
end
          

Acesso a variáveis

Constantes
> class Magazine
>     MAX_PAGES = 30
> end
 => 30 
> Magazine::MAX_PAGES
 => 30 
          

Acesso a variáveis

Variáveis de instância
> class Magazine
>     def initialize
>         @max_pages = 30 # instance variable
>     end
>     def max_pages
>         @max_pages
>     end
> end
 => nil 
> m = Magazine.new
 => #<Magazine:0x000000024c5610 @max_pages=30>
> m.max_pages
 => 30 
          

Acesso a Variáveis

Variáveis de classe
> class Magazine
>     @@max_pages = 30 # class variable
>     def initialize
>         # ... 
>     end
>     def self.max_pages
>         @@max_pages
>     end
> end
 => nil 
> Magazine.max_pages
 => 30 
          

Símbolos

languagem = :ruby
framework = :rails
system = :linux
          
"String's imutáveis cujo valor é o próprio símbolo"
> lang = :ruby
 => :ruby 
> lang.to_s
 => "ruby" 
> framework = "rails".to_sym
 => :rails 
          
> new_lang = "ruby".to_sym
 => :ruby
> new_lang.object_id
 => 321608 
> lang.object_id
 => 321608 
          

Array

Coleção de objetos ordenados

Indexados por números inteiros começando em 0

> arr = [1, "2", :c, {"name" => "Joao Lucas"}, 5]
 => [1, "2", :c, {"name"=>"Joao Lucas"}, 5] 
> arr[0]
 => 1 
> arr.last
 => 5 
          
> numbers = [1, 2, 3, 4, 5, 6]
 => [1, 2, 3, 4, 5, 6] 
> numbers.min
 => 1 
> numbers.max
 => 6 
> numbers.reverse
 => [6, 5, 4, 3, 2, 1]
          

Array

> numbers
 => [1, 2, 3, 4, 5, 6] 
> numbers.shuffle
 => [1, 4, 6, 3, 2, 5] 
> numbers.push 7
 => [1, 2, 3, 4, 5, 6, 7] 
> numbers << 8
 => [1, 2, 3, 4, 5, 6, 7, 8] 
> numbers.pop
 => 8 
> numbers
 => [1, 2, 3, 4, 5, 6, 7] 
          

Hash

Coleçao de pares chave-valor

Indexados por objetos de qualquer tipo

> h = {"lang" => "Ruby", "os" => "Linus", "db" => "Postgres"}
 => {"lang"=>"Ruby", "os"=>"Linus", "db"=>"PostgreSQL"} 
> h.keys
 => ["lang", "os", "db"] 
> h.values
 => ["Ruby", "Linus", "PostgreSQL"] 
> h[10] = "Ruby classes"
 => "Ruby classes" 
> h
 => {"lang"=>"Ruby", "os"=>"Linus", "db"=>"PostgreSQL", 10=>"Ruby classes"} 
> h[{"a" => "b"}] = "C"
 => "C" 
> h.delete("db")
 => "PostgreSQL" 
> h
 => {"lang"=>"Ruby", "os"=>"Linus", 10=>"Ruby classes", {"a"=>"b"}=>"C"}
          

Hashes com Símbolos

Ruby 1.8

> tools = {:lang => "Ruby", :framework => "Rails"}
 => {:lang=>"Ruby", :framework=>"Rails"}
          

Ruby 1.9

> tools = {lang: "Ruby", framework: "Rails"}
 => {:lang=>"Ruby", :framework=>"Rails"} 
          

Importante

# ...
user.name
          
O que isso não é ?
  • name é uma variável presente no objeto user
  • name é algum tipo de estrutura de dados presente no user
O que isso é

user é o receptor ao qual enviamos uma chamada de método

Considerando que user responde à chamada name

# ...
user.name() # ou user.send(:name) 
          

Joy to use

Yukihiro "Matz" Matsumoto

O código deve ser bastante claro

+

O código deve ser conciso

=

Código simples, efetivo e fazer exatamente o que ser propôe a fazer

Ruby e "Modo Poesia"

Armando Fox, University of California, Berkeley

def print_key_value( hash )
  hash.each_pair { |key, value| puts "chave: #{key} - value: #{value}" }
end
          
> print_key_value({ user: "Joao lucas", email: "jlucasps" })
          
> print_key_value( user: "Joao lucas", email: "jlucasps" )
          
> print_key_value user: "Joao lucas", email: "jlucasps" 
          
chave: user - value: Joao lucas
chave: email - value: jlucasps@gmail.com
          

Ruby e "Modo Poesia"

user.age.should(be() >= 18)
user.age.should be >= 18
          
if !logged_in?() # unless logged_in?()
  (redirect_to(login_page)) and return()
end
# ...
(redirect_to(login_page)) and return() unless logged_in?()
# ...
redirect_to login_page and return unless logged_in?
          

Blocks

arr = [1, 2, 3, 4, 5]
arr.map do |n|
    n + 30
end
 => [31, 32, 33, 34, 35] 
          
  • Chamamos o método .map( ) com um block
  • O bloco interage com a variável n dentro do método .map( )
  • Cada elemento é somado a 30

Blocks

Criar um novo método iterate! e adicionar à classe Array

class Array
  def iterate!
      self.each_with_index do |n, i|
        self[i] = yield n
      end
  end
end
        
> array = [1, 2, 3, 4]
 => [1, 2, 3, 4] 
> array.iterate! { |n|
>   (n * 3) + 5
> }
 => [8, 11, 14, 17]
        
Ao chamar o yield, iremos executar o bloco de código fornecido ao método

Procs

class Array
  def iterate!( &code )
    self.each_with_index do |n, i|
      self[i] = code.call( n )
    end
  end
end
        
> array = [10, 11, 12, 13]
 => [10, 11, 12, 13] 
> array.iterate! do |n|
>   n ** 2
> end
 => [100, 121, 144, 169] 
        

Methods

class Caller
  def self.exec_before( method_name)
    @@before = method_name 
  end

  def self.exec_after( method_name )
    @@after = method_name
  end

  def execute( &code )
    method(@@before).call if defined? @@before
    code.call
    method(@@after).call if defined? @@after
  end
end
        

Métodos de classe para salvar símbolos nos atributos da classe

Método para executar uma Proc entre duas chamadas de métodos

Methods

class Executor < Caller

  exec_before( :say_hello )
  exec_after( :say_bye )


  def say_hello
    puts "Hello, I'm here!"
  end

  def say_bye
    puts "Good bye!"
  end
end
        

Classe com dois métodos configurados para serem executados como before e after

Methods

exec = Executor.new

exec.execute do 
  puts "I do my job"
end

# Hello, I'm here!
# I do my job
# Good bye!
        

Callbacks executados

Let's go to Rails

0