Ruby: Get a method's class or module name - ruby

I'm trying to understand a mixin precedence situation. If I run foo.bar I'm trying to figure out exactly which bar will be executed. Here is a snipped irb session where I tried to find out where an array's assoc method is defined.
2.3.0 :032 > ray = ['cat', nil, 'dog']
=> ["cat", nil, "dog"]
2.3.0 :033 > ray.methods
=> [:fill, :assoc, :rassoc, :uniq, ...
2.3.0 :034 > ray.method("assoc").class_or_module_name
NoMethodError: undefined method `class_or_module_name' for #<Method: Array#assoc>
from (irb):34
from /Users/mark/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
2.3.0 :035 > ray.methods("assoc").class_or_module_name
NoMethodError: undefined method `class_or_module_name' for #<Array:0x007ffb8aa286a8>
from (irb):35
from /Users/mark/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
2.3.0 :036 > ray.methods("assoc")
=> [:fill, :assoc, :rassoc, :uniq, :uniq!, :compact, ...
If possible I would like to see the methods and their source location that lost precedence.

To find out which class or module defines a method (rather than what file), use Method#owner.
For example,
[].method(:last).owner #=> Array
[].method(:flat_map).owner #=> Enumerable
You'll actually find that a lot of the methods that Array could get from Enumerable, it actually defines itself (presumably to provide a more efficient implementation):
irb(main):018:0> Enumerable.instance_methods.select {|meth_name| [].method(meth_name).owner == Array }
=> [:to_a, :to_h, :sort, :count, :find_index, :select, :reject, :collect, :map, :first, :include?, :reverse_each, :zip, :take, :take_while, :drop, :drop_while, :cycle]

In general, to know where a method is defined you can use source_location(docs), e.g.
ray.method("assoc").source_location
although in this case it will return nil since assoc is a native method. It will work for other methods, e.g.
ray.methods.map{ |m| [m, ray.method(m).source_location] }
For native methods you can use Pry, e.g.
pry(main)> ? ray.assoc
From: array.c (C Method):
Owner: Array
Visibility: public
[...]
? is a shorthand for show-doc.

Related

How to use RSpec expectations in irb

I'd want to use [1,2,3].should include(1) in irb. I tried:
~$ irb
1.9.3p362 :001 > require 'rspec/expectations'
=> true
1.9.3p362 :002 > include RSpec::Matchers
=> Object
1.9.3p362 :003 > [1,2,3].should include(1)
TypeError: wrong argument type Fixnum (expected Module)
from (irb):3:in `include'
from (irb):3
from /home/andrey/.rvm/rubies/ruby-1.9.3-p362/bin/irb:16:in `<main>'
But it doesn't work though it's a valid case. How can I use [1,2,3].should include(1)?
You are close, but calling include on top-level you will be calling Module#include. To get around it you need to remove the original include method so that RSpec's include gets called instead.
First let's figure out where the system include comes from:
> method :include
=> #<Method: main.include>
Ok. It looks like it's defined in main. This is the Ruby top-level object. So let's rename and remove the original include:
> class << self; alias_method :inc, :include; remove_method :include; end
Now we can get down to business:
> require 'rspec'
> inc RSpec::Matchers
> [1,2,3].should include(1)
=> true

Method called on an object when displayed on the console in Ruby

I am willing to call a method when trying to display an object, but I don't find which method is used, for example:
[41] pry(main)> u
=> {"id"=>3}
[42] pry(main)> u.inspect
=> "#<User id=3>"
[43] pry(main)> u.to_s
=> "#<User id=3>"
[44] pry(main)> puts c
#<User id=3>
=> nil
I would like to know which method is called for the first case.
User is not an ActiveRecord class, it inherits from Hashie.
Thanks for your help!
It's probably the rails method attributes - though it is a feature of Pry, not of the standard rails console which would give you ruby-1.9.2-p290 :047 > u
=> #<u:0x8a2f6cc #id=3>

Ruby methods() method

I want to understand how Ruby method methods() work.
I tried to Google with "ruby methods" but it's not what i need.
Also i've seen ruby-doc.org, but i didn't find this method.
Can you expain me how it works in details or give me a link?
Update
I experimented with methods() method and got such results:
'lab rat' code
class First
def first_instance_mymethod
end
def self.first_class_mymethod
end
end
class Second < First
def second_instance_mymethod
end
def self.second_class_mymethod
end
end
Work with Classes
#returns available methods list for class and ancestors
puts Second.methods.grep(/mymethod/)
# => second_class_mymethod
# => first_class_mymethod
#returns Class methods list for current class only
puts Second.methods(false)
# => second_class_mymethod
Work with Objects
obj = Second.new
def obj.obj_singleton_mymethod
end
#returns available methods list for object and ancestors
puts obj.methods.grep(/mymethod/)
# => second_instance_mymethod
# => first_instance_mymethod
#returns current object class methods
puts obj.methods(false)
# => obj_singleton_mymethod
The accepted answer misses a slight point. A fuller answer was given in the comment by keymone - .methods returns an array of symbols being names of all the methods defined on the given instance. For example:
irb(main):012:0> object = ""
=> ""
irb(main):013:0> object.instance_eval("def foo;:bar;end")
=> nil
irb(main):014:0> object.methods.include?(:foo)
=> true
irb(main):016:0> "".methods.include?(:foo)
=> false
I'm not entirely sure why it's not in the ruby 1.9 docs (it seems to still be in the code), but you can see the documentation in the 1.8.7 docs: http://www.ruby-doc.org/core-1.8.7/classes/Object.html#M000032
Basically, in ruby 1.9 it just returns a list of the symbols (names) for all the methods in a given class and its ancestors. (ruby 1.8 it returned a list of strings)
I'm on Ruby 2.2.5 and I am unfortunately not getting this to work when passed false any longer. I do remember back on older versions of Ruby, passing false to this method used to return only the class-level methods.
However, as of Ruby 2.2.5, here's what I'm getting
class Thingy < ApplicationRecord
def hello
end
end
class Apple < Thingy
def self.goodbye
end
def booty
end
end
results:
2.2.5 :001 > a = Thingy.new
=> #<Thingy id: nil, created_at: nil, updated_at: nil>
2.2.5 :002 > a.methods(false)
=> []
2.2.5 :003 > b = Apple.new
=> #<Apple id: nil, created_at: nil, updated_at: nil>
2.2.5 :004 > b.methods(false)
=> []
2.2.5 :005 > Apple.methods(false)
=> [:attribute_type_decorations, :_validators, :defined_enums, :goodbye]
2.2.5 :006 > Thingy.methods(false)
=> [:attribute_type_decorations, :_validators, :defined_enums]
2.2.5 :007 >
the only time passing false returns anything interesting to me is to examine class-level methods only (those that start with self.) Otherwise it seems to not be helpful anymore.

How to retrieve a class name?

I am using Ruby on Rails 3.0.7 and I would like to retrieve the class name, also if it is namespaced. For example, if I have a class named User::Profile::Manager I would retrieve the Manager string from that using some unknown to me Ruby or Ruby on Rails method and in a secure way.
BTW: What other "usefull" information that are "commonly" used can I get for the class?
Some useful simple metaprogramming calls:
user = User::Profile::Manager.new(some_params)
user.class # => User::Profile::Manager
user.class.class # => Class
user.class.name # => "User::Profile::Manager"
user.class.name.class # => String
# respond_to? lets you know if you can call a method on an object or if the method you specify is undefined
user.respond_to?(:class) # => true
user.respond_to?(:authenticate!) # => Might be true depending on your authentication solution
user.respond_to?(:herpderp) # => false (unless you're the best programmer ever)
# class.ancestors is an array of the class names of the inheritance chain for an object
# In rails 3.1 it yields this for strings:
"string".class.ancestors.each{|anc| puts anc}
String
JSON::Ext::Generator::GeneratorMethods::String
Comparable
Object
PP::ObjectMixin
JSON::Ext::Generator::GeneratorMethods::Object
ActiveSupport::Dependencies::Loadable
Kernel
BasicObject
If you want the lowest-level class from User::Profile::Manager I'd probably do the following [using a regex for this seems like overkill to me ;)]:
user = User::Profile::Manager.new
class_as_string = user.class.name.split('::').last # => "Manager"
class_as_class = class_name.constantize # => Manager
Edit:
If you actually want to look through some more metaprogramming calls, check the docs for the Object and Module classes, and check out the google results for "Ruby Metaprogramming".
Have you tried class method:
class A
class B
end
end
myobject = A::B.new
myobject.class
=> A::B
To expand on #JCorcuera's answer, some other useful information can be found with kind_of? and methods
class A
class B
def foo
end
end
end
myobject = A::B.new
p myobject.class
=> A::B
p myobject.kind_of? A::B
=> true
p myobject.methods
=> [:foo, :nil?, :===, :=~, ...
p myobject.methods.include? :foo
=> true

Array.find method problem

I find this line in the ZenTest source code:
result = #test_mappings.find { |file_re, ignored| filename =~ file_re }
The #test_mappings and result here are both Array object, but I didn't found 'find' method on Array class in ruby doc. I also tried it on irb:
irb(main):014:0> Array.respond_to? :find
=> false
irb(main):015:0> [1,2,3].find
LocalJumpError: no block given
from (irb):15:in `find'
from (irb):15:in `each'
from (irb):15:in `find'
from (irb):15
irb(main):016:0> [1,2,3].find{|x| x>1}
=> 2
Could any one explain it to me? How could find method also return an Array object? thanks in advance.
Array includes the Enumerable module, which adds the find method.
In your example you tested Array.respond_to. This will only return true for class methods of Array. find is an instance method, so respond_to? must be invoked on an instance of the class.
>> a = Array.new
=> []
>> a.respond_to? :find
=> true
Another sometimes useful trick is calling the 'methods' function which lists all the methods available to the instance of the object and using the grep method to filter out for something specific. It also gives you a good picture of what standard methods are provided by base classes without referring to docs.
a = Array.new
=> []
>> a.methods.grep /find/
=> ["find", "find_all"]

Resources