When I tried fixnum.new is giving undefined method error.
Fixnum.new # undefined method `new' for Fixnum:Class (NoMethodError)
Why its give undefined method. What mechanism behind the fixnum class. please explain.
If I want to make some class like fixnum (A class without new method) then what should I do?
I am going with below code but I am feeling its bad code.
class TestClass < Fixnum
end
When I tried to create new object like below:
TestClass.new #undefined method `new' for TestClass:Class
is this correct way? or if you have another way please explain here.
As I explained in this answer, Fixnum doesn't provide a .new method. That's because you expect to create a new Fixnum (or a descendant such as Integer or Float) in the following way
1.3
1
and because, despite they are objects, there are no multiple instances of a Fixnum. In the same answer I also explained how you can use a proxy class around objects that doesn't offer such initialization.
Here's a code example
class MyFixnum < BasicObject
def initialize(value)
#fixnum = value
end
def inc
#fixnum + 1
end
def method_missing(name, *args, &block)
#fixnum.send(name, *args, &block)
end
end
m = MyFixnum.new(1.3)
m.to_i
# => 1
If I got your question right, you are trying to write a class that is not instantiatable using the new method. You could borrow the idea from the Singleton module and make the new (and allocate) method private:
class Whatever
private_class_method :new, :allocate
end
Whatever.new
# NoMethodError: private method `new' called for Whatever:Class
Because there are Fixnum objects for every (and only) integer value. No other objects should be created. Therefore inheriting from Fixnum is, probably, not a good idea.
You may want to use composition instead:
class TestClass
attr_reader :num # fixnum
end
Related
so I have the following anonymous class definition:
let!(:fake_class) do
Class.new(Integer) do
def initialize(value)
#value = value
end
def ==(other)
#value == other
end
def coerce(other)
[#value, other]
end
def to_s
#value.to_s
end
end
end
But when I do:
fake_class.new 4
I just get undefined method 'new' for #<Class:0x00007fc065377c88>
I've tried doing
define_method :initialize do |value|
#value = value
end
no difference
the only way it responds to new is if I do
class << self
def new(value)
#value = value
end
end
but that obviously won' work as I need it to act like a real class.
Why do I see lots of tutorials using intialize and it working as expected yet it doesn't seem to work for me? Is it becuase i'm defining it in rspec or somthing?
The issue here is nothing to do with rspec, nor anonymous classes.
The problem is that in ruby, you cannot subclass Integer*.
Ruby stores small Integers (formerly known as Fixnums) as immediate values, using some of the low bits of the word to tag it as such, instead of a pointer to an object on the heap. Because of that, you can't add methods to a single "instance" of Integer, and you can't subclass it.
If you really want an "Integer-like" class, you could construct a workaround with a class that has an integer instance variable, and forward method calls appropriately:
class FakeInteger
def initialize(integer)
#integer = integer
end
def method_missing(name, *args, &blk)
ret = #integer.send(name, *args, &blk)
ret.is_a?(Numeric) ? FakeInteger.new(ret) : ret
end
end
* Technically you can, but since you cannot instantiate any objects from it, it's pretty useless :)
Your code is correct but Integer does not respond to .new and so your child class will also not respond to .new.
irb(main):001:0> Integer.new
NoMethodError (undefined method `new' for Integer:Class)
When you call Integer(123) you actually call a global function defined here:
https://github.com/ruby/ruby/blob/v2_5_1/object.c#L3987
https://github.com/ruby/ruby/blob/v2_5_1/object.c#L3178
I have searched around for the answer to this and I can see a lot of similar problems but I still do not understand what I am doing wrong here. I have declared a Ruby class and attempted to new it and then call some instance methods on the instance, so why do I get the NoMethodError on my start method?
class MyClass
def initialize
self.class.reset
end
def self.reset
...
end
def self.start(port)
...
end
end
test = MyClass.new
test.start '8082' <- here <- undefined method `start' for #<MyClass:0x2f494b0> (NoMethodError)
As you can see I am a Ruby noob. Any help would be appreciated. I can change my class structure but I would really like to understand what I am doing wrong here.
here start is a class method.
By your current approach, you can use it in the following way
MyClass.start '8080'
But if you want to use it on instance of class then use the following code
class MyClass
def initialize
self.class.reset
end
def self.reset
...
end
def start(port)
...
end
end
test = MyClass.new
test.start '8080'
You are using start as a Class variable, the method names preceded with self-keyword make those methods as Class methods. So if you really want to not change your class then you should call it like this:
MyClass.start '8080'
Else you can remove the self from your reset and start methods and make them as Instance methods and use them as:
test = MyClass.new
test.start '8082'
Imagine I want to write my own math operators like "+"
The simple version would be:
def plus(a,b)
return a+b
end
But this is not what the real "+" does.
I want 3.add(4) # =>7
But how do I tell ruby to take the object that I used my method on?
I tried
def add(c)
return self+c
end
But I get the error message:
:in <main>': private methodadd' called for 3:Fixnum (NoMethodError)
The problem
You defined the method:
def add(c)
return self + c
end
and attempted to use it thus:
3.add(4) #=> NoMethodError: private method `add' called for 3:Fixnum
Understanding this error message
This error message tells you exactly what the problem is. I think your problem is simply that you don't understand how Ruby invokes methods on objects.
When Ruby sees 3.add(4) it first looks at the receiver, 3, and determines:
3.class #=> Fixnum
This tells it where the method add is defined: in the class Fixnum or in one of Fixnum's ancestor's classes or modules.
So it looks for it there, doesn't find it, and issues an error message. We can confirm it's not there:
Fixnum.instance_methods.include?(:add)
#=> false
So where is add defined?
You did define it, though, so where is it? Let's find out:
method(:add).owner
#=> Object
Object.instance_methods.include?(:add)
#=> false
Object.instance_methods returns an array of all of public instance methods defined on Object and Object's ancestors. add is not among those, so we conclude add is a protected or private method:
Object.protected_instance_methods.include?(:add)
#=> false
Object.private_instance_methods.include?(:add)
#=> true
Let's try invoking that method on an instance of Object:
Object.new.add(4)
#=> NoMethodError:
# private method `add' called for #<Object:0x007fdb6a27fa68>
That makes sense, considering that Object#add is private. We can, however invoke private methods with Object#send:
Object.new.send(:add,4)
#NoMethodError: undefined method `+' for #<Object:0x007fdb6a28e068>
As an exercise, make sure you understand the steps Ruby took that led to her raising this exception (that the instance method + is not defined on Object, or equivalently, that the instance of Object does not have a method +).
By the way, where did you define add? By that, I mean what what was the value of self when you defined it? Let's see:
self #=> main
self.class #=> Object
We see that add must be defined on the class for which its receiver is an instance. (A mouthful, yes, but it's important, so make sure you understand that).
Why is Object#add private rather than public?
Consider:
def greet
puts 'hi'
end
class A
end
A.private_instance_methods.include?(:add)
#=> true
A.new.send(:greet)
#=> 'hi'
The is because A inherits greet from Object:
A.ancestors.include?(Object) #=> true
If Object#greet were public, every built-in class and every class you define would have a public instance method greet. That would result in a great deal of misery. (Suppose you had a method great and mistyped it greet!) Even the private greet could cause trouble.)
Where should add be defined?
Since add.class => Fixnum, we define it thus:
class Fixnum
def add(other)
self + other
end
end
Fixnum.instance_methods.include?(:add) #=> true
3.add(4) #=> 7
Had I included the line puts "self#{self}" after class Fixnum it would have printed "Fixnum". Salting your code with puts statements that show the value of self often helps in understanding what's going on.
One last thing:
method(:add).owner
#=> NameError: undefined method `add' for class `Object'
Why did this not return Fixnum? Since method has no explicit receiver (i.e., no xx.method), Ruby assumes the receiver to be self, which here is:
self #=> main
so she looks for the method method in self.class => Object, and you know what she finds (or, I should say, doesn't find). Instead, we need to write:
Fixnum.instance_method(:add).owner #=> Fixnum
or
3.method(:add).owner #=> Fixnum
Here 3 can of course be replaced by any instance of Fixnum.
Note I've simplified this explanation somewhat. In searching for a method, Ruby also looks in the receiver's singleton class. This is not an issue for immediate objects (numbers, symbols, true, false and nil), however, as they do not have singleton classes:
3.singleton_class #=> TypeError: can't define singleton
By contrast, for example:
[1,2].singleton_class #=> #<Class:#<Array:0x007fbcf18c01a8>>
The plus-sign (+) in ruby can be overridden pretty much like any other method (you can look for operator-overloading):
class MyOperator
attr_accessor :text
def initialize(text)
#text = text
end
def +(operand)
"#{self.text} #{operand.text}"
end
def to_s
self.text
end
end
a = MyOperator.new "Hello"
b = MyOperator.new "World"
puts (a+b)
So there is not much magic to it. But you have to be careful if the overloading the operators make sense in your context.
I have this Ruby code where I try to implement the Singleton pattern manually:
class A
#a = A.new
def self.instance
p 'initialized'
#a
end
private_class_method :new
end
A.instance #=> prints 'initialized'
Unfortunately, the object will be created before A.instance is even called. To avoid this, I thought of changing the code:
class A
#a = nil
def self.instance
p 'initialized'
#a ||= A.new
end
private_class_method :new
end
A.instance
I get "private method `new' called for A:Class (NoMethodError)" error though. This is very puzzling, why do I get this error in the second example and not in the first? The only difference is that in the second example .new is called in a class method definition. I deliberately put private_class_method on the bottom so this kind of error is prevented (putting it on the top will give the error for both examples). Btw, I'm aware this will work if I change #a from being a class instance variable to a class variable (to start with ##). I don't understand why this would work, since I know instance variables are relative to SELF and SELF is the class, both where I initialize #a to nil and where I lazy instantiate it in self.instance.
Here is a strange thing.
A.new doesn't work because you should call private method only directly, so you should use explicit new call.
In the other hand new call is something like implicit self.new but self.new will raise an exception like A.new. And this is the strange part I don't understand
class A
def self.instance
p 'initialized'
# ok
new
# should be ok but it is not
self.new rescue p("error self.new: #{$!}")
# should fail
A.new rescue p("error A.new: #{$!}")
end
private_class_method :new
end
A.instance
# "initialized"
# "error self.new: private method `new' called for A:Class"
# "error A.new: private method `new' called for A:Class"
PS: http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby
You can't use explicit receiver with private methods
SO: Understanding private methods in Ruby
I can easily inherit from, say, String for example, like this:
class MyString < String
def stuff
self + ' and stuff'
end
end
# This works:
MyString.new('things').stuff # => 'things and stuff'
But how can I inherit from Rational, which has no constructor? For example:
def MyRat < Rational
def inc
self + 1
end
end
# I have tried to initialize like this:
MyRat.new(10).inc # => NoMethodError: undefined method `new' for MyRat:Class
MyRat(10).inc # => NoMethodError: undefined method `MyRat' for main:Object
MyRat.send(:initialize, 10).inc # => TypeError: already initialized class
# ???
# None of it works!
I can't find a way to initialize my new class.
You can define your own object to be a proxy around Rational.
class MyRat < BasicObject
def initialize(value)
#rational = Rational(value)
end
def inc
#rational + 1
end
def method_missing(name, *args, &block)
#rational.send(name, *args, &block)
end
end
Methods defined in your class will be used, otherwise the class will delegate to the rational instance.
r = MyRat.new(10)
# MyRat#inc is used
r.inc
# => (11/1)
# to_int delegates to Rational
r.to_int
# => 10
A partial explanation of because Numeric has no initialize is available in this thread
Looking at the C code, I see that new() exists in Numeric and Float,
but it is specifically removed:
rb_cInteger = rb_define_class("Integer", rb_cNumeric);
rb_undef_alloc_func(rb_cInteger);
rb_undef_method(CLASS_OF(rb_cInteger), "new");
#....and for floats..
rb_undef_alloc_func(rb_cFloat);
rb_undef_method(CLASS_OF(rb_cFloat), "new");
The ruby source code contains no explanation for the removal of new.
That's why I'm wondering what the reasoning behind this was. It does
not seem to be technical limitation in the ruby interpreter.
Currently, it does not make much sense to me.
and the reason is because
It's an internal optimization. Fixnums do not have to be created and
they never have to be GC'ed. This goes a long way to make math faster
than it would be with ordinary objects (at least for Fixnums).
Additional suggestions and alternatives are explained in this article The Complete Numeric Class.