In this blog thoughtbot team outlined how they test their factories first. I like this approach. Since we prefer using minitest here is how we implemented it. It is similar to how the thoughtbot blog has described. However I still want to blog about it so that in our other projects we can use similar approach.
First under spec directory create a file called
factories_spec.rb . Here is how our file looks.
Next I need to tell rake to always run this test file first.
When rake command is executed then it goes through all the
.rake and loads them. So all we need to do is to create a rake
file called factory.rake and put this file under
lib/tasks .
The problem with above code is that class names in the html markup was
meant for web design. By using css class for functional work, I
have made both the design team and the front end development team
perpetually terrified of change.
If designer wants to change markup from
1
<divclass='first actions'>xxx<div>
to
1
<divclass='first actions-items'>xxx<div>
they are not too sure what JavaScript code might break. So they work
around it.
Same goes for JavaScript developers. They do not want to unintentionally
remove a class element otherwise the web design might get messed up.
There has to be a better way which clearly separates the design elements
from functional elements.
data-behavior to rescue
“Nick Quaranto” of 37Signals presented “Code spelunking in the All New
Basecamp” ( videoblog ) . In his presentation he mentioned about data-behavior .
data-behavior usage can be best understood by an example.
Now in the above case the designer can change the css class all he wants
and it will have no impact on JavaScript functionality.
More usage of data-behavior
Based on this data-behavior approach I changed some part of
nimbleShop to use data-behavior. Here is the commit.
Personally I am surprised at people using old style of development.
data-behavior is a very simple and effective tool to combat the problem
of having clear separation between designer elements and JavaScription
functional work.
Notice that in the first case the mixin code was executed first. In the
second case the mixin code was execute later.
Here is how it works
Here is mergeMixins code which accepts the mixins and the base class. In the first case the mixins list is just the mixin and the base class is the main class.
At run time all the mixin properites are looped through. In the first
case the mixin m has a property called skill .
Runtime detects that both mixin and the base class has a property called
skill . Since base class has the first claim to the property a
call is made to link the _super of the second function to the
first function.
So at the end of the execution the mixin code points to base code as
_super.
It reveres itself in case of create
In the second case the mixin skillJavaScript and the
main are the mixins to base class of Class. The mixin
is the first in the looping order. So the mixin has the first claim to
key skill since it was unclaimed by base class to begin with.
Next comes the main function and since the key is already taken the wrap
function is used to map _super of main to point to the mixin .
Remember in Create and Extend it is the last one that executes first
Here we have a Util class. But notice that all the methods on this class
are class methods. This class does not have any instance variables.
Usually a class is used to carry both data and behavior and ,in this case,
the Util class has only behavior and no data.
Similar utility tools in ruby
Now to get some perspective on this discussion lets look at some ruby
methods that do similar thing. Here are a few.
So these are not classes but modules. That begs the question why the
smart guys at ruby-core implemented them as modules instead of creating
a class the way I did for Util.
Reason is that Class is too heavy for creating only methods like
double. As we discussed earlier a class is suppossed to have both data
and behavior. If the only thing you care about is behavior then ruby
suggests to implement it as a module.
extend self is the answer
Before I go on to discuss extend self here is how my Util class will
look after moving from Class to Module.
Here Calculator is a module that is extending another module.
Now that we understand that a module can extend another module look at
the above code and question why module M is even needed. Why can’t we
move the method double to module Calculator directly. Let’s try that.
I got rid of module M and moved the method double inside module
Calculator. Since module M is gone I changed from extend M to
extend Calculator.
One last fix.
Inside the module Calculator what is self. self is the module
Calculator itself. So there is no need to repeat Calculator twice. Here is
the final version
Everytime I would encounter code like extend self my brain will pause
for a moment. Then I would google for it. Will read about it. Three
months later I will repeat the whole process.
The best way to learn it is to use it. So I started looking for a case
to use extend self. It is not a good practice to go hunting for code
to apply an idea you have in your mind but here I was trying to learn.
Here is a before snapshot of methods from Util class I used in a project.
Much better. It makes the intent clear and ,I believe, it is in line with
the way ruby would expect us to use.
Another usage inline with how Rails uses extend self
Here I am building an ecommerce application and each new order needs to
get a new order number from a third party sales application.
The code might look like this. I have omitted the implementation of the
methods because they are not relevant to this discussion.
Here the method next_order_number might be making a complicated call
to another sales system. Ideally the class Order should not expose
method next_order_number . So we can make this method private but
that does not solve the root problem. The problem is that model Order
should not know how the new order number is generated. Well we can move
the method next_order_number to another Util class but that would
create too much distance.
Much better. The class Order is not exposing method next_order_number
and this method is right there in the same file. No need to open the
Util class.
To see practical examples of extend self please look at Rails source
code and search for extend self. You will find some interesting usage.
This is my first serious attempt to learn usage of extend self so that
next time when I come across such code my brain does not freeze. If you
think I have missed out something then do let me know.
to_s is simply the string representation of the object.
Why the failure
Before we look at to_str lets examine a case where ruby raises error.
12345678910
e=Exception.new('not sufficient fund')# case 1putse# case 2puts"notice: #{e}"# case 3puts"Notice: "+e
Here is the result
123
notsufficientfundNotice:notsufficientfund`+': can't convert Exception into String (TypeError)
In the first two cases the to_s method of object e was printed.
However in case ‘3’ ruby raised an error.
Lets read the error message again.
1
`+': can't convert Exception into String (TypeError)
In this case on the left hand side we have a string object. To this
string object we are trying to add object e. Ruby could have called
to_s method on e and could have produced the result. But ruby
refused to do so.
Ruby refused to do so because it found that the object you are trying to
add to string is not of type String. When we call to_s we get the
string representation of the string. But the object might or might not
be behaving like a string.
Here we are not looking for the string representation of e. What we
want is e to behave a like string. And that is where to_str comes in
picture. I have a few more examples to clear this thing so hang in
there.
What is to_str
If an object implements to_str method then it is telling the world
that my class might not be String but for all practical purposes treat
me like a string.
So if we want to make exception object behave like a string then we can
add to_str method to it like this.
1234567
e=Exception.new('not sufficient fund')defe.to_strto_sendputs"Notice: "+e#=> Notice: not sufficient fund
Now when we run the code we do not get any exception.
What would happen if Fixnum has to_str method
Here is an example where ruby raises exception.
12
i=10puts'7'+i#=> can't convert Fixnum into String (TypeError)
Here Ruby is saying that Fixnum is not like a string and it should not be
added to String.
We can make Fixnum behave like a string by adding a to_str method.
Before the refactoring was done Path is a subclass of String. So it
is String and it has all the methods of a string.
As part of refactoring Path is no longer extending from String.
However for all practical purposes it acts like a string. This line is
important and I am going to repeat it. For all practical purposes Path
here is like a String.
Here we are not talking about the string representation of Path. Here
Path is so close to String that practically it can be replaced for a
string.
So in order to be like a String class Path should have to_str
method and that’s exactly what was done as part of refactoring.
During discussion with my friends someone suggested instead of defining
to_str tenderlove could have just defined to_s and the result would
have been same.
Yes in that case the result you see on console when you do
1
putsPath.new('world')
would be same but if you do not define to_str then following code
would fail.
1
puts'hello '+Path.new('world')
So the difference between defining to_s and to_str is not just what
you see in the output.
Conclusion
If a class defines to_str then that class is telling the world that
altought my class is not String you can treat me like a String.