# Sunday, November 30, 2008

Continued work on my resource-oriented library for ASP.NET MVC has expanded to include an XDocument based view engine for ASP.NET MVC.

This means we can now use VB.NET XML literals to define XHTML views (or any XML views).

Get the latest from SVN.

.net | html | mvc | REST | vb.net | web | xml
Sunday, November 30, 2008 10:49:44 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  | 
# Wednesday, November 26, 2008

Now that the ASP.NET MVC API has settled down I decided to bring some of my ideas about REST and resource-oriented programming to it.

The following screencast shows my current prototype in action:
http://www.aboutcode.net/screencasts/snooze-aspnet-mvc.wmv

I'm keen for comments and feedback.

The source code is currently available via SVN here:
http://svn2.assembla.com/svn/snooze/branches/aspnet

.net | c# | mvc | REST | screencast | web
Wednesday, November 26, 2008 3:23:02 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
# Saturday, November 08, 2008

Nemerle includes SQL macros. These make writing basic ADO.NET code a lot easier. They won't replace a complex ORM solution, but are fantastic for quick data access code. The main win is compile time query checking! That's right... if you misspell a column, table, etc, you get a compile error.

Watch the Screencast

Before

using System;
using System.Data.SqlClient;
 
namespace Demo
{
    module Program
    {
        Main() : void
        {
            using (conn = SqlConnection(@"Data Source=(local)\SQLEXPRESS;Initial Catalog=Customers;Integrated Security=SSPI"))
            {
                conn.Open();
 
                using (cmd = SqlCommand("select Id, FirstName, LastName from Customer where IsPrefered=1", conn))
                {
                    using (reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            def id = reader.GetInt32(0);
                            def firstName = reader.GetString(1);
                            def lastName = reader.GetString(2);
                            Console.WriteLine("{0}: {1} {2}", id, firstName, lastName);
                        }
                    }
                }
            }
 
            _ = Console.ReadLine();
        }
    }
}

After

using System;
using System.Data.SqlClient;
using Nemerle.Data;
 
[assembly: ConfigureConnection("System.Data.SqlClient.SqlConnection", @"Data Source=(local)\SQLEXPRESS;Initial Catalog=Customers;Integrated Security=SSPI")]
 
namespace Demo
{
    module Program
    {
        Main() : void
        {
            using (conn = SqlConnection(@"Data Source=(local)\SQLEXPRESS;Initial Catalog=Customers;Integrated Security=SSPI"))
            {
                conn.Open();
 
                ExecuteReaderLoop("select id, firstName, lastName from Customer where IsPrefered=1", conn, {
                    Console.WriteLine("{0}: {1} {2}", id, firstName, lastName);
                });
            }
 
            _ = Console.ReadLine();
        }
    }
}
Saturday, November 08, 2008 5:59:28 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 

Correctly implementing structural equality involves a lot of code. My macro implements this for you.

Watch the Screencast

Before

using System;
using System.Console;
using Nemerle.Utility;
 
module Program
{
    [Record]
    public class Location
    {
        public Latitude : double;
        public Longitude : double;
 
        public override Equals(other : object) : bool
        {
            match (other)
            {
                | null => false
                | l is Location => l.Latitude == Latitude && l.Longitude == Longitude
                | _ => false;
            }
        }
 
        public override GetHashCode() : int
        {
            Latitude.GetHashCode() ^ Longitude.GetHashCode()
        }
 
        public static @==(l1 : Location, l2 : Location) : bool
        {
            def l1IsNull = object.ReferenceEquals(l1, null);
            def l2IsNull = object.ReferenceEquals(l2, null);
            match (l1IsNull, l2IsNull)
            {
                | (true, true) => true
                | (false, false) => l1.Equals(l2)
                | _ => false
            }
        }
 
        public static @!=(l1 : Location, l2 : Location) : bool
        {
            !(l1 == l2)
        }
    }
 
