Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,583
|
Comments: 51,213
Privacy Policy · Terms
filter by tags archive
time to read 2 min | 326 words

Boo has gotten a lot better in terms of flexibility lately, a lot better. I was able to churn this little DSL in about an hour:

OnCreate Account:
	Entity.AccountNumber = date.Now.Ticks
	
	
 OnCreate Order:
	if Entity.Total > Entity.Account.MaxOrderTotal:
BeginManualApprovalFor Entity

From the perspective of the DSL, it is very easy to use, and from the implementer perspective, this was ridiculously easy to implement.

The only half-way complex thing here is the introduce base class action, which is usually the first approach that you take, which is why I don't consider it complex. Then you can just do create the base class:

abstract class DslBase:

	[property(Entity)] 
entity as object
        def OnCreate(entity as System.Type, action as callable()):
		Actions.RegisterOnCreate(entity.Name, action)
		
	abstract def Execute():
		pass
	
	def BeginManualApprovalFor(order as Order):
		print "Starting approval process for Order #${order.Id}"

In the base class you just do what you would normally do, in this case, it just register the new action. Here is the implementation:

class Actions:
	
	static onCreateActions = {}
	
	static def RegisterOnCreate(entityName as string, action as callable()):
		onCreateActions[entityName] = action
		
	
	static def OnCreate(entity as object):
		entityName = entity.GetType().Name
		action = onCreateActions[entityName] as callable()
		if not action:
			print "No action defined for ${entityName}"
			return
		dsl = (action.Target as DslBase)
		dsl.Entity = entity
		action()

The client code is simply:

SampleDSL().Prepare("Sample.boo")

account = Account(MaxOrderTotal: 100)

print "Before: ${account.AccountNumber}"
Actions.OnCreate( account )
print "After: ${account.AccountNumber}"

order = Order(Account: account, Total: 500 )
Actions.OnCreate( order )

All you have left then is to get a rich enough library of methods on the DslBase, for the business user to work with, document how this is done, and that is it.

time to read 2 min | 346 words

Boo has the concept of Has Literals, and it can really make a difference in a lot of cases. It makes some things possible to write. Even leaving aside common things like dictionaries constants, consider this signature:

public void Configure(IDictionary options)
{
	// do work
}

In Boo, I can call this method like this:

config.Configure({
	"connection_string": 	"data source...",
	"batch_size":		15
//	etc
})

This  is much clearer than the C# option, but we can do better.

public class UnknownHashLiteralKeyToStringLiteral : ProcessMethodBodiesWithDuckTyping
{
	public override void OnReferenceExpression(ReferenceExpression node)
	{
		IEntity entity = NameResolutionService.Resolve(node.Name);
		//search for the left side of a key in a hash literal expression
		if (node.ParentNode is ExpressionPair 
                && ((ExpressionPair) node.ParentNode).First == node
                && node.ParentNode.ParentNode is HashLiteralExpression)
		{
                	ExpressionPair parent = (ExpressionPair) node.ParentNode;
	                StringLiteralExpression literal = CodeBuilder.CreateStringLiteral(node.Name);
	                parent.First = literal;
	                parent.Replace(node, literal);
	                return;
        	}
		base.OnReferenceExpression(node); 
	}
}

Now, we have to register it in the compiler:

compiler.Parameters.Pipeline.Replace(
    typeof(ProcessMethodBodiesWithDuckTyping), 
    new UnknownHashLiteralKeyToStringLiteral());

Now, we can write this kind of code:

config.Configure({
	connection_string: 	"data source...",
	batch_size:		15
//	etc
})

It make the syntax much clearer, and it make quite a bit of a difference in the clarify of the code. I am going to put it into Brail, MonoRail has quite a few of methods that takes dictionaries, and it would make the syntax even nicer.

time to read 1 min | 115 words

Okay, I intended to post about this in more details, but I want to wrap up this day, I added support for native facilities in Binsor. By native I mean facilities that expect to be configured by Windsor XML configuration. Since I am mostly the only one that is writing Binsor based facilities, this has been a problem when people wanted to use the standard facilities.

You can see the syntax here, very Yaml like, I think :-)

I am going to post soon about how I managed to get this syntax to work.

Facility("loggerFacility", LoggingFacility, 
	loggingApi: "Log4net", 
	configFile: "Config/log4net.config",
	NestedConfig: {
		something: "foo",
		bar: "nar"
		}
	) 

Boo's DSL

time to read 1 min | 50 words

Yeah, better support for DSLs in Boo!

I am using Boo as my programming language of choice, and I really like the ability to just drop off and build new syntax any way I want to. This new change make it even easier, hence more approachable, so this is very cool.

time to read 2 min | 251 words

Chris Holmes commented on my thinking for tools, but I think that he missed a crucial distinction that I made (but not clear enough).

If you require a tool in order to work effectively with something, this is an issue. By requiring a tool I mean something beyond VS + R#, which are the bare minimum stuff that you need to be effective in C# (it does says something on C#, doesn't it?). The Entity Framework Designer is a good example for something where I think that the dependence on the tools indicate a problem. I have been corrected about requiring the SCSF to work effectively with the CAB, which was good to hear.

