I'm a Java-developer toying with Ruby, and loving it. I have understood that because of Ruby's metaprogramming facilities my unit-tests become much cleaner and I don't need nasty mocking frameworks. I have a class which needs the File class's services and in my test I don't want to touch my real filesystem. In Java I would use some virtual file system for easier "seams" to pass fake-objects in but in Ruby that's obviously overkill. What I come up seems already really nice compared to the Java-world. In my class under test I have an optional constructor parameter:
def initialize(file_class=File)
When I need to open files within my class, I can then do this:
#file_class.open(filename)
And the call goes to either the real File-class, or in case of my unit-test, it goes to a fake-class which doesn't touch the filesystem. I know there must be a better way to do this with metaprogramming?
Mocha (http://mocha.rubyforge.org/) is a very good mocking library for ruby. Depending on what you're actually wanting to test (i.e. if you want to just fake out the File.new call to avoid the file system dependency or if you want to verify that the correct arguments are passed into File.new) you could do something like this:
require 'mocha'
mock_file_obj = mock("My Mock File") do
stubs(:some_instance_method).returns("foo")
end
File.stubs(:new).with(is_a(String)).returns(mock_file_obj)
In the case you've outlined, I'd suggest that what you're doing seems fine. I know that it's a technique that James Mead (the author of Mocha) has advocated. There's no need to do metaprogramming just for the sake of it. Here's what James has to say about it (and a long list of other techniques you could try)
This is a particularly difficult challenge for me. With the help I received on this question, and some extra work on my behalf, here's the solution I arrived at.
# lib/real_thing.rb
class RealThing
def initialize a, b, c
# ...
end
end
# test/test_real_thing.rb
class TestRealThing < MiniTest::Unit::TestCase
class Fake < RealThing; end
def test_real_thing_initializer
fake = mock()
Fake.expects(:new).with(1, 2, 3).returns(fake)
assert_equal fake, Fake.new(1, 2, 3)
end
end
Related
Some context
I'm playing with Ruby to deepen my knowledge and have fun while at the same time improving my knowledge of Esperanto with a just starting toy project called Ĝue. Basically, the aim is to use Ruby facilities to implement a DSL that matches Esperanto traits that I think interesting in the context of a programming language.
The actual problem
So a first trait I would like to implement is inflection of verbs, using infinitive in method declaration (ending with -i), and jussive (ending with -u) for call to the method.
A first working basic implementation is like that:
module Ĝue
def method_missing(igo, *args, &block)
case igo
when /u$/
celo = igo.to_s.sub(/u$/, 'i').to_s
send(celo)
else
super
end
end
end
And it works. Now the next step is to make it more resilient, because there is no guaranty that celo will exists when the module try to call it. That is, the module should implement the respond_to? method. Thus the question, how do the module know if the context where module was required include the corresponding infinitive method? Even after adding extend self at the beginning of the module, inside of the module methods.include? :testi still return false when tested with the following code, although the testu call works perfectly:
#!/usr/bin/env ruby
require './teke/ĝue.rb'
include Ĝue
def testi; puts 'testo!' ;end
testu
Note that the test is run directly into the main scope. I don't know if this makes any difference with using a dedicated class scope, I would guess that no, as to the best of my knowledge everything is an object in Ruby.
Found a working solution through In Ruby, how do I check if method "foo=()" is defined?
So in this case, this would be checkable through
eval("defined? #{celo}") == 'method'
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.
I am working through Learn Ruby The Hard Way and came across something intriguing in exercise 49.
In parser.rb I have a function named skip(word_list, word_type) at the top level, which is used to skip through unrequited words (such as stop words) in user input. It is not encapsulated in a class or module. As per the exercise I have to write a unit test for the parser.
This is my code for the Unit Tests:
require "./lib/ex48/parser"
require "minitest/autorun"
class TestGame < Minitest::Test
def test_skip()
word_list = [['stop', 'from'], ['stop', 'the'], ['noun', 'west']]
assert_equal(skip(word_list, 'stop'), nil)
assert_equal(skip([['noun', 'bear'], ['verb', 'eat'], ['noun', 'honey']], 'noun'), nil)
end
end
However, when I run rake test TESTOPTS="-v" from the command line, these particular tests are skipped. This seems to be because there is a clash with the skip method in the Minitest module because they run perfectly after I change the name to skip_words.
Can someone please explain what is going on here exactly?
"Top level functions" are actually methods too, in particular they are private instance methods on Object (there's some funkiness around the main object but that's not important here)
However minitest's Test class also has a skip method and since the individual tests are instance methods on a subclass of Test you end up calling that skip instead.
There's not a very simple way of dealing with this - unlike some languages there is no easy way of saying that you want to call a particular superclass' implementation of something
Other than renaming your method, you'll have to pick an alternative way of calling it eg:
Object.new.send(:skip, list, type)
Object.instance_method(:skip).bind(self).call(list, type)
Of course you can wrap this in a helper method for your test or even redefine skip for this particular Test subclass (although that might lead to some head scratching the day someone tries to call minitest's skip.
I have a question similar to this one. I'm writing an app that has an addon system. There's an Addon mixin module, which detects when it's included and registers the new addon automatically:
module Addon
def self.included(receiver)
addon = receiver.new # Create an instance of the addon
(snip) # Other stuff to register the addon
addon.on_register # Tell the instance it was registered
end
end
Here is an example of how the mixin would be used:
class MyAddon
def on_register
puts "My addon was registered"
end
include Addon # ** note that this is at the end of the class **
end
As noted above, this implementation requires that the include be at the bottom of the class. Otherwise on_register isn't defined at the time that self.included gets called.
My concern is that an addon developer might accidentally put the include at the top, causing the addon not to work. Or that there might be a derived class or something that would extend the MyAddon class after it was already included.
Is there a better way to go about this?
After distilling the other answers and some other info I found, I wanted to document the answer that ended up working for me.
As this question explains, you can't detect at include() time when a class is "done" being defined. So, relying on the 'included' callback to create the objects was not a very robust solution.
The solution instead was to discover all of the addons and instantiate them after everything had been loaded. The only constraint placed on addon developers was that their code had to share a common top-level module namespace.
I still don't know if this is the best way to do it, but it definitely works better than what I started with.
Here is the code that searches the module for addons. It starts at a passed-in namespace and searches recursively for classes that include the addon class:
def find_and_instantiate(mod, addons)
consts = mod.constants
consts.each do |c|
sym = mod.const_get(c)
if (sym.class == Module)
find_and_instantiate(sym, addons)
else
if (sym.class == Class && sym.include?(Addon))
addons << sym.new(#container)
end
end
end
end
The best I can come up with is to notify the user of your module that it needs to be included after the #on_register method has been declared:
module Addon
def self.included(receiver)
raise "include #{self.name} after the #on_register method is defined" unless receiver.method_defined? :on_register
receiver.new.send(:on_register)
end
end
This is less than ideal but it will prevent aggravating mistakes until you discover a better way of doing this.
Sorry, but I have to hand this to you. So you want to hear your code is clever, pal. Yes, it is, it is too clever. But if you want to be concerned about other developers, you will have to stop being clever and start being normal.
Ruby is an OO language. The basis of OOP is that I define my object structure and their methods first, and then, when everything is defined, I instantiate my world ideally with a single call MyApp.new. That way, it does not matter what I have defined first. 'include' calls serve to establish the module inheritance hierarchy, nothing else.
But no, you do not want to do OOP. You want to abuse the included hook and instantiate receiver (!) in it, and call its instance methods. That's what they call obfuscated code. In other words, you go from OOP back to the old good goto style directive programming. Ruby allows you to obfuscate, not to limit your abilities, but with great power great responsibility, you yourself must exercise moderation.
You will yoursef have to refactor your code to make it normal. We cannot do that for you, because we don't know what do you want to achieve. Who knows, maybe you idea is worthy of a genius. Too bad we don't know it from your question. Some addon system you have. I'm asking you: Do you need it? Isn't good old mixin system good enough for you? Are you sure you are not programming Java in Ruby? And, then, is your app going to be greater than Rails? If yes, go ahead with the addon system. If not – stop playing around and invest your time in writing the algos that actually do what your app is suppose to do rather than creating inextricable addon systems in advance. If you are working in a company - which I doubt - make sure you let your boss read this.
In ruby, I understand that module functions can be made available without mixing in the module by using module_function as shown here. I can see how this is useful so you can use the function without mixing in the module.
module MyModule
def do_something
puts "hello world"
end
module_function :do_something
end
My question is though why you might want to have the function defined both of these ways.
Why not just have
def MyModule.do_something
OR
def do_something
In what kind of cases would it be useful to have the function available to be mixed in, or to be used as a static method?
Think of Enumerable.
This is the perfect example of when you need to include it in a module. If your class defines #each, you get a lot of goodness just by including a module (#map, #select, etc.). This is the only case when I use modules as mixins - when the module provides functionality in terms of a few methods, defined in the class you include the module it. I can argue that this should be the only case in general.
As for defining "static" methods, a better approach would be:
module MyModule
def self.do_something
end
end
You don't really need to call #module_function. I think it is just weird legacy stuff.
You can even do this:
module MyModule
extend self
def do_something
end
end
...but it won't work well if you also want to include the module somewhere. I suggest avoiding it until you learn the subtleties of the Ruby metaprogramming.
Finally, if you just do:
def do_something
end
...it will not end up as a global function, but as a private method on Object (there are no functions in Ruby, just methods). There are two downsides. First, you don't have namespacing - if you define another function with the same name, it's the one that gets evaluated later that you get. Second, if you have functionality implemented in terms of #method_missing, having a private method in Object will shadow it. And finally, monkey patching Object is just evil business :)
EDIT:
module_function can be used in a way similar to private:
module Something
def foo
puts 'foo'
end
module_function
def bar
puts 'bar'
end
end
That way, you can call Something.bar, but not not Something.foo. If you define any other methods after this call to module_function, they would also be available without mixing in.
I don't like it for two reasons, though. First, modules that are both mixed in and have "static" methods sound a bit dodgy. There might be valid cases, but it won't be that often. As I said, I prefer either to use a module as a namespace or mix it in, but not both.
Second, in this example, bar would also be available to classes/modules that mix in Something. I'm not sure when this is desirable, since either the method uses self and it has to be mixed in, or doesn't and then it does not need to be mixed in.
I think using module_function without passing the name of the method is used quite more often than with. Same goes for private and protected.
It's a good way for a Ruby library to offer functionality that does not use (much) internal state. So if you (e.g.) want to offer a sin function and don't want to pollute the "global" (Object) namespace, you can define it as class method under a constant (Math).
However, an app developer, who wants to write a mathematical application, might need sin every two lines. If the method is also an instance method, she can just include the Math (or My::Awesome::Nested::Library) module and can now directly call sin (stdlib example).
It's really about making a library more comfortable for its users. They can choose themself, if they want the functionality of your library on the top level.
By the way, you can achieve a similar functionality like module_function by using: extend self (in the first line of the module). To my mind, it looks better and makes things a bit clearer to understand.
Update: More background info in this blog article.
If you want to look at a working example, check out the chronic gem:
https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb
and Handlers is being included in the Parser class here:
https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
He's using module_function to send the methods from Handlers to specific instances of Handler using that instance's invoke method.