Sunday, March 30, 2008

Fixing Mac OS X - Leopard's Spaces

If anyone has turned on "Spaces" in Leopard, you'll know why Apple decided to ship it turned off; the window switcher (Command-Tab) doesn't understand Spaces, and will automatically warp you to the first space that has that application running on it. In practice, this is horrible if you have apps running on different spaces (browsers, terminal, textmate, etc). Luckily, Apple has a way of changing that behavior! In 10.5.2 they introduced a default option to disable space switching on Command-Tab. Open up Terminal or iTerm and type the following:
defaults write com.apple.Dock workspaces-auto-swoosh -bool NO
killall Doc

This will make Command-Tab only switch between applications running in the same Space. However, if you switch to an Application which is not in your current Space, it will still warp you to the Space where it is not warp you between spaces; you much always switch spaces manually. Regardless, it's much better and makes Spaces much more usable. Though, Workspaces in Gnome still feel much better.

Friday, March 28, 2008

Exploring the Dynamic Silverlight SDK

Dynamic Silverlight is the catch-phrase I use to describe the integration between dynamic languages and Silverlight. The fact that I need to even call it by a name means that it isn't the norm, not the standard, not implied, and that sucks. Granted, Ruby on Rails yells in your face that it uses Ruby, so maybe it's not that bad. =) The Dynamic Silverlight SDK is the toolset developers will need on their machines to develop Silverlight applications using dynamic languages. End-users need nothing more than the Silverlight runtime. Getting the bits I will always tell you to download dynamic language support in Silverlight from http://dynamicsilverlight.net/get. This package contains the latest binaries and sources of IronRuby and IronPython, as well as the Dynamic Language Runtime (DLR), which both the languages depend on. However, this is not the only place dynamic languages support exists in Silverlight. These languages, plus Managed JScript, are shipped in the Silverlight2 SDK. Though, these bits are from the end of February, which are significantly older than the bits on http://dynamicsilverlight.net/get ... it's great for getting started with dynamic silverlight if you already have the SDK installed, but it's just a snapshot of the Silverlight integration ... not the latest-and-greatest bits. I'm sure you have some questions already:
Wait, why isn't Managed JScript on http://dynamicsilverlight.net?
How come we need to download the bits?
Will the users of my application have to download this as well?
Why isn't this in Silverlight already?
Looking at the bits

So, you have the package on your disk and you've unzipped it, now what? The package contents are pretty straight-forward, but let me explain what some things mean.

/bin

Contains the compiled binaries for the DLR (Microsoft.Scripting.dll), IronRuby (IronRuby.dll and IronRuby.Libraries.dll), IronPython (IronPython.dll and IronPython.Modules.dll), and Managed JScript (Microsoft.Jscript.Runtime.dll and Microsoft.Jscript.Compiler.dll). Also, it contains Chiron.exe, a command-line tool which lets you develop a dynamic-language application in Silverlight with just a text-editor and a browser. I'll talk about this more later.

/scr

Contains the source to all the binaries in the /bin folder. We've provided a DynamicSilverlight.sln file so you can open it and build in Visual Studio easily. The DLLs it produces can be replaced with the DLLs in the /bin directory, and they will be loaded into Silverlight automatically.

/samples

A few samples in python and ruby to get you started. You can run them with the following scripts:

/server.bat

Runs Chiron in the "server" mode, and causes your default browser to open to the dynamic silverlight directory. You can then navigate into the samples, and click on their HTML file(s) to see them run. Run this only on Windows.

/server

Same as server.bat, except this is for Mac (requires Mono to be installed)

/README.txt

Basically this blog post

/LICENSE.txt

Copy of the license this package is under, which is the Microsoft Public License (MSPL)

That's the Dynamic Silverlight SDK! The next post will be about how to use Chiron to develop a Silverlight application in Ruby or Python.

Silverlight and dynamic languages

In the beginning of this month the free-love dynamic language guys and I released an open-source-licensed integration with Silverlight, making Ruby and Python able to run in the browser. This was pretty freakin' exciting for me, since it's what I've been working on since joining Microsoft in July'07. Though, it's been really hard for me to not talk about this stuff, since I was blogging about my last big project like every week, and we were releasing stuff just as fast. I want to get this Silverlight work along the same lines of involvement, so here we go! =) As any new project, our documentation is a little lacking. Though we have a website, a CodePlex project, and mailing lists, the information helping people get started with the project is hidden in those 3 places. To remedy that, I'm going to make a series of "Silverlight and dynamic languages" posts: Exploring the Dynamic Silverlight SDK Making a Silverlight application in Ruby/Python/JScript Deploying your Dynamic Silverlight application These are the first three that I'm working on, but definitely not the last! Let me know what area of dynamic languages in Silverlight interests you, and I'll make sure to write about it!

Thursday, March 27, 2008

RailsConf 2008