    module Program
    {
        Main() : void
        {
            def l1 = Location(30, 70);
            def l2 = Location(30, 70);
            def l3 = Location(40, 90);
 
            WriteLine("l1.Equals(l2) -> {0}", l1.Equals(l2));
            WriteLine("l1 == l2 -> {0}", l1 == l2);
            WriteLine("l1 != l2 -> {0}", l1 != l2);
            WriteLine("l1.GetHashCode() == l2.GetHashCode() -> {0}", l1.GetHashCode() == l2.GetHashCode());
            WriteLine("l1 != l3 -> {0}", l1 != l3);
 
            _ = ReadLine();
        }
    }
}

After

using System;
using System.Console;
using Nemerle.Utility;
using SampleMacros;
 
module Program
{
    [Record]
    [ImplementEquality(Latitude, Longitude)]
    public class Location
    {
        public Latitude : double;
        public Longitude : double;
    }
 
    module Program
    {
        Main() : void
        {
            def l1 = Location(30, 70);
            def l2 = Location(30, 70);
            def l3 = Location(40, 90);
 
            WriteLine("l1.Equals(l2) -> {0}", l1.Equals(l2));
            WriteLine("l1 == l2 -> {0}", l1 == l2);
            WriteLine("l1 != l2 -> {0}", l1 != l2);
            WriteLine("l1.GetHashCode() == l2.GetHashCode() -> {0}", l1.GetHashCode() == l2.GetHashCode());
            WriteLine("l1 != l3 -> {0}", l1 != l3);
 
            _ = ReadLine();
        }
    }
}

ImplementEquality.n

using Nemerle;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Macros;
 
namespace SampleMacros
{
    [MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Class)] 
    public macro ImplementEquality(typeBuilder : TypeBuilder, params members : list[PExpr]) 
    { 
        ImplementEqualityModule.AddEqualsMethod(typeBuilder, members); 
        ImplementEqualityModule.AddEqualityOperator(typeBuilder); 
        ImplementEqualityModule.AddInequalityOperator(typeBuilder); 
    } 
 
 
    module ImplementEqualityModule 
    { 
        public AddEqualsMethod(typeBuilder : TypeBuilder, members : list[PExpr]) : void 
        { 
            def other = Macros.NewSymbol(); 
            def comparisons = members.Map(m => { 
                def s = Splicable.Name(Name(m.ToString())); 
                <[ (this.$s).Equals($(other : name).$s) ]> 
            }); 
 
 
            def b = comparisons.Tail.FoldLeft(comparisons.Head, (c, acc) => <[ $acc && $c ]>); 
            typeBuilder.Define(<[ decl: 
                public override Equals(obj : object) : bool 
                { 
                    match (obj) { 
                        | null => false 
                        | $(other : name) is $(typeBuilder.ParsedTypeName) => $b 
                        | _ => false 
                    } 
                } 
            ]>); 
 
 
            def hashCodes = members.Map(m => { def s = Splicable.Name(Name(m.ToString())); <[ this.$s.GetHashCode() ]> }); 
            def hashCode = hashCodes.Tail.FoldLeft(hashCodes.Head, (c, acc) => <[ $acc ^ $c ]>); 
            typeBuilder.Define(<[ decl: 
                public override GetHashCode() : int 
                { 
                    $hashCode 
                } 
            ]>); 
        } 
 
 
        public AddEqualityOperator(typeBuilder : TypeBuilder) : void 
        { 
            typeBuilder.Define(CreateEqualityOperator(typeBuilder.ParsedTypeName, false)); 
        } 
 
 
        public AddInequalityOperator(typeBuilder : TypeBuilder) : void 
        { 
            typeBuilder.Define(CreateEqualityOperator(typeBuilder.ParsedTypeName, true)); 
        } 
 
 
        CreateEqualityOperator(typeRef : PExpr, invert : bool) : ClassMember.Function 
        { 
            def op = Splicable.Name(Name(if (invert) "!=" else "==")); 
 
 
            <[ decl: 
                public static $op(p1 : $(typeRef), p2 : $(typeRef)) : bool 
                { 
                    def p1Null = object.ReferenceEquals(null, p1); 
                    def p2Null = object.ReferenceEquals(null, p2); 
                    match (p1Null, p2Null) { 
                        | (true, true) => true 
                        | (false, false) => $(if (invert) <[false == p1.Equals(p2)]> else <[p1.Equals(p2)]> ) 
                        | _ => false 
                    } 
                } 
            ]> 
        } 
    } 
 
 
 
}
Saturday, November 08, 2008 5:18:15 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [3]  | 

