Saturday, July 25, 2009

RightJS Is Faster Than Pure Dom

Well, I'm cooking a new version of RightJS. I've optimized this and that, tuned here and there. And then I've run the TaskSpeed test and it looks like RightJS works faster than pure dom.



That's not a fake, seriously, I've got this result from Safari 4. jQuery has in this test 883 points.

Sure, that's because of the way the original test was written, but the result is just hilarious 8)

PS: Goin' to publish the new version in the next couple of days

Thursday, July 23, 2009

Transparent Dates and Times Internationalization in Rails

The basic internationalization approach in Ruby on Rails supposes that you translate the dates and times like that

Created at: <%= I18n.localize @model.created_at, :format => :short %>

But most of us use the "to_s" method to format times, like that

Created at: <%= @model.created_at.to_s :short %>

Mostly because you usually don't think much about i18n when a project is just starting up, and then it's kinda sweet, nice and short way of doing that.

So, usually when it comes to the internationalization, the project is already pretty much covered with the to_s methods. If you were lucky you might had created a single helper method which processes all the dates and times in your project and then it's simple, but if you didn't you might think about highjacking the "to_s" method of the Time class. Like that.

class Time
def to_s(format=:default)
I18n.localize self, :format => format
end
end

But if you do so, you will probably broke the things. Because first of all the "to_s" method supposed to work like an alias for the "strftime" method, secondly this method is used to convert times and dates in the :db format and if it was not translated properly it will break your models, thirdly it's naughty when you completely replace such a method.

Okay here is a better way of doing that

[Date, Time, ActiveSupport::TimeWithZone].each do |klass|
klass.instance_eval do
define_method :to_s_with_i18n do |*args|
format = args.first || :default
if format.is_a?(Symbol) && format != :db
I18n.localize(self, :format => format)
else
to_s_without_i18n(*args)
end
end
alias_method_chain :to_s, :i18n
end
end

It keeps the original method and doesn't touch the custom and database formats. The ActiveSupport::TimeWithZone class is the Rails class for the UTC times you need to process it too.

Monday, July 20, 2009

Inline IE hacks with SASS

SASS is a nested css engine written in ruby. It's a pretty powerful and handy tool with lots of features inside, http://sass-lang.com

I'm using it on my current project and find it quite useful. The only thing which was bugging me is that I tend to use inline IE hacks in my css, like that

div.box {
cursor: pointer;
* cursor: hand;
}

And it seems like sass doesn't support such a feature, at least I haven't found it in their documentation.

But in reality it does actually has support of the feature, just it is not documented. It looks like that

#my-block
:cursor pointer
*cursor: pointer

Note, there should be no space betwen '*' sign and the property name

Friday, July 17, 2009

Customizing The Rails Forms Builder

The word "customer", usually means someone who come and say "I wanna custom stuff". And because it is their nature they do it all the time. Sometimes several times a day.

I'm skipping here the obvious question "why would I need to customize a forms builder?" and get straight to the point.

So you need to customize your forms. Big time. And if the first what comes on your mind are helper methods and partial templates, this article is for you.

And please don't think about monkey patching rails form-builder. Don't behave like a php developer thinking he can use rails. Lord save their poor souls.

There are better way of doing that.

First of all you should realize that in 99.99% of cases you should not change the default rails templates. Meaningly that

<% form_for(@model) do |f| -%>
<%= f.error_messages %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<% end -%>

Despite that it is a simple structure, with a little bit of imagination and css magic you can make it look like anything you need.

Secondly you really should pay a dollar of penalty every time you think about monkey patching. Ruby is not just a monkey patching language it is object oriented too, and rails form builder is a quite well organized structure.

Instead of patching, we will create our own form-builder using advantages of the inheritance and then swap the default builder from the built-in to our own one. This way we can change the logic of the forms building transparently for the templates, you even can have several form-builders which behave differently and swap them depend on the context.

The basic example would look like this. You create another helper module called FormsHelper and save it along with the other helpers in your application

module FormsHelper
def self.included(base)
ActionView::Base.default_form_builder = CustomFormBuilder
end