Tools can make you more effective, but I think that you should always learn without them. Case in point, I am currently teaching people about .Net (I'll have a seperate post about it soon, I promise) and teaching them stuff like NHibernate or Active Record would be actively harmful for them at this stage, when they don't understand the basics of ADO.Net completely yet. In my opinion, it is always a good idea to know what the tool is doing, why, and where its shortcomings are.

Oh, and about the program in notepad thing, I don't program C# in notepad (usually), but I have written fully fledged applications in Boo from notepad and the command line. Boo makes it easy & painless to do so, and it is a pleasure (and painless) to work with it.

Booish fun

time to read 4 min | 755 words

Booish is a command interpreter for the Boo language, this means that it gives you the full power of Boo and the .NET framework at your finger tips.

I just needed to find the number of methods in mscorlib:

import System.Reflection

mscorlib = typeof(object).Assembly

methodCount = 0

typeCount = 0

for t in mscorlib.GetTypes():

      typeCount +=1

      for m in t.GetMethods():

            methodCount += 1

print "Types ${typeCount}, Methods: ${methodCount}"

The result:

Types 2319, Methods: 27650
time to read 7 min | 1271 words

After reading a bit about Jasper, I decided that I would like to see what it would take to build it with NHibernate and Boo. I am going to implement it and write the post at the same time, so you would get near real time documentation of the process.

  • 18:05, decided that I want this syntax:

    import Bumbler

     

    conStr = "Data Source=localhost;Initial Catalog=Northwind;Integrated Security=True;";

     

    bumble = Bumble.Through(conStr)

    for customer in bumble.Customers:

          print "Customer ${customer.ContactName}"

    c

    = bumble.GetCustomer("TRADH")
  • 19:10, finished building client interface and quick & dirty mapping from database implementation.
  • 19:24, finished code generation, now working on runtime compilcation...
  • 19:54: finished runtime code generation
  • 20:13, can now successfully query the database using NHibernate just from connection string. Starting to work on dynamic implementation.
  • 20:16, done basic dynamics, now playing with Booish.
  • 20:21, the code above now works, and I am going for dinner.
  • 21:10, back from dinner, final polish...
  • 21:13, done!

So, about two hours of work, most of which had to do with generating the mapping from the database. I have cut some corners there, so it is SQL Server only, and it can't support a legacy app, adding support for the more complex cases is simply adding it to the mapping generation, nothing else. I made sure that adding new functionality would be easy, however.

Right now, you can get the code, just run the application, and you will get a shell that you can use to interact with the objects and the database. You need to start a new Bumble (you can simply cut/paste the code above) and then play with it. You can also reference the assembly and work with it directly using Boo.

Getting the code:

svn co https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/SampleApplications/Bumbler

By foul moon

time to read 10 min | 1942 words

Because I know that I will need it...

# Not very accurate, but apperantly good enough for most purposes

# source: http://www.faqs.org/faqs/astronomy/faq/part3/section-15.html

def IsFullMoon(dateToCheck as date):

      two_digit_year as decimal = dateToCheck.Year - ((dateToCheck.Year/100)*100)

      remainder as decimal = two_digit_year %19

      if remainder > 9:

            remainder -= 19;

      phase as decimal = (remainder * 11) %30

      if dateToCheck.Month == 1:

            phase+=3

      elif dateToCheck.Month == 2:

            phase+=4

      else:

            phase+= dateToCheck.Month

      phase+=dateToCheck.Day

      if dateToCheck.Year < 2000:

            phase -= 4

      else:

            phase -= 8.3

      phase = phase % 30

      return 14.5 < phase and phase < 15.5

Expected usage:

if IsFullMoon(DateTime.Now):

      raise SqlException("""Transaction (Process ID 179) was deadlocked on lock resources with another
process and has been chosen as the deadlock victim. Rerun the transaction."""
)

Update: I am still struggling with the code for WasChickenSacrifised(), will be glad to get suggestions...

time to read 7 min | 1272 words

I just got a patch file that SVN couldn't handle. I handled the issue with this piece of code, here for future reference:

import System.IO

 

file = """random.patch""";

lines = File.ReadAllLines(file)

currentFile as TextWriter

for line in lines:

      if line.StartsWith("+++"):#new file

            currentFile.Dispose() if currentFile is not null

            fileName = line.Replace("+++","").Replace("(revision 0)","").Trim()

            currentFile = File.CreateText(fileName)

            print fileName

            continue

      continue if not line.StartsWith("+")

      currentFile.WriteLine( line.Substring(1) )

I love Boo!

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  2. Webinar (7):
    05 Jun 2025 - Think inside the database
  3. Recording (16):
    29 May 2025 - RavenDB's Upcoming Optimizations Deep Dive
  4. RavenDB News (2):
    02 May 2025 - May 2025
  5. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats
}