I'm learning ruby, I come up on something that I don't understand. I know that modules in ruby are used for namespacing with :: (or .) and mixing with include directive.
The problem comes when I group some methods inside a module, without putting them inside a class.
Here's an example:
module Familiar
#this will not work
def ask_age
return "How old are you?"
end
#this will work
def Familiar::greeting
return "What's up?"
end
end
# this call returns **NoMethodError**
puts(Familiar::ask_age())
# this call works fine
puts(Familiar::greeting())
Why do I need to include the namespace to define the method, I'm already inside the namespace Familiar why do I have to repeat my self and put Familiar::greeting
You can test my example online following this link: http://codepad.org/VUgCVPXN
The Ruby documentation on Module answers this in its introduction text.
This form:
module Familiar
def ask_age
return "How old are you?"
end
end
defines #ask_age as an instance method on Familiar. However, you can't instantiate Modules, so you can't get to their instance methods directly; you mix them into other classes. Instance methods in modules are more or less unreachable directly.
This form, by comparison:
module Familiar
def self.ask_age
return "What's up?"
end
end
defines ::ask_age as a module function. It is directly callable, and does not appear on included classes when the module is mixed into another class.
Related
I've come from using Python and I'm very confused as to how the "magic" of Ruby on Rails works.
1. There are no require statements anywhere
In Python, in order to access functions from anywhere, you must import. I assume it's the same for base ruby. But when using rails, I can call hidden variables and functions, defined in other modules, without any require statements on the top of the page.
E.g. I can have a file as such:
class CartsController < ApplicationController
....
def show
begin
#cart = Cart.find(params[:id])
rescue ActiveRecord::RecordNotFound
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to store_url, notice: 'Invalid cart'
end
end
Where logger, redirect, and the such are all not defined. Does it simply inherit from ApplicationController up some convoluted tree, or does it somehow access those namespaces through other mechanisms?
2. Using methods that don't exist
This is valid rails code
current_item = line_items.find_by_product_id(product_id)
where find_by_products_id has not been defined anywhere and yet, Rails somehow dynamically "creates" the method on the fly. Any technical insight on how this is done?
Thanks for your help!
Rails' "Magic" makes extensive use of method_missing and const_missing.
When you try and call a method that is not defined, ruby fires a call to method_missing.
This is used by libraries like ActiveRecord to implement dynamic finders.
method_missing example:
SomeModel.find_by_some_field("some_value") is not defined.
This calls SomeModel.method_missing(:find_by_some_field, "some_value").
ActiveRecord then translates this call to `SomeModel.where(:some_field => "some_value")
(for performance purposes, ActiveRecord then dynamically defines this method, so next time find_by_some_field is defined)
const_missing example:
SomeModel has not yet been required.
The Ruby interpreter calls const_missing with the param "SomeModel"
Rails follows the convention "SomeModel" should be defined in a file called some_model.rb so const_missing just tries require "some_model".
Ok. You asked a lot of questions in one. It will be hard to explain all ruby and rails magic in one answer but I'll try to give you some useful resources where you can find some answers.
1) About require statements. If you are new to ruby and rails it will be hard to understand how rails application is initialized. Here is a tutorial were you can some useful information:
http://guides.rubyonrails.org/initialization.html
If you need more information about particular method you can always look into documentation. For example redirect_to method info:
http://apidock.com/rails/ActionController/Base/redirect_to
2) About "Using methods that don't exist". This is one of the most beautiful feature of ruby language called metaprogramming. This is also advanced topic. Here are some useful resources:
http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Pros/dp/1934356476
Ruby metaprogramming online tutorial
http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/
http://rubylearning.com/blog/2010/11/23/dont-know-metaprogramming-in-ruby/
Since neither of the existing answers mention it: yes, things like redirect_to are inherited by way of ApplicationController. In this particular case, redirect_to is defined in the module ActionController::Redirecting, which is included in ActionController::Base (from which ApplicationController inherits).
I am using a plugin in Rails, and I call its methods without problems:
plugin_module::class_inside_module.method_a(...)
I want to re-open the class_inside_module and add a new method, I tried in many different ways. I can't figure out why in this way doesn't work:
class plugin_module::class_inside_module
def new_method
puts 'new method'
end
end
I get the error: uninitialized constant plugin_module, but how is possible if I can call without problem plugin_module::class_inside_module.any_methods ?
Do you know why I get that error ? why "uninitialized constant" ? (it is a class declaration :-O )
Do you have any ideas how I can add a new methods in a class inside a module (that is part of a plugin) ?
Thank you,
Alessandro
If you have written your class and module-names like you did, so plugin_module instead of PluginModule this is against ruby/rails standards, and rails will not be able to automatically find the class and module.
If you write something like
module MyModule
class MyClass
end
end
Rails will expect this file to be located in lib\my_module\my_class.
But this can always easily be overwritten by explicitly doing a require.
So in your case, when you write
module plugin_module::class_inside_module
Rails will not know where to find the module plugin_module.
This way of writing only works if module plugin_module is previously defined (and loaded).
So either add the correct require, or rename your modules to standard rails naming, or write it as follows:
module plugin_module
class class_inside_module
This way will also work, because now the order no longer matters.
If the module is not known yet, this will define the module as well.
Either you are re-opening the class, or you define it first (and the actual definition will actually reopen it).
Hope this helps.
Have you tried reopening the module that's wrapping the class, rather than relying on ::?
module plugin_module
class class_inside_module
def new_method
puts 'new_method'
end
end
end
By the way, you know that the proper name for modules and classes is use CamelCase with a capital first letter?
module PluginModule
class ClassInsideModule
def new_method
puts 'new_method'
end
end
end
I am just getting started with Ruby on Rails. Coming from the Java world, one thing that I am wondering is how do Ruby/Rails developers find out where methods are actually defined.
I am used to just clicking on the method in Eclipse to find where is is defined even in third party libraries (supposing I have the source code).
A concrete example: I am trying to find out how the Authlogic gem apparently changes the constructor of my User class to require an additional parameter (called :password_confirmation) even though the User class doesn't even inherit from anything related to Authlogic.
Probably I am just overlooking something really obvious here (or maybe I still can't wrap my head around the whole "convention over configuration" thing ;-))
It's slightly difficult to quickly find the method location for dynamic languages like Ruby.
You can use object.methods or object.instance_methods to quickly find out the methods.
If you are using Ruby 1.9, you can do something like this:
object.method(:method_name).source_location
For more information on source_location - click here
The Pry gem is designed precisely for this kind of explorative use-case.
Pry is an interactive shell that lets you navigate your way around a program's source-code using shell-like commands such as cd and ls.
You can pull the documentation for any method you encounter and even view the source code, including the native C code in some cases (with the pry-doc plugin). You can even jump directly to the file/line where a particular method is defined with the edit-method command. The show-method and show-doc commands also display the precise location of the method they're acting on.
Watch the railscast screencast for more information.
Here are some examples below:
pry(main)> show-doc OpenStruct#initialize
From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/ostruct.rb # line 46:
Number of lines: 11
visibility: private
signature: initialize(hash=?)
Create a new OpenStruct object. The optional hash, if given, will
generate attributes and values. For example.
require 'ostruct'
hash = { "country" => "Australia", :population => 20_000_000 }
data = OpenStruct.new(hash)
p data # -> <OpenStruct country="Australia" population=20000000>
By default, the resulting OpenStruct object will have no attributes.
pry(main)>
You can also look up sourcecode with the show-method command:
pry(main)> show-method OpenStruct#initialize
From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/ostruct.rb # line 46:
Number of lines: 9
def initialize(hash=nil)
#table = {}
if hash
for k,v in hash
#table[k.to_sym] = v
new_ostruct_member(k)
end
end
end
pry(main)>
See http://pry.github.com for more information :)
None of people advising Pry gem mentionned the method called find-method, which is probably what author was looking for.
Here's the example:
pry(main)> find-method current_user
Devise::Controllers::Helpers
Devise::Controllers::Helpers#current_user
WebsocketRails::ConnectionAdapters::Base
WebsocketRails::ConnectionAdapters::Base#current_user_responds_to?
Then, you can browse the method code by following #banister's tips.
You could use something like pry. See its railscast also.
There are several ways to change an existing class. E.g. if you want to modify the String class write:
class String
def my_custom_method
puts "hello!"
end
end
But there are other options like mixing in modules or adding/modifying methods by using meta-programming.
Anyhow, having some object you can always:
puts obj.methods.inspect
Either do it in your code or use the debugger.
The other option is to read the code. In particular you should read the gem's unit tests (./spec, ...). There are quite a lot of authors stating that unit tests make documentation obsolete.
In Ruby you can also add both class and instance methods to a given class by using mixins.
Essentially if you have a module you can add its methods to a given class using both include and extend class methods. A brief example on how those works is the following
Module A
def foo
"foo"
end
end
Module B
def bar
"bar"
end
end
Class YourClass
include A
extend B
end
p YourClass.new.foo # gives "foo" because the foo method is added as instance method
p YourClass.bar # gives "baz" because the bar method is added as class method
Because Ruby is a dynamic language, these statements can be used everywhere. So to come to your question there is no need to extend an authlogic class to get its methods. Many plugins uses this instruction when loaded
ActiveRecord::Base.send :include, ModuleName
In this way they tell to every AR object to include some plugin defined module and you get all the methods in AR objects.
Another technique used by many acts_as plugins is to include their modules only when the acts_as call is used in the base class.
Other useful references
What is the difference between include and extend in Ruby?
A quick tutorial about mixins
I am using Ruby on Rails 3 and and I am trying to implement a new plugin. In order to learn, I am viewing inside and I am studying some popular plugins.
What I choosed is WillPaginate and in a its file there is something like this:
module WillPaginate
class << self
...
end
end
if defined? Rails
WillPaginate.enable_activerecord if defined? ActiveRecord
WillPaginate.enable_actionpack if defined? ActionController
end
I would like to know
Why the if defined? Rails statement is outside the module statement? When will be run istructions inside that?
What means and how can\should I use class << self?
module WillPaginate defines Ruby name scope and groups these methods so they can be later included with one call into some class. The if defined? Rails is outside the module because the code inside that if might include the whole module into some ActiveRecord class. And the if is executed exactly at the time when will_paginate.rb file is loaded.
All methods in that block are class methods. So later it is possible to make calls like YourModelClass.foo.
The if defined? Rails block is evaluated at load time, ie during require 'will_paginate'. That allows will_paginate to be used with or without Rails.
The class << self section is a way to define a group of methods on the WillPaginate module without having to define them all as def self.method_name. Either way works (except for a few edge cases I can't remember now), so it's mostly just a style choice.
I'm trying to add a function that will be accessible throughout all parts of my program. I want something like:
def GlobalFunctions.my_function(x,y)
puts x + y
end
to be accessible for all models. Specifically I am trying to use a function like this in my seeds.rb file but I am most likely going to be reusing the code and don't want any redundancy. Now I know I can make a simple class, but I could also make a module. What are some reasons to go in either direction? And once I've decided on which type to use, how do I make it accessible throughout the whole program?
I have tried a module, but I keep getting " Expected app/[module file] to define [ModuleName]"
You'd define a class for something you'll want to make instances of. In this case, a module would probably be better, as modules basically just group code together:
module GlobalFunctions
def self.my_function(x,y)
puts x+y
end
end
GlobalFunctions.my_function(4,5) # => 9
Alternatively, you could define it on Kernel, and then just call it anywhere. Kernel is where methods like puts are defined.
def Kernel.my_function(x,y)
puts x + y
end
my_function(4,5) # => 9
Adding methods to Kernel (answer from PreciousBodilyFluids) is usually considered a bad smell and can lead to some really hard to find bugs in large projects.
It's much more accepted to relevantly namespace the code and put in to /lib/.
class Formatting
def self.bold(str)
return "<strong>#{str}</strong>"
end
end
You can then:
require 'formatting'
puts Formatting.bold("text")
or
require 'formatting'
include Formatting
puts bold("text")
It'll be clear to anyone who comes to the code later what you're using too. If you're using Rails you won't need the require.
PreciousBodilyFluids is correct, and if this GlobalFunctions is part of a RoR project, you may want to name the file global_functions.rb and place it in the lib/ directory to help you avoid the error message you posted at the end of your question.