rails - ruby>- lang




O que é attr_accessor em Ruby? (12)

Atributos e métodos de acesso

Atributos são componentes de classe que podem ser acessados ​​de fora do objeto. Eles são conhecidos como propriedades em muitas outras linguagens de programação. Seus valores são acessíveis usando a "notação de ponto", como em object_name.attribute_name. Ao contrário do Python e de algumas outras linguagens, o Ruby não permite que variáveis ​​de instância sejam acessadas diretamente de fora do objeto.

class Car
  def initialize
    @wheels = 4  # This is an instance variable
  end
end

c = Car.new
c.wheels     # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>

No exemplo acima, c é uma instância (objeto) da classe Car. Tentamos, sem sucesso, ler o valor da variável de instância de rodas de fora do objeto. O que aconteceu foi que Ruby tentou chamar um método chamado wheels dentro do objeto c, mas nenhum método foi definido. Em suma, object_name.attribute_name tenta chamar um método chamado attribute_name dentro do objeto. Para acessar o valor da variável wheels do lado de fora, precisamos implementar um método de instância com esse nome, que retornará o valor dessa variável quando chamado. Isso é chamado de um método de acesso. No contexto de programação geral, a maneira usual de acessar uma variável de instância de fora do objeto é implementar métodos de acesso, também conhecidos como métodos getter e setter. Um getter permite que o valor de uma variável definida dentro de uma classe seja lido a partir do exterior e um setter permite que seja escrito a partir do exterior.

No exemplo a seguir, adicionamos métodos getter e setter à classe Car para acessar a variável wheels de fora do objeto. Este não é o "caminho Ruby" de definir getters e setters; serve apenas para ilustrar o que os métodos getter e setter fazem.

class Car
  def wheels  # getter method
    @wheels
  end

  def wheels=(val)  # setter method
    @wheels = val
  end
end

f = Car.new
f.wheels = 4  # The setter method was invoked
f.wheels  # The getter method was invoked
# Output: => 4

O exemplo acima funciona e um código semelhante é comumente usado para criar métodos getter e setter em outros idiomas. No entanto, o Ruby fornece uma maneira mais simples de fazer isso: três métodos internos chamados attr_reader, attr_writer e attr_acessor. O método attr_reader torna uma variável de instância legível a partir do exterior, attr_writer torna-a gravável e attr_acessor torna-a legível e gravável.

O exemplo acima pode ser reescrito assim.

class Car
  attr_accessor :wheels
end

f = Car.new
f.wheels = 4
f.wheels  # Output: => 4

No exemplo acima, o atributo wheels será legível e gravável de fora do objeto. Se em vez de attr_accessor, usamos attr_reader, seria somente leitura. Se usássemos attr_writer, seria somente escrita. Esses três métodos não são getters e setters em si mesmos, mas, quando chamados, criam métodos getter e setter para nós. Eles são métodos que dinamicamente (programaticamente) geram outros métodos; isso é chamado de metaprogramação.

O primeiro exemplo (mais longo), que não emprega os métodos internos do Ruby, deve ser usado somente quando um código adicional é requerido nos métodos getter e setter. Por exemplo, um método setter pode precisar validar dados ou fazer alguns cálculos antes de atribuir um valor a uma variável de instância.

É possível acessar (ler e gravar) variáveis ​​de instância de fora do objeto, usando os métodos internos instance_variable_get e instance_variable_set. No entanto, isso raramente é justificável e geralmente é uma má ideia, já que contornar o encapsulamento tende a causar todo tipo de estragos.

Eu estou tendo dificuldade em entender attr_accessor em Ruby. Alguém pode explicar isso para mim?


Explicação simples sem qualquer código

A maioria das respostas acima usa código. Esta explicação tenta respondê-lo sem usar nenhum, através de uma analogia / história:

Partes externas não podem acessar segredos internos da CIA

  • Vamos imaginar um lugar realmente secreto: a CIA. Ninguém sabe o que está acontecendo na CIA além das pessoas dentro da CIA. Em outras palavras, pessoas externas não podem acessar nenhuma informação na CIA. Mas como não adianta ter uma organização que é completamente secreta, certas informações são disponibilizadas para o mundo exterior - apenas coisas que a CIA quer que todos saibam, é claro: por exemplo, o diretor da CIA, quão ambientalmente amigável este departamento é comparado a todos os outros departamentos governamentais, etc. Outras informações: por exemplo, quem são seus agentes secretos no Iraque ou no Afeganistão - esses tipos de coisas provavelmente permanecerão em segredo pelos próximos 150 anos.

  • Se você estiver fora da CIA, só poderá acessar as informações disponibilizadas para o público. Ou, para usar o jargão da CIA, você só pode acessar informações "limpas".

  • As informações que a CIA quer disponibilizar para o público em geral fora da CIA são chamadas: atributos.

O significado dos atributos de leitura e gravação:

  • No caso da CIA, a maioria dos atributos é "somente leitura". Isto significa que se você é um partido externo à CIA, pode perguntar: "quem é o diretor da CIA?" e você receberá uma resposta direta. Mas o que você não pode fazer com atributos "somente leitura" é fazer mudanças na CIA. Por exemplo, você não pode fazer um telefonema e, de repente, decidir que quer que Kim Kardashian seja a diretora, ou que você quer que Paris Hilton seja a comandante-em-chefe.

  • Se os atributos lhe deram acesso "write", então você poderia fazer alterações se quisesse, mesmo se estivesse fora. Caso contrário, a única coisa que você pode fazer é ler.

    Em outras palavras, os acessadores permitem que você faça perguntas, ou faça alterações, em organizações que, de outra forma, não permitem a entrada de pessoas externas, dependendo se os acessadores são acessos de leitura ou gravação.

Objetos dentro de uma classe podem acessar facilmente uns aos outros

  • Por outro lado, se você já estava dentro da CIA, então pode facilmente chamar seu agente da CIA em Cabul, porque esta informação é facilmente acessível, já que você já está dentro dela. Mas se você estiver fora da CIA, simplesmente não terá acesso: você não poderá saber quem é (acesso de leitura) e não poderá alterar sua missão (acesso de gravação).

Exatamente a mesma coisa com classes e sua capacidade de acessar variáveis, propriedades e métodos dentro delas. HTH! Qualquer dúvida, por favor, pergunte e espero que eu possa esclarecer.


A principal funcionalidade do attr_accessor sobre os outros é a capacidade de acessar dados de outros arquivos.
Então você normalmente teria attr_reader ou attr_writer, mas a boa notícia é que Ruby permite combinar esses dois com attr_accessor. Eu penso nisso como o meu método de ir porque é mais bem arredondado ou versátil. Além disso, tenha em mente que, no Rails, isso é eliminado porque é feito para você no back end. Então, em outras palavras: é melhor usar o attr_acessor nos outros dois porque você não precisa se preocupar em ser específico, o acessor cobre tudo. Eu sei que isso é mais uma explicação geral, mas me ajudou como iniciante.

Espero que isso tenha ajudado!


Basicamente, eles falsificam atributos de dados acessíveis publicamente, o que Ruby não tem.


Define um atributo nomeado para este módulo, em que o nome é symbol.id2name, criando uma variável de instância (@name) e um método de acesso correspondente para lê-lo. Também cria um método chamado name = para definir o atributo.

module Mod
  attr_accessor(:one, :two)
end
Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]

Digamos que você tenha uma Person turma.

class Person
end

person = Person.new
person.name # => no method error

Obviamente, nunca definimos o name método. Vamos fazer isso.

class Person
  def name
    @name # simply returning an instance variable @name
  end
end

person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error

Aha, podemos ler o nome, mas isso não significa que podemos atribuir o nome. Esses são dois métodos diferentes. O primeiro é chamado de leitor e este último é chamado de escritor . Nós não criamos o escritor ainda, então vamos fazer isso.

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

