Constructor overriding - ruby

I have a class:
class One
def initialize; end
end
I need to create a new class with my own constructor like this:
class Two < One
def initialize(some)
puts some
super
end
end
Two.new("thing")
but when I launch the code, I got an error:
thing
test.rb:10:in `initialize': wrong number of arguments (1 for 0) (ArgumentError)

super in this case (without parentheses) is a special form. It calls the superclass method with the original params.
Instead try calling
super()

Related

How do extend FileClass in Ruby?

use ruby version is 2.0.0p648
I want extend File Class returns change "extend". But returned method returns is normal function.
Why returned normal function?
class File
alias_method :__open__, :open
def open()
'extend'
end
end
p File.open('test.txt')
#<File:test.txt>
class File
class << self
alias_method :__open__, :open
def open(*)
'extend'
end
end
end
File.open('test.txt') # => "extend"
File.__open__('test.txt') # => #<File:test.txt>
Explanation
File.open is a class method, yet you are aliasing and redefining at the instance scope. To alias a class method, you will need to do so on the singleton class. You can do this with the syntax class << self; end. To oversimplify things, accessing the singleton class essentially lets you use instance level syntax at the class scope, so you can also define class methods there without preceding the method name with self. e.g. self.open
Once you're redefining File.open you'll want to respect the API of the original method as pertains to arguments. If your overriding method doesn't use any arguments as in your example, then you can give a splat * operator as the single parameter. This means that the method can take 0 or more arguments without throwing an error, but they won't be used in the method body. Otherwise, if you define the method with the signature def open() (or the equivalent and stylistically preferred def open) then you'll get an ArgumentError when you call Foo.open('test.txt') because you're passing more arguments than the method expects.
class File
class << self
alias_method :__open__, :open
def open
'extend'
end
end
end
File.open('test.txt') # => ArgumentError: wrong number of arguments (given 1, expected 0)

Why the ruby code will generate an ArgumentError?

Hi I'm working on Ruby Koans. I was wondering why the ArgumentErrorwould be raised if the Dog6.new is returned in the code down below?
class Dog6
attr_reader :name
def initialize(initial_name)
#name = initial_name
end
end
def test_initialize_provides_initial_values_for_instance_variables
fido = Dog6.new("Fido")
assert_equal "Fido", fido.name
end
def test_args_to_new_must_match_initialize
assert_raise(ArgumentError) do
Dog6.new
end
end
Is it because Dog6.newdoesn't have any arguments? Thank you!!
Yes, your assumption is correct.
Dog6.new implicitly calls Dog6#initialize to initialize the newly created instance (one might think about MyClass#initialize as about the constructor for this class,) which apparently has one required argument. Since no argument was given to the call to Dog6.new, the ArgumentError is being raised.
Just adding that if you want to have a constructor with no arguments (after all - some dogs don't have a name....) you could have a default value for the name parameter.
def initialize(name = nil)
#name = name
end
In the initializer for the Dog6 class, initial_name is defined as a parameter required for object construction. If this class were to be instantiated without this argument, an ArgumentError would be raised because the class definition has a method signature such that Dog6.new is invalid, like you guessed. In this case the error you would see would be:
ArgumentError: wrong number of arguments (0 for 1)
Read more about the ArgumentError exception here.

Defining a method in Rubymine returns "undefined method" error

I am executing a class with only this code in rubymine:
def saythis(x)
puts x
end
saythis('words')
It returns an error: undefined method `saythis', rather than printing the string 'words'. What am I missing here? Replicating this code in irb prints the string 'words'.
I assume you wrote a class like the one below and did not write that code into a irb console. The problem is that you define an instance method, but try to call the method from the class level.
class Foo
def say_this(x) # <= defines an instance method
puts x
end
say_this('words') # <= calls a class method
end
There a two ways to "fix" this:
Define a class method instead of an instance method: def self.say_this(x)
Call the instance method instead of the class method call: new.say_this(x)

Ruby class override without inheritance