class CustomFormBuilder < ActionView::Helpers::FormBuilder
# your custom methods go here
end
end

Inside the class you will have access to the form builder context with all its built in methods and variables. For the beginning you should know about the following ones

  • @template - the template context, you call this variable if you need to call the basic helpers

  • @object - the current model of the form

  • @object_name - the string name under which the form knows the model


Okay now lets play with the thing a little. Say the customer says "don't like the <h2> header on the error reports, the one with the number of errors on the form". No problem, we just override the built in method

def error_messages(options={})
super options.reverse_merge(:header_message => nil)
end

Then say you as many other developers usually put your forms in a partial and then depends on the model state change the submit button caption. something like this

form_for(@model) do |f|
f.submit @model.new_record? ? "Create" : "Save"

This is a little bit annoying. Say I'd like just call it <:%= f.submit %> and want the form automatically set the caption. Here is the code

def submit(caption=nil, options={})
super(caption || @object.new_record? ? "Create" : "Save"), options
end

Then I got completely lazy and started to want my form builder to build a block of label + text-field in a single call, like this

form_for(@model) do |f|
f.labeled_text_field :name

# this should build the thing like that
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>

# you could do it like this
def labeled_text_field(name, options={})
@template.content_tag(:p, label(name) + text_field(name, options))
end

Then, all the sudden, your customer comes back and says a scary thing "I like this, but I want for this particular controller, there actually was the h2 header saying 'Oh noooo!'. Yes, just for this special case".

No, my friend we are not going to the monkey patchers hell! We just define another form-builder over our own builder, and automatically swap it in the particular controller

class SpecialFormBuilder < CustomFormBuilder
def error_messages(options={})
super options.reverse_merge(:header_message => "Oh noooo!")
end
end

class ParticularController < ApplicationController
before_filter :swap_form_builder

def swap_form_builder
ActionView::Base.default_form_builder = SpecialFormBuilder
end
end

Think you understand the idea. If you do the things in a serious way, lord will love you and grand you a big deal of flexibility and rapidness.

This is pretty much it. Have a good one!

Thursday, July 9, 2009

Decimal to Hex and Hex to Decimal in JavaScript

Generally JavaScript doesn't have a particular data type or class for hex values but it still provides couple of features which will let you work with hex data.

In similar to Ruby you can keep your hex values in strings and the convert them into decimal values back and forth.

var hex = 'FF';

var dec = parseInt(hex, 16); // -> 255

dec = dec + 255;

hex = dec.toString(16); // -> '1ff'

Tuesday, July 7, 2009

Psychic Abilities Test

I've created another toy, Psych Test.

The thing is fairly simple, you've seen it lots of times in movies. You have a standard 36 playing cards deck, and one by one you are trying to guess the next card suit color. Red or black.

Well... I'm not a psychic but I know what are you thinking.

"...50%...", right?

I bet, if you ask any of your friends or colleagues who is occupied in CS, mathematics or physics you'll have the same exact answer. But the thing is not actually that simple, and here is where the fun begins.

If you open up the link above and will click on the same exact prediction button during the whole test, the result will be exactly those 50%, well +/- 1% in some unlucky situations. You might repeat the test several times, it's pretty consistent almost without any deviations.

But if you will have the same test, but will actually try to guess the next card's color, you'll have a different result, usually in range between 40 and 60%. And you almost never will have 50% again.

You should try it to believe, you can check the source code too, there is no back door. Everything is fair.

So what do you think, how is that possible? Do you think it is you actual ability to predict the future affects the result?

I could tell a spooky story about underground CIA laboratories where they study those things since 60s, and that there is a standard measurement for such tests and an exact percentage which defines you as a proven psychic.

Or, if you prefer, we could think about the problem rationally. There are just four practically independent cases and two of them correct, so the result should be close to 50% every time, no matter which button you choose. But yet it's ain't like that.

As you understand this is not the test for a psychic abilities, this is a test for rational thinking.

Okay, I'm not going to marinade you any further, as you come here and read this far I owe you an answer.

