How to Introspect Things in Ruby

How do I introspect things in Ruby?

Sure, it's even simpler than in Python. Depending on what information you're looking for, try:

obj.methods

and if you want just the methods defined for obj (as opposed to getting methods on Object as well)

obj.methods - Object.methods

Also interesting is doing stuff like:

obj.methods.grep /to_/

To get instance variables, do this:

obj.instance_variables

and for class variables:

obj.class_variables

Ruby method introspection

There is an established format for these things. You can modify the following to meet your needs.

class Object
def argument_count m; method(m).arity end
def argument_names m; method(m).parameters end
end

Greeter.argument_count(:greet) # => -2
Greeter.argument_names(:greet) # => [[:req, :name], [:opt, :weekday]]

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

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?.

How do I inspect the methods of a Ruby object?

methods takes an optional boolean parameter, which specifies whether to also list the methods from the object's class and its superclasses or just the object's singleton methods. So you can do obj.methods(false) to only get the singleton methods defined on obj.

If you want the methods defined by the object's class, but not those defined by its superclasses, you can get that by calling instance_methods(false) on the object's class, so it's obj.class.instance_methods(false).

Ruby: Get list of different properties between objects

needs some tweaking, but here's the basic idea:

module CompareIV
def compare(other)
h = {}
self.instance_variables.each do |iv|
print iv
a, b = self.instance_variable_get(iv), other.instance_variable_get(iv)
h[iv] = b if a != b
end
return h
end
end

class A
include CompareIV
attr_accessor :foo, :bar, :baz

def initialize(foo, bar, baz)
@foo = foo
@bar = bar
@baz = baz
end
end

a = A.new(foo = 1, bar = 2, baz = 3)
b = A.new(foo = 1, bar = 3, baz = 4)

p a.compare(b)

A better way to introspect a capture

A better way to introspect ...

In general, a better way to do anything in any programming language is to not introspect if you can avoid it.

In general, in Raku, you can avoid manual introspection. See the section Introspection toward the end of this answer for further discussion.

... a capture

The best tool for getting the functionality that introspection of a capture provides is to use a signature. That's their main purpose in life.

I want to test the type of the first object in a signature

Use signatures:

proto handle(|) {*}
multi handle( Pod $node ) { ... }
multi handle( Str $string ) { ... }
multi handle( Nil ) { ... }

The following shows some ways I have found that work.

While they do what you want, they are essentially ignoring all of Raku's signature features. They reduce the signature to just a binding to the capture as a single structure; and then use manual introspection of that capture in the routine's body.

There's almost always a simpler and better way to do such things using signatures.

why does [|c[0].WHAT ~~ Rat, with c[0] == 3/2] not work?

I'll simplify first, then end up with what your code is doing:

say    3/2        ~~ Rat;  # True
say (3/2) ~~ Rat; # True
say (3/2).WHAT ~~ Rat; # True
say |((3/2).WHAT ~~ Rat); # True
say (|(3/2).WHAT) ~~ Rat; # False
say |(3/2).WHAT ~~ Rat; # False

The last case is because | has a higher precedence than ~~.

Is there a better way than stringifying and testing for the string equivalent of the Type?

OMG yes.

Use the types, Luke.

(And in your use case, do so using signatures.)

Introspection

Compared to code that manually introspects incoming data in the body of a routine, appropriate use of signatures will typically:

  • Read better;

  • Generate better low-level code;

  • Be partially or fully evaluated during the compile phase.

If a language and its compiler have addressed a use case by providing a particular feature, such as signatures, then using that feature instead of introspection will generally lead to the above three benefits.

Languages/compilers can be broken into four categories, namely those that:

  1. Do not do or allow any introspection;

  2. Allow the compiler to introspect, but not devs;

  3. Allow both the compiler and devs to introspect, but aim to make it a last resort, at least for devs;

  4. Enable and encourage devs to introspect.

Raku(do) are in the third category. In the context of this SO, signatures are the primary feature that all but eliminates any need for a dev to manually introspect.

Fastest/One-liner way to list attr_accessors in Ruby?

There is no way (one-liner or otherwise) to list all methods defined by attr_accessor and only methods defined by attr_accessor without defining your own attr_accessor.

Here's a solution that overrides attr_accessor in MyBaseClass to remember which methods have been created using attr_accessor:

class MyBaseClass
def self.attr_accessor(*vars)
@attributes ||= []
@attributes.concat vars
super(*vars)
end

def self.attributes
@attributes
end

def attributes
self.class.attributes
end
end

class SubClass < MyBaseClass
attr_accessor :id, :title, :body
end

SubClass.new.attributes.inspect #=> [:id, :title, :body]

How to get activerecord associations via reflection

Model.reflections gives information about a model's associations. It is a Hash keyed on the association name. e.g.

Post.reflections.keys # => ["comments"]

Here is an example of some of the information it can be used to access:

Post.reflections["comments"].table_name # => "comments"
Post.reflections["comments"].macro # => :has_many
Post.reflections["comments"].foreign_key # => "message_id"

Note: this answer has been updated to cover Rails 4.2 based on MCB's answer and the comments below. In earlier versions of Rails the reflection's foreign_key was accessed using primary_key_name instead, and the keys for the reflections may be symbols instead of strings depending on how the association was defined e.g. :comments instead of "comments".



Related Topics



Leave a reply



Submit