How can I find a Ruby method dependencies? - ruby

Is there a way to get the list of methods that implement a Ruby method when this method is invoked?
For example:
def foo
puts "foo"
end
def foo2
foo
end
I want to know that when calling "foo2" it calls 1st "foo" and 2nd "puts" and the corresponding files these methods are defined into. (If "puts" calls other methods, I would like to know them too)
Is that possible? and if 'yes' how? I could say that my question is about finding the method dependencies.

You can sort of get this using set_trace_func, but since Ruby is dynamic you would also need test code to call the methods so that the call order is printed.
set_trace_func proc { |event, filename, line, id, binding, klass| puts "#{klass}##{id}" }
In Ruby 2.0, TracePoint is a superior alternative.

Static code analysis, especially one you'd like to perform (listing all methods called within a method), is very hard in ruby (close to impossible) because the language is dynamic and allows for very strong metaprogramming techniques. Even the parser itself doesn't know the methods required until it tries to execute the code.
Example: calling eval with code read from a file.

Related

Ruby: understanding data structure

Most of the Factorybot factories are like:
FactoryBot.define do
factory :product do
association :shop
title { 'Green t-shirt' }
price { 10.10 }
end
end
It seems that inside the ":product" block we are building a data structure, but it's not the typical hashmap, the "keys" are not declared through symbols and commas aren't used.
So my question is: what kind of data structure is this? and how it works?
How declaring "association" inside the block doesn't trigger a:
NameError: undefined local variable or method `association'
when this would happen on many other situations. Is there a subject in compsci related to this?
The block is not a data structure, it's code. association and friends are all method calls, probably being intercepted by method_missing. Here's an example using that same technique to build a regular hash:
class BlockHash < Hash
def method_missing(key, value=nil)
if value.nil?
return self[key]
else
self[key] = value
end
end
def initialize(&block)
self.instance_eval(&block)
end
end
With which you can do this:
h = BlockHash.new do
foo 'bar'
baz :zoo
end
h
#=> {:foo=>"bar", :baz=>:zoo}
h.foo
#=> "bar"
h.baz
#=> :zoo
I have not worked with FactoryBot so I'm going to make some assumptions based on other libraries I've worked with. Milage may vary.
The basics:
FactoryBot is a class (Obviously)
define is a static method in FactoryBot (I'm going to assume I still haven't lost you ;) ).
Define takes a block which is pretty standard stuff in ruby.
But here's where things get interesting.
Typically when a block is executed it has a closure relative to where it was declared. This can be changed in most languages but ruby makes it super easy. instance_eval(block) will do the trick. That means you can have access to methods in the block that weren't available outside the block.
factory on line 2 is just such a method. You didn't declare it, but the block it's running in isn't being executed with a standard scope. Instead your block is being immediately passed to FactoryBot which passes it to a inner class named DSL which instance_evals the block so its own factory method will be run.
line 3-5 don't work that way since you can have an arbitrary name there.
ruby has several ways to handle missing methods but the most straightforward is method_missing. method_missing is an overridable hook that any class can define that tells ruby what to do when somebody calls a method that doesn't exist.
Here it's checking to see if it can parse the name as an attribute name and use the parameters or block to define an attribute or declare an association. It sounds more complicated than it is. Typically in this situation I would use define_method, define_singleton_method, instance_variable_set etc... to dynamically create and control the underlying classes.
I hope that helps. You don't need to know this to use the library the developers made a domain specific language so people wouldn't have to think about this stuff, but stay curious and keep growing.

In a Ruby module, how do you test if a method exists in the context which use the module?

Some context
I'm playing with Ruby to deepen my knowledge and have fun while at the same time improving my knowledge of Esperanto with a just starting toy project called Ĝue. Basically, the aim is to use Ruby facilities to implement a DSL that matches Esperanto traits that I think interesting in the context of a programming language.
The actual problem
So a first trait I would like to implement is inflection of verbs, using infinitive in method declaration (ending with -i), and jussive (ending with -u) for call to the method.
A first working basic implementation is like that:
module Ĝue
def method_missing(igo, *args, &block)
case igo
when /u$/
celo = igo.to_s.sub(/u$/, 'i').to_s
send(celo)
else
super
end
end
end
And it works. Now the next step is to make it more resilient, because there is no guaranty that celo will exists when the module try to call it. That is, the module should implement the respond_to? method. Thus the question, how do the module know if the context where module was required include the corresponding infinitive method? Even after adding extend self at the beginning of the module, inside of the module methods.include? :testi still return false when tested with the following code, although the testu call works perfectly:
#!/usr/bin/env ruby
require './teke/ĝue.rb'
include Ĝue
def testi; puts 'testo!' ;end
testu
Note that the test is run directly into the main scope. I don't know if this makes any difference with using a dedicated class scope, I would guess that no, as to the best of my knowledge everything is an object in Ruby.
Found a working solution through In Ruby, how do I check if method "foo=()" is defined?
So in this case, this would be checkable through
eval("defined? #{celo}") == 'method'

Homebrew Formula Syntax

I'm having much trouble understanding the syntax of a Homebrew Formula.
Let's have a look at this example:
require "formula"
class Foo < Formula
url "http://example.com/foo-0.1.tar.gz"
homepage ""
sha1 "1234567890ABCDEF1234567890ABCDEF"
# depends_on "cmake" => :build
def install
system "./configure", "--prefix=#{prefix}", "--disable-debug", "--disable-dependency-tracking"
# system "cmake", ".", *std_cmake_args
system "make install"
end
end
What exactly does the following syntax means?
url "http://example.com/foo-0.1.tar.gz"
Is it some kind of a variable assignment? Construction of a url object?
I'm sorry but after passing over a whole Ruby tutorial, I still didn't understand it.
Also, please try to explain what this syntax is:
system "make install"
From what I have searched, Ruby doesn't have such method (or at least it doesn't call the system() method like this).
You'll find that these are calls to methods of the Formula class that Foo derives from (Foo < Formula). For example, the system method that's confusing you is just a method being called in Formula. Have a look in Formula.rb and you'll find most of your answers.
Homebrew is a complex program, with its functionality well-separated across different objects, as you'd expect. You may therefore need to trace some of the calls into other objects. For example, while Formula does have a url method, and that's what the url like you ask about is calling, you'll find that call is passed to a SoftwareSpec object, which then stores it in a Resource instance variable as well as adding it to the dependency collector.
Also, please try to explain what this syntax is:
system "make install"
From what I have searched, Ruby doesn't have such method (or at least
it doesn't call the system() method like this).
Ruby does in fact have a system() method, and it is called exactly like that, see here:
http://www.ruby-doc.org/core-2.1.2/Kernel.html
For instance, run this program:
system "ls *"
However, in ruby if a method does not have an explicit receiver, then ruby implicitly uses whatever object is self to call the method, i.e. self.system(...).
Inside a class, but outside any defs, self is the class:
class Dog
p self #=>Dog
end
And inside an instance method:
class Dog
def bark
p self
puts 'woof'
end
end
d = Dog.new
d.bark
--output:--
#<Dog:0x00000100a40280>
woof
self is the Dog instance that called the method, d in this case. Those hieroglyphics are what ruby uses to denote a instance of a class.
Whenever you see a method call without an explicit receiver, such as
system "./configure", "--prefix=#{prefix}", "--disable-debug", "--disable-dependency-tracking"
it's good practice to say to yourself, self.system(...) Which object is self? Your code boils down to this:
class Foo < Formula
def install
system(...)
end
end
self.system(..) Which object is self? self will be the instance of Foo that calls the install() method. I would immediately assume that the system() call finds ruby's system() method--and the only way that wouldn't happen is if the Formula class defines a method named system(), and as Matt Gibson astutely checked, Formula does define a system() method.
What exactly does the following syntax means?
url "http://example.com/foo-0.1.tar.gz"
Ruby translates that to:
self.url(""http://example.com/foo-0.1.tar.gz")

Why is 'super' a keyword rather than a method in Ruby?

In Ruby, super is a keyword rather than a method.
Why was it designed this way?
Ruby's design tends toward implementing as much as possible as methods; keywords are usually reserved for language features that have their own grammar rules. super, however, looks and acts like a method call.
(I know it would be cumbersome to implement super in pure Ruby, since it would have to parse the method name out of caller, or use a trace_func. This alone wouldn't prevent it from being a method, because plenty of Kernel's methods are not implemented in pure Ruby.)
It behaves a little differently, in that if you don't pass arguments, all of the current arguments (and block, if present) are passed along... I'm not sure how that would work as a method.
To give a rather contrived example:
class A
def example(a, b, c)
yield whatever(a, b) + c
end
end
class B < A
def example(a, b, c)
super * 2
end
end
I did not need to handle the yield, or pass the arguments to super. In the cases where you specifically want to pass different arguments, then it behaves more like a method call. If you want to pass no arguments at all, you must pass empty parentheses (super()).
It simply doesn't have quite the same behaviour as a method call.
super doesn't automatically call the parent class's method. If you imagine the inheritance hierarchy of a ruby class as a list, with the class at the bottom and Object at the top, when ruby sees the the super keyword, rather than just check the the parent class, it moves up the entire list until it finds the first item that has a method defined with that name.
I'm careful to say item because it could also be a module. When you include a module in to a class, it is wrapped in an anonymous superclass and put above your class in the list I talked about before, so that means if you had a method defined for your class that was also defined in the module, then calling super from the class's implementation would call the module's implementation, and not the parent class's:
class Foo
def f
puts "Foo"
end
end
module Bar
def f
puts "Bar"
super
end
end
class Foobar < Foo
include Bar
def f
puts "Foobar"
super
end
end
foobar = Foobar.new
foobar.f
# =>
# Foobar
# Bar
# Foo
And I don't believe that it is possible to access this 'inheritance list' from the ruby environment itself, which would mean this functionality would not be available (However useful it is; I'm not every sure if this was an intended feature.)
Hm, good qustion. I'm not sure how else (besides using super) you would you reference the super version of a given method.
You can't simply call the method by name, because the way that polymorphism works (how it figures out which version of that method to actually call, based on the object class) would cause your method to call itself, spinning into an infinite set of calls, and resulting in a stack overflow.

method_missing in "Programming Ruby" over my head

method_missing
*obj.method_missing( symbol h , args i ) → other_obj
Invoked by Ruby when obj is sent a
message it cannot handle. symbol is
the symbol for the method called, and
args are any arguments that were
passed to it. The example below
creates a class Roman, which responds
to methods with names consisting of
roman numerals, returning the
corresponding integer values. A more
typical use of method_missing is to
implement proxies, delegators, and
forwarders.
class Roman
def roman_to_int(str)
# ...
end
def method_missing(method_id)
str = method_id.id2name
roman_to_int(str)
end
end
r = Roman.new
r.iv ! 4
r.xxiii ! 23
r.mm ! 2000
I just heard about method-missing and went to find out more in Programming Ruby but the above explanation quoted from the book is over my head. Does anyone have an easier explanation? More specifically, is method-missing only used by the interpreter or is there ever a need to call it directly in a program (assuming I'm just writing web apps, as opposed to writing code for NASA)?
It's probably best to not think of ruby as having methods. When you call a ruby "method" you are actually sending a message to that instance (or class) and if you have defined a handler for the message, it is used to process and return a value.
So method_missing is a special definition that gets called whenever ruby cannot find an apropriate handler. You could also think of it like a * method.
Ruby doesn't have any type enforcement, and likewise doesn't do any checking as to what methods an object has when the script is first parsed, because this can be dynamically changed as the application runs.
What method_missing does, is let you intercept and handle calls to methods that don't exist for a given object. This provides the under-the-hood power behind pretty much every DSL (domain-specific language) written in Ruby.
In the case of the example, every one of 'r.iv', 'r.mm', and so on is actually a method call to the Roman object. Of course, it doesn't have an 'iv' or an 'mm' method, so instead control is passed to method_missing, which gets the name of the method that was called, as well as whatever arguments were passed.
method_missing then converts the method name from a symbol to a string, and parses it as a Roman number, returning the output as an integer.
It's basically a catch-all for messages that don't match up to any methods. It's used extensively in active record for dynamic finders. It's what lets you write something like this:
SomeModel.find_by_name_and_number(a_name, a_number)
The Model doesn't contain code for that find_by, so method_missing is called which looks at is says - I recognize that format, and carries it out. If it doesn't, then you get a method not found error.
In the Roman example you provide it illustrates how you can extend the functionality of a class without explicitly defining methods.
r.iv is not a method so method_missing catches it and calls roman_to_int on the method id "iv"
It's also useful when you want to handle unrecognized methods elsewhere, like proxies, delegators, and forwarders, as the documentation states.
You do not call "method_missing" (the interpreter calls it). Rather, you define it (override it) for a class which you want to make to be more flexible. As mentioned in other comments, the interpreter will call your version of method_missing when the class (or instance) does not ("explicitly"?) define the requested method. This gives you a chance to make something up, based on the ersatz method/message name.
Have you ever done any "reflection" programming in Java? Using this method would be as if the class to be accessed via reflection could look at the string (excuse me, "symbol") of the method name if a no-such-method exception was thrown, and then make something up as that method's implementation on the fly.
Dynamic programming is kind of a "one-up" on reflection.
Since you mention web apps I'll guess that you are familiar with Ruby on Rails. A good example of how method_missing can be used is the different find_by_<whatever> methods that's available. None of those methods actually exist! They are synthesized during run time. All of this magic happens because of how ruby intercepts invocations of non-existing methods.
You can read more about that and other uses of method_missing here.
ActiveRecord uses method_missing to define find_by methods. But since, method_missing is basically a last resort method, this can be a serious performance bottleneck. What I discovered is that ActiveRecord does some further awesome metaprogramming by defining the new finder method as a class method !! Thus, any further calls to the same finder method would not hit the method_missing because it is now a class method. For details about the actual code snippet from base.rb, click here.

Resources