RailsConf 2008 Just registered today! I don't have a talk there, but I may tag-team it up w/John Lam to show off our Rails integration ... IronRuby on the server, and IronRuby on the client =) I'm also trying to talk the Assistment guys into coming along, hopefully they can. Anyway, it's kinda cool that I'm going, especially since Rails is this word that will always remind me of the thing that kept me doing what I'm doing. I'm sure this is true for so many others out there. So thanks, and see you all soon.

Monday, March 24, 2008

Teaser: Rails and the Blue Nebula

I'll just leave you with a dump of Mongrel starting up ... with a couple choice lines bolded ...
jimmysch-gemini-mac:SilverlightOnRails jimmy$ ./script/server => Booting Mongrel (use 'script/server webrick' to force WEBrick) => Rails application starting on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server ** Starting Mongrel listening at 0.0.0.0:3000 ** Starting Rails with development environment... ** Initializing Silverlight ** Generating client.xap ** Rails loaded. ** Loading any Rails specific GemPlugins ** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart). ** Rails signals registered. HUP => reload (without restart). It might not work well. ** Mongrel 1.1.2 available at 0.0.0.0:3000 ** Use CTRL-C to stop.
More on this later =)

Parsing JSON in IronRuby

When John Lam and I were preparing for MIX, there were a lot of crazy JSON-serialization coding going on in our demo apps. And none of them were pretty. My implementation was outright dangerous ... it's a good thing I trust Flickr to not send me dangerous JSON. =) After we got back from MIX, I started working on making Dynamic Silverlight play better in the wild, and this JSON issue was the first on my list to attack. Ok, it got pushed a little further down on the que due to all these crazy "PM" tasks I have to do, but never-the-less I've got something to talk about =) Wait, Dangerous? Yep, dangerous! John's solution was much safer, since it used the JSON serializer in Silverlight, but it required an assembly and, well, uck! More seriously, serialization is not what I'm looking for; it's simply converting the JSON arrays/hashes to Ruby array/hashes, and making sure the key/value pairs are valid JSON. Serializing to an object model isn't as interesting to me, as I may have an object that already supports instantiating itself with JSON (Rails' ActiveRecord models ... more on this in a future post =)). Anyway, you can check out John's solution if you have a C# object model that needs to serialize/deserialize into JSON. My first stab at this was wrong on so many levels:
  def json_str
    @str.
    split(":".to_clr_string).
    join("=>".to_clr_string).
    to_clr_string
  end

Yep, that's right ... replace all occurrences of ":" with "=>" .. eek! That'll work fine until you have time values that look like "2007/03/24 09:00:00". =) Then what do I do with this transformed string?

  def parse
    ScriptRuntime.
    create.get_engine("rb").
    create_script_source_from_string(json_str).
    execute
  end

That's right, I eval it! (Why did I write my own eval? Because we don't have eval working in IronRuby today, so this is how you'd use the Hosting APIs of the DLR to implement it). No parsing/making sure the string doesn't reformat my drive or anything. =P

So, you write crappy code ... got a fix?

Yeah, thanks genius ... that's the point of this spheel. Anyway, the solution is to write a real JSON parser in Ruby. There are JSON libraries for Ruby already (gem install json), but I wanted a simple stand-alone parser to include in a Silverlight application. Luckily, that's not a extremely hard task as the JSON semantics are pretty straight-forward. Though, I'm a lazy bastard, so I'm not going to write my own!

Ruby Quiz #155 talks about parsing JSON, and shows a hand-rolled recursive decent parser. It didn't work as-advertised in IronRuby (to be expected though, IronRuby isn't finished yet), so I adapted it to work in IronRuby. This parser not only gets the semantics right, but makes sure I'm not eval-ing random stuff (it makes sure it parses as JSON before eval-ing). Anyway, here's all 154 lines of glory:

require "Microsoft.Scripting"
include Microsoft::Scripting::Hosting

