Shell Scripting with Objective-C
blog.manbolo.com
blog.manbolo.com
#!/bin/bash
set -eu
curl -s "https://raw.githubusercontent.com/manbolo/appicon/master/mask.png" >"icon_mask.png"
for app_id in "$@"
do
metadata=$(curl -s "http://itunes.apple.com/us/lookup?id=$app_id")
icon_url=$(echo $metadata | jq -r ".results[0].artworkUrl512")
name=$(echo $metadata | jq -r ".results[0].trackCensoredName")
icon_base="icon_$name"
curl -s "$icon_url" >"$icon_base.png"
convert "$icon_base.png" "icon_mask.png" -compose copy-opacity -composite "$icon_base.png"
for size in 1024 512 120 114 60 57
do
convert "$icon_base.png" -resize "${size}x${size}" "${icon_base}_${size}x${size}.png"
done
done
rm icon_mask.png
Run like ./appicon.bash 400274934 598581396
Notes- didn't replicate the slugify
- dependencies: imagemagick, jq
- here without spaces: http://pastebin.com/yBPwHwdk
- to get the same clarity as the python & Obj-C samples, I'd probably be approaching the same length.
10a11
> name=$(echo $name | tr -cd '[:blank:][:alnum:]' | tr -s '[:blank:]' '-' | tr '[:upper:]' '[:lower:]')Here is an implementation in Objective-Smalltalk (http://objective.st):
#!/usr/bin/env stsh
#-<void>processIconForApp:appId
framework:AppKit load.
framework:EGOS_Cocoa load.
nonChars := NSCharacterSet letterCharacterSet invertedSet.
str := '_'.
[ :self |
((self componentsSeparatedByCharactersInSet:nonChars) componentsJoinedByString:str) lowercaseStri
] installInClass: NSString withMethodHeaderString:'slugString'.
mask := http://raw.githubusercontent.com/manbolo/appicon/master/maskInverted.png.
appInfo := ref:http://itunes.apple.com/us/lookup getWithArgs id: appId
iconURL := var:appInfo/results/0/artworkUrl512.
name := var:appInfo/results/0/trackCensoredName.
icon := context evaluateScriptString: iconURL.
#(1024 512 120 114 60 57 ) do:[ :width |
c := MPWCGBitmapContext rgbBitmapContext: width @ width.
c scale: width / icon pixelsWide.
c maskedBy:mask draw:[ :aContext | aContext drawImage:icon. ].
scaled := c image.
outname := name slugString ,'_', width stringValue, '_', width stringValue , '_.png'.
file:{outname} := scaled representationUsingType:4 properties:nil.
].
This processes a single icon per call. The only dependency apart from AppKit (and obviously Objective-Smalltalk) is MPWDrawingContext, which I load via EGOS_Cocoa.(also, the pedant in me would like to point out that this is not "shell scripting" as you're not scripting a shell, but it's super cool regardless)
I'm starting to use Go for these sorts of things because it's really fast. I'd try objc but if I want to move my programs to a Linux server, I'm out of luck.
But I wanted libdispatch, blocks, all the stuff in the newer objc runtime, etc. Back then that meant playing all sorts of games compiling a specific objc runtime (there's more than one outside of apple), in a specific order with other things from GNUstep, using clang at certain steps instead of gcc to compile it all. It was a mess, but if I had really wanted to I probably could have pulled it off, and now I'm sure things have improved. I moved the entire thing to python and forgot about it though.
But I've always liked the idea of writing little things that have no GUI of any kind in objc, I wrote a few commandline utilities in objc and loved it. Background services on the system (mac or linux either one) would be fun too I think.
In this case, the GP is correct: NSImage is part of the UI toolkit (AppKit); it is not a core API exposed by, say, Foundation.
"You can say that [NSJSONSerialization JSONObjectWithData:resultsData options:0 error:nil]; is more verbose than r.json() but verbosity is an Objective-C convention, for the better or the wors[e]"
For this sort of task, like one of the other commenters, I would almost certainly write something quick and simple (and fairly unstructured) in bash; if it needed to be more maintainable, I'd write it in Ruby. Using a verbose, static typed language just seems wrong here.
Of course, for any given programmer and any given task, using the language with which they are most familiar is often a very good option (obviously only in circumstances where it is possible to perform the task in that language and its specific attributes don't jeopardise the successful running of the task).
So I am not surprised someone is trying to use it as a so-called shell script. The cocoa frameworks really contains a lot of convenient API (ex. when it comes to python, you have to install PIL or something else to process images). But on the other hand the objective-c shell scripting can not be used on platform other than OSX. That is a disadvantage.
It was more a play experiment than a true try to replace Python/Ruby/Go scripting. I was very intrigued by "Objective-C Minimalism" http://bou.io/ObjectiveC-Minimalism.html and wanted to see what would be scripting in Objective-C with all new features (Objects literals, ARC etc...)
c = [t v]
Can you tell me what c represents, and where it got its value? Sure, from [t v], but what are those? No, you can't. You finished reading it really quickly, but you understand very little about what is going on."A lot more text" is there for a reason: to explain what is going on.
How about:
cellsToUpdate = [tableView visibleCells]
This code tells you exactly what each item means. I find clear naming really nice to work with. Not that I would necessarily use exactly that line as a way of doing things, but hopefully you get the idea.