XPath and Clojure

9 11 2008

I’ve modified previous script to use Java’s XPath to extract RSS titles.

(import '(javax.xml.parsers DocumentBuilderFactory DocumentBuilder)
        '(org.w3c.dom Document Node)
        '(javax.xml.xpath XPathFactory XPath XPathExpression XPathConstants)
  )

(let [domFactory (doto (. DocumentBuilderFactory newInstance) (setNamespaceAware true))
      builder (. domFactory newDocumentBuilder)
      doc (. builder parse "/Users/jgoamakf/hotnews.rss")
      factory (. XPathFactory newInstance)
      xpath (. factory newXPath)
      expr (. xpath compile "//title/text()")
      result (. expr evaluate doc (. XPathConstants NODESET))
      ]
   (loop [index 0
          len (. result getLength)]
     (if (< index len)
       (do
         (println (. (. result item index) getNodeValue))
         (recur (inc index) len)))
))




RSS titles with Clojure

2 11 2008

This script prints every title appeared in RSS 2.0 feed.

(clojure/refer 'clojure.xml)

(let 
  • An error has occurred; the feed is probably down. Try again later.
(doseq entry content (let [el (get (get entry :content) 0)] (if (= (get el :tag) :title) (println (get (get el :content) 0)) ))) )

You need a RSS 2.0 XML file on your local hard drive before invoke.

% ftp http://images.apple.com/main/rss/hotnews/hotnews.rss
% java -cp clojure/clojure.jar clojure.lang.Script rsstitles.clj 




Emacs and Dropbox

28 10 2008

Emacs usually creates backup files(filename~) and autosave files(#filename#)
when you modify existing text files.

In my opinion, this behavior is not optimum for Dropbox folder because

  1. The Dropbox folder is already version controlled, so you don’t need backup copies
  2. Frequent writes to a remote folder result in waste of network bandwidth

These elisp configurations prevents Emacs from creating backup and autosave files
inside the Dropbox folder.

Don’t create backup files.

(setq backup-enable-predicate
      (lambda (name)
        (not (string-match "Dropbox" name))))

Create autosaves under /tmp/jgoamakf.

(setq auto-save-file-name-transforms '((".*/Dropbox/.*" "/tmp/jgoamakf/\\1" t)))




Custom Sheets don’t need their own xib files

9 08 2008

When you want to use custom sheets, Apple’s Documentation suggests that you create another xib file for the sheets(Using Custom Sheets).

But in fact, you don’t have to use a separate xib.

1. Create a controller class which handles both parent window and sheet window.

SheetTestController.h

@interface SheetTestController : NSObject {
	IBOutlet NSWindow *mainWindow;  //paent window
	IBOutlet NSWindow *sheetWindow; //sheet window
}

- (IBAction)showSheet:(id)sender; // open sheet on parent window
- (IBAction)closeSheet:(id)sender;// close sheet

@end

SheetController.m

@implementation SheetTestController

- (IBAction)showSheet:(id)sender
{
	[NSApp beginSheet: sheetWindow
	   modalForWindow: mainWindow
		modalDelegate: self
	   didEndSelector: @selector(didEndSheet:returnCode:contextInfo:)
		  contextInfo: nil];	
}

- (IBAction)closeSheet:(id)sender
{
    [NSApp endSheet:sheetWindow];
}

- (void)didEndSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
    [sheet orderOut:self];
}

@end

2. Add “Show Sheet” button to parent window.

parentWindow

3. Add a sheet window, and put “close sheet” button on the window.

sheetWindow
make sure that “Visible At Launch” is unchecked.
sheetWindowAttributes

4. Add a SheetTestController object to the xib.

sheetControllerInstance

5. Connection settings of SheetTestController should be like this.

sheetControllerConnections

This is a little easier than “separate xib” way, but has disadvantages noted below.

  • increses memory usage because the sheet window always takes up some memory instead of instanciated only when necessary.
  • It’s difficult to use the sheet window from other xib files.




Fast Enumeration with NSEnumerator

2 04 2008

While reading The Objective-C 2.0 Programming Language, I found that Fast Enumeration can be used with NSEnumerator(The Objective-C 2.0 Programming Language: Fast Enumeration).

Suppose you have an array which you want to itarete over.

NSArray *tmpArray =
    [NSArray arrayWithObjects:@"first", @"second", @"third", nil];

Use the for statement against the reverseEnumerator obtained from the array. It loops through the array starting from the last element and proceed to the first.

NSEnumerator *enumerator = [tmpArray reverseObjectEnumerator];
for(NSString *s in enumerator) {
    NSLog(@"%@", s);
}




Draw on CGLayer

24 03 2008

I modified Create an on-memory CGImageRef to draw the small blue rectangle on a CGLayer, and combines the CGLayer to the background graphics context to generate the image. The result should remain same.

const int height = 250;
const int width = 400;
	
CGColorSpaceRef  imageColorSpace = CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );

CGContextRef context = CGBitmapContextCreate (NULL, width, height,
                                    8, width * 4,
                                    imageColorSpace, kCGImageAlphaPremultipliedLast);

CGContextSetRGBFillColor (context, 1.0, 0.8, 0.8, 1);
CGContextFillRect (context, CGRectMake (0, 0, width, height ));

// Addition starts here.
CGLayerRef          layer;
CGContextRef        layerContext;

layer = CGLayerCreateWithContext(context,CGSizeMake(width, height),NULL);
layerContext = CGLayerGetContext(layer);

CGContextSetRGBFillColor(layerContext, 0, 0, 1, 1);
CGContextFillRect (layerContext, CGRectMake (80, 80, 40, 30));
	
CGContextDrawLayerInRect(context, CGRectMake(0, 0, width, height), layer);
// Addition finished.

CGImageRef image = CGBitmapContextCreateImage(context);

[imageView setImage:image imageProperties:nil];
	
CGColorSpaceRelease( imageColorSpace );
CGLayerRelease(layer);
CGContextRelease(layerContext);
CGContextRelease(context);
CGImageRelease( image );




Create an on-memory CGImageRef

21 03 2008

To create an on-memory CGImageRef object and display it through IKImageView, follow these steps.

  1. Create a Bitmap Graphics Context with the CGBitmapContextCreate() function.
  2. Draw some graphics on the Bitmap Graphics Context.
  3. Create an CGImageRef object from the Bitmap Graphics Context with the CGBitmapContextCreateImage() function.This CGImageRef object contains the same image as the Bitmap Graphics Context drawn in step 2.
  4. Pass the CGImageRef to IKImageView.
const int height = 250;
const int width = 400;

CGColorSpaceRef  imageColorSpace =
        CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );

CGContextRef context = CGBitmapContextCreate (NULL, width, height,
         8, width * 4, imageColorSpace,
         kCGImageAlphaPremultipliedLast);

CGContextSetRGBFillColor (context, 1.0, 0.8, 0.8, 1);
CGContextFillRect (context, CGRectMake (0, 0, width, height ));

CGContextSetRGBFillColor(context, 0, 0, 1, 1);
CGContextFillRect (context, CGRectMake (80, 80, 40, 30));

CGImageRef image = CGBitmapContextCreateImage(context);

[imageView setImage:image imageProperties:nil];

CGColorSpaceRelease( imageColorSpace );
CGContextRelease(context);
CGImageRelease( image );