When I call A.new inside of B, is there a way to automatically get certain objects without specifying it? I want to pass self from B into A automatically without specifying it.
class A
initialize object=target-self
end
end
class B
A.new
end
Then, I don't have to type this every time I want self to be passed in default unless I specify another class.
A.new self
This is straightforward. All you have to do is write:
class A
def initialize(object = self)
# work with object
end
end
There is always a value for self in Ruby. In the example you provided, it will evaluate to the B class. To get it to be an instance of the class, just call the method during initialization:
class B
def initialize
A.new # self is a B instance here
end
end
Related
I have a library that I would use in an app by using a class that wraps the library object in a new class by inheriting from it and adding a few instance variables. I can change the library code if need be. Here is the problem:
class A
def process_it
# Make a new instance
aa = self.class.new
do_something_to(aa)
end
def do_something_to(item)
item
end
end
class B < A
def initialize(extra = "Default extra")
#extra = extra
super()
end
def extra
#extra
end
end
# I want B to inherit A's methods, like #process_it but:
b = B.new("Non-default extra")
puts b.process_it.extra => Default extra
The output should have been "Non-default extra" and the problem is that, in the parent class I call self.class.new but can pass no parameter to it to set #extra. In the call, self.class is B, the inherited class, but when I write the parent class library, A, I cannot predict what, if any parameters, should be passed to self.class.new. Indeed, I might have class C < A with different parameters for initialize.
Is there a proper way to write the code in library A to instantiate a new instance of the self class that takes possible parameters into account?
Will #dup work for you? Instead of aa = self.class.new, change it to aa = self.dup
I'd like to reference an object while instantiating it in order to pass it to another object I'm instantiating. What I mean:
A.new(B.new(self))
In this case, self would refer to the scope in which I'm actually calling A.new. What I want is for self (or whatever other keyword) to refer to the newly instantiated A object, so that B would have a reference to A. Is there a way to do this?
The way you have written it (A.new(B.new(self))) is impossible, due to a circular reference.
In order to create an instance of A, you need an instance of B; in order to create the instance of B, you need the instance of A.
There are a few ways you tweak the implementation to make this possible, but you must first resolve this chicken-and-egg problem between the A and B. For example:
class A
def initialize
#b = yield(self)
end
end
class B
def initialize(a)
#a = a
end
end
A.new { |a| B.new(a) }
Note that in the above code, a is being initialized first. It is only being yielded in the scope after the object has been created.
Or, here's another way:
class A
def initialize
#b = B.new(self)
end
end
class B
def initialize(a)
#a = a
end
end
A.new
Like above, the instance of A is being created first. But this time, I've done all the initialization in one go rather than building it within the new() methed call.
One final example:
class A
attr_writer :b
def initialize
end
end
class B
def initialize(a)
#a = a
end
end
A.new.tap { |a| a.b = B.new(a) }
In this example, I have fully initialized a before defining its attribute of b. This could just as easily have been written in two lines of code, with a regular variable instead of the closure:
a = A.new
a.b = B.new(a)
I am trying to call a method that will create an object of another class. When I do, I get feedback that the object has been created, but I can't seem to to do anything with that object (such as call a method from that objects class). Here is an example:
class A
def initialize
end
def generate
var = B.new
end
end
class B
def initialize
end
def declare
puts "I exist!"
end
end
test = A.new
test.generate
var.declare
This returns an "Undefined local variable or method 'var'" error. Am I going about this wrong? The best I can figure is that I am creating this object only within the instance, but even when I try doing stuff with it in the instance it comes back undefined. Is there another way to do this I am not thinking of, or am I doing this wrong? Thanks!
var is only "visible" within the generatemethod. Move it out of the class.
class A
def generate
B.new
end
end
class B
def declare
puts "I exist!"
end
end
test = A.new
var = test.generate # var is an instance of B
var.declare # => I exist!
Method chaining is also possible, avoiding variables.
A.new.generate.declare # => I exist!
Here is my code:
class Klass
["thing", nil].each do |i|
instance_variable_set("##{i}reqs", {})
end
def initialize(var)
#reqs[var] = self
end
end
Klass.new("hello")
Which gives me the error:
in initialize': undefined method[]=' for nil:NilClass (NoMethodError)
I shouldn't be getting this error because the loop at the top should have initialized #reqs in it's second iteration. What is going on?
Instance variables belong to particular instances. That's why they are called instance variables.
In line 3, you set the instance variable called #reqs of the object Klass. In line 6, you access the instance variable called #reqs of an instance of the class Klass. Those are two completely different, distinct objects each with its own set of instance variables. Heck, those two objects don't even have the same class! (Klass's class is Class, whereas Klass.new's class is Klass.)
In line 6, #reqs is uninitialized, and uninitialized instance variables evaluate to nil.
There are many different ways to fix this, depending on your exact circumstances and requirements, the easiest way would be to initialize the instance variables in the initialize method, after all, that's what that method is there for:
class Klass
def initialize(var)
['thing', nil].each do |i|
instance_variable_set(:"##{i}reqs", {})
end
#reqs[var] = self
end
end
Klass.new('hello')
Remember, the problem was that the instance variables were initialized in one object, and accessed in another. This solution moves the initialization to the same object that was doing the reading.
However, the dual is also possible: move the reading to where the initialized variables are:
class Klass
['thing', nil].each do |i|
instance_variable_set(:"##{i}reqs", {})
end
def initialize(var)
self.class.instance_variable_get(:#reqs)[var] = self
end
end
Klass.new('hello')
This is kind of ugly, so let's add an attr_reader:
class Klass
['thing', nil].each do |i|
instance_variable_set(:"##{i}reqs", {})
end
class << self; attr_reader :reqs end
def initialize(var)
self.class.reqs[var] = self
end
end
Klass.new('hello')
Obviously, these two do very different things. It is unclear from your question which of the two you actually want.
A third possibility would be using class variables:
class Klass
['thing', nil].each do |i|
class_variable_set(:"###{i}reqs", {})
end
def initialize(var)
##reqs[var] = self
end
end
Klass.new('hello')
Note that this does yet another different thing. Again, whether you want that or not is not clear from your question.
The loop at the top is defining an instance variable for the Class, not for any object of the class.
So for the object, it doesn't exist.
From the looks of it, you want a hash common to the whole class where you store each created object in the hash. Assuming you don't have issues with class inheritance, you'd be better of with a class variable.
so...
class Klass
["thing",nil].each do |i|
class_variable_set("###{i}reqs", {})
end
def initialize(var)
##reqs[var] = self
end
end
Klass.new("hello")
If you define class like this:
class Klass
instance_variable_set(:#name, 'dog')
def self.name
#name
end
def name
#name
end
end
then
Klass.name # => 'dog'
instance = Klass.new
instance.name # => nil
Now you can see the difference. Your variable is defined on class level, not instance level.
I know self is the receiver of the method calling.
But I do not know if there is not self in method definition.
code example:
class One
def kk
"kk"
end
def self.kkk
"kkk"
end
end
puts One.new.kk
puts One.kkk
Why do I need to use new method for One used like One.new.kk ?
self.kkk here defines a class method of One. As you know, self is the receiver. In the context here it is the One class.
And One.new returns an instance of class One. kk is an instance method that only called by an instance.
class Demo2
def self.method1(a)
p a.is_a? Demo2
end
def method2(b)
p b.to_s
end
end
a=Demo2.new
# here, if you type a.... wait for hint, you just can only get method2()
# just because it class self.
a.method2('123')
Demo2.method1(a)
p Demo2 # this is a class
p a # this a class instance
>'123'
>true
>Demo2
>#<Demo2:0x290d768>
I think this simple code can make you clear, I don't talk OOP with you, that's so boring!^_^