4

Using Ruby 2.2.1, How to list all methods (preferrably Array of String names) of a class that is only defined in that class / file where include and extend methods are filtered out. I want to distinguish class and instance methods as well.

Currently, I can get all the uninherited methods using MyClass.methods(false) but this still includes methods that are part of an include Module.

Explicitly, say, I have:

class MyClass < BaseClass
  extend AnotherBaseClass
  include MyModule

  def foo
  end
  
  def bar
  end
end

I want to get:

somecodethatreturnssomething
#=> ['foo', 'bar']
# Not including BaseClass, AnotherBaseClass, and ModuleClass methods

UPDATE:

@Wand Maker's answer is correct when I run it in a separate irb console. However, I still have a problem specifically that I am including ActionView::Helpers::UrlHelper in MyClass. I always get extra methods: default_url_options?, default_url_options=, and default_url_options. I thought that include behaves the same regardless of Rails or not, so I didn't tag this question with Rails.

I even added byebug at the end of the file of MyClass, so that I could inspect the class and run MyClass.singleton_methods(false) or run MyClass.instance_methods(false). But they still include these three unwanted methods.

I can remove these three extra methods from the array manually, so I could get the dynamic list of methods of my class, but I am just afraid that in the future my app will break if there's an update or something that will add new methods to the class (unknowingly).

UPDATE:

The 3 methods only get added in Rails 3 it seemed (the project I'm working on), but not in Rails 4 (as @Wand Maker and I have tested).

This is the exact code (where I removed already everything, but still getting same results/problem)

# lib/my_class.rb
class MyClass
  include ActionView::Helpers::UrlHelper

  def welcome
    puts 'Hello Jules!'
  end

  def farewell
    puts 'Goodbye Jules!'
  end
end

byebug

Or I could delete that file: my_class.rb (and copy and paste that whole code in rails console)

But, still getting the same problem.

Cadoiz
  • 1,446
  • 21
  • 31
Jay-Ar Polidario
  • 6,463
  • 14
  • 28
  • FYI: If I use `MyClass < ActionController::Base` and use `MyClass.methods`, then, I see `default_url_options?` and other methods. If I use `MyClass.methods(false)`, I don't see those methods. Can you please share exact code how you are listing the methods and what is the base class of your real-life `MyClass`? – Wand Maker Dec 18 '15 at 15:26
  • @WandMaker I updated the question with the exact stripped-down code where I am still getting the three methods. – Jay-Ar Polidario Dec 18 '15 at 15:39

1 Answers1

10

You can do something like below:

MyClass.instance_methods(false)
#=> [:foo, :bar]

If you want to include any class methods defined in MyClass, you could do:

MyClass.instance_methods(false) + MyClass.singleton_methods(false)

Here is working example with all classes/modules defined

class BaseClass
  def moo
  end
end

module AnotherBaseClass
  def boo
  end
end

module MyModule
  def roo
  end
end

class MyClass < BaseClass
  extend AnotherBaseClass
  include MyModule

  def self.goo
  end

  def foo
  end

  def bar
  end
end

p MyClass.instance_methods(false) + MyClass.singleton_methods(false)
#=> [:foo, :bar, :goo]

p RUBY_VERSION
#=> "2.2.2"
Wand Maker
  • 18,476
  • 8
  • 53
  • 87
  • That will still return methods defined in included Modules. – zwippie Dec 18 '15 at 14:24
  • @zwippie I see. I have added full example, it seems to not do what you are saying. Let me know if I overlooked something. – Wand Maker Dec 18 '15 at 14:26
  • Try `Fixnum.instance_methods(false)` in `pry`. – Aleksei Matiushkin Dec 18 '15 at 14:27
  • @WandMaker Your (corrected) example does indeed return the correct methods, but I'm still trying to figure out if this is always working. For example, if I open a rails console and try `MyModel.instance_methods(false)` (where `MyModel` is an ActiveRecord class), I still get tons of methods not directly defined in `MyModel`, like all the `before_/after_` hooks. – zwippie Dec 18 '15 at 14:37
  • @mudasobwa It returns an array of 36 method names - same 36 methods listed in documentation - http://ruby-doc.org/core-2.2.0/Fixnum.html, does not have any methods from parent `Integer` – Wand Maker Dec 18 '15 at 14:39
  • 1
    @WandMaker indeed, outside of Rails it likely returns correct results. Inside rails console it drives bonkers :) – Aleksei Matiushkin Dec 18 '15 at 14:51
  • @WandMaker you're code perfectly works when I run it. However, I am still in a problem specifically that I am including ActionView::Helpers::UrlHelper in one of my class in Rails. When I include that, I always get extra methods: default_url_options?, default_url_options=, default_url_options. Maybe this outside already of my question because it is specific in Rails. I just thought that `include` should behave the same way regardless of Rails or not. Any idea why I am getting these extra methods? – Jay-Ar Polidario Dec 18 '15 at 14:57
  • I even added byebug at the end of that file of my custom class, just so that I could inspect immediately the class, and can be sure that Rails wont inject or add extra stuff to my class. But I am still getting extra default_url_options. I can remove these three manually from the array, but I am just afraid that (in my app im building), that there would be some other new methods in the future that might pop-up, and then my app will break. – Jay-Ar Polidario Dec 18 '15 at 15:01
  • @Jay-ArPolidario AFAIK, RAILS is heavy on meta-programming, it defines methods dynamically to the given class if it includes certain module or extend a class. I do not have answer to your specific query yet as when I include the said module `ActionView::Helpers::UrlHelper` in the above code sample, I did not see additional methods getting added - may be there is more than that module. Is your class a Controller? – Wand Maker Dec 18 '15 at 15:15
  • @WandMaker I tried it on Rails 4, and now I do not have those methods. It seems that only in Rails 3.2 (the project I am working on) that those three methods get included. I actually copy and paste the whole class of mine into rails console, just so I am sure that Rails have already loaded everything, and that Rails won't add new methods to whatever code I run on the console. But still in Rails 3.2, those three methods still exists. Haha. Thank you for your answer though, I guess I will just manually remove these three methods for now :) – Jay-Ar Polidario Dec 18 '15 at 15:28
  • @zwippie, found nothing better than `.reject{|m| m =~ /\A(after|before|autosave|validate)/ }` – okliv Apr 14 '16 at 19:13
  • 1
    shortcut: .methods(false) returns an array of obj's public and protected singleton methods. – ogelacinyc Apr 15 '19 at 03:47