Why do people use `Module.send(:prepend, …)`? - ruby

I'm learning how to use Module.prepend instead of alias_method_chain in my Ruby code, and I've noticed that some people use send to call it (example):
ActionView::TemplateRenderer.send(:prepend,
ActionViewTemplateRendererWithCurrentTemplate)
While others call it directly (example):
ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)
And, although I haven't seen anyone use this style, I suspect from the documentation that you could even write this in the module you're prepending from:
module ActionViewTemplateRendererWithCurrentTemplate
# Methods you're overriding go here
prepend_features ActionView::TemplateRenderer
end
Is there some difference between these three styles? Is there a reason to favor one over the others?

Module#prepend was added to Ruby version 2.0.0.
It was originally added as a private method, with the intended use case being in the following format:
module Foo
# ...
end
class Bar
prepend Foo
# ... The rest of the class definition ...
end
However, it soon became apparent that in many cases people wanted to prepend a module to a class without defining any other aspects of the class (in that section of code). Hence, the following pattern became common:
Bar.send(:prepend, Foo)
In Ruby version 2.1.0, this issue was addressed by making Module#prepend a public method - so you can now simply write this as:
Bar.prepend(Foo)
However, note that if you are writing a library that is required to support Ruby 2.0.0 (even though official support ended on 24th Feb 2016), then you must unfortunately stick to the old .send(:prepend, ...) approach.
Module#include (which has been in the Ruby language since its inception) was also a private method in version <= 2.0.0, and was made public in 2.1.0.

Related

Organizing monkey patches