InheritConstructors is a handy macro when you need to simply pass all arguments to a base constructor.

Watch the Screencast 

Before

using System;

 

namespace MacrosDemo

{

    public class MyBaseClass

    {

        public this(name : string, foo : int, bar : bool)

        {

            _name = name;

            _foo = foo;

            _bar = bar;

        }

 

        _name : string;

        _foo : int;

        _bar : bool;

 

        public virtual Test() : string

        {

            "Hello from MyBaseClass"

        }

    }

 

    public class MySubClass : MyBaseClass

    {

        public this(name : string, foo : int, bar : bool)

        {

            base(name, foo, bar)

        }

 

        public override Test() : string

        {

            "Hello from MySubClass"

        }

    }

 

    module Program

    {

        Main() : void

        {

        }

    }

}

After

using System;

using Nemerle;

 

namespace MacrosDemo

{

    public class MyBaseClass

    {

        public this(name : string, foo : int, bar : bool)

        {

            _name = name;

            _foo = foo;

            _bar = bar;

        }

 

        _name : string;

        _foo : int;

        _bar : bool;

 

        public virtual Test() : string

        {

            "Hello from MyBaseClass"

        }

    }

 

    [InheritConstructors]

    public class MySubClass : MyBaseClass

    {

        public override Test() : string

        {

            "Hello from MySubClass"

        }

    }

 

    module Program

    {

        Main() : void

        {

        }

    }

}

Saturday, November 08, 2008 5:13:02 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

This is a simple macro I use to make transactions feel like apart of the Nemerle language.

Watch the Screencast

Before

using System;
using System.Transactions;
 
namespace Demo
{
    module Program
    {
        Main() : void
        {
            using (trans = TransactionScope())
            {
                // Do some stuff in a transaction
                // ...
 
                // Remember to call Complete when finished!
                trans.Complete();
            }
        }
    }
}

After

using System;
using System.Transactions;
using SampleMacros;
 
namespace Demo
{
    module Program
    {
        Main() : void
        {
            transaction 
            {
                // Do some stuff in a transaction
                // ...
 
            }
        }
    }
}

transaction.n

using System;
using System.Transactions;
 
namespace SampleMacros
{
    public macro transaction(block) syntax ("transaction", block)
    {
        <[ 
            using (t = TransactionScope()) {
                $block;
                t.Complete();
            }
        ]>
    }
}
Saturday, November 08, 2008 5:08:54 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

The [Record] macro is applied to classes and makes it very easy to create simple data-transfer objects.

Watch the Screencast

Before

using System;

 

namespace MacrosDemo

{

    public class CustomerDto

    {

        public Id : int;

        public FirstName : string;

        public LastName : string;

        public IsPrefered : bool;

 

        public this(id : int, firstName : string, lastName : string, isPrefered : bool)

        {

            Id = id;

            FirstName = firstName;

            LastName = lastName;

            IsPrefered = isPrefered;

        }

    }

 

    module Program

    {

        Main() : void

        {

            def dto = CustomerDto(1, "John", "Smith", true);

        }

    }

}

 

After

using System;

using Nemerle.Utility;

 

namespace MacrosDemo

{

    [Record]

    public class CustomerDto

    {

        public Id : int;

        public FirstName : string;

        public LastName : string;

        public IsPrefered : bool;

    }

 

    module Program

    {

        Main() : void

        {

            def dto = CustomerDto(1, "John", "Smith", true);

        }

    }

}

 

Saturday, November 08, 2008 5:04:29 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  |