Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Heey I am new to Ruby. I need to create a factory method, which will return me an object of a class. Using that object I should be able to access the variables of the class. I have written the following code, but I surely have miss something.
class Super
##super_temp = 1
def Super.get_instance(world)
platform = world
if ##instance == nil
if platform==1
##instance = BaseA.new
else
##instance = BaseB.new
end
end
return ##instance
end
end
class BaseA < Super
##base_temp = 2
end
class BaseB < Super
##base_temp = 3
end
class Demo
def Demo.call_demo
obj = Super.get_instance(0)
puts "---------temp is #{obj.base_temp}"
end
end
Demo.call_demo
I need to retrieve the value of base_temp in class Demo.
Don't use ## (Why should we avoid using class variables ## in rails?) - # solves your problem just as easily.
Aside from that, all that is missing in your code is a getter:
class Super
#super_temp = 1
def Super.get_instance(world)
platform = world
if #instance == nil
if platform==1
#instance = BaseA.new
else
#instance = BaseB.new
end
end
return #instance
end
def base_temp
self.class.base_temp
end
def self.base_temp
#base_temp
end
end
class BaseA < Super
#base_temp = 2
end
class BaseB < Super
#base_temp = 3
end
class Demo
def Demo.call_demo
obj = Super.get_instance(0)
puts "---------temp is #{obj.base_temp}"
end
end
Demo.call_demo
# ---------temp is 3
The instance getter (implemented as self.class.base_temp) calls the class method base_temp of the instance's class. If we add prints of the internal products of the function, you can have some insights about its internals:
class Super
def base_temp
p self
p self.class
p self.class.base_temp
end
end
BaseA.new.base_temp
# #<BaseA:0x000000027df9e0>
# BaseA
# 2
BaseB.new.base_temp
# #<BaseB:0x000000027e38b0>
# BaseB
# 3
Related
I am writing the Ruby program found below
class Animal
attr_reader :name, :age
def name=(value)
if value == ""
raise "Name can't be blank!"
end
#name = value
end
def age=(value)
if value < 0
raise "An age of #{value} isn't valid!"
end
#age = value
end
def talk
puts "#{#name} says Bark!"
end
def move(destination)
puts "#{#name} runs to the #{destination}."
end
def report_age
puts "#{#name} is #{#age} years old."
end
end
class Dog < Animal
end
class Bird < Animal
end
class Cat < Animal
end
whiskers = Cat.new("Whiskers")
fido = Dog.new("Fido")
polly = Bird.new("Polly")
polly.age = 2
polly.report_age
fido.move("yard")
whiskers.talk
But when I run it, it gives this error:
C:/Users/akathaku/mars2/LearningRuby/Animal.rb:32:in `initialize': wrong number of arguments (1 for 0) (ArgumentError)
from C:/Users/akathaku/mars2/LearningRuby/Animal.rb:32:in `new'
from C:/Users/akathaku/mars2/LearningRuby/Animal.rb:32:in `<main>'
My investigations shows that I should create objects like this
whiskers = Cat.new("Whiskers")
Then there should be an initialize method in my code which will initialize the instance variable with the value "Whiskers".
But if I do so then what is the purpose of attribute accessors that I am using? Or is it like that we can use only one and if I have to use attribute accessors then I should avoid initializing the instance variables during object creation.
initialize is the constructor of your class and it runs when objects are created.
Attribute accessors are used to read or modify attributes of existing objects.
Parameterizing the constructor(s) gives you the advantage of having a short and neat way to give values to your object's properties.
whiskers = Cat.new("Whiskers")
looks better and it's easier to write than
whiskers = Cat.new
whiskers.name = "Whiskers"
The code for initialize in this case should look like
class Animal
...
def initialize(a_name)
name = a_name
end
...
end
All attr_reader :foo does is define the method def foo; #foo; end. Likewise, attr_writer :foo does so for def foo=(val); #foo = val; end. They do not do assume anything about how you want to structure your initialize method, and you would have to add something like
def initialize(foo)
#foo = foo
end
Though, if you want to reduce boilerplate code for attributes, you can use something like Struct or Virtus.
You should define a method right below your class name, something like
def initialize name, age
#name = name
#age = age
end
I'm trying to make a game but I am having problems settinga default value for an attribute and having a different default value for each subclass.
Here is the problem:
class Player
attr_accessor :hp
#hp = 2
end
class Harper < Player
#hp = 5
end
bill = Harper.new.hp #=>nil
I'm expecting Harper.new.hp to be 5 but it's showing nil instead, and I don't understand why.
The problem with your initialization is that it exists at the class level. That is, you are creating a class instance variable (confusing?) not an object-instance variable as you expect.
In order to create an instance variable you need to do it in a method run at the instance level, like the initialize method which runs when you create an object with the "new" method.
Example:
class Hello
#world = "World!"
def initialize
#to_be_or_not_to_be = "be!"
end
end
=> :initialize
inst = Hello.new
inst.instance_variables
=> [:#to_be_or_not_to_be]
Hello.instance_variables
=> [:#world]
inst.class.instance_variables
=> [:#world]
You need to place your assignments on an initialize function:
class Player
attr_accessor :hp
def initialize
#hp = 2
end
end
class Harper < Player
def initialize
super ## May not be necessary for now.
#hp = 5
end
end
bill = Harper.new.hp
# => 5
new class method runs instance method initialize, so your code should look like:
class Harper < Player
def initialize
#hp = 5
end
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
i have simple, how to return array with class instances ? I'm trying to return the array, but this variable return an empty array.
For example :
class Library
def initialize
##books = []
end
def all
##books
end
def add_book(arg = {})
#book = Book.new(arg)
##books << #book
end
end
class Book
attr_accessor :name, :year, :author, :content
def initialize( arg = {})
#name = arg[:name]
#year = arg[:year]
#author = arg[:author]
#content = arg[:content]
end
end
##books is a Library class variable. I am using method add_book to put books into #books, but how can i return array of these instances ? Sorry for bad english.
Thanks in advance !
When you call the method new to create a new object, ruby runs the initialize method. Since the initialize method sets ##books to an empty array, of course Library.new.all will return an empty array.
Class variables are shared by all instances of a class, so it doesn't make sense to be resetting it when you initialize a new Library as you'd be zeroing out the books stored in all other Library instances. From your usage it looks like you want a plain instance variable:
class Library
def initialize
#books = []
end
# you could replace this method with a `attr_reader :books`
def all
#books
end
# consider changing the method signature to accept a Book instance
def add_book(arg = {})
#books << Book.new(arg)
end
end
This question already has answers here:
When to use `self.foo` instead of `foo` in Ruby methods
(3 answers)
Closed 9 years ago.
When do you use self.property_name in Ruby?
Use self when calling a class's mutator. For example, this won't work:
class Foo
attr_writer :bar
def do_something
bar = 2
end
end
The problem is that 'bar = 2' creates a local variable named 'bar', rather than calling the method 'bar=' which was created by attr_writer. However, a little self will fix it:
class Foo
attr_writer :bar
def do_something
self.bar = 2
end
end
self.bar = 2 calls the method bar=, as desired.
You may also use self to call a reader with the same name as a local variable:
class Foo
attr_reader :bar
def do_something
bar = 123
puts self.bar
end
end
But it's usually better to avoid giving a local variable the same name as an accessor.
self references the current object. This lends itself to many uses:
calling a method on the current object
class A
def initialize val
#val = val
end
def method1
1 + self.method2()
end
def method2
#val*2
end
end
Here running A.new(1).method1() will return 3. The use of self is optional here - the following code is equivalent:
class A
def initialize val
#val = val
end
def method1
1 + method2()
end
def method2
#val*2
end
end
self is not redundant for this purpose though - operator overloading makes it neccessary:
class A
def initialize val
#val = val
end
def [] x
#val + x
end
def method1 y
[y] #returns an array!
end
def method2 y
self.[y] #executes the [] method
end
end
This shows how self must be used if you want to call the current object's [] method.
referencing attributes
You can generate the methods to read and write to instance variables using attr_accessor and co.
class A
attr_accessor :val
def initialize val
#val = val
end
def increment!
self.val += 1
end
end
Using self is redundant here because you can just reference the variable directly, eg. #val.
Using the previous class, A.new(1).increment! would return 2.
method chaining
You can return self to provide a form of syntactical sugar known as chaining:
class A
attr_reader :val
def initialize val
#val = val
end
def increment!
#val += 1
self
end
end
Here, because we are returning the current object, methods can be chained:
A.new(1).increment!.increment!.increment!.val #returns 4
creating class methods
You can define class methods using self:
class A
def self.double x
x*2
end
def self.quadruple x
self.double(self.double(x))
end
end
This will enable you to call A.double(2) #= 4 and A.quadruple(2) #=8. Note that in a class method, self references that class because the class is the current object.
how the value of self is determined
The current value of self in a particular method is set to the object that that method was called upon. Normally this uses the '.' notation. When you run some_object.some_method(), self is bound to some_object for the duration of some_method, meaning that some_method can use self in one of the ways mentioned above.
Using self is used will reference the current object accessible within a program. Therefore, self.property is used when accessing a variable through a attr_accessor of some sort. In must cases, it can be used in place of #property from within an object.
I'm studying Ruby and my brain just froze.
In the following code, how would I write the class writer method for 'self.total_people'? I'm trying to 'count' the number of instances of the class 'Person'.
class Person
attr_accessor :name, :age
##nationalities = ['French', 'American', 'Colombian', 'Japanese', 'Russian', 'Peruvian']
##current_people = []
##total_people = 0
def self.nationalities #reader
##nationalities
end
def self.nationalities=(array=[]) #writer
##nationalities = array
end
def self.current_people #reader
##current_people
end
def self.total_people #reader
##total_people
end
def self.total_people #writer
#-----?????
end
def self.create_with_attributes(name, age)
person = self.new(name)
person.age = age
person.name = name
return person
end
def initialize(name="Bob", age=0)
#name = name
#age = age
puts "A new person has been instantiated."
##total_people =+ 1
##current_people << self
end
You can define one by appending the equals sign to the end of the method name:
def self.total_people=(v)
##total_people = v
end
You're putting all instances in ##current_people you could define total_people more accurately:
def self.total_people
##current_people.length
end
And get rid of all the ##total_people related code.
I think this solves your problem:
class Person
class << self
attr_accessor :foobar
end
self.foobar = 'hello'
end
p Person.foobar # hello
Person.foobar = 1
p Person.foobar # 1
Be aware of the gotchas with Ruby's class variables with inheritance - Child classes cannot override the parent's value of the class var. A class instance variable may really be what you want here, and this solution goes in that direction.
One approach that didn't work was the following:
module PersonClassAttributes
attr_writer :nationalities
end
class Person
extend PersonClassAttributes
end
I suspect it's because attr_writer doesn't work with modules for some reason.
I'd like to know if there's some metaprogramming way to approach this. However, have you considered creating an object that contains a list of people?