I read a blog post that recommends namespacing your monkey patches so they can be easily viewed and included.
For example:
module CoreExtensions
module DateTime
module BusinessDays
def weekday?
!sunday? && !saturday?
end
end
end
end
Would go in the: lib/core_extensions/class_name/group.rb file.
It can be included in the DateTime class with the Module#include instance method (which a class inherits because a Class is a Module)
# Actually monkey-patch DateTime
DateTime.include CoreExtensions::DateTime::BusinessDays
My question is where do the include statements go? Is there a convention?
For example:
I have the following monkey patches:
# http://www.justinweiss.com/articles/3-ways-to-monkey-patch-without-making-a-mess/
module CoreExtensions
module String
module Cases
def snakecase
return self if self !~ /[A-Z]+.*/
# http://rubular.com/r/afGWPWLRBB
underscored = gsub(/(.)([A-Z])/, '\1_\2')
underscored.downcase
end
def camelcase
return self if self !~ /_/ && self =~ /[A-Z]+.*/
split('_').map{ |e| e.capitalize }.join
end
end
end
end
That live inside the lib/core_extensions/string/cases.rb file.
Where should I put my String.include CoreExtensions::String::Cases statement?
Also to be clear this is just a ruby project, does that make a difference?
I've tried putting it inside lib/devify.rb
require 'devify/version'
require 'devify/some_dir'
require 'devify/scaffold'
require 'devify/tree_cloner'
require 'devify/renderer'
require 'devify/project'
require 'devify/tasks/some_task'
require 'devify/tasks/bootstrap'
require 'core_extensions/string/cases'
module Devify
String.include CoreExtensions::String::Cases
end
This works and it makes sense why it works. It's because my entire app lives inside the Devify module or namespace.
This way is also good because I'm not polluting the global namespace correct? Because I'm only monkey patching Strings that live inside Devify?
Just not sure not if this is the right way to go about it.
It doesn't matter where you put the include call.
Calling String.include will always monkey patch the one String class that is used by all the strings in the entire object space. So best put the instruction at the top level as to not mislead readers of the code.
Monkey patching is always global.
It is a powerful feature and can be used for good.
If you are authoring a gem be aware that you're sharing a global namespace with others. The same is also true for top-level modules and even the gem name though. Shared namespaces are just a reality of shared code.
If you are looking for lexically scoped monkey patches look into the new refinement feature that was introduce with Ruby 2.
Refinements are an idea taken from Smalltalk's class boxes. Refinements are not without their own issues though, for example they lack support for introspection and reflection. Thus essentially making them stealth and unfit for production use.
If you are looking to limit the monkey patches to some string object only, consider either subclassing String or calling extend on an instance.
Although ruby offers many ways of changing the content of a class or a method dynamically, the monkey patching can lead to big problems and strange bugs. I read this post (http://www.virtuouscode.com/2008/02/23/why-monkeypatching-is-destroying-ruby/) about why it´s a bad idea to use monkey-patching.
In summary, many things that he says make sense. When you create a monkey-patching, you are assuming that it will only works at that project, and, maybe you can create collisions and unprevisible side-effects when more libraries with similar purposes are put together.
There are cases where the benefits of the monkey-patching were awesome, like ActiveSupport way of dealing with dates manipulation by monkey-patching the Fixnum class with the ago or from_now methods, or as the method to_json. However, monkey patching should be avoided.
The point is: Ruby is an object-oriented language, and you can achieve your objectives using object composition, or any other patterns. Monkey-patching, at some way, leads you in the opposite direction of object oriented philosophy, since you add more responsibilities to an pre-existent class and increases it's public interface to serve a new funcionallity.
Besides, it's not explicit the behavior of that class and the public methods available. You cannot know, by looking at the class definition, what it makes and what is it's role at the system, and how it interact with other objects. It makes a simple task much more harder at the end.
Monkey patching makes everything much more smaller and simpler, apparently, but avoiding it makes your code much more maintanable, easier to debug, read and test, and much more elegant, since it is compliant to the "OOP" patterns.

How come every class in Ruby inherits from Object?

How come every class in Ruby inherits from Object even though you never have to specify that behavior?
You would expect something like:
class Foo < Object; end
but
class Foo; end
is enough. How does Ruby do this internally?
The question of how Ruby does this internally is not entirely meaningful since the specific mechanism is intentionally undocumented and could change with later releases despite the language spec staying the same. Additionally, there are many Ruby interpreters out there, and they could all implement this behavior differently.
For MRI, if you look at the source for Class.new you'll see that if there are no arguments it sets the super to Object:
if (argc == 0) {
super = rb_cObject;
}
rb_define_class from the C API works similarly (by passing NULL to rb_define_class_id):
if (!super) super = rb_cObject;
I have no idea which code path class Foo; end ends up taking, but it doesn't really matter.
Internally, when you define a class like this:
class Foo < Bar; end
Ruby (at least the MRI and Rubinius versions) calls a C method, very similar to this:
rb_define_class( "Foo", parent_class );
where parent_class is set to point to Bar (I don't know much about the C code that finds Bar from the bare name you specified, but that is not relevant to your question).
When you write
class Foo; end
Then the value of parent_class used is rb_cObject, which is pre-defined in the core of Ruby, and this reference is also attached to the Object constant, so it will find the same Ruby value if you specify class Foo < Object
Ultimately, this is just a standard defaulting mechanism, same as you might implement in a method definition. It is all defined in a similar way to using default values of any other parameter, just the syntax used to express it is different; deciding whether to use the default or accept your choice of base class is handled by the Ruby parser.
If you want to learn more about internals of Ruby - at least MRI Ruby and Rubinius - at this level, you could start with learning about C native extensions. This PDF covers the basics very well. The internal structure of MRI Ruby is actually a large and quite "flat" C API, which is relatively easy to code if you know only a little C. Rubinius is a bit different, but still presents the same API for compatibility with native extensions.
This is by design of the language, vide ri Object:
Object is the default root of all Ruby objects. Object inherits from
BasicObject which allows creating alternate object hierarchies. Methods on
object are available to all classes unless explicitly overridden.

Subclassing a Java class in JRuby, with Generics information

I'm trying to create an actor, using the newest Akka version (2.3.2 right now) using JRuby. Problem is, I keep getting the error:
Java::JavaLang::IllegalArgumentException: erased Creator types are unsupported, use Props.create(actorClass, creator) instead
Basically, I'm following the code here on Akka Documentation
I cannot create a akka.japi.Creator, because this requires Generic information, and these are erased at run-time (and JRuby is basically a run-time-everywhere). What I already tried:
class GreetingActor < UntypedActor
def onReceive(message)
if (message.is_a? Greeting)
puts("Hello " + message.who)
end
end
end
system = ActorSystem.create("MySystem")
greeter = system.actorOf(Props.create(GreetingActor))
The last line fails with erased Creator types are unsupported. I tried to wrap it under a akka.japi.Creator, but with the same error (as Creator needs generics information, and JRuby doesn't provide it). I've tried to use "become_java!" on GreetingActor, but it returns nil (JRuby can't create new java classes from Ruby classes if the Ruby class extends from a Java class).
Is there a way to declare the Creator passing generics information?
I was trying to do the same thing and while I don't have an answer to the title's question I do have an answer for getting the example working. You have to use a different means of constructing the Props instance.
You need to use a factory:
java_import 'akka.actor.UntypedActorFactory'
class GreetingActorFactory
include UntypedActorFactory
def create
GreetingActor.new
end
end
Then you can use it as follows:
system = ActorSystem.create("GreetingSystem")
props = Props.create(GreetingActorFactory.new)
greeter = system.actorOf(props, "greeter")
greeter.tell(Greeting.new("John Weathers"), nil)
Hopefully, this helps you get further along!
I've already solved the Akka problem using the following gist: https://gist.github.com/mauricioszabo/6a713fd416c512e49f70
Still, the JRuby implementation may fail on other libraries that depends on not-erased types, but for now, I can work around in Akka using the code above.

Monkey patching built-in ruby classes in limited scopes

I'm working on an internal Ruby DSL and to make it look as pretty as possible I need to monkey patch the Symbol class and add some operators. I want to be responsible in how I do this and would like to limit the scope and lifetime of the patches to a specific block of code. Is there a standard pattern for doing this? Here's some pseudo-code to show what I'm thinking:
class SomeContext
def self.monkey_patch_region(&block)
context = SomeContext.new
context.monkey_patch_Symbol
context.instance_eval(&block)
context.unmonkey_patch_Symbol
end
# magical method
def monkey_patch_Symbol
#...
end
# another magical method
def unmonkey_patch_Symbol
#...
end
end
I believe, that you're looking for ruby refinements. The feature has landed in ruby trunk, but it might be reverted before 2.0
I've heard about mixology gem. It was designed to mixin and unmix modules. Maybe it can be useful to monkey and unmonkey patches.
UPDATE: mixology won't help you, as it (un)mixes modules to objects (as with extend), not to classes (as with include), and you want monkey/unmonkey core classes, not their objects individually. Anyway I intend to maintain this answer as possibly useful reference for someone else.

Is it possible to namespace methods added to existing classes in Ruby?

I'm writing some code in which I'd like to add some methods to a predefined class, like so:
class Model # this class already exists
def my_method
# code here
end
end
Is there any way to namespace this, using Modules or otherwise?
There will be a mechanism to do this in Ruby 2.0, although it is not exactly clear what exactly that mechanism is going to be. For the past almost 10 years, the frontrunner seemed to be Selector Namespaces, but recently Classboxes and even more recently, Refinements have taken the lead. In fact, if I am not mistaken, Refinements are actually currently implemented in the YARV trunk.
With all currently existing versions (including the soon to be released 1.9.3), however, there is no way to do this.
That's one of the reasons why monkey patching should generally be avoided.
Just write your methods inside a Module and include it in Model:
module SomeModule
def my_method
end
end
class Model
include SomeModule
end

Resources