Is initialize method (constructor) private or public in ruby?
Let's see:
class Test
def initialize; end
end
p Test.new.private_methods.sort.include?(:initialize)
This prints true, so initialize is a private method. This makes sense, it is only called by the new class method if the object is created. If we want, we can do something like this:
class Test
def initialize
#counter = 0
end
def reset!
initialize
end
end
Misusing the constructor like this could however lead to problems if it does more than simple variable initialization.
The initialize method in a class automatically becomes Private.
You can check it using:
puts ClassName.private_methods.sort
Related
I want a piece of code to run before any other static methods run, is it possible to do something in the spirit of the following?
class MyClass
def self.initialize
#stuff = 1
end
def self.print_stuff
puts #stuff
end
end
My Ruby version of interest is 2.3.
Every chunk of code in Ruby is an expression. Even a class definition is a series of expressions: method definitions are expressions that have the side-effect of adding the method to the class.
This is how meta-programming methods work. attr_reader is a private method call where the implicit self is the class. So, long story short, you aren't restricted inside a class body, you can put whatever code you want to run in the context of the class:
class MyClass
#stuff = 1
def self.print_stuff
puts #stuff
end
end
There's no such thing as an explicit metaclass initializer. The class itself is "initialized" as it's defined, so it's perfectly valid to do this:
class MyClass
# Code here will be executed as the class itself is defined.
#stuff = 1
def self.print_stuff
puts #stuff
end
end
MyClass.print_stuff
Remember that def itself is a form of method call and defining a class in Ruby involves sending a bunch of messages (method calls) around to the proper context objects, such as the class itself as it's being defined.
I was wondering how I could call a method in an instance of a class in another class.
This is what I came up with
class ClassA
def method
return "This is a method_from_class_A"
end
end
class ClassB
def initialize
#method_from_class_A=instance.method
end
def method_calls_method
#method_from_class_A
end
end
instance=ClassA.new
instance2=ClassB.new
puts instance2.method_calls_method
But I get this error:
Testing.rb:9:in initialize': undefined local variable or method
instance' for # (NameError) from
Testing.rb:19:in new' from Testing.rb:19:in'
How could I fix it?
Thank you for your response.
From your description this seems to be what you're going for:
class ClassB
def initialize
#instance_of_class_a = ClassA.new
end
def method_calls_method
#instance_of_class_a.method
end
end
Or to pass in the ClassA instance (this is called dependency injection):
class ClassB
def initialize(class_a_instance)
#instance_of_class_a = class_a_instance
end
def method_calls_method
#instance_of_class_a.method
end
end
instance_a = ClassA.new
instance_b = ClassB.new(instance_a)
puts instance_b.method_calls_method
Another Option would be to take a look at class methods: https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/113-class-variables
So in your code it would look similar to this:
class ClassA
def self.method
return "This is a method_from_class_A"
end
end
class ClassB
def method_calls_method
ClassA.method
end
end
instance=ClassB.new
puts instance.method_calls_method
*Notice the self. in ClassA to signify a class method. This is similar to a static method in other languages.
According to wikipedia: https://en.wikipedia.org/wiki/Method_(computer_programming)#Static_methods
Class(static) methods are meant to be relevant to all the instances of a class rather than to any specific instance.
You see class methods used a lot in the ruby Math class:
http://ruby-doc.org/core-2.2.2/Math.html
For example taking a square root of a number in is done by using the class method Math.sqrt. This is different from an instance method which would look like object.method instead Class.method. There are a lot of resources and tutorials out that explains this concept in more detail and probably clearer.
Consider the following example in Ruby:
class ParentClass
private def method
puts "private method"
end
end
class ChildClass < ParentClass
def method
puts "overridden, but should be private too"
end
end
ParentClass.new.method #=> raises exception
ChildClass.new.method #=> produces "overridden, but should be private too"
If I have no control over the code of ChildClass, is it possible to make it inherit method visibility from ParentClass?
Your question has nothing to do with inheritance. What is relevant here is the timing of the class method private. See the simplified example below. When called, this method turns the relavant method existing at that point into a private method.
class A
def foo; "foo1" end
private :foo
new.foo # => NoMethodError: private method `foo' called for #<A:0x007f321204fec0>
end
When you alter the method after private has applied, then a new method is defined with the same name, and the effect of private that applied to the previous definition is gone.
class A
def foo; "foo2" end
new.foo # => "foo2"
end
When you call private again on it, then it becomes private:
class A
private :foo
new.foo # => NoMethodError: private method `foo' called for #<A:0x007f3211ff6de8>
end
To illustrate this using your original example...
class ChildClass
private :method
end
... can be done after the initial definition of ChildClass and will make the method method private.
To summarize, visibility is a property of a (defined) method, not a property of a method name. So you cannot redefine a method but have the private status of a previous method with the same name but you can change the private status of the current method.
All objects, first prefer to their own defined methods, even if their parent classes has also the same named method. But if you really want in some ocaasion, to call the parent class method, then you can take a help from #class_eval for the same :
class ParentClass
private
def biz
puts "private method"
end
end
class ChildClass < ParentClass
def biz
puts "overridden, but should be private too"
end
end
ChildClass.class_eval do
remove_method :biz
self.new.biz
end
# private method `biz' called for #<ChildClass:0x8c3532c> (NoMethodError)
Now, see ChildClass object is calling the private method from the ParentClass. Now to make the call successful, you need to use #send.
ChildClass.class_eval do
remove_method :biz
self.new.send :biz # => private method
end
Another way, I used in most cases is :-
unbind = ParentClass.instance_method(:biz)
unbind.bind(ChildClass.new).call # => private method
Really, when you do inherit or mixin, whatever methods are not physically don't come in to the child or mixed in class respectively. They(parent class or mixed in module) are actually added to the method lookup chain of the class ChildClass.
The following code works:
class MyClass
def method_a
method_b
end
private
def method_b
puts "Hello!"
end
end
m = MyClass.new
m.method_a
Changing the call to method_b to self.method_b however does not work:
def method_a
self.method_b
end
I get a NoMethodError. I'm under the impression that self just resolves to the instance of the class when inside an instance method. Why does self.method_b cause problems?
Note: self.method_b works when private is changed to protected.
Note: if the above methods are changed to class methods then calling self.method_b from method_a doesn't throw the NoMethodError.
This is how private methods work in Ruby. They cannot be called with an explicit receiver (unless it is a setter method; see below).
Read more in the section on Access Control from the Pickaxe.
Private methods whose names end with an = may be invoked using self.method_name = ... as this is necessary to differentiate them from setting a local variable:
class Foo
def try
set_foo(1) # Invokes private method
self.set_foo(2) # ERROR: private method `set_foo' called for ...
self.send(:set_foo,3) # Invokes private method
bar = 1 # Sets local variable
self.bar = 2 # Invokes private method
self.send(:bar=,3) # Invokes private method
end
private
def set_foo(v)
#foo = v
end
def bar=(v)
#bar = v
end
end
Foo.new.bar = 42 # ERROR: private method `bar=' called for ...
That's just how Ruby works: when you provide an explicit object reference, NoMethodError is raised to show the code is breaking intent. You could do a self.send and it would work.
Without the explicit reference, Ruby doesn't do the same visibility check; see this and/or this for a bit more detail.
Nutshell is that private methods can't be called with an explicit receiver, even if it's self.
I want a method to be executed every 5 minutes, I implemented whenever for ruby (cron). But it does not work. I think my method is not accessible.
The method I want to execute is located in a class. I think I have to make that method static so I can access it with MyClass.MyMethod. But I can not find the right syntax or maybe I am looking in the wrong place.
Schedule.rb
every 5.minutes do
runner "Ping.checkPings"
end
Ping.rb
def checkPings
gate = Net::Ping::External.new("10.10.1.1")
#monitor_ping = Ping.new()
if gate.ping?
MonitorPing.WAN = true
else
MonitorPing.WAN = false
end
#monitor_ping.save
end
To declare a static method, write ...
def self.checkPings
# A static method
end
... or ...
class Myclass extend self
def checkPings
# Its static method
end
end
You can use static methods in Ruby like this:
class MyModel
def self.do_something
puts "this is a static method"
end
end
MyModel.do_something # => "this is a static method"
MyModel::do_something # => "this is a static method"
Also notice that you're using a wrong naming convention for your method. It should be check_pings instead, but this does not affect if your code works or not, it's just the ruby-style.
Change your code from
class MyModel
def checkPings
end
end
to
class MyModel
def self.checkPings
end
end
Note there is self added to the method name.
def checkPings is an instance method for the class MyModel whereas def self.checkPings is a class method.
Instead of extending self for the whole class, you can create a block that extends from self and define your static methods inside.
you would do something like this :
class << self
#define static methods here
end
So in your example, you would do something like this :
class Ping
class << self
def checkPings
#do you ping code here
# checkPings is a static method
end
end
end
and you can call it as follows : Ping.checkPings
There are some ways to declare a static method in RoR.
#1
class YourClassName
class << self
def your_static_method (params)
# Your code here
end
end
end
#2
class YourClassName
def self.your_status_method
// Your code here
end
end
You cannot have static methods in Ruby. In Ruby, all methods are dynamic. There is only one kind of method in Ruby: dynamic instance methods.
Really, the term static method is a misnomer anyway. A static method is a method which is not associated with any object and which is not dispatched dynamically (hence "static"), but those two are pretty much the definition of what it means to be a "method". We already have a perfectly good name for this construct: a procedure.