`initialize` seems to check the arguments given to `new` - ruby

I am looking at this code:
class Mo
def new(indy, rome = 1)
initialize(indy, rome)
end
def initialize(indy, rome)
...
end
end
Mo.new(2)
I get this output:
test.rb:6:in `initialize': wrong number of arguments (1 for 2) (ArgumentError)
If I add the default value for rome in the definition to new, it works:
class Mo
def new(indy, rome = 1)
initialize(indy, rome)
end
def initialize(indy, rome = 1)
...
end
end
Mo.new(2)
Why?

Because Mo.new(2) calls the method Mo.new, which by default calls the method Mo#initialize with the single argument 2 that it received, but your Mo#initialize expects two arguments.

No need for new method, because initialize is "middleware" for allocating (creating) ruby object
class Mo
def initialize(indy, rome = 1)
#indy = indy
#rome = rome
end
end
i = Mo.new(2)
This means ruby does not enter in new method
You can check it by:
puts Mo.method(:new).source_location
# => nil
but you are able to override self.new in you Mo class
def self.new(indy, rome = 1)
end
then
p Mo.method(:new).source_location
# =>["mo.rb", 2]
And it does not enter in initialize method then
P.S.
It's not good practice, but if you want to execute you code, you should call
Mo.new(2).new(3)
because your new is Mo instance method

When you write a code like
Class Foo
def new
...
end
end
You define an instance method for the object with class Foo. But when you create a new instance, you call a class' method new. If you want to rewrite method Foo.new, you should write like:
Class Foo
def self.new
....
end
end
But actually it is a bad idea to declare your own method new for classes

Related

Can we call normal constructor and paramatrised constructor at a time in Ruby?

I tried like this. The file name of ClassA is instanceAndClassMethods
class ClassA
def initialize #constructor
puts "This is my constructor"
end
def initialize(a,b)
c=a-b
puts c
end
end
From other class I called above class as both are in same folder like:
require './instanceAndClassMethods' #filename should not contain spaces
obj = ClassA.new #constructor are automatically called when object is created
obj=ClassA.new(33,33)
When I run from command prompt, I'm getting:
Traceback (most recent call last):
2: from callMeth.rb:4:in `<main>'
1: from callMeth.rb:4:in `new'
C:/Users/vkuma102/Desktop/Ruby Learning/instanceAndClassMethods.rb:7:in `initial
ize': wrong number of arguments (given 0, expected 2) (ArgumentError)
If this is the case then it is difficult right whereas we can call both normal constructor and constructor with parameters in Java
No, Ruby does not have method overloading. Unlike e.g. Java or Crystal, you only get one method of the same name per class. Your second def is overwriting the first. It's like writing foo = 7; foo = 19 - the value 7 is not accessible any more from foo.
If you want to distinguish different argument lists, you need to do it yourself. Fortunately, unlike Java, Ruby has optional parameters (i.e. parameters with default values):
class ClassA
def initialize(a=nil, b=nil)
if a && b
c = a - b
puts c
else
puts "This is my constructor"
end
end
end
In addition to the overloading solution, which Amadan suggested, you can also provide factory methods to complement your constructor, for example:
class Foo
def initialize(_a = nil, _b = nil, _c = _nil)
#a, #b, #c = _a, _b, _c
end
# factories
def self.make_fancy_foo(x,y,z)
new(bar(x),y+1,baz(z-y))
end
def self.make_special_foo(x)
new(x,x,x)
end
end
This is how you can use them:
foo1 = Foo.new
foo2 = Foo.new(88)
foo3 = Foo.new(3,6,9)
foo4 = Foo.make_fancy_foo(7,-1,5)
foo5 = Foo.make_special_foo(6)
You're overwriting the first constructor, you can only have one method per name in ruby, to achieve the behavior you want you can do something like:
class ClassA
def initialize(a=nil, b=nil)
a && b ? puts(a+b) : puts "This is my constructor"
end
end
Or:
class ClassA
def initialize(*args)
arg.any? ? deal_with_params : puts "This is my constructor"
end
end

save instances in global variable

