Reflexão em Ruby

Neste post, vamos analisar como é possível utilizar reflexão na linguagem ruby.

A Linguagem Ruby

Ruby é classificado como Dinamicamente Tipado, ou seja, os objetos ruby possuem tipos, por exemplo um objeto Carro é um Carro, no entanto as variáveis, que por sua vez referenciam estes objetos, não possuem tipo, então o código abaixo funcionaria sem nenhum problema:

carro = Carro.new
carro = 2
carro = "Carro"
carro = nil

Outro aspecto importante sobre ruby é que a linguagem é dinâmica, e por dinâmica entenda que é possível adicionar ou modificar código, em tempo de execução (metaprogramação) e obter informações sobre os próprios objetos, também em tempo de execução (reflexão).

Reflexão

Já vimos, meio que sem querer, como funciona a Reflexão em ruby, no post anterior. Lembra que fizemos “self.class”? Este é um método implementado na classe Object, que retorna qual a classe do objeto que variável está referenciando. No ruby, assim como no Java, todas as classes herdam de Object, então todas as classe possuem este método. Vamos analisar alguns exemplos deste método:

1.9.3p125 :011 > 1.class
 => Fixnum 
1.9.3p125 :012 > "String".class
 => String

Objetos e Mensagens

Calma ai, como é que 1 tem o método “class”? 1 não é um número? Sim, e por isso ele É um objeto da classe Fixnum, que por sua vez, herda da classe object. Ou seja, tudo é um objeto. E toda chamada de método é na verdade um envio de mensagem! Vamos ver na prática como funciona:

1.9.3p125 :001 > 1.class
 => Fixnum 
1.9.3p125 :002 > 1.send(:class)
 => Fixnum 

O método “send” envia uma mensagem ao objeto. O parâmetro “:class” é um símbolo ruby (todo símbolo começa com ‘:’ na frente). Pense num símbolo como sendo uma string constante que o valor é ela mesma, então :class é uma string constante com valor “class”. Ao executar o método “send”, enviamos um símbolo e o método vai tentar executar um método que possua o mesmo nome daquele símbolo (por isso os métodos também precisam seguir a convenção snake_case). Então quando executamos “1.class” é o mesmo que estarmos enviando uma mensagem ao objeto “1” para executar o método “class”.

Veja mais alguns exemplos, caso ainda tenha dúvidas:

1.9.3p125 :001 > 1 + 3
 => 4 
1.9.3p125 :002 > 1.send(:+, 3)
 => 4 
1.9.3p125 :003 > "hello world".upcase
 => "HELLO WORLD" 
1.9.3p125 :004 > "hello world".send(:upcase)
 => "HELLO WORLD"

Um pouco mais sobre Reflexão

O método “respond_to?” verifica se aquele objeto pode responder a uma determinada mensagem. Por exemplo:

1.9.3p125 :006 > "hello world".respond_to?(:upcase)
 => true

Para finalizar a parte de reflexão, vamos ver um método que mostra todos os métodos, ou todas as mensagens, que um objeto pode executar, é o “methods”:

1.9.3p125 :007 > "hello world".methods
 => [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[], :[]=, :insert, :length, :size, :bytesize, :empty?, :=~, :match, :succ, :succ!, :next, :next!, :upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :byteslice, :to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase, :downcase, :capitalize, :swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes, :chars, :codepoints, :reverse, :reverse!, :concat, :<<, :prepend, :crypt, :intern, :to_sym, :ord, :include?, :start_with?, :end_with?, :scan, :ljust, :rjust, :center, :sub, :gsub, :chop, :chomp, :strip, :lstrip, :rstrip, :sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr, :tr_s, :delete, :squeeze, :count, :tr!, :tr_s!, :delete!, :squeeze!, :each_line, :each_byte, :each_char, :each_codepoint, :sum, :slice, :slice!, :partition, :rpartition, :encoding, :force_encoding, :valid_encoding?, :ascii_only?, :unpack, :encode, :encode!, :to_r, :to_c, :>, :>=, :<, :<=, :between?, :nil?, :!~, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

Meio confuso né? Bom, na verdade ele retorna um array contendo todos os métodos que um determinado objeto possui, por isso que fica bem bagunçada a saída.

Por hoje é só, espero que a OO do ruby tenha ficado um pouco mais clara. No próximo post vamos ver a metaprogramação. Se gostou do post compartilhe com seus amigos e colegas, senão, comente o que pode ser melhorado. Encontrou algum erro no código? Comente também. Possui alguma outra opinião ou alguma informação adicional? Comenta ai! 😀

Anúncios

Um comentário sobre “Reflexão em Ruby

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s