¿Cómo se enumeran los objetos actualmente disponibles en el alcance actual en Ruby?
-
04-07-2019 - |
Pregunta
Soy nuevo en Ruby y estoy jugando con el IRB.
Descubrí que puedo enumerar métodos de un objeto usando el método ".methods", y que self.methods me da lo que quiero (similar al directorio de Python (incorporados)?), pero ¿cómo puedo encontrar los métodos de una biblioteca/módulo que he cargado mediante include y 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>
Estoy acostumbrado a Python, donde uso la función dir() para lograr lo mismo:
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>>
Solución
ObjectSpace.each_object podría ser lo que estás buscando.
Para obtener una lista de los módulos incluidos, puede usar Module.included_modules .
También puede verificar si un objeto responde a un método caso por caso usando object.respond_to? .
Otros consejos
No estoy completamente seguro de lo que quieres decir con "objetos actuales". Puede iterar sobre ObjectSpace, como ya se mencionó. Pero aquí hay algunos otros métodos.
local_variables
instance_variables
global_variables
class_variables
constants
Hay una trampa. Deben llamarse en los ámbitos correctos. Entonces, justo en IRB, o en una instancia de objeto o en el ámbito de la clase (básicamente, en todas partes) puede llamar a los primeros 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", ...]
Pero umm, ¿qué pasa si quieres que tu programa realmente los evalúe sin necesidad de que los escribas de manera manual? El truco es evaluar.
eval "@inst_var" #=> 42
global_variables.each do |v|
puts eval(v)
end
Los 2 últimos de los 5 mencionados al principio deben evaluarse a nivel de módulo (una clase es un descendiente de un módulo, por lo que funciona).
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"
Aquí hay algunos trucos más para explorar en diferentes direcciones
"".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...", ...]
El método dir()
es no está claramente definido ...
Nota: porque se suministra
included_modules
principalmente como una conveniencia para su uso en un mensaje interactivo, intenta proporcionar un conjunto interesante de nombres más de lo que intenta suministrar un conjunto definido rigurosa o consistentemente de nombres y su comportamiento detallado puede cambiar entre versiones.
... pero podemos crear una aproximación cercana en Ruby. Hagamos un método que devuelva una lista ordenada de todos los métodos agregados a nuestro alcance por los módulos incluidos. Podemos obtener una lista de los módulos que se han incluido utilizando el método print
.
Al igual que Kernel
, queremos ignorar el " default " métodos (como false
), y también queremos centrarnos en " interesante " conjunto de nombres Por lo tanto, ignoraremos los métodos en methods()
, y solo devolveremos los métodos que se definieron directamente en los módulos, ignorando los métodos heredados. Podemos lograr lo siguiente pasando local_variables
al método included_methods
. Poniendo todo junto, obtenemos ...
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
Puede pasarle una clase, un objeto o nada (el valor predeterminado es el alcance actual). Probémoslo ...
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"]
<=> también incluye variables definidas localmente, y eso es fácil. Solo llama ...
local_variables
... desafortunadamente, no podemos simplemente agregar la llamada <=> a <=> porque nos daría las variables que son locales para el método <=>, y eso no sería muy útil. Entonces, si desea incluir variables locales con los métodos_incluidos, simplemente llame ...
(included_methods + local_variables).sort
Escribí una gema para eso:
$ 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
Estoy trabajando en una mejora de las opciones de paso y la configuración predeterminada, pero por ahora sugeriría que agregue lo siguiente a su archivo .irbrc:
require 'method_info'
MethodInfo::OptionHandler.default_options = {
:ancestors_to_exclude => [Object],
:enable_colors => true
}
Esto habilita los colores y oculta los métodos que tiene cada objeto, ya que generalmente no estás interesado en ellos.
¿Qué pasa con:
Object.constants.select{|x| eval(x.to_s).class == Class}
Eso enumera las clases disponibles para mí. No soy un experto en rubíes y me dejaron caer en una consola de rubíes sin tener idea de qué clases estaban disponibles. Ese trazador de líneas fue un comienzo.
Para acceder a todas las instancias de objetos en ruby, use ObjectSpace
http: //www.ruby-doc .org / core-1.8.7 / classes / ObjectSpace.html # M000928
Sin embargo, esto se considera lento (incluso para ruby), y puede que no esté habilitado en algunos intérpretes (por ejemplo, jRuby puede deshabilitar ObjectSpace ya que es mucho más rápido confiar en jvm para gc sin necesidad de rastrear estas cosas en jRuby).
Puede pasar los mensajes .methods a la biblioteca/módulo incluso antes de cargarlo, para ver todos los métodos disponibles.Haciendo self.methods
simplemente devuelve todos los métodos que contiene el objeto Object.Puedes ver esto haciendo self.class
.Entonces digamos que desea ver todos los métodos en el módulo Archivo.simplemente lo haces File.methods
y obtendrá una lista de todos los métodos que existen en el módulo Archivo.Quizás esto no sea lo que desea, pero debería ser algo útil.