Re: Factor

Factor: the language, the theory, and the practice.

GitHub Vanity

Monday, January 24, 2011

#github #networking

There was a blog post on The Changelog yesterday describing a project that can give at-a-glance statistics about a GitHub user. The project is called vain and is open source. Since implementing APIs is fun (at least the first few times), I thought I would show how to implement the vain utility using Factor and the GitHub API.

USING: accessors assocs combinators formatting http.client
json.reader kernel math sequences sorting utils ;

Experiment

We can experiment with the GitHub API in the Factor Listener, looking at seejohnrun, the creator of vain:

IN: scratchpad "https://github.com/api/v2/json/user/show/seejohnrun"
               http-get nip json> .
H{
    {
        "user"
        H{
            { "followers_count" 18 }
            {
                "gravatar_id"
                "3a0541ed3d5324bb54b9f07990be20ae"
            }
            { "login" "seejohnrun" }
            { "public_gist_count" 0 }
            { "public_repo_count" 23 }
            { "location" "Verona, NJ" }
            { "created_at" "2009/03/19 10:29:18 -0700" }
            { "type" "User" }
            { "id" 64965 }
            { "blog" "https://johncrepezzi.com" }
            { "email" "john@crepezzi.com" }
            { "name" "John Crepezzi" }
            { "company" "Patch" }
            { "permission" json-null }
            { "following_count" 11 }
        }
    }
}

Implement

We can use the set-slots word (similar to how we implemented Reddit “Top”) to get the user details:

TUPLE: user blog company created_at email followers_count
following_count gravatar_id id location login name permission
public_gist_count public_repo_count type ;

: user-info ( login -- user )
    "https://github.com/api/v2/json/user/show/%s" sprintf
    http-get nip json> "user" swap at
    user new [ set-slots ] keep ;

Similarly, we can access a list of public repositories for a specific user:

TUPLE: repository created_at description fork forks
has_downloads has_issues has_wiki homepage language name
open_issues organization owner private pushed_at size url
watchers ;

: repositories ( login -- seq )
    "https://github.com/api/v2/json/repos/show/%s" sprintf
    http-get nip json> "repositories" swap at
    [ repository new [ set-slots ] keep ] map ;

Using this, we have everything we need to implement vain:

: vain ( login -- )
    [
        user-info {
            [ login>> ]
            [ followers_count>> ]
            [ public_repo_count>> ]
        } cleave
        "%s - %s followers - %s public repositories\n" printf
    ] [
        repositories [ watchers>> ] inv-sort-with [
            {
                [ name>> ]
                [ watchers>> "%s watchers" sprintf ]
                [ forks>> "%s forks" sprintf ]
                [ fork>> "(FORK)" "" ? ]
            } cleave "%-25s %12s %12s %s\n" printf
        ] each
    ] bi ;

Try It

You can see the output for seejohnrun.

IN: scratchpad "seejohnrun" vain
seejohnrun - 18 followers - 23 public repositories
ice_cube                  255 watchers     15 forks 
database_validation        60 watchers      4 forks 
track_history              57 watchers      4 forks 
easy_translate             39 watchers      2 forks 
vain                       23 watchers      2 forks 
console_tweet              15 watchers      1 forks 
tweetStream4J               6 watchers      3 forks 
my_tunes                    3 watchers      1 forks 
locale_base                 2 watchers      1 forks 
Open-Stanza                 2 watchers      1 forks 
Pretty-Damn-Fancy           1 watchers      1 forks 
rstack                      1 watchers      1 forks 
dependable                  1 watchers      1 forks 
quick_short                 1 watchers      1 forks 
html_namespacing            1 watchers      0 forks (FORK)
usps                        1 watchers      0 forks (FORK)
dotfiles                    1 watchers      1 forks 
datejs                      1 watchers      0 forks (FORK)
redis-repeater              1 watchers      1 forks 
roflscale                   1 watchers      1 forks 
weatherbug                  1 watchers      1 forks 
gravatar_helper             1 watchers      1 forks 
columnizer                  1 watchers      1 forks

Bonus

Some fun with Gravatar pictures:

The code for this is on my GitHub.