Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shortcut to assigning instance variables

I'm following Codecademy's Ruby course, about 85% done.

Over and over it asks you to create a class and pass in some parameters and make them instance variables, like this for example:

class Computer
    def initialize(username, password)
        @username = username
        @password = password
    end
end

Every time, it asks you to make the exact same instance variables as the parameters you passed in.

It made me wonder if there is a Ruby way to handle this automatically, removing the need to type it all out yourself every time.

I am aware you can do

class Computer
    def initialize(username, password)
        @username, @password = username, password
    end
end

but that's hardly less typing.

I did some searching and found that you can create a set of 'getters' using attr_reader like

class Song
    attr_reader :name, :artist, :duration
end

aSong = Song.new("Bicylops", "Fleck", 260)
aSong.artist # "Fleck"
aSong.name # "Bicylops"
aSong.duration # 260

But as far as I can tell that's not really what I'm looking for. I'm not trying to auto create getters and/or setters. What I'm looking for would be something like this

class Person
    def initialize(name, age, address, dob) #etc
        # assign all passed in parameters to equally named instance variables
        # for example
        assign_all_parameters_to_instance
        # name, age, address and dob would now be accessible via
        # @name, @age, @address and @dob, respectively
    end
end

I did some searching for ruby shortcut for assigning instance variables and alike but couldn't find an answer.

Is this possible? If so, how?

like image 477
Tim Avatar asked Nov 30 '14 16:11

Tim


People also ask

How do I assign an instance variable?

Values can be assigned during the declaration or within the constructor. Instance variables can be accessed directly by calling the variable name inside the class. However, within static methods (when instance variables are given accessibility), they should be called using the fully qualified name.

How do you declare an instance variable in Objective C?

In Objective-C, instance variables are commonly created with @propertys. An @property is basically an instance variable with a few extra bonus features attached. The biggest addition is that Objective-C will automatically define what's called a setter and a getter for you automatically.

Can you change instance variables?

We can modify the value of the instance variable and assign a new value to it using the object reference. Note: When you change the instance variable's values of one object, the changes will not be reflected in the remaining objects because every object maintains a separate copy of the instance variable.


3 Answers

Person = Struct.new(:name, :artist, :duration) do
  # more code to the Person class
end

Your other option is to pass a Hash/keyword of variables instead and use something like ActiveModel::Model https://github.com/rails/rails/blob/master/activemodel/lib/active_model/model.rb#L78-L81

def initialize(params={})
  params.each do |attr, value|
    self.instance_variable_set("@#{attr}", value)
  end if params
end
like image 114
avl Avatar answered Sep 28 '22 01:09

avl


First of all, your second block with set of attr_reader will not work. Because you are providing 3 arguments to default initialize method, which accepts 0 arguments.

Answer to your question is no, there is no such method, unless you are going to define it yourself using metaprogramming.

like image 21
Rustam A. Gasanov Avatar answered Sep 28 '22 00:09

Rustam A. Gasanov


assign_all_parameters_to_instance can't exist the way you would want it to. It would need to have access to its caller's local variables or parameters, which is a very awkward thing to do, and a violation of method encapsulation.

However, you could just generate a suitable initialize method:

class Module
  private def trivial_initializer(*args)
    module_eval(<<-"HERE")
      def initialize(#{args.join(', ')})
        #{args.map {|arg| "@#{arg} = #{arg}" }.join("\n")}
      end
    HERE
  end
end

class Computer
  trivial_initializer :username, :password
end

Computer.new('jwm', '$ecret')
# => #<Computer:0x007fb3130a6f18 @username="jwm", @password="$ecret">
like image 39
Jörg W Mittag Avatar answered Sep 28 '22 00:09

Jörg W Mittag