Sunday, February 25, 2007

Writing Domain Specific Languages with Python

  • The process of writing DSL is the same in all languages.
    • You write an ideal spec.
    • Then, you try to fit the spec so that it's kind of valid syntax for the language you use.
  • An example of ideal domain language (well, maybe not so ideal, but quite good):

test '/Login':
GetReq(uname = 'a_user',
password = '')
expect_tmpl: 'login.tmpl'
expect_tmpl_has: 'errorMsg'
expect_tmpl_data: { 'uname':'a_user',
'missing_fields' : ['Password']}
expect_session_lacks: 'uid'
  • Now the same but as a valid Python syntax:

test_serv('/Login',
GetReq(uname = 'a_user',
password = ''),
expect_tmpl = 'login.tmpl',
expect_tmpl_has = 'errorMsg',
expect_tmpl_data = { 'uname':'a_user',
'missing_fields' : ['Password']},
expect_session_lacks = 'uid')

  • Useful tricks inclue:
    • keyword args (expect_tmpl_data=...)
    • unbounded arg lists (*args)
    • operator overloading __add__(self, other_form)
    • reflection via hasattr, getattr, vars and friends
  • Thanks to Dan Milstein for his talk at PyCon about Little Languages in Python.

IronPython and Windows Forms talk

The presentation in html version

TabbedImages application

  • We got some good feedback after the presentation.
  • To my surprise there were many people already playing with IronPython.
  • What's even more surprising, there were some people that have already used Windows Forms.
  • Watch the tabbedimages application, I'm going to extend it with some interesting features.
  • If you browse the sources for it, you'll find some simple tests in the MainTest.py.
  • They exist because I'm afraid I'm not able to not do Test Driven Development.

Saturday, February 24, 2007

PyCon 2007

The PyCon conference is really great.
So far I was at the following talks:
  • Internationalization
  • Parsing revisited
  • Developing desktop applications with Dabo
    • I didn't know that creating applications with wxPython is such a pain.
    • The Dabo core is simply a layer above the wxPython.
    • The application they used on the presentation was an image viewer.
    • The API was really nice and in many cases reminded me a simplified version of WinForms API (where you uses strings instead of overused in .Net enumerations).
    • wxPython (so Dabo as well) works on all important platforms (Windows, Linux, MacOS)
  • WSGI - an introduction
    • Because there are many different Python web frameworks, WSGI goal is to be able to integrate different layers of different applications.
    • I'm still not sure how it could be used in the Ruby world and if there is any need for that.
  • Writing parsers and compilers with PLY
    • Recently, I'm working quite a lot with parsers and PLY is the main tool we use.
    • It's very good, very efficient, very elegant
    • You declare your grammar rules using docstrings
  • Creating the WhatWhat project with TurboGears
    • WhatWhat is a very simple project tracking tool that was implemented in 4 days using TurboGears.
    • It seems that frameworks like TurboGears are becoming quite easy to learn and use.
    • Not sure if as easy as Ruby on Rails, though.
    • I'm still not convinced what could be the reason for me not to use Rails in web applications :)
  • pyweek: making games in 7 days
  • Creating games with Pygame on the GP2X
  • SQLAlchemy
    • Looks like a very powerful ORM tool for Python.
    • Reminds me of Hibernate.
    • There is a tool called Elixir which is a layer on top of SQLAlchemy and is more similar to the Ruby ActiveRecord.
    • Migrations are only available as extensions.
    • However, they are different than Ruby migrations. I didn't quite understand what is really the difference. I was told that Ruby migrations are dangerous because they do too many things for you (!?).
    • It seems to me the above is one of the fundamental differences between Python and Ruby programmers.
  • IronPython: Present and future
    • That was definitely the best talk so far, IMO.
    • Jim is doing a great work in Microsoft.
    • My name even appeared at his slide :-)
    • He wasn't able to read my name, though ;-)
    • What's so difficult with my name? - Andrzej Krzywda
    • There were screenshots of Michael's tutorial on IronPython and Windows Forms.
    • Seo was mentioned, of course. He is the author of FePY - the Comunnity Edition of IronPython.
    • The reason of this special edition is that MS can't easily apply patches that are sent by non-MS people.
    • IronPython is supported by the MS Robotics project.
    • Jim presented a small IP script where he used some MS Gaming API to create a simple 3d game.
    • There is a growing support for IronPython in ASP.NET
  • Embedding Little Languages in Python
    • Little Languages is what the rest of the world calls Domain Specific Languages.
    • The talk was about how to use Python to create such a DSL.
    • The idea is the same as always with DSL:
      • Firstly, you think of an ideal specification.
      • You try to use the language features to fit to the spec.
    • Python features that are helpful:
      • Keyword args
      • * args
      • getattr, hasattr
    • The speaker used _ convention in his code examples.
    • I also prefer it, but it doesn't seem to be so popular in the Python community (it is in Ruby community).

