abhimanyuaryan
abhimanyuaryan

Reputation: 4044

shorthand for accessor methods in ruby class variables

I want some short way and less duplicate way of creating accessor methods for class variables. Here, I see that there is too much same looking code i.e. methods. Is there any short way like we have for our instance variables. @foobar which will have attr_accessor :foobar

class User
    @@user_id = 0
    @@user_long = 0
    @@user_lat = 0 

    # User ID

    def self.user_id=(id)
        @@user_id = id
    end

    def self.user_id
        @@user_id
    end

    # Longitude 

    def self.user_long=(longitude)
        @@user_long = longitude
    end

    def self.user_long
        @@user_long
    end

    # Latitude 

    def self.user_lat=(latitude)
        @@user_lat = latitude
    end

    def self.user_lat
        @@user_lat
    end
end


User.user_id = 23423423
User.user_long = -342.34
User.user_lat = 343.3

puts User.user_lat
puts User.user_lat
puts User.user_id

Upvotes: 2

Views: 480

Answers (3)

Jörg W Mittag
Jörg W Mittag

Reputation: 369614

In general, it is very much preferred to use instance variables instead of class variables, because of the somewhat strange sharing semantics of class variables:

class User
  class << self
    attr_accessor :user_id, :user_long, :user_lat
  end

  self.user_id   = 0
  self.user_long = 0
  self.user_lat  = 0 
end

User.user_id   #=> 0
User.user_long #=> 0
User.user_lat  #=> 0

User.user_id   = 23423423
User.user_long = -342.34
User.user_lat  = 343.3

User.user_id   #=> 23423423
User.user_long #=> -342.34
User.user_lat  #=> 343.3

But if you absolutely must use class variables, you can simply write your own methods for generating setters and getters. It's not like there's anything magical about Module#attr_accessor, it's a method just like any other method:

class Module
  def cvar_reader(*names)
    names.each do |name|
      define_singleton_method(name) { class_variable_get(:"@@#{name}") }
    end
  end

  def cvar_writer(*names)
    names.each do |name|
      define_singleton_method(:"#{name}=") {|value| class_variable_set(:"@@#{name}", value) }
    end
  end

  def cvar_accessor(*names)
    cvar_reader *names
    cvar_writer *names
  end
end

class User
  cvar_accessor :user_id, :user_long, :user_lat

  self.user_id   = 0
  self.user_long = 0
  self.user_lat  = 0 
end

User.user_id   #=> 0
User.user_long #=> 0
User.user_lat  #=> 0

User.user_id   = 23423423
User.user_long = -342.34
User.user_lat  = 343.3

User.user_id   #=> 23423423
User.user_long #=> -342.34
User.user_lat  #=> 343.3

However, it seems like a strange design, regardless of whether you use class instance variables or class variables. Why have a class at all, when you cannot have more than one user in your system anyway? Why not just use an object?

class << (User = Object.new)
  attr_accessor :user_id, :user_long, :user_lat
end

User.user_id   = 0
User.user_long = 0
User.user_lat  = 0 

User.user_id   #=> 0
User.user_long #=> 0
User.user_lat  #=> 0

User.user_id   = 23423423
User.user_long = -342.34
User.user_lat  = 343.3

User.user_id   #=> 23423423
User.user_long #=> -342.34
User.user_lat  #=> 343.3

Upvotes: 2

jtwarren
jtwarren

Reputation: 31

What you might be looking for is something like this,

class User
  class << self
    attr_accessor :user_id
  end
end

Which will create instance variables on the class's metaclass, rather than class variables. This might give you what you need but I do suggest reading and understanding Ruby's object model.

Upvotes: 1

rohit89
rohit89

Reputation: 5773

You can do it like this:

class User
  @user_id = 0
  @user_long = 0
  @user_lat = 0 
  class << self
    attr_accessor :user_id, :user_long, :user_lat
  end
end

Upvotes: 4

Related Questions