My Colour Theme

July 24, 2011 at 12:06 AM | categories: codes | View Comments

This works fine on 256-colour terminal. Screenshot

(require 'color-theme)

;foregrounds
(defvar gainsboro "#dcdcdc")
(defvar pearlaqua "#88d8c0")
(defvar blue "#7ea4cd")
(defvar slategray "#708090")
(defvar wisteria "#c9a0dc")
(defvar papayawhip "#ffefd5")

;backgrounds
(defvar bg "#343434")
(defvar gray "#595959")


(defun boring ()
  (interactive)
  (color-theme-install
   (list
    'boring

     `((background-color . ,bg)
       (background-mode . dark)
       (border-color . ,bg)
       (cursor-color . ,gainsboro)
       (foreground-color . ,gainsboro)
       (mouse-color . ,bg))

     `(plain ((t (:foreground ,gainsboro))))
     `(reserved ((t (:foreground ,blue))))
     `(comment ((t (:foreground ,slategray))))
     `(funclass ((t (:foreground ,pearlaqua))))
     `(consvar ((t (:foreground ,papayawhip))))
     `(literal ((t (:foreground ,wisteria))))
     '(exception ((t (:inherit literal :bold t))))

     `(hilite ((t (:background ,gray))))

     `(fringe ((t (:background ,bg))))
     `(mode-line ((t (:foreground ,gainsboro :background ,gray))))
     '(region ((t (:inherit hilite))))
     '(flymake-errline ((t (:inherit hilite))))
     '(minibuffer-prompt ((t (:inherit reserved :bold t))))

     '(font-lock-builtin-face ((t (:inherit reserved))))
     '(font-lock-keyword-face ((t (:inherit reserved :bold t))))
     '(font-lock-function-name-face ((t (:inherit funclass))))
     '(font-lock-type-face ((t (:inherit funclass :bold t))))
     '(font-lock-comment-face ((t (:inherit comment))))
     '(font-lock-string-face ((t (:inherit literal))))
     '(font-lock-variable-name-face ((t (:inherit consvar))))
     '(font-lock-constant-face ((t (:inherit consvar :bold t))))
     '(font-lock-warning-face ((t (:inherit exception))))

     '(comint-highlight-input ((t (:inherit plain))))
     '(comint-highlight-prompt ((t (:inherit reserved :bold t))))

     '(eshell-prompt  ((t (:inherit reserved :bold t))))
     '(eshell-ls-directory ((t (:inherit reserved))))
     '(eshell-ls-executable ((t (:inherit literal))))
     '(eshell-ls-archive ((t (:inherit consvar))))
     '(eshell-ls-product ((t (:inherit consvar :bold t))))
     '(eshell-ls-symlink ((t (:inherit funclass))))
     '(eshell-ls-special ((t (:inherit funclass :bold t))))
     '(eshell-ls-unreadable ((t (:inherit comment :bold t))))
     '(eshell-ls-missing ((t (:inherit comment :bold t))))
     '(eshell-ls-backup ((t (:inherit comment))))
     '(eshell-ls-clutter ((t (:inherit comment))))


     '(isearch ((t (:inherit hilite :bold t))))
     `(isearch-lazy-highlight-face ((t (:background ,gray))))

     '(erc-action-face ((t (:inherit plain))))
     '(erc-default-face ((t (:inherit plain))))
     '(erc-input-face ((t (:inherit plain))))
     '(erc-notice-face ((t (:inherit comment))))
     '(erc-nick-default-face ((t (:inherit funclass))))
     '(erc-nick-msg-face ((t (:inherit funclass))))
     '(erc-my-nick-face ((t (:inherit funclass :bold t))))
     '(erc-current-nick-face ((t (:inherit funclass :bold t))))
     '(erc-timestamp-face ((t (:inherit consvar))))
     '(erc-prompt-face ((t (:inherit consvar))))
     '(erc-direct-msg-face ((t (:inherit reserved))))
     '(erc-error-face ((t (:inherit exception))))
     )))

(setq frame-background-mode 'dark) ;for rst
(provide 'boring)
Read and Post Comments

Pyramid Traversal and MongoDB

March 27, 2011 at 10:06 PM | categories: codes | View Comments

This post will talk about creating a simple web application with Pyramid and MongoDB. It will also talk about using a traversal method to map a requested URL to a callable function (controller/method/view/etc) in your application code.

The App

Enter Troll, an anonymous board web application. It is a simple application that is similar to a blog app (post and comment). The features are:

  • Sorted by activity (recently commented posts come first).
  • Automatic removal for the least commented post (there is a maximum number of posts).
  • Lord Inglip summoning pedestal (read: recaptcha).

The non-features:

  • No pagination. Maybe later with webhelper. Post limit is set to 10 by default anyway.
  • No test.
  • etc

The app uses a single mongodb collection for posts. The comments are embedded to a post document.

Source code is available here.

The Stack

This app uses few technologies

Traversal

NOTE : Traversal is optional in Pyramid. You can still use URL dispatch (pattern matching thing).

Traversal is a method of matching a requested URL to your application code just like a more familiar method, URL parsing and comparing it to a set of patterns. Traversal requires you to build a resource tree which is probably analogous to a file-system hierarchy. Pyramid will take a URL, and then traverse your resource tree trying to find a resource for that URL. Once a resource is found, Pyramid will try to find a function associated with that resource. The resource object found (or last traversed) is called context.

This post gave me a good idea about traversal.

For this application, two kinds of resource object are needed. The first one is the root object. This object will act as a container to post objects.

class Root(object):
    __name__ = None
    __parent__ = None

    def __init__(self, request):
        self.collection = request.db.post

    def __getitem__(self, name):
        post = Post(self.collection.find_one(dict(_id=ObjectId(name))))
        return _assign(post, name, self)

    def __len__(self):
        return self.collection.count()

    def __iter__(self):
        return ( _assign(Post(x), str(x['_id']), self) for x in self.collection.find().sort('updated', DESCENDING) )

The __getitem__ method will return post object (the child of the root object). The root object contains all posts. _assign is just a simple function to set some attributes of resource object.

def _assign(obj, name, parent):
    obj.__name__ = name
    obj.__parent__ = parent
    return obj

Next is the post object. This object is a slightly modified python dictionary (pymongo returns mongodb document as a python dict). Resource tree objects need to have a __parent__ attribute.

class Post(dict):
    def __init__(self, a_dict):
        super(Post, self).__init__(self)
        self.update(a_dict)
        self.__name__ = None
        self.__parent__ = None

The Views

This is the function for viewing a resource object.

@view_config(renderer='single.html', context=resources.Post)
@view_config(renderer='index.html', context=resources.Root)
def view(context, request):
    form = TrollForm()
    return {'p': context, 'form': form}

Pyramid allows you to write a function once and then register it multiple times for different contexts. Coming up is the function for handling post and comment addition.

@view_config(name='add', request_method='POST', context=resources.Post)
@view_config(name='add', request_method='POST', context=resources.Root)
def add(context, request):
    author = request.params['name']
    content = request.params['content']
    _add(context, author, content)
    return HTTPFound(location=request.resource_url(context))

Here is the _add function.

def _add(context, author, content):
    if context.__parent__ is None:
        _post(context.collection,
              author,
              content)
    else:
        _comment(context.__parent__.collection,
                 context['_id'],
                 author,
                 content)

Finally, doing insert/upsert to MongoDB.

def _post(collection, author, content):
    p = dict(author=author,
             content=content,
             comments=[],
             updated=datetime.utcnow(),
             time=datetime.utcnow())
    collection.insert(p)
    #remove unpopular post if >  10
    if collection.find().count() > 10:
        collection.remove({'_id': [x for x in collection.find().sort("updated", DESCENDING)][-1]['_id']})


def _comment(collection, post_id, author, comment):
    post = collection.find_one(dict(_id=post_id))
    time = datetime.utcnow()
    post['comments'].append(dict(author=author,
                                 comment=comment,
                                 time=time))
    post.update(dict(updated=time))
    collection.save(post)

Templating

Post form and comment form have the same fields (author, content, and captcha) and use the same form class (from wtforms). To prevent typing the same thing in many places, I created a template macro.

<%def name="createform(c, form)">
    <% link = request.resource_url(c)%>
    <form method="POST" action="${link}@@add">
        <div> ${form.name.label}: ${form.name(size=50)}</div>
        <div> ${form.content.label}: ${form.content(rows=5, cols=50)}</div>
        ${form.captcha}
        <input type="submit" value="Submit!"/>
    </form>
</%def>

This macro takes a context and a form object, to generate an html form. URL for any resource can easily be retrieved via resource_url method on request object. The '@@' means the start of a view name. Pyramid will traverse the URL until '@@', and search for a view named 'add' for that context.

This is how to use it.

${createform(request.context, form)}

If you want to use it on another template file, import it first.

<%namespace file="base.html" import="createform" />

Conclusion

Pyramid is a fun framework to tinker with.

Source Code

Read and Post Comments

Hello World

March 12, 2011 at 10:24 PM | categories: codes | View Comments

I finally decided to stop using wordpress and do static blogging instead. I chose Blogofile as my new blog engine because it's python, pretty active and has good docs.

My Changes

These are what I learned.

  • I want to write my blog in rst format. I am not familiar with it so I am going to use my blog as a learning tool. The problem is, currently, rst does not play nice with code highlighting. Luckily, there is already a great solution for that.

  • I feel pygments' default style, 'murphy', does not look right in my theme so I changed the default style to 'friendly' by putting this on syntax_highlighter.py:

    config = {'style': 'friendly'}
    
  • Blogofile assumes that your disqus username is similar to your site name (sitename.disqus.com). You might want to store them in a different variables if they are different, and use them accordingly on template files.

  • Be sure sure to load your css files made by pygments:

    % for css_file in bf.config.filters.syntax_highlight.mod.css_files_written:
        <link rel='stylesheet' href='${css_file}' type='text/css' />
    % endfor
    

That is probably it. I also learned about mako a bit. So, all set? Not quite. There is one thing left.

Deployment Method

Using a static blogging engine (web compiler) needs you to figure out how you want to update your blog on live server. It is a lot of work compared to usual dynamic blogging but with the right tools it can be handled. The plus is it is easy moving/updating sites once you are set.

I am still undecided on this issue. Here are my concerns:

  • Do I include compiled files in version control? or just the source?
  • What is the favorable method for me to bring the site live? mercurial hook or fabric and scp/rsync?

I tried mercurial hooks and it went well. I also installed python 2.7.1 and blogofile on the server, so the blog can be built there. I have a feeling that I will not decide on this matter for a long time and continue to use only ssh and scp. Nevertheless, I am going to put this on revision control even if I do not end up using its hooks for deployment.

Update : I chose to use fabric to manage this blog. Only compiled html files are deployed (build locally).

Read and Post Comments