Come elenchi gli oggetti attualmente disponibili nell'ambito corrente in Ruby?
-
04-07-2019 - |
Domanda
Sono nuovo a Ruby e sto giocando con l'IRB.
Ho scoperto che posso elencare i metodi di un oggetto usando il metodo ".methods" e che self.methods mi dà quello che voglio (simile al metodo dir( di Pythonbuiltin)?), ma come posso trovare i metodi di una libreria/modulo che ho caricato tramite include e 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>
Sono abituato a Python, dove utilizzo la funzione dir() per ottenere la stessa cosa:
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>>
Soluzione
ObjectSpace.each_object potrebbe essere ciò che che stai cercando.
Per ottenere un elenco di moduli inclusi è possibile utilizzare Module.included_modules .
Puoi anche verificare se un oggetto risponde a un metodo caso per caso usando object.respond_to? .
Altri suggerimenti
Non sono del tutto sicuro di cosa intendi per "oggetti attuali". Puoi iterare su ObjectSpace, come è già stato menzionato. Ma qui ci sono alcuni altri metodi.
local_variables
instance_variables
global_variables
class_variables
constants
C'è un gotcha. Devono essere chiamati negli ambiti giusti. Quindi, proprio in IRB, o in un'istanza di oggetto o nell'ambito della classe (quindi praticamente ovunque) puoi chiamare i primi 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", ...]
Ma umm, cosa succede se si desidera che il programma li valuti effettivamente senza che sia necessario digitarli manualmente? Il trucco è eval.
eval "@inst_var" #=> 42
global_variables.each do |v|
puts eval(v)
end
Gli ultimi 2 dei 5 citati all'inizio devono essere valutati a livello di modulo (una classe è un discendente di un modulo, quindi funziona).
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"
Ecco alcuni altri trucchi da esplorare in diverse direzioni
"".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...", ...]
Il metodo dir()
è non chiaramente definito ...
Nota: poiché
included_modules
è fornito principalmente come comodità per l'uso su un prompt interattivo, tenta di farlo fornire un insieme interessante di nomi più di quanto cerchi di fornire a set rigorosamente o coerentemente definito di nomi e il suo comportamento dettagliato può cambiare tra le versioni.
... ma possiamo creare una stretta approssimazione in Ruby. Facciamo un metodo che restituirà un elenco ordinato di tutti i metodi aggiunti al nostro ambito dai moduli inclusi. È possibile ottenere un elenco dei moduli che sono stati inclusi utilizzando il metodo print
.
Come Kernel
, vogliamo ignorare " default " metodi (come false
) e vogliamo anche concentrarci sul " interessante " insieme di nomi. Pertanto, ignoreremo i metodi in methods()
e restituiremo solo i metodi definiti direttamente nei moduli, ignorando i metodi ereditati. Possiamo realizzare il successivo passando local_variables
nel metodo included_methods
. Mettendo tutto insieme otteniamo ...
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
Puoi passargli una classe, un oggetto o niente (il valore predefinito è l'ambito corrente). Proviamolo ...
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"]
<=> include anche variabili definite localmente, ed è facile. Chiama ...
local_variables
... sfortunatamente, non possiamo semplicemente aggiungere la <=> chiamata a <=> perché ci darebbe le variabili locali al metodo <=> e non sarebbe molto utile. Quindi, se vuoi che le variabili locali siano incluse con i metodi inclusi, chiama ...
(included_methods + local_variables).sort
Ho scritto una gemma per questo:
$ 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
Sto lavorando per migliorare le opzioni di passaggio e le impostazioni predefinite delle impostazioni, ma per ora ti suggerisco di aggiungere quanto segue al tuo file .irbrc:
require 'method_info'
MethodInfo::OptionHandler.default_options = {
:ancestors_to_exclude => [Object],
:enable_colors => true
}
Questo abilita i colori e nasconde i metodi che ogni oggetto ha, dal momento che di solito non ti interessano.
Che dire di:
Object.constants.select{|x| eval(x.to_s).class == Class}
Questo elenca le classi disponibili per me. Non sono un esperto di rubini e venivo lasciato cadere su una consolle di rubini senza avere idea di quali fossero le lezioni a portata di mano. Quella linea era un inizio.
Per accedere a tutte le istanze degli oggetti in Ruby usi ObjectSpace
http://www.ruby-doc.org/core-1.8.7/classes/ObjectSpace.html#M000928
Tuttavia, questo è considerato lento (anche per Ruby) e potrebbe non essere abilitato in alcuni interpreti (ad es.jRuby può disabilitare ObjectSpace poiché è molto più veloce facendo affidamento su jvm per gc senza dover tenere traccia di queste cose in jRuby).
È possibile passare i messaggi .methods alla libreria / al modulo anche prima di caricarlo, per vedere tutti i metodi disponibili. Fare self.methods
restituisce semplicemente tutti i metodi che contiene l'oggetto Object. Puoi vederlo facendo self.class
. Quindi supponiamo che tu voglia vedere tutti i metodi nel modulo File. Fai semplicemente File.methods
e otterrai un elenco di tutti i metodi esistenti nel modulo File. Questo, forse, non è quello che vuoi, ma dovrebbe essere in qualche modo utile.