The thing is simple but not that obvious. There's no mathematical or logical problem, every time you click any of those buttons, you've got an exact 50% probability to score. But in case when you click the same button all the time, you put your guess against an almost ideal random sequence generated by the computer. And that's why you have this pretty close 50% result every time.

But when you do the "guessing", your brain follows some patterns and tries to predict the next card. Yes, generally that's a random process and every guess as good as any other, but the distribution of those guesses in time is not such good as a random distribution generated by the computer. There are fluctuations and attempts to guess, which affect the quite short 36 cards selection and gives you the non 50% result.

The first time you test the computer's random numbers generator, the second time you test your own.

Sunday, July 5, 2009

Call vs. Apply

Today I'm going to tell you an educational story.

var f = function() {};

var test = function(callback) {
var time = new Date();
(10000).times(callback);
console.log(new Date() - time);
};

var test_with_apply = function() {
test(function() {
f.apply(this, [0,1,2,3,4,5,6,7,8,9]);
});
};

var test_with_call = function() {
test(function() {
f.call(this, 0,1,2,3,4,5,6,7,8,9);
});
};

(10).times(test_with_apply);
console.log('--');
(10).times(test_with_call);

The moral

119
122
118
118
128
119
120
119
119
120
--
55
56
55
55
55
55
55
56
56
55

Thursday, July 2, 2009

Sudoku Game In JavaScript and RightJS

In order to have some show off cases for my RightJS project I've written basic Sudoku Game.

Nothing really special but a quite nice implementation though. Check it out you will like it.

Wednesday, July 1, 2009

Sudoku Puzzle Generating, Pragmatic Way

Couple of days ago I described how you could generate a good random sudoku field, today I'm going to advocate for just opposite thing. There's no controversy in really, just there are different cases, when you should and when you should not do that.

You should or could write your own sudoku puzzles generator if you are particularly interested in the field and ready to spend lots and lots of time, getting deep in all the various rules which actually make a good sudoku. Well at least it will keep your self-esteem up.

But if you are just writing some implementation of the sudoku game, you actually better not to do that. And here is why.

  • Sudoku generating is a random process with generally unpredictable duration. There is a good chance that your generator will get unlucky and stuck. And a hanging over application is the last thing you want your user to see.
  • The process of generating of a really good, hard sudoku usually takes time, sometimes a few seconds
  • There are lots of rules you need to get into, implement test over, and then if you are not an expert in sudoku you wont be able to check it out if you have done everything properly
  • You will probably forget and never use again all the knowledge you gain during the implementation. I don't want to call it a waste of time, but I'm pretty sure there are better ways to actually waste your time.
  • A good sudoku generator might be quite big and complicated piece of software, which will be hard to test and support.

Luckily there are better ways to do that. Use other people's work to be precise. There are lots and lots of online sudoku generators, or you could use any desktop applications, most of them cache boards in files. I used the gnome-sudoku application, it lets you generate any number of sudoku and saves them in the files in the gnome configuration directory, or you can grab my archive right here puzzles.zip

What about the number of puzzles ask you? You need some storage to keep them and have big enough collection to keep the user happy.

Actually not, and here is the trick of the article. You actually can keep just a few puzzles for each level and then generate new puzzles out of the originals. You can safely do the following things with your puzzles

  • Rotate them
  • Flip in any way
  • Randomly shuffle rows and columns inside the 3x3 boxes
  • Shuffle rows and columns of the 3x3 boxes

As the result, if you say have initially a collection out of 16 puzzles, then you can rotate and flip it in 5 ways, then you can shuffle rows and columns in 9 ways in each of the nine 3x3 boxes, and eventually you can have 9 combinations of the 3x3 blocks.

16 * 5 * 9 * 9 * 9 = 58320

That's more than enough for your user never see the same puzzle twice in a row. More of that, all of those puzzles will be really consistent by the difficulty level because initially it is just the same puzzle.

And for the end you can see a possible JavaScript implementation right here boards.js

This is pretty much it. Have a good one!