Friday, January 19, 2007

Groovy and SwingBuilder

In my comparison of IronPython, Groovy and JRuby I used a "naked" Swing API to create a GUI application using Groovy. Groovy comes with a nice library called SwingBuilder that simplifies a lot of work with Swing. I couldn't find any documentation for SwingBuilder but the source code is pretty straight-forward. In my opinion, the best thing in the SwingBuilder version is the way you declare that a form has a button:

def frame = swing.frame(defaultCloseOperation: WC.EXIT_ON_CLOSE) {
button('OK', actionPerformed: click)
}

You can pass a closure to the frame method.
I really like this way. It allows you to create your GUI in a more declarative way.

As was suggested by Martin C. Martin and Dierk Koenig (many thanks!) on the Groovy-user list, the code might look something like the following:

import javax.swing.WindowConstants as WC

click = { event ->
event.source.text = "Pressed!"
}

def swing = new groovy.swing.SwingBuilder()
def frame = swing.frame(
size: [200, 200],
defaultCloseOperation: WC.EXIT_ON_CLOSE,
title: 'Hello' ) {
button('OK', actionPerformed: click)
}

frame.show()

Thursday, January 11, 2007

Iron Python on Balloons

Have you ever wondered how to create a simple application that uses balloons to notify about some events? Below is the result of my spike on how I could use IronPython and Windows Forms to create such thing.



Basically, it should:

  1. show an icon in the system tray

  2. NotifyIcon is a class that allows you to display an icon in the system tray.

  3. display a tooltip every n milliseconds

  4. It was easily achieved by using the notifyIcon.ShowBalloonTip method and the Timer (and its Tick event) class.

  5. have a context menu that allows you to exit the application

  6. The ContextMenu class.


Just paste the code to the Main.py file, prepare a test.ico file and run it with:
ipy Main.py

import clr

clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Drawing import Icon
from System.Windows.Forms import (Application, ContextMenu,
MenuItem, NotifyIcon, Timer)


class Main(object):

def __init__(self):
self.initNotifyIcon()
timer = Timer()
timer.Interval = 60000
timer.Tick += self.onTick
timer.Start()


def initNotifyIcon(self):
self.notifyIcon = NotifyIcon()
self.notifyIcon.Icon = Icon("test.ico")
self.notifyIcon.Visible = True
self.notifyIcon.ContextMenu = self.initContextMenu()


def onTick(self, sender, event):
self.notifyIcon.BalloonTipTitle = "Hello, I'm IronPython"
self.notifyIcon.BalloonTipText = "Who are you?"
self.notifyIcon.ShowBalloonTip(1000)


def initContextMenu(self):
contextMenu = ContextMenu()
exitMenuItem = MenuItem("Exit")
exitMenuItem.Click += self.onExit
contextMenu.MenuItems.Add(exitMenuItem)
return contextMenu


def onExit(self, sender, event):
self.notifyIcon.Visible = False
Application.Exit()


if __name__ == "__main__":
main = Main()
Application.Run()

Update:Marcin shows how to achieve the same with Groovy.

Sunday, December 17, 2006

Creating GUI with IronPython, Groovy and JRuby

I was curious what are the differences between the following tools when it comes to creating a GUI desktop application:
  • IronPython (with Windows Forms)
  • Groovy (with Swing)
  • JRuby (with Swing)

I prepared a simple example for each of them. The application shows a form with one button. This button when clicked changes its own text.

IronPython:

tested with 1.1a1 (1.1) on .NET 2.0.50727.42

  • Native windows
  • Possible to pass parameters in the constructor (form = Form(Text="test"))
  • Nice += for event handlers
  • As such a simple example it should work with Mono on Linux, however not sure about more complicated ones.

import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Windows.Forms
import Application, Button, Form
from System.Drawing import Size


form = Form(
Text="Hello",
Size=Size(200, 200)
)

button = Button(Text="OK!")