I need to save all instances of an object in a global variable, so I can access that instances from another object. There is no need to pass them like parameteres.
In my solution I have a mixin with a method that puts the instance in a variable, also I used an open class technique to include that mixin in Object, so other objects use that method (and not only ONE class).
class Object
include Favourite
end
module Favourite
def favourite_it
#if the variable its not initialized:
#favourites.class == Array.class ? #favourites.push(self) :
#favourites = [].push(self)
end
def get_favourites
#favourites
end
end
#this class is only an example
class Dog
def initialize age
#age = age
end
end
class Dog_T
#all instances of this class will be saved in the variable
def initialize age
#age = age
favourite_it
end
end
class Handler
def do_something
#here I need to access the variable with all the instances of favourites to do something to them
end
end
And here is a simple test
handler = Handler.new
d1 = Dog_T.new(10)
d2 = Dog_T.new(12)
all_f = Handler.get_favourites
expect(all_f[0].age).to eq 10
expect(all_f[1].age).to eq 12
d3 = Dog_T.new(15)
all_f = Handler.get_favourites
expect(all_f[3].age).to eq 15
I tried to do this, but only each instance save itself in a different list (it makes sense because I'm not using global variables yet).
How can I do to have only one list, add the instances when are created and have the ability to empty and manipulate that list from Handler?
Ruby supports using a class variable in a Module. You also need a reader method for the Dog_T object to be able to access the instance variable. Since Favourite doesn't know anything about the object, you will want to use respond_to? to guard against calling an non-existent method in the list. For example, if there were a Dog_R class that did not have a method age but did add itself, you would get a runtime error blindly calling the age method on members of the Favourite array.
module Favourite
##favourites = [] # you can use a class variable in module
def self.favourite_it(obj) # singleton method of the class
##favourites.push(obj)
end
def self.get_favourites # singleton method of the class, see below for usage example
##favourites
end
end
class Object
include Favourite
end
class Dog
def initialize age
#age = age
end
end
class Dog_T
attr_reader :age # you need a reader to able to access it
def initialize age
#age = age
Favourite.favourite_it(self)
end
end
d1 = Dog_T.new(10)
d2 = Dog_T.new(12)
all_f = Favourite.get_favourites
all_f.each do |obj|
puts "#{obj.class}: #{obj.age if obj.respond_to?(:age)}"
end
puts '-' * 20
d3 = Dog_T.new(15)
all_f = Favourite.get_favourites
all_f.each do |obj|
puts "#{obj.class}: #{obj.age if obj.respond_to?(:age)}"
end
The output of this program is:
Dog_T: 10
Dog_T: 12
--------------------
Dog_T: 10
Dog_T: 12
Dog_T: 15

Ruby Instance Methods and Variables

There is something that i don't understand about ruby class instance variable or methods**.
So i have this code that keeps on giving me this error and i cant understand
Looks ruby thinks that i am trying to call for Float.in_celsius but I want to make this call within my class instance.
#-----------------------------------
def ftoc(fr)
fr = fr.to_f
if (fr == 32)
c = 0
elsif (fr == 212)
c = 100
else
c = (fr-32.0)*(5.0/9.0)
end
return c
end
def ctof (cl)
cl = cl.to_f
f = (cl*(9.0/5.0))+32.0
return f
end
#-----------------------------------
class Temperature
attr_accessor :in_celsius, :in_fahrenheit
#class metods
def self.from_celsius(cel)
puts "from celsious\n"
puts "cel: #{cel}\n"
#in_fahrenheit = cel
#in_celsius = ctof(cel)
puts "==============================\n"
return #in_celsius
end
def self.in_celsius
#in_celsius
end
end
puts "==============================\n"
puts Temperature.from_celsius(50).in_celsius
puts Temperature.from_celsius(50).in_fahrenheit
and Error is
test.rb:54: in '<main>' : undefined method 'in_celsius' for 122.0:float (noMethod Error)
enter code here
You have a fundamental misunderstanding of how classes work in Ruby. Right now all of your variables and methods are defined at class level. That means that everything you do in the methods is acting directly on the class itself. Instead, you should create instances of Temperature.
class Temperature
# special method called when creating a new instance
def initialize celsius
#in_celsius = celsius
#in_fahrenheit = celsius * 9 / 5.0 + 32
end
def self.from_celsius celsius
new celsius # built in method to create an instance, passes argument to initialize
end
# we defined initialize using celsius, so here we must convert
def self.from_fahrenheit fahrenheit
new((fahrenheit - 32) * 5 / 9.0)
end
private_class_method :new # people must use from_celsius or from_fahrenheit
# make instance variables readable outside the class
attr_accessor :in_celsius, :in_fahrenheit
end
Temperature.from_celsius(50).in_celsius
This code isn't perfect (from_fahrenheit does a redundant conversion) but it should give you the idea of how to redesign your class.
from_celsius is returning a float which doesn't have an in_celsius method. You need it to return an instance of Temperature which would have that method.
Got to say your intent is a tad confusing, unless you have some other uses for the class Temperature, so it's bit hard to say which way you should go.
Let's see the code puts Temperature.from_celsius(50).in_celsius in details:
Call to singleton method ::from_celsius of Temperature class. That is ok (with some stranges), and t returns as instance of Float class because of result of #ctof method.
Call to instance method #in_celsius of object, which is returned from the previous method. Since it was the Float, the ruby interpreter searches for its instance method #in_celsius, hasn't find it out, and throws the NoMethodError exception.
How to fix.
Since you treat ::from_celsius as a constructor of Temperature class, I believe, that you shell to pass the floating value into the new method, and return created object. You will have class code as follows:
def initialize( value )
#in_fahrenheit = cel
#in_celsius = ctof(cel)
end
def self.from_celsius(cel)
puts "from celsious\n"
puts "cel: #{cel}\n"
temp = Temperature.new( cel )
puts "==============================\n"
return temp
end

Local variable output is not being shown

I am trying to run a simple program:
class Pras
def samleMethod
a = 12
p "a"
end
end
There are no errors, but why is not output being shown?
Edit
class Pras
def samleMethod
a = 12
p a
end
end
class Pras
def samleMethod
a = 12
p a
end
end
In this you are creating a class named Pras with public method named sampleMethod.
I assume you have some knowledge with OOP
so when ever you are accessing a a method you need to create an instance of class to access it.
p = Pras.new
Now you can access the method using the instance
p.sampleMethod
or both in one line as
Pras.new.sampleMethod
I would suggest you to have a through look at this tuts. http://www.tutorialspoint.com/ruby/ruby_quick_guide.htm
methods will not be executed unless they are called.
Try this code online here
You are printing the string 'a' rather than the variable. Use this instead: p a
Edit:
As Rostyslav mentioned, you are not executing anything: Try Pras.new.samleMethod
Works perfectly for me:
Here we define class:
irb(main):014:0> class Pras
irb(main):015:1> def samleMethod
irb(main):016:2> a = 12
irb(main):017:2> p a
irb(main):018:2> end
irb(main):019:1> end
=> nil
Here's how to create and instance object of that class and call instance method with actually do printing:
irb(main):020:0> Pras.new.samleMethod
12
=> 12

What is the difference between def func(var) and def func=(var)?

In a class definition, what is the difference between these two methods?
def func(var)
...
end
def func=(var)
...
end
Is there any, or is one of them not valid?
Both of them are valid method definitions. But the second one is defining a 'setter' method - you can call this method with the following syntax:
obj.func = 123
This statement will be translated into
obj.func=(123)
You can take a look at this answer where I explain this syntax in a bit more detail.
To explain some things about reader/writer AKA getter/setter methods in Ruby:
Ruby doesn't force us to use = in the method definition for a setter. We get to choose whether the method has one.
Consider this:
class Foo
# automagically creates:
# .v
# .v=
attr_accessor :v
def initialize(v)
puts "inside initialize(#{ v })"
#v = v
end
def setter(v)
puts "inside setter(#{ v })"
#v = v
end
def setter=(v)
puts "inside setter=(#{ v })"
#v = v
end
end
f = Foo.new(1)
puts f.v
f.setter(2)
puts f.v
f.setter = 3
puts f.v
f.setter=(4)
puts f.v
f.v = 5
puts f.v
f.v=(6)
puts f.v
Running the code outputs:
inside initialize(1)
1
inside setter(2)
2
inside setter=(3)
3
inside setter=(4)
4
5
6
The = is simply another letter in the method name because Ruby is smart enough to know if it sees f.setter = 3 it should use the setter=(v) method.
Ruby doesn't force using = to set a variable, you can decide if it makes more sense to you when you define the method. It is idiomatic that we use = because it helps make a setter look like an assignment, removing the urge to name all the setters something like set_v(v).
These are defining the getter and setter methods if you will. Say you have a Person class with a phone attribute.
class Person
def phone
#phone
end
def phone=(number)
#phone = number
end
end
Now you could change the phone attribute (managed internally in the #phone) by simply setting the property which will invoke the phone= method.
john = Person.new
john.phone = "123-456-7890"
It looks like a property assignment on the outside. Other characters that you can stack at the end of a method name are ? for boolean getters, ! for destructive operations. Again, these are just conventions and you're free to use these three characters as you want. However, code simply looks more natural with these symbols around. For example,
question.closed?
document.destroy!

Resources