Impressionante. Agora podemos escrever e ler a variável de instância @name usando métodos de leitura e gravação. Exceto, isso é feito com tanta frequência, por que perder tempo escrevendo esses métodos toda vez? Nós podemos fazer isso mais fácil.

class Person
  attr_reader :name
  attr_writer :name
end

Mesmo isso pode se tornar repetitivo. Quando você quer o leitor e o escritor apenas use o acessor!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

Funciona da mesma maneira! E adivinhe: a variável de instância @name em nosso objeto de pessoa será definida como quando fizemos manualmente, para que você possa usá-la em outros métodos.

class Person
  attr_accessor :name

  def greeting
    "Hello #{@name}"
  end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

É isso aí. Para entender como os attr_reader , attr_writer e attr_accessor realmente geram métodos para você, leia outras respostas, livros, documentos do ruby.


Eu também enfrentei esse problema e escrevi uma resposta um pouco longa para essa questão. Há algumas ótimas respostas sobre isso já, mas qualquer um que esteja procurando mais esclarecimentos, espero que minha resposta possa ajudar

Inicializar Método

Initialize permite que você defina dados para uma instância de um objeto após a criação da instância, em vez de configurá-los em uma linha separada em seu código toda vez que você criar uma nova instância da classe.

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


  def greeting
    "Hello #{@name}"
  end
end

person = Person.new("Denis")
puts person.greeting

No código acima, estamos definindo o nome “Denis” usando o método initialize passando Dennis através do parâmetro em Initialize. Se quiséssemos definir o nome sem o método initialize, poderíamos fazer assim:

class Person
  attr_accessor :name

  # def initialize(name)
  #     @name = name
  # end

  def greeting
    "Hello #{name}"
  end
end

person = Person.new
person.name = "Dennis"
puts person.greeting

No código acima, definimos o nome chamando o método attr_accessor setter usando person.name, em vez de definir os valores na inicialização do objeto.

Ambos os “métodos” de fazer este trabalho, mas inicializam, economizam tempo e linhas de código.

Este é o único trabalho de inicializar. Você não pode chamar em inicializar como um método. Para realmente obter os valores de um objeto de instância, você precisa usar getters e setters (attr_reader (get), attr_writer (set) e attr_accessor (ambos)). Veja abaixo para mais detalhes sobre eles.