I've just made this experiment:
class A < Hash
def foo
'foo'
end
end
class A < Hash
def bar
'bar'
end
end
So far I get the result I expected, the second declaration extends the first one. However I was surprised of this:
class A
def call
puts foo
puts bar
end
end
The code above works, but only if I declare it later. Otherwise I get:
TypeError: superclass mismatch for class A
Can I assume that in Ruby, it is safe skipping the superclass specification without side effects after making sure that the "original-first" declaration was parsed?
You are able to declare inheritance only on the first occurince of the class definition, so below variants will work:
When you've defined the same class inheritance:
class A < Hash
end
class A < Hash
end
When you've used default inheritance in the second case, that is treated as undefined inheritance:
class A < Hash
end
class A
end
When you've used default inheritance in both cases, the default inheritance is of Object class:
class A
end
class A
end
And below will not:
When you've used default inheritance in the first case, and next you tried to redefine it explicitly:
class A
end
class A < Hash
end
TypeError: superclass mismatch for class A
When you've used specified inheritance (in example String) in the first case, and next you tried to redefine it explicitly (in example with Hash):
class A < String
end
class A < Hash
end
TypeError: superclass mismatch for class A
#Малъ Скрылевъ explained this case a better way, so I wouldn't attempt that. But I would show you another way to do this.
One way to avoid the error is in your situation :
Instead of writing
class A
def call
puts foo
puts bar
end
end
Write it as below using Module#class_eval:
Evaluates the string or block in the context of mod, except that when a block is given, constant/class variable lookup is not affected. This can be used to add methods to a class. module_eval returns the result of evaluating its argument.
A.class_eval do
def _call
puts foo
puts bar
end
end

Why does this Ruby method need to be a class level method?

Here's a classic fizzbuzz in Ruby:
class PrimeChecker
def print_em
1.upto 100 do |fizzbuzz|
if (fizzbuzz % 2) == 0 && (fizzbuzz % 5) == 0
puts "fizzbuzz: " + fizzbuzz.to_s
elsif (fizzbuzz % 5) == 0
puts "fizz: "+fizzbuzz.to_s
elsif (fizzbuzz % 2) == 0
puts 'buzz: ' + fizzbuzz.to_s
else
puts "-" + fizzbuzz.to_s
end
end
end
end
PrimeChecker.print_em
When I execute this, I get this error:
undefined method 'print_em'.
I change the method to self.print_em and it works. Does this mean it's a class method (I think so)? Was the method "not found" before because I can only call such methods in a class on actual instances of the object? If I wanted it to be a instance method what is the syntax for that? I'm trying to understand Ruby, classes and methods better.
Class methods are just that: called on the class. Whereas instance methods are called on an instance of that class. An example is more useful:
class Foo
def self.bar
"This is a class method!"
end
def bar
"This is an instance method!"
end
end
Foo.bar # => "This is a class method!"
foo = Foo.new # This creates "foo" to be a new instance of Foo
foo.bar # => "This is an instance method!"
Note that "class methods" in Ruby are actually methods on the class object's singleton. This is a rather difficult concept to explain, and you can read more about it if you'd like.
It's not a class method as written; you need to run it with an instance of PrimeChecker:
pc = PrimeChecker.new
pc.print_em
Using self. turns it into a class method, runnable with the syntax you show.
It doesn't need to be a class method, it's just that that's how you're trying to execute it.
Q: When I run ruby.rb I get undefined method 'print_em'. I change the method to self.print_em and it works. Does this mean it's a class method (I think so).
A: Yes. class Bar; ... def self.foo defines a class method foo for class Bar.
Q: Was the method "not found" before because I can only call such methods in a class on actual instances of the object?
A: You were first defining it as an instance method. In that case, it is only available to instances of the class.
Q: If I wanted it to be a instance method what is the syntax for that?
A: The way you had it originally: class Bar; def foo defines instance method foo for class Bar
Yes, you are completely correct. Currently, the way you define it, you can evaluate the method with:
PrimeChecker.new.print_em
The reason def self.my_awesome_method defines it on the class side is because the stuff inside
class MyAwesomeClass
end
is being executed in the context of MyAwesomeClass. It's all Ruby code, as you can see! This enables you to do things like this:
class MyAwesomeClass
puts "Hello from innards of #{self}!" #=> Hello from the innards of MyAwesomeClass!
end
Method definitions will also only work if you call them after the definition location, for example:
class MyAwesomeClass
my_awesome_method # produces a nasty error
def self.my_awesome_method
puts "Hello world"
end
my_awesome_method # executes just fine
end
Hope this clears some things up.

Resources