So, here's a small one for you. No one's claiming it's pretty, but hell if it's not useful. If you've been following Plugin A Week, they're pushing a lovely piece of crack by the name of domains. I won't attempt to sell you on it (and neither do they, in truth), but I'm in love. I've tried to do the same with engines, without much success.

I've gotten to the point where I want any and everything I might even think about reusing in the future is a plugin. It's a bit beautiful. I write an "Image" plugin that handles everything I ever worry about with images. I write an "identity" plugin that takes care of everyting with users. It uses the image plugin. I build a "store" plugin that encapsulates an entire online store. Next next I get a client, I just svn propedit svn:externals vendor/plugins -- a quick migrate, and I'm done. Well, I guess I am selling now.

Ahem. So. I have a lot of plugins. Here's what I want to happen in TextMate:

Gimmie Dat

And, I plop this in lib/tasks/textmate.rake (yes, the irony of not making a plugin does not escape me):

namespace 'mate' do

  desc "Create a TextMate Project File"
  task :project => [:environment] do
    include Builder

    plugin_directories = Dir["#{File.dirname(__FILE__)}/../../vendor/plugins/*"]
    base_directory  = File.expand_path("#{File.dirname(__FILE__)}/../../")
    directory_filter   = "!.*/(\\.[^/]*|CVS|_darcs|_MTN|\\{arch\\}|blib|.*~\\.nib|.*\\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$"

    project_name = File.basename( base_directory )
    out = File.open( "#{base_directory}/#{project_name}.tmproj", 'w')

    xml = XmlMarkup.new(:target => out, :indent => 2)

    xml.instruct! :xml, :version => '1.0', :encoding => 'UTF-8'
    xml.declare! :DOCTYPE, :plist, :PUBLIC, "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"

    xml.plist :version => '1.0' do
      xml.dict do
        xml.key('documents')
        xml.array do
          # 
          # Base Document
          #
          xml.dict do
            xml.key('name')
            xml.string( File.basename(base_directory) )

            xml.key('regexFolderFilter')
            xml.string( directory_filter )

            xml.key('sourceDirectory')
            xml.key( base_directory )
          end

          #
          # Plugins
          #
          plugin_directories.each do |plugin|
            full_path = File.expand_path( plugin )
            plugin_name = File.basename( full_path )

            xml.dict do
              xml.key('children')
              xml.array do
                Dir["#{full_path}/*"].each do |plugin_file|
                  plugin_file_name = File.basename( plugin_file )
                  plugin_file_path = File.expand_path( plugin_file )
                  xml.dict do
                    if File.directory?( plugin_file_path )
                      xml.key('name')
                      xml.string( plugin_file_name )

                      xml.key('regexFolderFilter')
                      xml.string( directory_filter )

                      xml.key('sourceDirectory')
                      xml.string( plugin_file_path )
                    else
                      xml.key('filename')
                      xml.string( plugin_file_path )

                      xml.key('saveAsAbsolutePath')
                      xml.true
                    end
                  end
                end
              end #array
              xml.key('name')
              xml.string( plugin_name )
            end # dict
          end
        end # array
        xml.key('fileHierarchyDrawerWidth')
        xml.integer('200')

        xml.key('metaData')
        xml.dict

        xml.key('showFileHierarchyDrawer')
        xml.true

        xml.key('windowFrame')
        xml.string('{{0, 800}, {800, 600}}')
      end # dict
    end # version
    out.close
  end

end
Copy/Paste

THAT'S ALOTTA CODE! SO MUCH CODE!

Shut Up.

I'm lazy, and reverse engineering can't be that clean. Well, maybe it can. Certainly not after four beers, though.

Anyway, if you're project's called awesome-2-point-oh, run rake mate:project, and you'll have an awesome-2-point-oh.tmproj file in your project's root you can double-click on to get the above screenshot