

Shell Scripting with Objective-C - jicea
http://blog.manbolo.com/2014/06/01/shell-scripting-with-objectivec

======
gatehouse
Decided to give it a shot in bash.

    
    
        #!/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](http://pastebin.com/yBPwHwdk)

\- to get the same clarity as the python & Obj-C samples, I'd probably be
approaching the same length.

~~~
jicea
Author here, the bash version is too beautiful: compact and clean! I will
include it in the article if you're ok!

~~~
gatehouse
Sure.

------
mpweiher
This is very cool! The amount of functionality in modern application
frameworks like Cocoa is really amazing, and it is a shame that it tends to be
ignored/inaccessible for scripting tasks.

Here is an implementation in Objective-Smalltalk
([http://objective.st](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.

------
zrail
Ok, `NSImage initWithContentsOfURL` is _awesome_. I haven't ever done much GUI
coding, is that a standard type of thing in GUI toolkits?

(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)

~~~
melling
Shell scripting usually means writing in your shells (e.g sb, csh, zsh) native
script. The author is using it to mean small scripts that he runs in a shell,
which is fine with me.

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.

~~~
wtallis
You're not out of luck when it comes to using objc on linux, you just have to
forgo a lot of the newer APIs. But if you're using it on a server, chances are
you won't miss the GUI APIs that GNUstep lacks.

~~~
mrsteveman1
Indeed, I had an entire server blog engine written in objc, I had it running
quite well on a Mac VPS (Lion running on vmware on Xserves), that I intended
to move over to a Linode.

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.

------
bshimmin
This bit about summed it up for me:

"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).

------
ant_sz
The objective-c with ARC support really enjoys some advantages script
programing languages enjoy. Apple added many syntax sugar such as `@[]` to
build array and `@{}` to build dictionary, which makes it easy to write.

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.

~~~
jicea
Hi author here!

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](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...)

------
danra
Cringed when opening the link, expecting to find AppleScript. Things turned
out better than expected!

------
js2
Author could combine both worlds with pyobjc. Might be interesting to add that
as a comparison.

~~~
jicea
Hmmm, I didn't know pyobjc at all, sounds very cool: power of Cocoa with
expressiveness of Python!

------
callesgg
Personally I find the objective c stuff to take longer to read and understand
just because there is allot more text.

~~~
natch
What is going on in the below line?

    
    
        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.

~~~
shadesandcolour
I like Objective-C a whole lot, but this is a shitty example. You didn't show
what "a lot more text" looks like, you showed everyone what "proper variable
names" look like.

