Ruby methods() method - ruby

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.

Related

Calling a module function in a ruby module

I want to call a module function to define a constant in a utility module in ruby. However, when I try this I get an error message. Here comes the code and the error:
module M
ABC = fun
module_function
def self.fun
"works"
end
end
Error message:
NameError: undefined local variable or method `fun' for M:Module
Any ideas? I also tried it without self and with M.fun but no success...
It is just that the method is not defined when you assign fun to ABC. Just change the order:
module M
def self.fun
"works"
end
ABC = fun
end
M::ABC
#=> "works"
If you dislike the order (constants below methods), you might want to consider to have the method itself to memorize its return value. A common pattern looks like:
module M
def self.fun
#cached_fun ||= begin
sleep 4 # complex calculation
Time.now # return value
end
end
end
M.fun
# returns after 4 seconds => 2017-03-03 23:48:57 +0100
M.fun
# returns immediately => 2017-03-03 23:48:57 +0100
Test this in you irb console:
$ irb
2.3.3 :001 > module M
2.3.3 :002?> def self.fun
2.3.3 :003?> "worked"
2.3.3 :004?> end
2.3.3 :005?>
2.3.3 :006 > ABC = fun
2.3.3 :007?> end
=> "worked"
2.3.3 :008 > M
=> M
2.3.3 :009 > M::ABC
=> "worked"
2.3.3 :010 >
The fact is that now you defined self.fun before using it.
In your code you used the method before defining it.

Ruby: Get a method's class or module name

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.

Responding to one method but not to other in the same scope

With the following code
class User < ActiveRecord::Base
# ...
# code filtered from here
# ...
# both methods below are public methods
def humanized_roles
roles.collect {|e| e.name.humanize }.join(', ')
end
def role=( arg = nil)
self.roles = []
self.add_role arg.to_sym
end
end
This is happening
User.new.respond_to? :humanized_roles
# => false
User.new.respond_to? "role=".to_sym
# => true
rvm, ruby, rails versions
rvm 1.26.3
ruby 1.9.3p448 (2013-06-27 revision 41675) [x86_64-linux]
Rails 3.2.14
Am I missing something obvious?
In the interest of product release, I circumvented this issue and used a helper method to accept user object as parameter, instead of user.humanize_roles
Thank you everyone for your valuable time & responses.

Am I Understanding Objects in Ruby Correctly?

I feel this is fundamental to my understanding of Ruby and object-oriented programming in general, so I'm asking this fairly simplistic question here at the risk of looking foolish. I've been toying around with irb. I've created my first ever class:
$ irb
ruby-1.9.2-p290 :001 > class Person
ruby-1.9.2-p290 :002?> attr_accessor :firstname, :lastname, :gender
ruby-1.9.2-p290 :003?> end
=> nil
ruby-1.9.2-p290 :004 > person_instance = Person.new
=> #<Person:0x007f9b7a9a0f70>
ruby-1.9.2-p290 :005 > person_instance.firstname = "Bob"
=> "Bob"
ruby-1.9.2-p290 :006 > person_instance.lastname = "Dylan"
=> "Dylan"
ruby-1.9.2-p290 :007 > person_instance.gender = "male"
=> "male"
So Person.new is my object, right? Or is my object the combination of class Person and the attributes I've defined for that class?
Your object is the result of running Person.new, which you've captured in person_instance.
In ruby, attributes don't actually exist until they are first written, so before person_instance.firstname = "Bob", your instance has no attributes. After executing this statement it has a #firstname attribute, but no others.
You are right. Everything in ruby is an object. So when you create a new class 'person' it itself is an object of type class.
Strings are also objects, so after you've done
person_instance.firstname = "Bob"
then person_instance.firstname refers to a string object. So you can call
# Returns String, indicating that the object returned by
# person_instance.firstname is an instance of the String class.
person_instance.firstname.class
# Returns a not very informative number, but indicates that it is its own object
person_instance.firstname.object_id

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

Resources