How do you list the currently available objects in the current scope in ruby?
Asked Answered
R

7

40

I'm new to ruby and I'm playing around with the IRB.

I found that I can list methods of an object using the ".methods" method, and that self.methods sort of give me what I want (similar to Python's dir(builtins)?), but how can I find the methods of a library/module I've loaded via include and require?

irb(main):036:0* self.methods
=> ["irb_pop_binding", "inspect", "taguri", "irb_chws", "clone", "irb_pushws", "public_methods", "taguri=", "irb_pwws",
"public", "display", "irb_require", "irb_exit", "instance_variable_defined?", "irb_cb", "equal?", "freeze", "irb_context
", "irb_pop_workspace", "irb_cwb", "irb_jobs", "irb_bindings", "methods", "irb_current_working_workspace", "respond_to?"
, "irb_popb", "irb_cws", "fg", "pushws", "conf", "dup", "cwws", "instance_variables", "source", "cb", "kill", "help", "_
_id__", "method", "eql?", "irb_pwb", "id", "bindings", "send", "singleton_methods", "popb", "irb_kill", "chws", "taint",
 "irb_push_binding", "instance_variable_get", "frozen?", "irb_source", "pwws", "private", "instance_of?", "__send__", "i
rb_workspaces", "to_a", "irb_quit", "to_yaml_style", "irb_popws", "irb_change_workspace", "jobs", "type", "install_alias
_method", "irb_push_workspace", "require_gem", "object_id", "instance_eval", "protected_methods", "irb_print_working_wor
kspace", "irb_load", "require", "==", "cws", "===", "irb_pushb", "instance_variable_set", "irb_current_working_binding",
 "extend", "kind_of?", "context", "gem", "to_yaml_properties", "quit", "popws", "irb", "to_s", "to_yaml", "irb_fg", "cla
ss", "hash", "private_methods", "=~", "tainted?", "include", "irb_cwws", "irb_change_binding", "irb_help", "untaint", "n
il?", "pushb", "exit", "irb_print_working_binding", "is_a?", "workspaces"]
irb(main):037:0>

I'm used to python, where I use the dir() function to accomplish the same thing:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>>
Rackrent answered 23/10, 2008 at 5:38 Comment(0)
A
29

ObjectSpace.each_object could be what you are looking for.

To get a list of included modules you could use Module.included_modules.

You can also check if an object responds to a method on a case-by-case basis using object.respond_to?.

Adenoma answered 23/10, 2008 at 8:13 Comment(0)
M
49

I'm not entirely sure of what you mean by the 'current objects'. You can iterate over ObjectSpace, as has been mentioned already. But here are a few other methods.

local_variables
instance_variables
global_variables

class_variables
constants

There's one gotcha. They must be called at the right scopes. So right in IRB, or in an object instance or at class scope (so everywhere, basically) you can call the first 3.

local_variables #=> ["_"]
foo = "bar"
local_variables #=> ["_", "foo"]
# Note: the _ variable in IRB contains the last value evaluated
_ #=> "bar"

instance_variables  #=> []
@inst_var = 42
instance_variables  #=> ["@inst_var"]

global_variables    #=> ["$-d", "$\"", "$$", "$<", "$_", ...]
$"                  #=> ["e2mmap.rb", "irb/init.rb", "irb/workspace.rb", ...]

But umm, what if you want your program to actually evaluate them without needing you to type them manyally? The trick is eval.

eval "@inst_var" #=> 42
global_variables.each do |v|
  puts eval(v)
end

The last 2 of the 5 mentioned at the beginning must be evaluated at the module level (a class is a descendant of a module, so that works).

Object.class_variables #=> []
Object.constants #=> ["IO", "Duration", "UNIXserver", "Binding", ...]

class MyClass
  A_CONST = 'pshh'
  class InnerClass
  end
  def initialize
    @@meh = "class_var"
  end
end

MyClass.constants           #=> ["A_CONST", "InnerClass"]
MyClass.class_variables     #=> []
mc = MyClass.new
MyClass.class_variables     #=> ["@@meh"]
MyClass.class_eval "@@meh"  #=> "class_var"

Here's are a few more tricks to explore in different directions

"".class            #=> String
"".class.ancestors  #=> [String, Enumerable, Comparable, ...]
String.ancestors    #=> [String, Enumerable, Comparable, ...]

def trace
  return caller
end
trace #=> ["(irb):67:in `irb_binding'", "/System/Library/Frameworks/Ruby...", ...]
Monadism answered 25/10, 2008 at 6:18 Comment(0)
A
29

ObjectSpace.each_object could be what you are looking for.

To get a list of included modules you could use Module.included_modules.

You can also check if an object responds to a method on a case-by-case basis using object.respond_to?.

Adenoma answered 23/10, 2008 at 8:13 Comment(0)
F
6

The dir() method is not clearly defined...

Note: Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases.

...but we can create a close approximation in Ruby. Let's make a method that will return a sorted list of all methods added to our scope by included modules. We can get a list of the modules that have been included by using the included_modules method.

Like dir(), we want to ignore the "default" methods (like print), and we also want to focus on the "interesting" set of names. So, we will ignore methods in Kernel, and we will only return methods that were defined directly in the modules, ignoring inherited methods. We can accomplish the later by passing false into the methods() method. Putting it all together we get...

def included_methods(object=self)
  object = object.class if object.class != Class
  modules = (object.included_modules-[Kernel])
  modules.collect{ |mod| mod.methods(false)}.flatten.sort
end

You can pass it a class, an object, or nothing (it defaults to the current scope). Let's try it out...

irb(main):006:0> included_methods
=> []
irb(main):007:0> include Math
=> Object
irb(main):008:0> included_methods
=> ["acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh", "cos", "cosh", "erf", "erfc", "exp", "frexp", "hypot", "ldexp", "log", "log10", "sin", "sinh", "sqrt", "tan", "tanh"]

dir() also includes locally defined variables, and that's an easy one. Just call...

local_variables

...unfortunately, we can't just add the local_variables call to included_methods because it would give us the variables that are local to the included_methods method, and that wouldn't be very useful. So, if you want local variables included with the included_methods, just call...

 (included_methods + local_variables).sort
Fusco answered 24/10, 2008 at 2:13 Comment(3)
ok, I'm learning slowly. This brings on my next question, what's the difference between "include" and "require"? I'll go do some reading, but how can methods be seen which were loaded via "require"?Rackrent
An include will add the constants, methods, and module variables to the current scope. It is typically used to add functionality to a class. A require loads another ruby file (if it hasn't already been loaded). If you want to load it (even if it's already loaded) use the "load" method instead.Fusco
Typically a required file will load a class. For example require 'foo' will load the Foo classs. So, you can get a list of methods in that class by doing Foo.methods(false). If the required file is just a bunch of methods: orig = Object.private_methods; require 'foo'; p Object.private_methods - origFusco
R
5

I wrote a gem for that:

$ gem install method_info
$ rvm use 1.8.7 # (1.8.6 works but can be very slow for an object with a lot of methods)
$ irb
> require 'method_info'
> 5.method_info
::: Fixnum :::
%, &, *, **, +, -, -@, /, <, <<, <=, <=>, ==, >, >=, >>, [], ^, abs,
div, divmod, even?, fdiv, id2name, modulo, odd?, power!, quo, rdiv,
rpower, size, to_f, to_s, to_sym, zero?, |, ~
::: Integer :::
ceil, chr, denominator, downto, floor, gcd, gcdlcm, integer?, lcm,
next, numerator, ord, pred, round, succ, taguri, taguri=, times, to_i,
to_int, to_r, to_yaml, truncate, upto
::: Precision :::
prec, prec_f, prec_i
::: Numeric :::
+@, coerce, eql?, nonzero?, pretty_print, pretty_print_cycle,
remainder, singleton_method_added, step
::: Comparable :::
between?
::: Object :::
clone, to_yaml_properties, to_yaml_style, what?
::: MethodInfo::ObjectMethod :::
method_info
::: Kernel :::
===, =~, __clone__, __id__, __send__, class, display, dup, enum_for,
equal?, extend, freeze, frozen?, hash, id, inspect, instance_eval,
instance_exec, instance_of?, instance_variable_defined?,
instance_variable_get, instance_variable_set, instance_variables,
is_a?, kind_of?, method, methods, nil?, object_id, pretty_inspect,
private_methods, protected_methods, public_methods, respond_to?, ri,
send, singleton_methods, taint, tainted?, tap, to_a, to_enum, type,
untaint
 => nil

I am working on an improvement of passing options and settings defaults, but for now I would suggest you add the following to your .irbrc file:

require 'method_info'
MethodInfo::OptionHandler.default_options = {
 :ancestors_to_exclude => [Object],
 :enable_colors => true
}

This enables colours and hides the methods that every object has, since you're usually not interested in those.

Revenant answered 9/11, 2010 at 11:6 Comment(1)
I'm guessing that's not really what the question was about but oh jeebus is this ever what I needed for irb. The extensive use of mixins leading to way too many methods makes ruby libraries much harder to explore than python's, but this should very nicely help to sort through that. Now I just need a replacement for help() that's just as good.Downcome
P
3

What about:

Object.constants.select{|x| eval(x.to_s).class == Class}

That lists available classes for me. I am not ruby expert and I was being dropped at a ruby console with no idea of what classes were at hand. That one liner was a start.

Pickett answered 27/7, 2016 at 22:27 Comment(1)
This made my day. Thank you.Mutant
M
2

To access all object instances in ruby you use ObjectSpace

http://www.ruby-doc.org/core-1.8.7/classes/ObjectSpace.html#M000928

However, this is considered slow (even for ruby), and may not be enabled in some interpreters (e.g. jRuby can disable ObjectSpace as it is much faster relying in the jvm for gc without needing to track this stuff in jRuby).

Melaniemelanin answered 23/10, 2008 at 8:7 Comment(0)
S
0

You can pass the .methods messages to the library/module even before loading it, to see all the available methods. Doing self.methods just returns all the methods that the Object object contains. You can see this by doing self.class. So let's say you want to see all the methods in the File module. You simply do File.methods and you'll get a list of all the methods that exist in the File module. This, perhaps, isn't what you want, but it should be somewhat helpful.

Stagger answered 23/10, 2008 at 8:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.