class JSONParser
  # TODO: remove when eval is implemented
  def evaluate(str)
    ScriptRuntime.
    create.
    get_engine("rb").
    create_script_source_from_string(str).
    execute
  end

  # TODO: remove this when Struct is working properly
  class AST
    def initialize(value)
      @value = value
    end
    def value
      @value
    end
  end

  def parse(input)
    @input = StringScanner.new(input)
    if top_level = parse_object || parse_array
      top_level.value
    else
      error("Illegal top-level JSON object")
    end
  end

  private

  def parse_value
    trim_space
    parse_object or
    parse_array or
    parse_string or
    parse_number or
    parse_keyword or
    error("Illegal JSON value")
  ensure
    trim_space
  end

  def parse_object
    if @input.scan(/\{\s*/)
      object = Hash.new
      more_pairs = false
      while true
        key = parse_string
        break if key == false
        @input.scan(/\s*:\s*/) or error("Expecting object separator")
        object[key.value] = parse_value.value
        more_pairs = @input.scan(/\s*,\s*/) or break
      end
      error("Missing object pair") if more_pairs
      @input.scan(/\s*\}/) or error("Unclosed object")
      AST.new(object)
    else
      false
    end
  end

  def parse_array
    if @input.scan(/\[\s*/)
      array = Array.new
      more_values = false
      while true
        contents = begin
          parse_value
        rescue
          nil
        end
        break if contents == false or contents.nil?
        array << contents.value
        more_values = @input.scan(/\s*,\s*/) or break
      end
      error("Missing value") if more_values
      @input.scan(/\s*\]/) or error("Unclosed array")
      AST.new(array)
    else
      false
    end
  end

  def parse_string
    if @input.scan(/"/)
      string = String.new
      while true
        contents = parse_string_content
        contents = parse_string_escape if contents == false
        break if contents == false
        string << contents.value
      end
      @input.scan(/"/) or error("Unclosed string")
      AST.new(string)
    else
      false
    end
  end

  def parse_string_content
    if @input.scan(/[^\\"]+/)
      AST.new(@input.matched)
    else
      false
    end
  end

  def parse_string_escape
    if @input.scan(%r{\\["\\/]})
      AST.new(@input.matched[-1])
    elsif @input.scan(/\\[bfnrt]/)
      AST.new(evaluate(%Q{"#{@input.matched}"}))
    elsif @input.scan(/\\u[0-9a-fA-F]{4}/)
      AST.new([Integer("0x#{@input.matched[2..-1]}")].pack("U"))
    else
      false
    end
  end

  def parse_number
    if @input.scan(/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?\b/)
      AST.new(evaluate(@input.matched))
    else
      false
    end
  end

  def parse_keyword
    if @input.scan(/\b(?:true|false|null)\b/)
      matched = @input.matched == "null" ? "nil" : @input.matched
      val = evaluate(matched)
      AST.new(val)
    else
      false
    end
  end

  def trim_space
    @input.scan(/\s+/)
  end

  def error(message)
    if @input.eos?
      raise "Unexpected end of input."
    else
      raise "#{message}: #{@input.peek(@input.string.length)}"
    end
  end
end
Usage:
p = JSONParser.new
r = p.parse YOUR_JSON_DATA
Enjoy!
Blogged with the Flock Browser

Friday, March 14, 2008

New Dynamic Silverlight site!

http://dynamicsilverlight.net has got a shiny new look! Well, it just got it's first look, since before it was worse-looking than a 1990's-style website. Anyway, it's been bombarded with useful links, so let us walk through them: /see Here you'll find links to sample apps written in Ruby and Python. There's only 3 up there now, but we'll be adding more ... I promise. =) /get Download pointers to the Dynamic Silverlight SDK, Silverlight 2, Silverlight SDK, Visual Studio Tools, etc etc etc. Basically anything you could ever want to use to develop a Silverlight app is there. /learn Links to documentation, walk-throughs, blogs, talks, specs, and anything else to make you a browser ninja. /contribute So, when you're done getting and learning all about this stuff, time to actually talk to people! Here you'll find pointers to IronRuby/IronPython project information. Enjoy! =)

Thursday, March 13, 2008

Lang.NET Videos are back online

http://langnetsymposium.com/talks.asp
The videos are now hosted on downloads.microsoft.com, after a hosting fiasco and no where for 2GB of video to live. Luckily enough people care about those videos being available and helped to get them back up. The delay in getting them back up was mainly my fault: I was totally focused on MIX08 when the videos went down, so this week was the only time I had to bug people. Sorry for the delay, but I'm sure it gave you some free time =). And for those who asked, I also put direct links to the video files on the talks page. Enjoy!

Friday, March 07, 2008

Dynamic Silverlight

Silverlight 2 Beta 1 was released at MIX08 this past week. Since I work on the dynamic languages team, getting our languages working in Silverlight is definitely something I wanted to do ... and we have! http://dynamicsilverlight.net Dynamic Silverlight is finally released! You can download the binaries and sources to Ruby, Python (the Iron implementation), the dynamic language runtime (DLR), the dynamic language and Silverlight integration, and Chiron: a dynamic Silverlight development utility, all in once package ... along with samples for Ruby and Python. Everything here is released under the Microsoft Public License (MSPL), so feel free to extend it, fork it, etc. This release coincides with the release of Silverlight 2 Beta 1, as well as the MIX08 conference (http://visitmix.com). John Lam and I have a talk about dynamic silverlight at MIX, and we also had a lab which you can find here: http://dynamicsilverlight.net/mix08-hol-ruby.zip. John Lam has posted a walk-through of our MIX demos here: Part 1: http://www.iunknown.com/2008/03/dynamic-silverl.html Part 2: http://www.iunknown.com/2008/03/dynamic-silve-1.html Part 3: http://www.iunknown.com/2008/03/dynamic-silve-2.html This is what I've been working on since I started @ Microsoft in July'07, and I'm jazzed that I can now share it with people. Enjoy!