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)
Related
I'm near the finish of the Ruby track in Code Academy, and I'm curious about a peculiar thing: I was under the impression that a class is a repository of constants, methods, etc... and that in order to access most of them, you would first need to create an instance of that class or in some cases the methods of themselves can be invoked (as in they are all technically part of the global object). And then I saw something like this:
#Worked
Time.now
I understood as this as the method [now] of instance of class [Time] being invoked. I then tried to invoke the method on its own:
#Failed
now
and that failed, and I assumed that while a method can be created in the general scope [as part of the global object], if it relies on initialized variables of "parent" class, it cannot be called on its own, because it would not know which object to search for those initialized variables. Following that I created a test class:
class Clock
def initialize
#hours = 1
#minutes = 30
end
def showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
#this worked
watch = Clock.new
watch.showTime
#this failed
showTime
I then just created a basic method (assuming it's in the global level)
def mymethod
puts "The mighty METHOD!"
end
#Works
mymethod
and calling this method the way I did, without referencing the global object worked. So... the questions I have are as follows:
How can [Time.now] be called in this fashion? Shouldn't there be an instance of Time first created?
Why can't I call the method [now] on its own? Am I right that it relies on resources that it cannot find when called this way?
Why could I not call the method showTime on its own? But if I define any method on the "global" level I can access it without referencing the global object
First of all, your intuition is correct.
Every methods must be an instance method of some receiver.
Global methods are defined as private instance methods on Object class and hence seem to be globally available. Why? From any context Object is always in the class hierarchy of self and hence private methods on Object are always callable without receiver.
def fuuuuuuuuuuun
end
Object.private_methods.include?(:fuuuuuuuuuuun)
# => true
Class methods are defined as instance methods on the "singleton class" of their class instance. Every object in Ruby has two classes, a "singleton class" with instance methods just for that one single object and a "normal class" with method for all objects of that class. Classes are no different, they are objects of the Class class and may have singleton methods.
class A
class << self # the singleton class
def example
end
end
end
A.singleton_class.instance_methods.include?(:example)
# => true
Alternative ways of defining class methods are
class A
def self.example
end
end
# or
def A.example
end
Fun fact, you can define singleton methods on any object (not just on class objects) using the same syntax def (receiver).(method name) as follows
str = "hello"
def str.square_size
size * size
end
str.square_size
# => 25
"any other string".square_size
# => raises NoMethodError
Some programming language history — Singleton classes are taken from the Smalltalk language where they are called "metaclasses". Basically all object-oriented features in Ruby (as well as the functional-style enumerators on Enumerable) are taken from the Smalltalk language. Smalltalk was an early class-based object-oriented language created in the 70ies. It was also the language that invented graphical user interfaces like overlapping windows and menus et cetera. If you love Ruby maybe also take a look at Smalltalk, you might fall in love yet again.
This is known as a class method. If CodeAcademy didn't cover it, that's a shame. Here's some examples:
# basic way
class Foo
def self.bar; :ok; end
end
Foo.bar # => :ok
# alternate syntax
class Foo
class << self
def bar; :ok; end
end
end
# alternate syntax, if Foo class already exists
def Foo.bar; :ok; end
# alternate approach if Foo class already exists
Foo.class_exec do
def bar; :ok; end
end
# to define a class method on an anonymous 'class' for a single instance
# you won't need to use this often
Foo.new.singleton_class.class_exec do
def bar; :ok; end
end
# to define a class method on an instance's actual class
Foo.new.class.class_exec do
def bar; :ok; end
end
Another way to get class methods is to extend a module.
module FooMethods
def bar; :ok; end
end
module Foo
extend FooMethods
end
Foo.bar # => :ok
Note that with Modules, the methods are always defined as instance methods. This way they can be either extended into class scope or included into instance scope. Modules can also have class methods, using the exact same syntax / examples as shown above with classes. However there's not such as easy to load a module's class methods via include or extend.
How can [Time.now] be called in this fashion? Shouldn't there be an
instance of Time first created?
The Time.now method is a class method, not an instance method and therefore can be called directly on the Time class rather than an instance of it Time.new
Class methods are defined on the class themselves using the self keyword:
class Time
def self.now
# code
end
end
Time.now # works
Why can't I call the method [now] on its own? Am I right that it
relies on resources that it cannot find when called this way?
When you call a method "on its own" you're actually implicitly calling it on self:
self.now
The above is the same as just doing:
now
Why could I not call the method showTime on its own? But if I define
any method on the "global" level I can access it without referencing
the global object
You defined the showTime method on a specific class so you have to send that method to that class. When you define a method in the "global" scope you're implicitly defining it on self and the subsequent call to mymethod is actually self.mymethod so it will work.
Time.now is a class method.
To define a class method, you need to define the method with self. : def self.method_name
class Clock
#hours = 1
#minutes = 30
def self.showTime
puts "The time is: #{#hours}:#{#minutes}"
end
end
Clock.showTime
#=> The time is: 1:30
If you want to call now on its own, you can do so inside Time class :
class Time
puts now
#=> 2017-01-19 22:17:29 +0100
end
I was trying to implement my own attr_accessor method. I implemented that as follow.
class Object
def my_attr_accessor(*args) # self.my_attr_accessor(*args)
args.each do |arg|
define_method "#{arg}" do
return instance_variable_get("##{arg}")
end
define_method "#{arg}=" do |val|
instance_variable_set("##{arg}", val)
end
end
end
end
Then I created a class which calls the my_attr_accessor method.
class Runner
my_attr_accessor :name
end
test= Runner.new
test.name = "runner"
puts test.name
My question is even though I haven't explicitly defined self.my_attr_accessor method, it is acting as a class method. Can someone help me in figuring out how it's happening.
EDIT: Irrespective of making self.my_attr_accessor or my_attr_accessor in Object class, it works if I say my_attr_accessor within my Runner class. Why?
This is called "inheritance". In Ruby, subclasses "inherit" methods from their superclasses. In other words, if you send a message to an object, Ruby will look up a method whose name matches the message in the class of the object, and if it can't find it, it will follow that classes' superclass pointer, and then that classes' superclass pointer, and so on, until it either finds a matching method or reaches a class which doesn't have a superclass.
Since Class is a subclass of Object (indirectly via Module), it inherits Object's methods.
[Note: inheritance is a fundamental concept in Ruby, you should probably go back and learn the fundamentals of Ruby before trying advanced reflective metaprogramming. In particular how the ancestry chain (the superclass pointers) are constructed and message dispatch works.]
Since everything is an instance of Object in ruby, you can call your method from anywhere:
class Object
def my_attr_accessor(*args)
end
end
puts self.class # => Object
puts self.is_a?(Object) # => true
puts self.respond_to?(:my_attr_accessor) # => true
class Runner
puts self.class # => Class
puts self.is_a?(Object) # => true
puts self.respond_to?(:my_attr_accessor) # => true
my_attr_accessor :name
end
You create a new Runner with Runner.new. So you have an instance of the Runner class.
Since you called my_attr_accessor in your class block, you have created the method .name on your instance. This is important. my_attr_accessor is a call to the method my_attr_accessor. And in the base class, i.e. in Object, Ruby finds this method and calls it.
Now, you can call test.name = "runner".
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.
When you define a method, it returns a symbol with the same name as the method. Is there a point to this? Or is it just there as validation that you created it?
Like so:
def something
...
end
# => :something
IRb always displays the result of calling inspect on the value of the last expression that was evaluated. It doesn't matter whether that expression is a literal expression, a conditional expression, a message send, a class definition expression or a method definition expression.
Everything returns a value in Ruby, i.e. everything is an expression, there is no such thing as a statement in Ruby.
In the past, the return value of a method definition expression was undefined. Most Ruby implementations simply returned nil from a method definition expression, but Rubinius for example returned the CompiledMethod object for the method that was defined.
With Ruby 2.1, the return value of a method definition expression was standardized to be the Symbol corresponding to the method's name. This allows you to use the method definition expression as an argument in methods that expect the name of a method as an argument.
Some examples:
# Before Ruby 2.0:
def foo; end
private :foo
# After Ruby 2.0:
private def foo; end # similar for `protected`, `public`, `module_function`
# Before Ruby 2.0:
def map; end
alias_method :collect, :map
# After Ruby 2.0:
alias_method :collect, def map; end
On a personal note, I would have preferred a method definition expression to evaluate to an UnboundMethod object corresponding to that method, and methods like public, private, protected, alias_method, module_function etc. should be amended to accept UnboundMethods in addition to Symbols and Strings.
The person who proposed this had in mind a usage like this:
private def foo
...
end
protected def bar
...
end
Methods such as public, private, protected take symbols as arguments. The point was to make use of this syntax.
All method defs return symbols in Ruby >=2.1 (not just the ones in IRB).
For example:
class Foo
p def bar; end
end
# => prints :bar
Why is this interesting?
You may have noticed that there are many methods, particularly class-level methods, that take the symbolized name of another method as an argument. You may be familiar with before_filter in Rails controllers. Since method defs return symbols, you could potentially do this:
class MyController < ApplicationController
before_filter def my_filter
# do stuff
end
end
IRB respects the ruby standard “the result of last executed statement is returned from method.” Imagine the code:
def a
def b
# do stuff
end
end
What is the result of execution this code? It follows:
a
# => :b
a.class
# => Symbol < Object
That said, IRB executes the method definition and returns/prints out it’s result. Which is, apparently, a Symbol instance.
I'm trying to redefine the File.dirname method to first change %20s to spaces. But the following gives me an error
class File
old_dirname = instance_method(:dirname)
define_method(:dirname) { |s|
s = s.gsub("%20"," ")
old_dirname.bind(self).call(s)
}
end
This trhows a NameError exception: undefined method 'dirname' for class 'File'
What is the right way to do this?
As Chuck already wrote, File::dirname is a singleton method of the File class object (or more precisely an instance method of the File class object's metaclass), not an instance method of the File class.
So, you have to open up File's metaclass, not the File class itself:
#!/usr/bin/env ruby
class << File
old_dirname = instance_method :dirname
define_method :dirname do |*args|
old_dirname.bind(self).(*args).gsub '%20', ' '
end
end
require 'test/unit'
class TestFileDirname < Test::Unit::TestCase
def test_that_it_converts_percent20_to_space
assert_equal '/foo bar/baz', File.dirname('/foo%20bar/baz/quux.txt')
end
end
However, I agree with #sheldonh: this breaks the API contract of File::dirname.
Just be careful.
You're changing the behaviour of the method, not just its implementation. This is generally poor practice, because it weakens the value of the API as a dependable contract.
Instead, consider transforming the input closer to the point of receipt.
dirname is a class method of File, not an instance method, so you're just defining a new instance method. Also, the idiomatic way to alias a method is with alias. So:
class <<File
alias old_dirname dirname
def dirname(f)
old_dirname(f.gsub("%20", " "))
end
end
The class <<whatever syntax adds methods to an individual object — in this case, the File class.