Navigating through source code efficiently in Ruby - ruby-on-rails

I was trying to find the method being called when Item.where(dst: "video") is called (Item being a Mongoid model). Looking up in the source code, I see that criteria.rb is the place to go to. However, def where calls super. Then Origin::Selectable (included inside Origin::Queryable) defines it:
def where(criterion = nil)
criterion.is_a?(String) ? js_query(criterion) : expr_query(criterion)
end
Now, I would have to see where js_query and expr_query are, see what they do and so on.
It gets tough going through all this source code and modules, finding all the methods and then trying to figure out how it works.
Is there a better way to do this process to find out how things work?

You probably need to improve your editor experience. There are three remarkable abilities (besides many others like Eclipse/Aptana, NetBeans, etc):
RubyMine — not free, but probably the best one;
Atom Editor with RSense plugin — free (plugins are also available for SublimeText and TextMate2;
vim/emacs with [c|e]tags.
Depending on your choice you yield an ability to quickly navigate through your code with either Ctrl+Click or with your preferred keyboard shortcut.
Here on SO this question was asked an amount of times as well: https://stackoverflow.com/search?q=best+ruby+editor
Hope it helps.

If you know the class of the receiver (say A) and the method name (say foo), then you can do:
A.instance_method(:foo).source_location
That will give the file name and the line number in most cases. If it returns nil, then it is likely a C-defined method, which does not rely on other Ruby methods.
Another way is to use the pry gem or the method_source gem.

Related

How to make a custom method that can be used anywhere in rails app

I wish to make a custom method (e.g. def plus_two(x) x + 2 end and have it be accessible everywhere within the app - that is, accessible in the controller, model, console, views, tests, and any other .rb files. I currently have the same method defined in many areas of the app, and wish to make it DRY
How can this be achieved?
Note: I don't mind if calling the method requires prepending something (I have seen some answers where methods are prepended with :: or with a namespace, but otherwise have a preference to keep code succinct where possible
I have done some reading at similar questions (e.g. this one) but I can't quite get it
Reading the comments it seems like you are just looking for a clear and simple example of a method that is available everywhere in your application:
# in app/models/calculator.rb
module Calculator
def self.plus_two(x)
x + 2
end
end
Which can be called like this:
Calculator.plus_two(8)
#=> 10

Rails - Call a method form a model or helper with an alias

I have a helper called GlobalHelper.
There are a couple of constants (e.g. GLOBAL_URL) and methods (e.g. self.get_url) in it.
I'm trying to make an alias or an equivalent of the macros in C (#define URL) to access the constant and methods from any of my views and controllers easily.
For now I have to do it like this:
GlobalHelper.get_url(GlobalHelper::URL_TYPE_PAGE, ["page1"])
And I want to get rid of the GlobalHelper everywhere with alias/macro to get a code like this instead:
aliasmethod(aliasconstant, ["page1"])
How can I do that?
ruby is not c, so you should take a look how to write ideomatic ruby code before trying to bring such concepts into your project.
since i don't know what exactly your get_url method does, i can only give limited recommendations.
one thing that would probably result in much nicer code is using symbols instead of constants:
GlobalHelper.get_url(:page, ["page1"])
when using a Module instead of Class you can include it and call the method directly:
include GlobalHelper
get_url(...)
these are just examples of what could be done. not saying that this is better than explicitly calling GlobalHelper directly. nothing wrong with that at all.

How to analyze quickly the code definition from a given code

Let's say I'm in a really huge project and am curious how this line works:
authorize! :read_pipeline_schedule, user_project
authorize! is supposed to be method name. Is it a private function in the class, or DSL provided from a parent block, or including, or declared in a gem? Or maybe none of them?
I was using grep to find internal code and Google for external code such as gems, however I guess it's useful if I can see the call stack of the method. puts caller is printing from the place where I am although it can not be used for analyzing the above case.
I'd like to know the best practice.
You can grep your code and installed gems and, if name is unique enough, you'll quickly locate its definition and associated usages. However, if a name is a common one, like call, then this approach is useless.
Ruby is a dynamic language and, as such, is a nightmare for static analysis. You may guess where this comes from, but you just can't know for sure.
The only way to know is runtime introspection. So, in your example, put a breakpoint right before that line
binding.pry
authorize! :read_pipeline_schedule, user_project
You'll drop out to pry shell. Now you can do
show-source authorize!
And see where exactly this method is defined.
The easiest way is to ask the method itself:
method_object = method(:authorize!)
method_object.owner
# => returns module in which the method resides
method_object.source_location
# => returns file name and line number of source code where the method is defined
Note that source_location may return nil for methods which have no Ruby source code, e.g. dynamically generated methods or methods implemented in the interpreter internals (C functions in YARV, Java methods in JRuby, etc.)
I like caller(0), caller_locations, and the ever-incredible show-source

See where a symbol is defined in irb

I work on a pretty large rails project at work. Sometimes I need to hunt down class / constant definitions. Is there some built-in method in Ruby to do this for me? Example:
irb> SOME_CONSTANT.__file__
=> /some/path/to/a/file
This isn't exactly what you're looking for, but methods do have a .source_location method on them. You can use this to find out where a class is actually implemented. (Since ruby lets you reopen classes, this could be in multiple places)
for example, given an instance of an object, i:
i.methods.map do |method_name|
method_obj = i.method(method_name)
file, line = method_obj.source_location
file #map down to the file name
end.uniq
will give you a list of all the files where i's methods are implemented.
This will work for classes that have at least 1 method implemented in ruby. It won't work for constants, though.
At the very beginning before any file is loaded, insert a line that defines the class/constant that you want to check as something other than a module. For example, suppose you have class or other kind of constant A within your code, and want to know where it is defined. Then, at the very beginning of the main file, write
A = nil
Then, when the program is run, whenever it first meets the definition of class/constant A, it will show something like
some_path_to_a_file:line_number in `some_method': A is not a class (TypeError)
or
some_path_to_a_file:line_number: warning: already initialized constant A
Then, some_path_to_a_file:line_number will be the location where A is defined.
If you're using Ruby 1.9.2, #YenTheFirst's answer is correct: call #source_location on a Method object.
If you're using Ruby 1.8.7, then #source_location doesn't exist (yet). You'll need something like this implementation of a method. (There's another one or two floating around, but I can't find the other one real quick).

Rails organizing code

i happen to be kinda picky when programming something big. I try to find the best way to do it it terms of speed and complexity. Since i've been learning Rails the previous 3 months, i try to find the best techniques for everything. I would like to ask you how you would go about writing some code like this :
#defender = User.find_by_id(user_id)
#attacker = current_user.clone
#attacker_starting_attribs = current_user
#defender_starting_attribs = #defender.clone
#defenderWeapon = #defender.getEquippedWeapon
#attackerWeapon = #attacker.getEquippedWeapon
#combat = Combatant.fight(#attacker, #defender)
This code is about the battle outcome between two persons in a browser game. The code works well, but i've some problems in terms of good coding. In fact, i know that my code is bad here, that's why i ask you what a better version would be. Let me explain what happens in this code.
#defender is given by user_id, so i guess that this part is needed. Now, in #attacker i'm cloning the current_user. The reason is that Rails works on objects and current_user will be changed inside Combatant.fight. I need both the new hp and the old hp and that is why i'm cloning the object. The defender and attacker starting attribs illustrate that concept. Now, i get the weapons in instance variables, so that i can get their information inside the final view.
However, the weapons are needed inside the fight function and i execute the same getEquippedWeapon twice again inside fight(). I was not so comfortable with something like fight(#attacker, #defender, #attacker_weapon, #defender_weapon), but i don't also like the idea of repetition. So, i would like an opinion on that.
#combat is a hash containing the result of the combat. Fight happens and i get that hash back in the view.
I'm not pleased with my coding on that stage and i want your opinion. How would you do it ? Is there maybe a design pattern for that ? Please tell me your opinion.
Thanx :)
I'm finding it difficult to completely understand what you're trying to do. I get the gist of it though (2 people fighting). I won't be able to provide an answer yet, but hopefully this gets the ball rolling:
From the code you provided, #attacker_starting_attribs and #defender_starting_attribs aren't being used.
As far as "good techniques", I try to stay as OO as possible. Instead of
Combatant.fight(#attacker, #defender), I would do #attacker.fight(#defender)
As a ruby convention, method names are underscored. In your case, .get_equipped_weapon instead of .getEquippedWeapon, or even better .equipped_weapon.
Anyways, I bet if you provided more code, you'd get more answers.

Resources