Wednesday, October 27, 2010

Ruby On Rails: rspec failing with [no such file to load -- spec_helper]

I have started reading www.railstutorial.org. It is wonderful tutorial for learning Ruby on Rails (ror). I am at chapter 3 currently and tried to setup the unit testing.
After creating project and generating controllers, I installed growl for windows and then autotest, autotest-growl gems. But when I issued the following command:

rspec .\spec\controllers\pages_controller_spec.rb
I got following error:

:29:in `require': no such file to load -- spec_helper (LoadError)
 from :29:in `require'
 from F:/Code/Learning/ruby/todo/spec/controllers/pages_controller_spec.rb:1:in `'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/configuration.rb:306:in `load'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/configuration.rb:306:in `block in load_spec_files'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/configuration.rb:306:in `map'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/configuration.rb:306:in `load_spec_files'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/command_line.rb:18:in `run'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/runner.rb:55:in `run_in_process'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/runner.rb:46:in `run'
 from D:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-core-2.0.1/lib/rspec/core/runner.rb:10:in `block in autorun'

Going through much pain of reinstalling quite a few gems and banging my head, I went back to read the tutorial page again from beginning and make list of what I have already done as given in page. I found out that I had missed to execute following command:

rails generate rspec:install
It did the folowing:
create .rspec
  exist  
 create  spec/spec_helper.rb
 create  autotest
 create  autotest/discover.rb

Now I had got spec_helper.rb in my spec folder and was able to execute the tests (happily ever after ^_* ).

Also remember to install win32console-color gem to get colorfull info with autotest.
Happy Coding!

Tuesday, February 2, 2010

A way to resolve bugs

I just found a nice blog post by Chris Missal titled "How I Approach a Defect" via a tweet by Elijah Manor.
Chris outlines the systematic approach he takes when solving programming bugs (defects, as he calls them). He underlines the fundamental notion that you should actually fix the problem not just get the right answer for a particular case.
Like Five Ws (5Ws) Chris Missal's defect solving framework tries to ascertain that proper solution has been applied to remove defect by answering following questions:

Does This Solve the Problem? 

Is This Flexible, Maintainable, Clear and Simple?

Does This Leave the Code Better Than I Found It?

Is It Covered with Tests to be Future-Proof?

Is There Any Code that was Commented Out or Stale?

Do Any Named Variables or Classes Exist that Aren't Clear?

Are All Changes Relevant to the Fix?

Please read his post for details of what these questions mean.
Happy Coding!

Monday, November 9, 2009

Free .Net Profiler

I got link for free (as in beer) .Net profiler from eqatec.
It works with many languages:

LanguageVersionPlatform
C#
VB.NET
Managed C++
F#
C or C++
Java
.NET 3.5
.NET 3.0
.NET 2.0
.NET CF 3.5
.NET CF 2.0
.NET 1.1
WinXP, Vista
Windows Mobile
Windows CE
XP embedded
PocketPC, PDA
Linux

Tuesday, October 13, 2009

I got Google Wave Invite!!!

Wow, I got invitation for Google Wave.

Googlewave
preview
Thank you for signing up to give us early feedback on Google Wave. We're happy to give you access to Google Wave and are enlisting your help to improve the product.


can't wait to have a look. Will sure my experiences. Keep watching.....!

Dealing with TimeStamp columns with SubSonic 3 and MS Sql Server

Today someone asked a question at StackOverflow
regarding problem with SubSonic, not allowing to update record in table with "TimeStamp" typed column. I've been SS enthusiastic since long. I was quick to reply:

You don't need to worry about this. SubSonic is intelligent enough to handle this! Just create new object and assign values to properties and save it.
I then created a table to test it and it worked like charm.




User commented back that he is not able to make it work. It then occurred to me that he might be using SubSonic 3. I tested with SS3 and he was right there was something funny. I got following error:



What is this? SubSonic failed to take into account that a TimeStamp datatyped column should not be explicitly set in Insert or Update statements.

I fired .Net Reflector and opened SubSonic.Core.dll. It took me to the following method in SubSonic.Extensions.Database class:
public static ISqlQuery ToInsertQuery(this T item, IDataProvider provider) where T: class, new()
{
    Type type = typeof(T);

    ITable tbl = provider.FindOrCreateTable();

    Insert query = null;

    if (tbl != null)
    {
        Dictionary hashed = item.ToDictionary();

        query = new Insert(provider).Into(tbl);

        foreach (string key in hashed.Keys)
        {
            IColumn col = tbl.GetColumn(key);

            if ((col != null) && !(col.AutoIncrement || col.IsReadOnly))
            {
                query.Value(col.QualifiedName, hashed[key], col.DataType);
            }
        }
    }
    return query;

As you can see in this line:

It was checking if column was null or auto-increment, and was omitting it from column list for query. By default TimeStamp typed column should be readonly. But even if it was readonly the line above is not checking for ReadOnly property. I also tried to set it to null but it did not work.

I went to GitHub and forked subsonic source code. I was sure putting another check in if statement above will work:

if ((column != null) && !column.AutoIncrement && !column.IsReadOnly)

But when I opened the code the above method read something like this:
public static ISqlQuery ToInsertQuery(this T item, IDataProvider provider) where T : class, new()
{
    Type type = typeof(T);
    ITable tbl = provider.FindOrCreateTable();
    Insert query = null;
    if(tbl != null)
    {
        var hashed = item.ToDictionary();

        query = new Insert(provider).Into(tbl);

        foreach(string key in hashed.Keys)
        {
            IColumn col = tbl.GetColumn(key);
            if(col != null)
            {
                if(!col.AutoIncrement && !col.IsReadOnly)
                    query.Value(col.QualifiedName, hashed[key], col.DataType);
            }
        }
    }
    return query;
}
Hmm, the problem is already sorted out. The questioner is also using dll from some old build. I compiled, added reference and re-ran the test code. No luck. It confronted me with same error. I put break point at save statement to delve deeper. The column was never set as ReadOnly :(

I scourged the generated code and saw what it generated for TestTimeStamp table. It read:

public class TestTimeStampTable: DatabaseTable {
    public TestTimeStampTable(IDataProvider provider):base("TestTimeStamp",provider){
    ClassName = "TestTimeStamp";
    SchemaName = "dbo";
    ………………
    ………………

    Columns.Add(new DatabaseColumn("RowVersion", this)
    {
        IsPrimaryKey = false,
        DataType = DbType.Binary,
        IsNullable = false,
        AutoIncrement = false,
        IsForeignKey = false
    });
}

So problem was somewhere here! When creating column, SS was not putting if the column is readonly or not. I checked structs.tt T4 template.

It has following code:
<# foreach(var col in tbl.Columns){#>
    Columns.Add(new DatabaseColumn("<#=col.Name#>", this) {
         IsPrimaryKey = <#=col.IsPK.ToString().ToLower()#>,
         DataType = DbType.<#=col.DbType.ToString()#>,
         IsNullable = <#=col.IsNullable.ToString().ToLower()#>,
         AutoIncrement = <#=col.AutoIncrement.ToString().ToLower()#>,
         IsForeignKey = <#=col.IsForeignKey.ToString().ToLower()#>
    });

<# }#>

It is not even bothering to check if column is readonly or not :( I put following line after IsForeignKey line:
IsReadOnly = <#=col.DataType.ToLower().Equals("timestamp").ToString().ToLower() #>

On saving the file the code was regenerated. TestTimeStamp class now read:

Columns.Add(new DatabaseColumn("RowVersion", this) {
    IsPrimaryKey = false,
    DataType = DbType.Binary,
    IsNullable = false,
    AutoIncrement = false,
    IsForeignKey = false,
    IsReadOnly = true
});

I tried my luck again. It ran without any error. I ran it again, opened SQL Server Management Studio and executed SQL Query:

Select * From TestTimeStamp

Now it returned:

RowIDRowDescriptionRowVersion
---------------------------------------------------------
1Hello world!0x00000000000007D1
2Hello world, Again!0x00000000000007D2
(2 row(s) affected)
Happy Coding!

Friday, October 17, 2008

Showing HTML Content over Flash Movie - quick and dirty way!

I had faced a nasty problem few days ago. I was to show user a modal-popup (in html page) for Terms and Conditions for registration on a site. Popup was coming okay, but There was a flash movie at top of the page which was hidding upper portion of the dialog. The tested and widely used method is to put an Iframe at place where you want to show your content and absolute position your content and IFrame. For example, if you want to show a div above a flash movie, then place a IFrame like follows:
        <iframe style="position:absolute;top:250;left:150;"></iframe>
Then position the div exactly above this iframe like:
        <div style="position:absolute;top:250;left:150;"></div>

I was using jquery on the page to show dialog using ui.dialog plugin.
After fooling around sometime I devised following simple solution.

1)  put id attribute on movie element to uniquely identify the movie object. Like,
<object id="movie1"></object>
2)  before showing the dialog (or other content for that matter) call a javascript function to hide the movie. Like,
$("#movie1").css("display","none");

3)  now show dialog. Like,
$("#dialog").dialog("open");

4)  after closing the dialog, show the movie again. Like,
     $("#dialog").dialog("close");
$("#movie1").css("display","inline"); 

that's all folks, Happy Coding

Monday, January 28, 2008

Working with Anthem.NET and AJAXControlToolkit CalendarExtender

I've wasted almost complete day to debug what now seems very trivial. I'm using Anthem.NET in my project. I almost exclusively use Anthem.NET in my ASP.Net applications for AJAX. Almost because I've to rely on AjaxControlToolkit for some capabilities, like Calendar and ListSearchExtender.
I'm using Anthem ListBox box, and some textboxes on a page. Listbox generates a callback and textboxes are populated async'ly. One of the textboxes is for date input. I've used CalendarExtender control to show dropdown (I just love it for this thing) calendar. When page first loads calendar shows nicely, but as soon as callback is generated, it stops working.
After looking at generated page, I found code responsible for creating client side calendar. It is this one:
Sys.Application.add_init(function() {
$create(AjaxControlToolkit.CalendarBehavior, {"format":"dd/MMM/yyyy","id":"MyCal"}, null, null, $get("ctl00_ContentPlaceHolder1_txtPurchaseDate"));


So, it seemed very simple register a PostCallback function for ListBox, with $create method in it, to recreate calendar everytime a callback occured.

So far so good, but it cropped up control with duplicate id problem. I tried $dispose method from ajax.net library, but it told me that element I'm looking for is unavailable. Then I tried prototype to remove the said element from the DOM tree, but it was also not able to find element.

Then after googling many times for many things (in the meantime reading scripts in AjaxControlToolkit source code, using reflector to go through System.Web.Extensions.dll and using firebug extensively) I got to Ajax.NET reference on asp.net (now, don't laugh at me that it is not in my delicious, as I've been relying mostly on Anthem.NET).

There I found the whole story at page for Sys class [here]. I used $find method to get my element and used removeComponent to remove previous instance before creating new one.
Sys.Application.removeComponent($find("MyCal"));