def onClick(event, handler):
button.Text = "Pressed!"

button.Click += onClick
form.Controls.Add(button)

Application.Run(form)


Groovy:
tested with 1.0-RC-01
(Thanks to Marcin Domański for his help on this example)
  • Cross-platform
  • Elegant event handlers api (actionPerformed:click)
  • Possible to pass parameters in the constructor (as in IronPython)


import javax.swing.JFrame
import javax.swing.JButton

def frame = new JFrame(
title:"Hello",
size:[200, 200],
defaultCloseOperation:JFrame.EXIT_ON_CLOSE
)

def click = {
event -> event.source.text = "Pressed!"
}

def button = new JButton(
text:"OK!",
actionPerformed:click
)

frame.add(button)
frame.show()



JRuby
tested with 0.9.2
  • Cross-platform
  • JRuby allows you to call Java code using the more Ruby-like underscore_method_naming and to refer to JavaBean properties as attributes.
  • Event handlers using classes is not nice


require 'java'
include_class "javax.swing.JFrame"
include_class "javax.swing.JButton"
include_class "java.awt.event.ActionListener"

frame = JFrame.new("Hello")
frame.set_size(200,200)
frame.defaultCloseOperation = JFrame::EXIT_ON_CLOSE

button = JButton.new("OK!")

class ClickListener < ActionListener
def actionPerformed(event)
event.source.text = "Pressed!"
end
end

button.add_action_listener(ClickListener.new)

frame.add(button)
frame.show


Update: There is a simpler Groovy version with SwingBuilder.

Tuesday, November 21, 2006

Ruby For Rails review



Ruby for Rails is a book written by David A. Black, a well known guru in the Ruby community

In short: The book is great.

I'd recommend it for all people who have already tried Rails and appreciate its magic, but now want to understand what's going on under the hood.

What is Ruby On Rails?

In case you have lived on another planet for the last year, Ruby on Rails is a web development framework. For those of you who know how Django works you can read a good comparison of Django and RoR.

The structure of the book is organised as follows:

Chapter 1 The Ruby/Rails landscape
Chapter 2 Ruby building blocks.
Chapter 3 Built-in classes and modules
Chapter 4 Rails through Ruby, Ruby through Rails

Quoting the author the goal of this book is:

(..) That's the goal - to be able to bring Ruby skills to bear seamlessly on Ruby tasks. Whether it's writing an action, or a method in a helper file, or a highly specialized suite of methods like the rankings and favorites facility in the music store application, the ideal situation is one in which you have a large number of programming techniques at your command and you use whichever ones help you get your application to do what you want it to do.

Having finished this book I feel that not only my Ruby skills got enhanced but also I understand more about Rails code. It's much easier now to follow the discussions about creating DSLs using Ruby and also actually creating my own DSLs. Even though not all of the Rails features are covered in the book, (like migrations or plugins) I'm able to see how simply they are designed. It wasn't easy, though (almost 500 pages). Finishing this book took me some time. I tried to follow most of the examples in the book but it was worth the time spent on it.

I really enjoyed the chapters about dynamic programming. They cover the whole family of eval methods, the singleton class. All of these are heavily used when you want to create a DSL.
Another very useful chapter for me was the one about regular expressions. I'm this type of developer who keeps forgetting details how to prepare a more complex regex.

Thanks to the Ruby for Rails book I feel the Ruby way better. I think it's very important to understand the whole philosophy of a language. I remember (back in December 2004) my first Ruby on Rails code was either looking exactly as in tutorials or when I needed to build something more complicated it was actually Java coding using Ruby ;-) I was in a similar situation when I started working with Python. It was very tempting to just code Ruby using Python. Thanks to Michael's patience I think I'm getting better with Python now :-)

Let's take the following Rails code as an example:

class Edition < ActiveRecord::Base
belongs_to :publisher
end

All Rails newbies can tell you what this code does. I'm not really so sure if all of them are able to explain how is it actually done under the hood.

I like to call Rails a DSL for creating web applications. Despite the whole simplicity it provides it also means it is an additional layer of abstraction.

Quoting Joel Spolsky :

All non-trivial abstractions, to some degree, are leaky.

We must understand how is the abstraction created so that when in a need we can easily fix any problem that appears during Rails development.

Ruby for Rails is an excellent book. It covers all important topics about Rails development and highlights the Ruby way. If you already created some Rails applications but still feel there is some magic around you definitely should read this book.