Sinatra defines a number of methods which appear to live in the current scope, i.e. not within a class declaration. These are defined in the Sinatra gem.
I'd like to be able to write a gem which will create a function which I can call from the global scope, e.g
add_blog(:my_blog)
This would then call the function my_blog in the global scope.
Obviously I could monkeypatch the Object class in the gem with the add_blog function, but this seems like overkill as it would extend every object.
TL;DR extend-ing a module at the top level adds its methods to the top level without adding them to every object.
There are three ways to do this:
Option 1: Write a top-level method in your gem
#my_gem.rb
def add_blog(blog_name)
puts "Adding blog #{blog_name}..."
end
#some_app.rb
require 'my_gem' #Assume your gem is in $LOAD_PATH
add_blog 'Super simple blog!'
This will work, but it's not the neatest way of doing it: it's impossible to require your gem without adding the method to the top level. Some users may want to use your gem without this.
Ideally we'd have some way of making it available in a scoped way OR at the top level, according to the user's preference. To do that, we'll define your method(s) within a module:
#my_gem.rb
module MyGem
#We will add methods in this module to the top-level scope
module TopLevel
def self.add_blog(blog_name)
puts "Adding blog #{blog_name}..."
end
end
#We could also add other, non-top-level methods or classes here
end
Now our code is nicely scoped. The question is how do we make it accessible from the top level, so we don't always need to call MyGem::TopLevel.add_blog ?
Let's look at what the top level in Ruby actually means. Ruby is a highly object oriented language. That means, amongst other things, that all methods are bound to an object. When you call an apparently global method like puts or require, you're actually calling a method on a "default" object called main.
Therefore if we want to add a method to the top-level scope we need to add it to main. There are a couple of ways we could do this.
Option 2: Adding methods to Object
main is an instance of the class Object. If we add the methods from our module to Object (the monkey patch the OP referred to), we'll be able to use them from main and therefore the top level. We can do that by using our module as a mixin:
#my_gem.rb
module MyGem
module TopLevel
def self.add_blog
#...
end
end
end
class Object
include MyGem::TopLevel
end
We can now call add_blog from the top level. However, this also isn't a perfect solution (as the OP points out), because we haven't just added our new methods to main, we've added them to every instance of Object! Unfortunately almost everything in Ruby is a descendant of Object, so we've just made it possible to call add_blog on anything! For example, 1.add_blog("what does it mean to add a blog to a number?!") .
This is clearly undesirable, but conceptually pretty close to what we want. Let's refine it so we can add methods to main only.
Option 3: Adding methods to main only
So if include adds the methods from a module into a class, could we call it directly on main? Remember if a method is called without an explicit receiver ("owning object"), it will be called on main.
#app.rb
require 'my_gem'
include MyGem::TopLevel
add_blog "it works!"
Looks promising, but still not perfect - it turns out that include adds methods to the receiver's class, not just the receiver, so we'd still be able to do strange things like 1.add_blog("still not a good thing!") .
So, to fix that, we need a method that will add methods to the receiving object only, not its class. extend is that method.
This version will add our gem's methods to the top-level scope without messing with other objects:
#app.rb
require 'my_gem'
extend MyGem::TopLevel
add_blog "it works!"
1.add_blog "this will throw an exception!"
Excellent! The last stage is to set up our Gem so that a user can have our top-level methods added to main without having to call extend themselves. We should also provide a way for users to use our methods in a fully scoped way.
#my_gem/core.rb
module MyGem
module TopLevel
def self.add_blog...
end
end
#my_gem.rb
require './my_gem/core.rb'
extend MyGem::TopLevel
That way users can have your methods automatically added to the top level:
require 'my_gem'
add_blog "Super simple!"
Or can choose to access the methods in a scoped way:
require 'my_gem/core'
MyGem::TopLevel.add_blog "More typing, but more structure"
Ruby acheives this through a bit of magic called the eigenclass. Each Ruby object, as well as being an instance of a class, has a special class of its own - its eigenclass. We're actually using extend to add the MyGem::TopLevel methods to main's eigenclass.
This is the solution I would use. It's also the pattern that Sinatra uses. Sinatra applies it in a slightly more complex way, but it's essentially the same:
When you call
require 'sinatra'
sinatra.rb is effectively prepended to your script. That file calls
require sinatra/main
sinatra/main.rb calls
extend Sinatra::Delegator
Sinatra::Delegator is the equivalent of the MyGem::TopLevel module I described above - it causes main to know about Sinatra-specific methods.
Here's where Delgator differs slightly - instead of adding its methods to main directly, Delegator causes main to pass specific methods on to a designated target class - in this case, Sinatra::Application.
You can see this for yourself in the Sinatra code. A search through sinatra/base.rb shows that, when the Delegator module is extended or included, the calling scope (the "main" object in this case) will delegate the following methods to Sinatra::Application:
:get, :patch, :put, :post, :delete, :head, :options, :link, :unlink,
:template, :layout, :before, :after, :error, :not_found, :configure,
:set, :mime_type, :enable, :disable, :use, :development?, :test?,
:production?, :helpers, :settings, :register
Related
I have a Ruby module in a file called my_module.rb:
module My_module
def my_module_method
puts 'inside my method'
end
end
In a file my_class.rb in the same folder, I have a class contained within the module.
module My_module
class My_class
def my_object_method
My_module.my_module_method
end
end
end
My_module::My_class.new.my_object_method => 'undefined method 'my_module_method''
I was not expecting this error. I assumed that Ruby would run into the line 'My_module.my_module_method' and search for a module called 'My_module' and a method within it called 'my_module_method.' This is what Java does, for example. However, Ruby does not do this. In order to get my_object_method to work, I have to write in my_class.rb:
require 'my_module.rb'
Why doesn't Ruby search for My_module when I call my_object_method? It seems obvious what it should search for and therefore redundant to require the programmer to explicitly write 'yes, Ruby, please allow me to make calls to module-wide methods.' What am I missing?
Ruby doesn't automatically load files. If you need a code from some file, you have to load it (by calling require) explicitly.
Thus, when you run "ruby my_class.rb" it loads only this file and you have to define dependencies between files by yourself.
You seem to have a misunderstanding of how to define a class method. In order to make your method call work, you could define it as def self.my_method_name.
In both classes and modules, methods work the same when you define them as class methods using self. or alternatively the class << self syntax. However instance methods (methods without the self.) work differently in these 2 cases. In classes, as you seem to understand, they're accessible once you instantiate the class using .new. In modules, they're only accessible if you include or extend.
See also:
difference between class method , instance method , instance variable , class variable?
http://www.rortuts.com/ruby/ruby-include-vs-extend/
Oh any by the way. Ruby doesn't enforce any convention where you have 1 file per class (named identically). You need to manually require files wherever you need them. Although there are some frameworks such as Rails which auto-require files, and enforce naming conventions.
All over the Internet, I see people using "include" to bring new functionality to the main scope.
Most recenty, I saw this in an SO answer:
require 'fileutils' #I know, no underscore is not ruby-like
include FileUtils
# Gives you access (without prepending by 'FileUtils.') to
cd(dir, options)
cd(dir, options) {|dir| .... }
pwd()
Extend works too, but from my understanding, ONLY extend should work. I don't even know why the main object has the include functionality.
Inside the main scope:
self.class == Object #true
Object.new.include #NoMethodError: undefined method `include' for #<Object:0x000000022c66c0>
An I mean logically, since self.is_a?(Module) == false when inside the main scope, main shouldn't even have the include functionality, since include is used to add methods to child instances and main isn't a class or a module so there are no child instances to speak of.
My question is, why does include work in the main scope, what was the design decision that led to making it work there, and lastly, shouldn't we prefer "extend" in that case so as to not make the "extend/include" functionality even more confusing than it already may be thanks to people often using ruby hooks to invoke the other when one is called.
The main scope is "special". Instance methods defined at the main scope become private instance methods of Object, constants become constants of Object, and include includes into Object. There's probably other things I'm missing. (E.g. presumably, prepend prepends to Object, I never thought about it until now.)
From the Module
Module#append_features(mod) → mod => When this module is included in another, Ruby calls append_features in this module, passing it the receiving module in mod. Ruby’s default implementation is to add the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors.
Module#prepend_features(mod) → mod => When this module is prepended in another, Ruby calls prepend_features in this module, passing it the receiving module in mod. Ruby’s default implementation is to overlay the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors.
Can anyone help me to understand the below questions:
What more features of Module are defined as append and prepend except those default?
How they differ functionally?
When to use append_features and when prepend_features?
what is the difference between two bold lines as above?
What features of Module are defined as append and prepend?
As specified in the text you quoted:
the constants, methods, and module variables
How they differ functionally?
Both add methods of the mixed-in module to the passed module (class). The difference is in the lookup order of these methods, in case that the target class already has them defined:
include behaves as if the target class inherited mixed-in module:
module FooBar
def say
puts "2 - Module"
end
end
class Foo
include FooBar
def say
puts "1 - Implementing Class"
super
end
end
Foo.new.say # =>
# 1 - Implementing Class
# 2 - Module
prepend makes the methods from the mixed in module "stronger" and executes them first:
module FooBar
def say
puts "2 - Module"
super
end
end
class Foo
prepend FooBar
def say
puts "1 - Implementing Class"
end
end
Foo.new.say # =>
# 2 - Module
# 1 - Implementing Class
The example kindly ripped off from here: http://blog.crowdint.com/2012/11/05/3-killer-features-that-are-coming-on-ruby-2-0.html
When to use append_features and when prepend_features?
Use prepend when you want to keep methods of the target module (class) at the end of the method lookup chain.
Some real-world examples can be found by searching SO for ruby, module and prepend:
Overriding method by another defined in module
When monkey patching a method, can you call the overridden method from the new implementation?
Ruby: Module, Mixins and Blocks confusing?
(Note: I am mentioning only methods, as they are easiest to picture when it comes to inheritance and mixing-in, but the same applies to other features.)
I thought to add it as a comment to a good answer which #Mladen Jablanovic has already made but I couldn't due to my low reputation point.
I've found a more concise, clearer and more descriptive answer on a post here - Ruby modules: Include vs Prepend vs Extend and I post it here just in case someone needs it and could get it with less effort.
Direct quotes:
Though include is the most common way of importing external code into a class, Ruby provides also two other ways to achieve that: extend and prepend. However, they don’t have the same behavior at all, and these differences are often misunderstood by Ruby developers.
To understand how to use them, we must first have a deeper look into how Ruby is resolving methods to execute at runtime, using something called the ancestors chain.
When a Ruby class is created, it holds a list of constant names which are its ancestors. They are all the classes that the class inherits from, and the modules they include. For example, by calling ancestors on the String class, we get the list of its ancestors:
String.ancestors
=> [String, Comparable, Object, PP::ObjectMixin, Kernel, BasicObject]
include is the most used and the simplest way of importing module code. When calling it in a class definition, Ruby will insert the module into the ancestors chain of the class, just after its superclass.
Available since Ruby 2, prepend is a bit less known to Rubyists than its two other friends. It actually works like include, except that instead of inserting the module between the class and its superclass in the chain, it will insert it at the bottom of the chain, even before the class itself.
I would suggest reading the post to get a better understanding as it comes with examples.
RSpec adds a "describe" method do the top-level namespace. However, instead of simply defining the method outside of any classes/modules, they do this:
# code from rspec-core/lib/rspec/core/dsl.rb
module RSpec
module Core
# Adds the `describe` method to the top-level namespace.
module DSL
def describe(*args, &example_group_block)
RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
end
end
end
end
extend RSpec::Core::DSL
Module.send(:include, RSpec::Core::DSL)
What is the benefit of using this technique as opposed to simply defining describe outside any modules and classes? (From what I can tell, the DSL module isn't used anywhere else in rspec-core.)
I made this change a few months ago so that describe is no longer added to every object in the system. If you defined it at the top level:
def describe(*args)
end
...then every object in the system would have a private describe method. RSpec does not own every object in the system and should not be adding describe willy-nilly to every object. We only want the describe method available in two scopes:
describe MyClass do
end
(at the top-level, off of the main object)
module MyModule
describe MyClass do
end
end
(off of any module, so you nest your describes in a module scope)
Putting it in a module makes it easy to extend onto the main object (to add it to only that object, and not every object) and include it in Module (to add it to all modules).
Actually, if that's all there is in the code, I don't really believe it to be much better — if at all. A common argument is that you can easily check that RSpec is responsible for addinng this method in the global namespace by checking the method owner. Somehow it never felt this was needed, as the location of the method already stores that information.
Defining the method outside of any scope would have be equivalent to defining a private instance method in Object:
class Object
private
def double(arg)
arg * 2
end
end
double(3) # OK
3.double(3) # Error: double is private
self.double(3) # Error: double is private
I think privateness is a useful aspect, because it prevents from making certain method calls that have no meaning, that the code shown in the question lacks.
There's an advantge to defining the method in a module, though, but the RSpec code doesn't seem to make use of it: using module_function, not only do you preserve privateness of the instance method, but you also get a public class method. This means that if you have an instance method of the same name, you will still be able to refer to the one defined by the module, by using the class method version.
A common example of module_function is the Kernel module, which contains most function-like core methods like puts (another one is Math). If you're in a class that redefines puts, you can still use Kernel#puts explicitly if you need:
class LikeAnIO
def puts(string)
#output << string
end
def do_work
puts "foo" # inserts "foo" in #output
Kernel.puts "foo" # inserts "foo" in $stdout
end
end
I'm writing a small gem, and I want to define a DSL-like method, pretty much the same as the desc and task methods in Rake.
Rake defines them as private methods in the Rake::DSL module and then
self.extend Rake::DSL
to mix the module into the main object? (I'm a newbie and go ahead laugh if I'm wrong)
what are the benefits by doing so? is it because making these methods private can prevent any other objects to use them (that is, to prevent something like some_obj.desc) ?
what if I define the methods in Kernel
module Kernel
private
include Rake::DSL
end
Is there any difference?
If you define private method in Kernel module it will be available in the whole project. You will also rewrite desc method that project use to define rake task. But if you write your methods in your submodule and then extend it in superclass or some module - you can easily write any kind of DSL lang like you might saw in Rake or RSpec.
P.S. Making methods private prevents other moludes or classes (but not subclasses) to use them (but not owerwrite) - I mean module nesting hierarchy.
Just to extend the answer given by bor1s, about the private methods:
In ruby you have "private" and "protected" methods. What bor1s says, is correct when talking about "protected" methods. Declaring a method "private" additionally prevents other instances of the same class from using the method.
When you call a "private" method, you cannot use a dot in front of it - you cannot even use self., even though using or omitting self has usually the same effect.
class Xyzzy
private
def foo
puts "Foo called"
end
public
def do_it
foo # <= Is OK
self.foo # <= raises NoMethodError
end
end
Xyzzy.new.do_it
If you change 'private' to 'protected' in the code above, no error will be raised.
And about modules:
The final result of defining a method in Kernel and extending Kernel with the method defined in some module is the same: in both cases the method is global.
Using a module is just a little more elegant, as it groups your changes in one place, but I would say it's a matter of personal taste.
Usually you do not include methods in Kernel or Object (as it may be a little dangerous), but you include (or extend) a specific class or object which needs these methods, and in this case you need your methods grouped in a module.
Even Rake in version 0.9.0 stopped including the DSL commands in Object:
== Version 0.9.0
Incompatible *change*: Rake DSL commands ('task', 'file', etc.) are
no longer private methods in Object. If you need to call 'task :xzy' inside
your class, include Rake::DSL into the class. The DSL is still available at
the top level scope (via the top level object which extends Rake::DSL).