I have the following Ruby namespace problem:
I have a number of top-level methods in a "library", among these I have a get_name(param) method.
The problem is that I want to use this get_name(param) method inside a class that has its own get_name() method (without param!).
Of course this results in a problem as the 2 methods are different and the new one in the class overrides the top-level one.
Is there a way to do something like this:
def get_name(param)
puts param
end
class Foo
def get_name()
puts "name"
end
def bar()
self.get_name() #should work and print name, i.e. it uses the get_name method of Foo
get_name("abc") #should work and print abc, i.e. it uses the top-level method
end
end
I would like to know if there is an easy way to achieve this without having to alter the name or scope of the top-level methods. (The goal is to have those available without modification as global methods, but still be able to call instance methods of Foo without errors.
If the library methods are really top-level methods and are not part of any class or module, then, they will get defined as private methods of Object class.
You can do following to invoke it:
def bar()
self.get_name()
Object.send(:get_name, "abc") # Will print "abc" to console
end
The so called "top level method" is only a method of main object, which is only an Object. If you want that method to be able to be called (almost) anywhere, you should make it a kernel method.
module Kernel
def get_name(param)
puts param
end
end
Note that Kernel is almost at the tail of any classes ancestors chain (before BasicObject), which means almost all the objects are a Kernel. So in your Foo class, you can override it like this:
class Foo
def get_name(*args)
return super if args.any?
puts 'name'
end
end
Edit
If you can't make those top level methods kernel methods, you can store the main object in a constant or a global variable, and call those top level methods on it.
$main = self
class Foo
def get_name(*args)
return $main.send(:get_name, *args) if args.any?
puts 'name'
end
end
First off: there is no such thing as a "top-level method". There is exactly one kind of method in Ruby: instance methods.
The method you are referring to is a private instance method of Object. Since Object is a superclass of almost any other class (excluding Object and its superclasses), if you are sure that there are no other methods with the same name somewhere else in the inheritance hierarchy, you could use Method#super_method to get access to the method and then call it:
def get_name(param)
puts param
end
class Foo
def get_name
puts 'name'
end
def bar
get_name #should work and print name, i.e. it uses the get_name method of Foo
method(:get_name).super_method.('abc') #should work and print abc, i.e. it uses the top-level method
end
end
Foo.new.bar
# name
# abc
Alternatively, if you don't know whether there are any other methods by the same name within the inheritance hierarchy, you could grab a reference to the UnboundMethod directly from Object and then bind and call it:
class Foo
def bar
get_name #should work and print name, i.e. it uses the get_name method of Foo
Object.instance_method(:get_name).bind(self).('abc') #should work and print abc, i.e. it uses the top-level method
end
end
Foo.new.bar
# name
# abc
Related
From what I understand about self, it refers to the current instance of the class.
Isn't this the default behaviour at all times anyways? For example, isn't
self.var_one = method(args)
equivalent to
var_one = method(args)
If so, what is the use of self?
There are several important uses, most of which are basically to disambiguate between instance methods, class methods, and variables.
First, this is the best way to define class methods:
class Foo
def self.bar
"class method bar"
end
def bar
"instance method bar"
end
end
Foo.bar #returns "class method bar"
foo = Foo.new
foo.bar #returns "instance method bar"
Also, within instance methods self refers to the instance, within class methods it refers to the class, and it can always be used to distinguish from local variables.
class Bar
def self.foo
"foo!"
end
def baz
"baz!"
end
def self.success
foo #looks for variable foo, doesn't find one, looks for class method foo, finds it, returns "foo!"
end
def self.fail
baz #looks for variable baz, doesn't find one, looks for class method baz, doesn't find one, raises exception
end
def instance_success
baz #looks for variable baz, doesn't find one, looks for instance method baz, finds it, returns "baz!"
end
def instance_fail
foo #looks for variable foo, doesn't find one, looks for instance method foo, doesn't find one, raises exception
end
def local_variable
baz = "is my favorite method"
baz #looks for variable baz, finds it, returns "is my favorite method"
end
def disambiguate
baz = " is my favorite method"
self.baz + baz #looks for instance method baz, finds it, looks for local variable baz, finds it, returns "baz! is my favorite method"
end
end
So, in the end, you can avoid using self in many cases, but it's often helpful to use it to make sure that you don't inadvertently create naming conflicts later on. Sometimes those can create bugs that are very hard to find. In the end it's often a matter of personal style.
As noted in the comments, one more really important thing:
In a class, if you have a method like this:
def bar=(string)
...
end
And in another method you call:
def other_method
bar = "abcd"
end
It isn't going to call your bar= method, it's going to create a local variable bar. So, in this case you use self to tell Ruby not to create a local variable:
def other_method
self.bar = "abcd"
end
The same thing applies if you want to take an argument with the name of a method:
def example
...
end
def other_thing(example)
self.example(example)
end
If you left off self Ruby would assume you meant the local variable with the same name.
So, in general, self in method names is used to distinguish between class and instance variables, and everywhere else you use it when Ruby needs help distinguishing between method calls and local variables or local variable assignment.
I hope that makes sense.
In most cases self.foo is indeed redundant because you can just write foo for the same effect, but in this case it is not and the self is required.
var_one = method(args) will create a local variable called var_one, it will not call any method or do anything else to self.
self.var_one = method(args) will call the method var_one= on self with the argument method(args).
Another case where the use of self is non-optional would be if you want to pass it as an argument to a method, i.e. some_method(self) - you can't do that without the self keyword.
One other use of self is to declare class methods (similar to static methods in Java).
class foo
def self.bar
#do class related stuff here
end
end
That being said, you could also have used def foo.bar instead for the method signature.
Here's an example:
def run miles
self.miles = miles
end
In this case self will help. In most cases self is redundant.
Is there a way to bind an existing method to an existing instance of an object if both the method and the instance are passed as symbols into a method that does that if the instance is not a symbol?
For example:
def some_method
#do something
end
some_instance = Klass.new(something)
def method_that_binds(:some_method, to: :some_instance)
#how do I do that?
end
Your requirements are a little unusual, but it is possible to do this mostly as you say:
class Person; end
harry = Person.new
barry = Person.new
def test
puts 'It works!'
end
define_method :method_that_binds do |a_method, to|
eval(to[:to].to_s).singleton_class.send(:define_method, a_method, &Object.new.method(a_method))
end
method_that_binds :test, to: :harry
harry.test
# It works! will be sent to STDOUT
barry.test
# undefined method 'test'
This doesn't actually use a named parameter, but accepts a hash with a to key, but you can see you can call it in the way you want. It also assumes that the methods you are defining are defined globally on Object.
The API you want doesn't easily work, because you have to know from which scope you want to access the local variable. It's not quite clear to me why you want to pass the name of the local variable instead of passing the content of the local variable … after all, the local variable is present at the call site.
Anyway, if you pass in the scope in addition to the name, this can be accomplished rather easily:
def some_method(*args)
puts args
puts "I can access some_instance's ivar: ##private_instance_var"
end
class Foo; def initialize; #private_instance_var = :foo end end
some_instance = Foo.new
def method_that_binds(meth, to:, within:, with: [])
self.class.instance_method(meth).bind(within.local_variable_get(to)).(*with)
end
method_that_binds(:some_method, to: :some_instance, within: binding, with: ['arg1', 'arg2'])
# arg1
# arg2
# I can access some_instance's ivar: foo
As you can see, I also added a way to pass arguments to the method. Without that extension, it becomes even simpler:
def method_that_binds(meth, to:, within:)
self.class.instance_method(meth).bind(within.local_variable_get(to)).()
end
But you have to pass the scope (Binding) into the method.
If you'd like to add a method just to some_instance i.e. it's not available on other instances of Klass then this can be done using define_singleton_method (documentation here.)
some_instance.define_singleton_method(:some_method, method(:some_method))
Here the first use of the symbol :some_method is the name you'd like the method to have on some_instance and the second use as a parameter to method is creating a Method object from your existing method.
If you'd like to use the same name as the existing method you could wrap this in your own method like:
def add_method(obj, name)
obj.define_singleton_method(name, method(name))
end
Let's say we have a class A with a method a and a local variable c.
class A
def a; 10 end
end
c = '5'
And we want to add the method A#a to c.
This is how it can be done
c.singleton_class.send :define_method, :b, &A.new.method(:a)
p c.b # => 10
Explanations.
One way to add a method to an object instance and not to its class is to define it in its singleton class (which every ruby object has).
We can get the c's singleton class by calling the corresponding method c.signleton_class.
Next we need to dynamically define a method in its class and this can usually be accomplished by using the define_method which takes a method name as its first argument (in our case :b) and a block. Now, converting the method into a block might look a bit tricky but the idea is relatively simple: we first transform the method into a Method instance by calling the Object#method and then by putting the & before A.new.method(:a) we tell the interpreter to call the to_proc method on our object (as our returned object is an instance of the Method, the Method#to_proc will be called) and after that the returned proc will be translated into a block that the define_method expects as its second argument.
Forgive me for my english.
I am a php programmer and now i want to learn Ruby.
In php if you want to call function "foo" within a class, you simply call foo(), and if you want to call method "foo" you call this->foo().
The question is, is it possible to call function and method with the same name in Ruby?
For example:
def foo
puts "In foo function"
end
class A
def call_foo
foo
#How can i call foo function, not a method?
end
def foo
puts "In foo method"
end
end
a = A.new
a.call_foo #Prints "In foo method"
There is no such thing as a function in Ruby, only methods.
If you define a method at the top-level it is an instance method of Object.
If you define a class without a superclass, it's superclass is Object.
So, your A#foo simply overrides Object#foo. And if it overrides Object#foo, it should respect its contract. You should never need to call Object#foo on an A, if A#foo implements Object#foo's contract correctly (and it should, otherwise it would be a violation of the Liskov Substitution Principle). If you want to reuse Object#foo's implementation within A#foo, you can defer to the superclass implementation using super.
Note: what you want is possible using reflection, but the correct solution would be to fix your design:
def foo
puts "In foo function"
end
class A
def call_foo
self.class.superclass.public_instance_method(:foo).bind(self).()
end
def foo
puts "In foo method"
end
end
a = A.new
a.call_foo #Prints "In foo function"
The foo method outside of your class definition is bound to Object, which is an instance of Class. So to call your method you can do:
> Object.foo
=> "In foo function"
But as it was pointed out before, you should rather declare this method in an appropiate class.
You can also declare this method as class method with:
class A
def self.foo
puts "In foo class method"
end
end
Now you can call it without creating an A instance:
> A.foo
=> puts "In foo class method"
I'm wondering if there's a way to return an object instead of a string when calling an object without any methods.
For instance:
class Foo
def initialize
#bar = Bar.new
end
end
Is there any way to define the Foo class so that the following happens:
foo = Foo.new
foo #returns #bar
In the specific case I'm interested in I'm using a presenter in a Rails view. The presenter sets up one main object and then loads a bunch of related content. The important part looks like this:
class ExamplePresenter
def initialize( id )
#example = Example.find( id )
end
def example
#example
end
...
end
If I want to return the example used by the ExamplePresenter I can call:
#presenter = ExamplePresenter.new(1)
#presenter.example
It would be nice if I could also return the example object by just calling:
#presenter
So, is there a way to set a default method to return when an object is called, like to_s but returning an object instead of a string?
If I understand correctly, you want to return the instance of Example when you call the ExamplePresenter instance. Such a direct mechanism does not exist in any language, and even if it did, it would block all access to the ExamplePresenter instance and its methods. So it is not logical.
There is something you can do however. You can make the ExamplePresenter class delegate methods to the Example instance inside it. Effectively you do not get a real Example from #presenter but you get an ExamplePresenter that passes all eligible methods into its internal Example effectively acting in behalf of it.
Some ways of doing this is:
method_missing
class ExamplePresenter
… # as defined in the question
def method_missing symbol, *args
if #example.respond_to?(symbol)
#example.send(symbol, *args)
else
super
end
end
end
This will pass any method call down to the internal Example if the ExamplePresenter cannot respond to it. Be careful, you may expose more than you want of the internal Example this way, and any method already defined on ExamplePresenter cannot be passed along.
You can use additional logic inside method_missing to limit exposure or pre/post process the arguments/return values.
Wrapper methods
You can define wrapper methods on ExamplePresenter that do nothing but pass everything to the internal Example. This gives you explicit control on how much of it you want to expose.
class ExamplePresenter
… # as before
def a_method
#example.a_method
end
def another_method(argument, another_argument)
#example.another_method(argument, another_argument)
end
end
This gets tedious fast, but you can also add logic to alter arguments before passing it along to the Example or post process the results.
You can also mix and match the above two methods
Delegator library
There is a library in Ruby stdlib called Delegator built exactly for this purpose. You may look into it.
Although this is not recommended, you can do:
class Foo
def self.new
#bar = Bar.new
end
end
If you actually do need to create an instance of Foo, then
class << Foo
alias original_new :new
end
class Foo
def self.new
self.original_new # It will not be useful unless you assign this to some variable.
#bar = Bar.new
end
end
I'm getting an error so I guess I have to reference a class method from inside of an instance method with self.class_method_name, but why is that?
Shouldn't it resolve this by itself? Confused.
def self.blah(string)
..
end
def some_method()
some_thing = blah("hello")
end
If you have
# This won't work
class Foo
def self.blah(string)
puts "self.blah called with a string of #{string}"
end
def some_method
# This won't work
self.blah("hello")
end
end
foo = Foo.new
foo.some_method
It won't work, because it'll look for the instance method Foo#blah. Instead, you're looking for Foo.bar.
To make some_method call Foo.bar, you have to make some_method refer to the Foo class, and then call blah on it.
class Foo
def self.blah(string)
puts "self.blah called with a string of #{string}"
end
def some_method
# This will work
self.class.blah("hello")
end
end
foo = Foo.new
foo.some_method
The reason you have def self.blah to define the method, but self.class.blah to call the method, is that in the former, self refers to the Foo class, while in the latter, self refers to the foo object, so you need self.class to refer to the Foo class.
It may be easier to think of self as part of the method name, that way it's clear that you never defined a blah method, you defined only a self.blah method. (To clarify: the previous sentence shouldn't be thought of too much, so please don't read into it, as it's not how things are actually working, just a sort of "layman's terms" attempt at describing why it doesn't work.)
Also, what if you had defined a blah instance method in addition to the class method? If calling blah was enough to access the class method, how would you call the instance method?
Finally, there really isn't any such thing as a class method in Ruby, "class methods" are really methods of the singleton class.