Is it possible to use methods defined in refinements in Sinatra views? - ruby

I have a class defined in a gem to which I am adding some methods via refinements (in Ruby 2.3.0). This class turns up in some Sinatra views (haml).
When I refer to these extra methods in a helper, there is not a problem. But in the view, I get an Undefined Method error.
Am I missing a trick, or is it that the using ... statement would need to go somewhere I just can't get to?
(Workaround: I can define helper methods to return the method on the object. But if I wanted to do that then I wouldn't have used refinements...)

The scope of refinement is determined lexically. Unless you rewrite the method inside haml that calls that method so that it becomes within the scope of the using command, you cannot use refinements. But I guess haml is internally using eval or something like that to evaluate the code you write in a haml file. In that case, it is impossible.

Related

How to get the method which is handling a method call

I have an app which uses Ruby 1.8. 6 in a Rails 2.2.2 app.
It has many definitions of the method url_for in various parts of the code base (classes, modules etc).
When debugging, I'd like to see in the log which method handles a specific call to url_for. E.g.,
foo = "bar"
baz = url_for(foo)
#would like to log the location of the url_for method which actually
#handled the call, here.
It's fine if the only way to do this is to raise an exception inside url_for and look at the stack trace, eg
baz = url_for(something_which_wont_raise_here_but_will_raise_inside_the_url_for_method)
To go further, what if the method is being called on an instance of a (heavily patched) class:
foo = #baz.bar("qux")
EDIT: I didn't specify that it was Ruby 1.8.6 in my question, and it looks like i can't use the .source_location method. Very sorry about not specifying the version earlier! Does anyone have any other ideas?
It sounds like you want to do
method(:url_for)
to get a Method object, and then use source_location to find out where it was defined
You can use method and source_location methods chain to get the location of the method definition.
For example:
If you do:
method(:url_for).owner
It will give you the module/class in which the method is defined. This should be enough to let you identify the method (unless the same method is redundantly defined in the same module multiple times). You can then look at the definition of url_for in that module/class.

Ruby method overriding in rails app

I got a few Classes that include the same module, I want to override one of the methods of the module in one place in my code.
How to do this?
I tried
module [Module_name]
def [method_to_override]
and add it to the autoload path of rails but no success
If you are using the module as a mixin, you can redefine the method in your class. The method defined at the class level will take precedence when called. The module as a mixin simply behaves as a superclass in this case.
If you are using the module as a namespace, I am not sure that there's a way to dynamically redefine the code as you are attempting to do. Perhaps opening the namespaced module in-place and including the new code for the method will work. I haven't tried this before.
Some reference material

Is this ruby metaprogramming abuse?

I am new to Ruby, and have a gem that I am making to interact with a JSONRPC API and basically all calls and responses are similar enough, that every API call can be handled with one function, like:
Module::api_command('APINamespace.NamespaceMethod')
but I would like to also (for convenience sake) be able to do:
Module::APINamespace.NamespaceMethod
Is there any reason not to do this by using Module.const_missing to return a dummy class that has a method_missing which will allow passing the call from Module::APINamespace.NamespaceMethod to Module::api_command('APINamespace.NamespaceMethod')
Is there a more elegant or civilized way to do this?
Yes, I'm sorry, but to my mind that hack is ridiculous. :)
First of all, i'm assuming that your api_command method is actually invoking methods on the APINamespace module, as implied by this line: Module::api_command('APINamespace.NamespaceMethod')
Given the above, why not just set a constant equal to APINamespace in your module?
MyModule::APINamespace = ::APINamespace
MyModule::APINamespace.NamespaceMethod()
UPDATE:
I'm still not entirely understanding your situation, but perhaps this:
module MyModule
def self.const_missing(c)
Object.const_get(c)
end
end
Now you can invoke any top-level constant as if it was defined on your module; say there was a module called StrangeAPI at top-level, if you use the hack above, you can now invoke its methods as follows:
MyModule::StrangeAPI.Blah()
Is this what you want?

Ruby style of accessing of elements of modules and classes

module Hints
module Designer
def self.message
"Hello, World!"
end
end
end
is there any way to use the following code to access the message method?
p Hints.Designer.message
Instead of
p Hints::Designer.message
The period . is only meant for accessing methods.
The double colon :: is used to indicate namespaces.
Both modules and classes can be nested in each other. This creates a namespace for the nested class. (Technically, Module is an instance of Class.) Thus, the following is correct no matter if Hints or Designer are a class or a module.
Hints::Designer.message
You can try yourself by opening irb on the command line. Hints.Designer.message says NoMethodError: undefined method 'Designer' for Hints:Module.
Update (as I am not allowed to comment...):
While many things in Ruby can be overwritten ("monkey patched"), basic operators cannot. :: is a basic language feature that is and should not be customizable (in order to prevent a big mess ;)).
You can use dot to access the message method, but you can't use it to access Designer module, because Designer it is not a method (but a constant). Dot is for invoking methods only.

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