20th
Now we are talking…
I see your puny garbage plate and I raise you a typical venezuelan street vendor’s burger. This will either kill you or make you immortal. Ingredients (in order):
- Mayo, ketchup & mustard
- Onions
- Cabbage
- Potato chips
- More mayo, ketchup & mustard
- Avocado
- Tomato
- Hamburger patty
- Chorizo
- Chicken
- Bacon & eggs
- Cheese
(Warning: DO NOT eat this.)
Now that IS a HAMBURGER :-D
Right now I’m on chapter 15 of my RWH book. This one talks about problems that get complicated without the use of a Monad, one of them is the System.Random API of Haskell. I’m going to start by introducing two typeclasses that this module exports for clarity’s sake:
RandomGen: a RandomGen represents an state that holds the random input, I like to think of it like a stream of some sort (stdin, stdout).
Random a: This typeclass is the abstraction of a Random value, all the common types of Haskell implement this typeclass (String, Integer, Float, Int, etc.)
What confused me for sometime, and I actually had to analyze throughly was how the interactions between the Random API and the IO Monad worked.
The following code was the one that got me thinking:
import System.Random hiding (next)
randomsIO :: Random a => IO [a]
randomsIO =
getStdRandom $ \g ->
let (a, b) = split g
in (randoms a, b)
Where the IO [a] comes from?, if this anonymous function is returning a type
([a], RandomGen) instead of an IO [a]. This got me really confused, at some point I thought that a StdGen was an instance of an IO, but realized pretty quickly that IO is not a classtype, but an instance of Monad.
The best way to figure this out was checking the types of getStdRandom:
getStdRandom :: (StdGen -> (a, StdGen)) -> IO a
getStdRandom receives as it’s first parameter, a function that receives a StdGen and then return a tuple with the first position being some value of an anonymous type and second position being a (probably altered) StdGen, the return of the getStdRandom is whatever the parameter function returned on the first parameter of the tupple, wrapped in an IO Monad.
So the only way to work with a random function, is with the use of a getStdRandom like interface, why is that?. I’m assuming this is a way to provide “factory functions” for random generated data, a pretty clever choice (yet confusing, at least for me). Another important reason is that this way it will keep things pure, you don’t have to use the IO Monad on the random functions definitions.
Haskell is fun :-).
El último mes pasó bastante rápido, ¿no? Un mes no es mucho tiempo, pero es un hecho que la expectativa de vida (en los Estados Unidos) es de solamente 936 meses. Realmente la vida la veo distinta cuando puedo ver toda mi vida ante mi en la forma de 936 puntitos.
Si cada punto representa un mes de tu vida tomada secuencialmente de izquierda a derecha, de arriba a abajo, he aquí algunos hitos/estadísticas interesantes.
[…]
¡Ahora mueve ese culo y haz algo este mes!
Wow… this is kinda heavy, I’ve spent 8 of those blobs learning Haskell :-s
On Web apps, sometimes we want to avoid unnecessary requests, one of those situations happens when there is a form that represents a record, and the values of this record haven’t changed. On these cases you would like the user to send an update request only when the values of the record’s form actually changed, this technique is called “dirty form”, and is a very common practice.
I checked out some of the plugins out there to solve this problem, however, the functionality was sometimes sketchy. That’s why I started to implement my own solution, with a BDD approach using Screw.Unit.
In this post we will be covering some BDD practices, and at the same time I will be explaining what this plugins may offer to your plugin toolbox. Let’s start by pointing out the structure of a jQuery plugins project:
jquery-plugins/
|-- lib/
|-- spec/
`-- vendor/
In the lib/ folder we will have all the plugins we would like to develop, the spec/ folder will have all the test-related files and the vendor/ folder we will store all the frameworks needed in order to run the specs. In this project we will be using the livequery plugin, the Screw.Unit test framework and the Smoke mocking framework.
The spec/ folder will be composed (at least) by this two core files:
spec/
|-- suite.html
`-- spec_helper.js
The suite.html file will contain all the HTML scenarios needed for the jQuery plugins to work. This will look something like this (read the HTML comments):
<html>
<head>
<!-- first we import the jQuery framework -->
<script src="../vendor/screw-unit/lib/jquery-1.3.2.js"></script>
<!-- All vendor/ js files go here -->
<script src="../vendor/jquery.livequery.js"></script>
<!-- We import all the files needed by Screw.Unit -->
<script src="../vendor/screw-unit/lib/jquery.fn.js"></script>
<script src="../vendor/screw-unit/lib/jquery.print.js"></script>
<script src="../vendor/screw-unit/lib/screw.builder.js"></script>
<script src="../vendor/screw-unit/lib/screw.matchers.js"></script>
<script src="../vendor/screw-unit/lib/screw.events.js"></script>
<script src="../vendor/screw-unit/lib/screw.behaviors.js"></script>
<!-- We import all the files needed by Smoke -->
<script src="../vendor/smoke/lib/smoke.core.js"></script>
<script src="../vendor/smoke/lib/smoke.mock.js"></script>
<script src="../vendor/smoke/lib/smoke.stub.js"></script>
<script src="../vendor/smoke/plugins/screw.mocking.js"></script>
<!-- Here we include all our plugins from the lib/ folder -->
<script src="../lib/jquery.when_changed.js"></script>
<!-- We import all the spec files from the spec/ folder -->
<script src="spec_helper.js"></script>
<script src="jquery.when_changed_spec.js"></script>
<!-- We include the stylesheet from Screw.Unit to have nice looking test results -->
<link rel="stylesheet" href="../vendor/screw-unit/lib/screw.css">
<!--
We create a class scenario that will hold all the DOM needed for a test suite to work, but hides it from the
test HTML
-->
<style>
.scenario {
position: absolute;
left: -9999
}
</style>
</head>
<body>
<!-- This will be the place were all the test will grab the elements -->
<div id="sandbox" class="scenario"></div>
<!--
We will have clean states (fixtures) for the plugins, all of them will
have the postfix "-clean-state" to specify that this is a virgin state of a test environment
In this example, for each test case we execute, the "when-changed-clean-state" contents will be assigned to the
"sandbox" content.
-->
<div id="when-changed-clean-state" class="scenario">
<form method="GET">
<input type="text" name="text" value="some value">
<textarea name="textarea">some value</textarea>
<input type="checkbox" name="checkbox" value="1" checked>
<input type="radio" name="radio" class="first" value="one" checked>
<input type="radio" name="radio" class="second" value="two">
<select name="select">
<option value="1" class="one" selected>One</option>
<option value="2" class="two">Two</option>
</select>
</form>
</div>
</body>
</html>
The spec_helper.js file will have all the common setup for the test environment.
// This function well put the HTML contents of the clean-state we are working on to the sandbox
function resetDOM(id) {
$("#sandbox").html($("#" + id + "-clean-state").html());
}
// If we want to put some global setup and teardown code, here is the place to put it
// for setup, inside the before block
// for teardown, inside the after block
Screw.Unit(function() {
before(function() {
});
after(function(){
});
});
So, now that we have established our test environment, its time to do the implementation of the plugin, we start by defining the specs for it on the spec/jquery.when_changed_spec.js file, this file will represent the tests made to the lib/jquery.when_changed.js file.
Screw.Unit(function(){
describe("$.fn.whenChanged", function(){
// We establish a new clean state for each test case
// with a resetDOM invocation before each spec.
before(function(){
resetDOM("when-changed");
});
describe("invoked on an input:text", function(){
it("should invoke the given function when value has changed on keyup");
it("should not invoke the given function when value has not changed on keyup");
it("should not consider new blank text on the edges as a new text");
it("should call the reverse callback when the value returns to the same");
});
});
});
So, in the given spec file we specified (for now) the behavior of the plugin when we are interacting with an input text field. we expand this definitions by giving actual test code to each spec.
describe("invoked on an input:text", function(){
// first we define the setup for each spec, assign the plugin behavior to an input
before(function(){
// When the value of the input:text change it's original value, an alert will be called.
$("#sandbox input:text").whenChanged(function(){
window.alert("The input text has changed it's value");
});
});
it("should invoke the given function when value has changed on keyup", function(){
mock(window).should_receive("alert").exactly(1).with_arguments("The input text has changed it's value");
// the event checking will be raised by a keyup event
$("#sandbox input:text").val("some random value different than the original").trigger("keyup");
});
});
On the previous code, we are using the Smock’s method mock, this will do a temporary replacement of the window.alert function, and will check that this is being called exactly 1 time, and with the argument “The input text has changed it’s value”. This way we can check that the callback assigned on the whenChanged invocation was actually being called when necessary. Next step is to implement a whenChanged function that is simple enough to make the spec pass.
(function($){
$.fn.whenChanged = function(callback) {
// we store the old values on each element
$(this).each(function(){
$(this).data("jquery.whenChanged.oldValue", $(this).val());
});
// we assign a keyup event binding using livequery
$(this).livequery("keyup", function(){
var oldValue = $(this).data("jquery.whenChanged.oldValue");
var newValue = $(this).val();
if (oldValue !== newValue) {
callback.apply(this);
}
});
return this;
};
})(jQuery);
So we implemented the most simple solution possible that makes our specs run (Just check the suite.html file on a browser and you should have the feedback right away), now we continue developing adding more specs and changing the code as we go.
it("should not invoke the given function when value has not changed on keyup", function(){
mock(window).should_receive("alert").exactly(0);
$(this).trigger("keyup");
});
We added other method that didn’t need any code to be changed, in this case we are checking that window.alert is not being called at all. Awesome let’s continue with the next spec.
it("should not consider new blank text on the edges as a new text", function(){
mock(window).should_receive("alert").exactly(0);
$(this).val(" some value ").keyup();
});
At this point, this specs fails with our current implementation, we are not stripping the spaces on the border, this can be fixed easily.
$.fn.whenChanged = function(callback) {
$(this).each(function(){
// NOTICE: Invoking $.trim here!
$(this).data("jquery.whenChanged.oldValue", $.trim($(this).val()));
});
$(this).livequery("keyup", function(){
var oldValue = $(this).data("jquery.whenChanged.oldValue");
// NOTICE: Invoking $.trim here!
var newValue = $.trim($(this).val());
if (oldValue !== newValue) {
callback.apply(this);
}
});
return this;
};
Now that we have stripped the spaces on the old value storage, when we check the stripped new value, it will still be the same as the old value and the callback won’t be called. Finally we have to add the reverse callback functionality.
before(function(){
// When the value of the input:text change it's original value, an alert will be called.
$("#sandbox input:text").whenChanged(
function(){
window.alert("The input text has changed it's value");
},
function(){
window.alert("The input returned to the same value");
}
);
})
it("should call the reverse callback when the value returns to the same", function(){
mock(window).should_receive("alert").exactly(1).with_arguments("The input text has changed it's value");
$(this).val("Changing input value").keyup();
mock(window).should_receive("alert").exactly(1).with_arguments("The input returned to the same value");
$(this).val("some value").keyup();
});
So at this point, this spec will break previous specs, this is because the alert function is being called, even when the value is not changed, so mock(window).should_receive("alert").exactly(0) won’t work.
// NOTICE: we change this to alert with an specific argument.
it("should not invoke the given function when value has not changed on keyup", function(){
mock(window).should_receive("alert").exactly(0).with_arguments("The input text has changed it's value");
$(this).trigger("keyup");
});
it("should not consider new blank text on the edges as a new text", function(){
mock(window).should_receive("alert").exactly(0).with_arguments("The input text has changed it's value");
$(this).val(" some value ").keyup();
});
At the same time we need to add a new callback parameter to the whenChanged method.
$.fn.whenChanged = function(callback, reverseCallback) {
$(this).each(function(){
$(this).data("jquery.whenChanged.oldValue", $.trim($(this).val()));
});
// we assign a keyup event binding using livequery
$(this).livequery("keyup", function(){
var oldValue = $(this).data("jquery.whenChanged.oldValue");
var newValue = $.trim($(this).val());
if (oldValue !== newValue) {
callback.apply(this);
}
else {
reverseCallback.apply(this);
}
});
return this;
};
Now this code should run successfully and we now have covered our bases with input:text selectors, I could talk about how added support to other form input types, but I rather not in order to keep this short. Some thoughts I can share though is that the whenChanged method changed A LOT, after realizing that each type of input has it’s own gotchas, I created an specific whenChange method for each kind of form element. All in all… I was always sure that nothing broke on this process because the specs always told me if anything I was doing added any bug. Uhmmm the smell of good test code on late nights is incredible.
I hope this post can help you get some guidelines on how to get started with development of Javascript code using BDD, one word of caution though: testing effects in Javascript is a nasty challenge, you may like to pass an option to your method specifying if you want effects or not. check your code doesn’t depend on setTimeout invocations, take my word, is a BIG PAIN to test that.
Good luck with your BDD sessions.
Today at the office, we had one of the weirdest Rails errors I have ever encountered
rails-project/vendor/rails/activesupport/lib/active_support/dependencies.rb:417:in `load_missing_constant’: Object is not missing constant Photo! (ArgumentError)
We looked up into the stack trace and we found the problem was being caused by this line:
vendor/rails/activerecord/lib/active_record/base.rb:2195:in `compute_type’
When we checked the code, we found a dead-end with a class_eval invocation (oh meta-programming damn you on debugging times)
# Returns the class type of the record using the current module as a prefix. So descendants of
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
modularized_name = type_name_with_module(type_name)
silence_warnings do
begin
class_eval(modularized_name, __FILE__, __LINE__)
rescue NameError
class_eval(type_name, __FILE__, __LINE__)
end
end
end
This error was caused in the first place because we created a new environment for running the app, we checked the files on config/environments/ to see the differences between them; we didn’t find that many, commenting the few lines that were different didn’t make any change.
A (very long) while later, we noticed that the config/amazon_s3.yml file didn’t have a set of keys for the environment we were trying to run, after adding them everything went by pretty smoothly.
What pissed me off (and probably this guy as well) is that the error displayed didn’t make any sense at all, wtf is “Object is not missing constant Photo!”?, seriously? I investigated a bit further and it seems to be related with the autoload feature of the Rails framework, geez thanks for the cryptic error message ¬¬
I hope this info helps some unfortunate developer out there.
For the last 4 months I’ve been using jQuery for Javascript development. To be honest, I didn’t got started before with jQuery because it didn’t seem too practical to me (no Class approach), but after looking carefully at the plugin model, it was truly a revelation of a good API for development.
So I started to accommodate to the jQuery’s way of things, and one of the API’s that got my interest in the past 2 months was the traversal one. I mean, what were those methods .find(), .end() and .endSelf(). Why I would go and use those methods when my standard code was always like:
$("#container .sub-container .items").click(..);
$("#container .sub-container .other-items").hover(..);
$("#container form.create-item").ajaxForm(..);
and never needed them. I guessed that the way I was doing things wasn’t the jQuery’s way; I mean, I could rewrite the previous code like this instead:
$("#container").
find(".subcontainer").
find(".items").
click(..).
end().
find(".other-items").
hover(..).
end().
end().
find("form.create-item").
ajaxForm().
end().
end();
Of course at first sight it didn’t look that good, but I was not too sure that it didn’t look bad either, it was just different. So I just let time tell me if it was good enough. I left that implementation and came back a month later, the WTF/min were almost none, I did still understand the code right away, it actually looked like a CSS funky syntax to me.
After deciding that it was indeed a good way to do things, I just started to look at the pros & cons of this funky syntax vs the normal syntax I used before. This is what I got
Funky syntax Pro’s
Funky syntax Con’s
Classic syntax Pro’s
Classic syntax Con’s
As you can see, there are some benefits and some pros attached to the use of this jQuery DSL; I don’t know if this is the way to go but I’m certain that I’m not the first one who came up with this (I haven’t read any book of jQuery yet). If you could leave some thoughts about what is the one you prefer and why, it would give much value to this discussion.
Until next time.
Have you ever been in a situation where you have this strange bug, that takes you more time than expected to find out what (tha hell) is going on? That happened to us (me and my team) last Rails Rumble when we were trying to have some stuff done after the creation of an element that had some tags associated to it.
The code looked something like the following:
## app/models/entry.rb
class Entry < ActiveRecord::Base
##################
### Extensions ###
##################
acts_as_taggable
#################
### Callbacks ###
#################
after_create :do_something_with_tags
def do_something_with_tags
self.tags.each do |tag|
# do something with tag
end
end
protected :do_something_with_tags
end
## app/controllers/entries_controller.rb
class EntriesController < ApplicationController
# ...
def create
@entry = Entry.new(params[:entry])
entry.tag_list = params[:tags]
if entry.save
# success
else
# failure
end
end
# ...
end
The problem was that the do_something_with_tags callback was not doing what it supposed to. At first we thought it was a problem with our implementation, but after some debugger sessions, we found out what the real problem was. The tags array didn’t correspond with the value of the the tag_list that was being assigned on the controller level.
After having some thoughts I decided to go inside the acts_as_taggable_redux source code (the version of acts_as_taggable that we were using), and I found something pretty peculiar related to the tag creation; This tags were being created on an after_save callback. The extract of the acts_as_taggable looked something like this:
def acts_as_taggable(options = {})
has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag
has_many :tags, :through => :taggings, :order => 'LOWER(name) asc', :select => "DISTINCT tags.*"
after_save :update_tags
extend ActiveRecord::Acts::Taggable::SingletonMethods
include ActiveRecord::Acts::Taggable::InstanceMethods
end
As you can tell, an after_save was invoking this callback update_tags; after looking more closely, this method was the one that created the tag list, (the one we needed for our custom callback do_something_with_tags to work). So I checked in the Rails documentation page the precedence of callbacks just to be sure which one was being invoked first. Our main problem was that our callback was an after_create, and those get executed after the after_save callbacks.
To solve this issue, we simply called the update_tags callback directly on the first line of our callback, making the final do_something_with_tags look something like this:
def do_something_with_tags
update_tags # invoke callback by hand
self.tags.each do |tag|
# do something with tag
end
end
Because the acts_as_taggable library is so well implemented (at least the redux version, I’m not sure about others), the second time the update_tags method was being invoked simply returned without repeating the process of tag creation again.
Small issues like this are the ones that keep you having debugging fun for hours. I hope this may help you if you are this kind of trouble.
So… it happened, the last weekend was the Rails Rumble, a really kick ass event that made me squeeze all my skills and drop all my social life for 48 hours. I learned a lot of lessons (some the hard way).
The competition organization was OUTSTANDING, starting with the registration/team page, everything worked really well. At the competition, the little details stand out pretty quickly, and they made me laugh a lot. Big brags for you guys.
I’ve read the post from the intredia guys, it got me thinking that it will also be a good thing to share some “Good Idea, Bad Idea” thougths (of course, I’m not going to repeat what they have told you already).
For the love of God, be sure that the plugins you are planning to use actually do what you are expecting them to do. It happened that I wanted to do (and at the end DID!) a twitter authentication for the system, I didn’t wanted to use TwitterAuth because it is to invasive, it assumes things, makes a lot of stuff and I don’t feel comfortable with it.
I thought.. “Gee this oauth-plugin looks awesome, and it has support for Twitter too!”, what I found out after actually trying to use it (on the rumble) was that it is not intended to do authentication, it’s intended only to use the Twitter API via oauth.
Don’t get me wrong, the plugin is AWESOME in what it does, It was actually my fault because I didn’t pay attention to their README when they said:
It requires an authentication framework such as acts_as_authenticated, restful_authentication or restful_open_id_authentication
At some point, I didn’t assume that the purpose of the plugin didn’t include authentication. So remember, think it twice before using planning to use plugin you don’t know that well (a.k.a used before).
This recommendation has a little bit of it’s history, it turns out that since 3 weeks ago, I dished Textmate in favor of Vim (Don’t throw tomatoes at me please!, I don’t regret it, say whatever you want :-p), Textmate is awesome, but when I started to use Vim, I felt all the love right away (after customizing a little bit of course).
The problem was that, to use this editor you need to learn and use a lot of commands. At Sunday afternoon, when your brain is starting to throw SEGFAULTS because you haven’t slept that well, the Vim goodness didn’t flow (I guess this happens when you are still thinking on the commands before actually using them on normal basis).
You know it, body needs food to do it’s thing… FullThrotle drinks kept me up on night time.
The perfect balance is 2 proficient Ruby coders, 1 sys-admin, and a Heck of a good designer, with that you should have all your needs covered (ah… and of course a good project to do).
Besides that I have a really good war story related to ActiveRecord callbacks caveats (I will have a blog post for this soon, promise), and the post-mortem evaluation of Paperback for judges, the app that we intended to create and partially did.
Thank you RailsRumble team for such a fun and great time, I had a blast… see you next year.
So, to make life easier to the judges of my application, I will straight down the main features and the issues I’ve found along the way. We start now.
Paperback in one sentence: “A day activity log manager with twitter-like interface”.
Paperback may look very similar to twitter when you log in, please be patient enough to pass through that. Paperback is intended to do something different.
You will have the entries organized by date, so you can navigate to an specific day and see what you did for audit purposes.
Some entries are related to projectX, some others to bug #123 of projectY. With categorization is easy for you to check entries related to an specific activity.
This way, you can do time estimates on your entries, and actually get some useful insight data out of it. Sadly , we didn’t have enough time to represent good charts about that data we are recollecting :-(.
Entries that had an estimation date could happen to be todos, so you could go to a pending page when you see all this entry representing a todo list instead of an activity log entry date. The only way you could check an entry as completed, was when you specify the actual time you took to finish it.
Normally you would use this as an activity log, but what would happen if people actually care of what you are doing, say your supervisor or team members?. I wanted to use twitter for this, but I considered that people that followed me for other reasons (social life, ruby community, etc) wouldn’t care about my progress on the bug #123 from the project XYZ. With Paperback we made explicit in which channels I want to follow a person.
As I said before, We wanted to use twitter for this, and in some cases we still want to, that’s why we use the Twitter authentication in the first place, to keep the identity you have from twitter. We added OpenID just to support more ways to get you in the project for judging purposes, as soon as the competition ends, the OpenID authentication will go out.
Sadly everything is not there, as its supposed to be on the final product, but we are proud to say that at least the core features are there, not polished nor well designed, but there.
To finish the entry, I will post a short screencast showing some of the features, we hope you find this product helpful, we surely do, Thanks for syntoynizying.