Getters, Setters (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: Todo o propósito de um getter é retornar o valor de uma determinada variável de instância. Visite o código de exemplo abaixo para um detalhamento sobre isso.

class Item

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

  def item_name
    @item_name
  end

  def quantity
     @quantity
  end
end

example = Item.new("TV",2)
puts example.item_name
puts example.quantity

No código acima, você está chamando os métodos “item_name” e “quantity” na instância de Item “example”. Os “puts example.item_name” e “example.quantity” retornarão (ou “obterão”) o valor dos parâmetros que foram passados ​​para o “exemplo” e os exibirão na tela.

Felizmente, em Ruby, existe um método inerente que nos permite escrever esse código de maneira mais sucinta; o método attr_reader. Veja o código abaixo;

class Item

attr_reader :item_name, :quantity

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

end

item = Item.new("TV",2)
puts item.item_name
puts item.quantity

Esta sintaxe funciona exatamente da mesma maneira, apenas nos salva seis linhas de código. Imagine se você tivesse mais 5 estados atribuíveis à classe Item? O código demoraria muito tempo.

Setters, attr_writer: O que me atrapalhou no início com os métodos setter é que, aos meus olhos, parecia executar uma função idêntica ao método initialize. Abaixo eu explico a diferença com base no meu entendimento;

Como dito anteriormente, o método initialize permite que você defina os valores para uma instância de um objeto na criação do objeto.

Mas e se você quisesse definir os valores posteriormente, após a criação da instância, ou alterá-los depois de serem inicializados? Este seria um cenário em que você usaria um método setter. Essa é a diferença. Você não precisa "definir" um estado específico quando estiver usando o método attr_writer inicialmente.

O código abaixo é um exemplo de uso de um método setter para declarar o valor item_name para essa instância da classe Item. Observe que continuamos a usar o método getter attr_reader para que possamos obter os valores e imprimi-los na tela, caso você queira testar o código por conta própria.

class Item

attr_reader :item_name

  def item_name=(str)
    @item_name = (str)
  end

end

O código abaixo é um exemplo do uso do attr_writer para encurtar novamente nosso código e economizar tempo.

class Item

attr_reader :item_name
attr_writer :item_name

end

item = Item.new
puts item.item_name = "TV"

O código abaixo é uma reiteração do exemplo de inicialização acima de onde estamos usando initialize para definir o valor de objetos de item_name após a criação.

class Item

attr_reader :item_name

  def initialize(item_name)
    @item_name = item_name
  end

end

item = Item.new("TV")
puts item.item_name

attr_accessor: Executa as funções de attr_reader e attr_writer, economizando mais uma linha de código.


Hmmm Muitas boas respostas. Aqui estão meus poucos centavos.

  • attr_accessor é um método simples que nos ajuda a limpar ( DRY-ing ) os métodos repetitivos de getter and setter .

  • Para que possamos nos concentrar mais em escrever lógica de negócios e não nos preocuparmos com setters e getters.


Para resumir um atributo, o atributo attr_accessor fornece dois métodos livres.

Como em Java, eles são chamados de getters e setters.

Muitas respostas mostraram bons exemplos, por isso vou ser breve.

#the_attribute

e

# the_attribute =

No antigo ruby ​​docs, um hash tag # significa um método. Também pode incluir um prefixo de nome de classe ... MyClass # my_method


Se você estiver familiarizado com o conceito de OOP, você deve estar familiarizado com o método getter e setter. attr_accessor faz o mesmo em Ruby.

Getter e Setter em geral

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"

Método de Setter

def name=(val)
  @name = val
end

Método getter

def name
  @name
end

Método Getter e Setter em Ruby

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"

attr_accessor é apenas um método . (O link deve fornecer mais informações sobre como funciona - veja os pares de métodos gerados e um tutorial deve mostrar como usá-lo.)

O truque é que a class não é uma definição em Ruby (é "apenas uma definição" em linguagens como C ++ e Java), mas é uma expressão que avalia . É durante essa avaliação quando o método attr_accessor é invocado, o que, por sua vez, modifica a classe atual - lembre-se do receptor implícito: self.attr_accessor , onde self é o objeto de classe "open" neste ponto.

A necessidade de attr_accessor e amigos é bem:

  1. Ruby, como o Smalltalk, não permite que variáveis ​​de instância sejam acessadas fora dos métodos 1 para esse objeto. Isto é, variáveis ​​de instância não podem ser acessadas na forma xy como é comum em Java ou Python. Em Ruby y é sempre tomado como uma mensagem para enviar (ou "método para chamar"). Assim, os métodos attr_* criam wrappers que @variable proxy da instância @variable access @variable através de métodos criados dinamicamente.

  2. Boilerplate é uma merda

Espero que isso esclarece alguns dos pequenos detalhes. Codificação feliz.

1 Isso não é estritamente verdadeiro e existem algumas "técnicas" em torno disso , mas não há suporte de sintaxe para o acesso "variável de instância pública".


attr_accessor é (como @pst declarado) apenas um método. O que ele faz é criar mais métodos para você.

Então esse código aqui:

class Foo
  attr_accessor :bar
end

é equivalente a este código:

class Foo
  def bar
    @bar
  end
  def bar=( new_value )
    @bar = new_value
  end
end

Você pode escrever esse tipo de método em Ruby:

class Module
  def var( method_name )
    inst_variable_name = "@#{method_name}".to_sym
    define_method method_name do
      instance_variable_get inst_variable_name
    end
    define_method "#{method_name}=" do |new_value|
      instance_variable_set inst_variable_name, new_value
    end
  end
end

class Foo
  var :bar
end

f = Foo.new
p f.bar     #=> nil
f.bar = 42
p f.bar     #=> 42




ruby