Pull to refresh

Применяем на практике знания, полученные на курсе An Introduction to Interactive Programming in Python (coursera.org)

Reading time 5 min
Views 11K
По мотивам этого поста.
В прошедшем 2012 году я, как и миллионы других пользователей открыл для себя бесплатное онлайн обучение. Всё началось с прекрасного стартапа Codecademy. Замечательные курсы про JavaScript, jQuery, Python, Ruby и другие занимали всё свободное время. Побочным эффектом стала практика чтения на английском. К середине года доступные уроки закончились и я стал интересоваться другими площадками, где можно продолжить самообучение. Как раз в то время на Хабре участились статьи про Coursera и я решил попробовать.
Первым курсом который привлек внимание был An Introduction to Interactive Programming in Python от Rice University. Недолго думая, я вступил в стройные ряды онлайн студентов.

Часть 1. Снова в школу

С первой же видео-лекции преподаватели курса (Joe Warren, Scott Rixner, Stephen Wong, John Greiner) располагают слушателей к дружеской обстановке и весёлому настроению. Достаточно сказать, что первым проектом для изучения стало написание консольной версии широко известной в кругах любителей The Big Bang Theory игры «Камень. Ножницы. Бумага. Ящерица. Спок.». Для тех кто не в курсе вот ее правила.
Все программирование в этом курсе происходит в специальной онлайн песочнице, что очень удобно, так как не надо таскать с собой повсюду исходники и дистрибутивы, а все свои эксперименты можно сохранять «в облаках». Как устроен процесс обучения в Coursera наверняка местной публике уже известно. Темы лекций и проекты по неделям были следующие:

  1. Expressions, variables, functions, conditionals. (Проект «Rock-Paper-Scissors-Lizard-Spock» game)
  2. Event-driven programming, local and global variables, buttons and input fields. (Проект «Guess the Number» game)
  3. The canvas, static drawing, timers, interactive drawing. (Проект Stopwatch: The Game)
  4. Lists, keyboard input, motion, positional/velocity control. (Проект «Pong» game)
  5. Mouse input, more lists, dictionaries, images. (Проект «Memory» game)
  6. Classes, tiled images. (Проект «Blackjack» game)
  7. Acceleration and friction, spaceship class, sprite class, sound Spaceship from. (Проект «RiceRocks» game)
  8. Sets, groups of sprites, collisions, sprite animation. (Проект Full «RiceRocks» game)

Каждый проект подробно описывают преподаватели в конце лекции. Для проектов предоставляются шаблоны, которые уже содержат глобальные переменные, конструкторы классов и вспомогательные функции. Остаётся только написать нужные методы и реализовать вывод на экран. Не буду приводить ссылки на выполненные задачи на случай если кто-нибудь решит пройти этот курс. Я выполнял все работы максимально близко к поставленной задаче. А вот так выглядит финальный проект товарища, который пошел дальше необходимого минимума и добавил всякие красивости: http://www.codeskulptor.org/#user7-0WgaPD23z9-0.py. Кстати -0 в конце URL это версия файла. При каждом сохранении версия инкрементируются и всегда можно посмотреть предыдущие итерации. Такой вот изящный Source Control.
Экзамен в конце курса отсутствует, возможно поэтому не выдается никаких подтверждений о его успешном прохождении. Однако во время курса среди студентов был проведён конкурс скринкастов, по результатам которого два победителя получили по iPad.

Часть 2. Быдлокод

Закончив курс со средним баллом 99.46 / 100, я конечно же почувствовал себя всемогущим программистом. И как раз вовремя подвернулась небольшая задача, которую я и не преминул решить, используя вновь приобретенные знания.
Задачка была следующая: для имеющегося каталога с кучей документации в формате .pdf cгенерировать HTML страничку со списком ссылок на файлы, отсортированных по вложенным каталогам. Ссылки должны быть удобочитаемые, а значит имя файла не годится и нужно лезть в каждый PDF и читать заголовок документа.
Немного курения мануалов по модулям pyPdf и markup и совсем немножко копипаста, и получилось нечто:

pdfdir2html.py
import os
import sys
from datetime import date
from pyPdf import PdfFileReader
import markup
import shutil

def getPdfTitle(filename):
    if not filename.endswith('.pdf'):
        return ""
    input1 = PdfFileReader(file(filename, "rb"))
    
    if not input1 or input1.getIsEncrypted():
        print ".file " + filename + " is encrypted..."
        return filename.split(os.sep)[-1]

    if input1.getDocumentInfo() == None or input1.getDocumentInfo().title == None:
        print ".file " + filename + " has no title..."
        return filename.split(os.sep)[-1]

    return "%s - %s" % (input1.getDocumentInfo().author, input1.getDocumentInfo().title)
        

def create_html_list(rootpath):
    rootpath = rootpath.rstrip(os.sep)
    start_level = rootpath.count(os.sep)

    page = markup.page( )
    page.init( 
        title="Pdf File List", 
        css=( 'bootstrap.css', 'style.css' ), 
        script={ 'script.js':'javascript' } 
        )

    page.div(class_='wrapper')

    for root, dirs, files in os.walk(rootpath):
        present_level = root.count(os.sep)
        actual_level = present_level - start_level
        
        caption = os.path.realpath(root).split(os.sep)[-1]

        if actual_level == 0:
            page.h1( caption, class_='caption' )
        elif actual_level == 1:
            page.h2( caption, class_='caption' )
        elif actual_level == 2:
            page.h3( caption, class_='caption' )
        elif actual_level == 3:
            page.h4( caption, class_='caption' )
        else:
            page.h5( os.path.relpath(root), class_='caption' )

        if len(files) < 1:
            continue

        file_list = [file for file in files]

        # begin list
        page.ol( class_='list' )

        for filename in file_list:
            title = getPdfTitle(os.path.relpath(root) + '\\' + filename).encode('ascii', 'ignore')
            
            if title == "":
                continue
            
            # to escape special characters
            title.encode('ascii', 'ignore')

            # list item
            page.li( class_='item' )
            page.a(title, href=os.path.realpath(root) + '\\' + filename, class_='link')
            page.li.close()

        # end list
        page.ol.close( )

    today = date.today()
    today.strftime("%d-%m-%Y")
    page.div("Last list refresh: " + str(today), class_='time')

    page.div.close()

    # print page

    # writing page to index.html file
    index_html = open('index.html', 'wt')
    index_html.write(str(page))
    index_html.close()

def copy_files(files, dst):
    for file in files:
        shutil.copy2(file, dst + "\\" + file)

def usage():
    print "Usage: pdfdir2html @path_to_pdf_files"

if __name__ == '__main__':
    print "Generate HTML list from folder with pdf files"

    if len(sys.argv) == 1:
        print "No arguments given!"
        usage()
    elif len(sys.argv) == 2:
        destination = str(sys.argv[-1])
        print ".converting folder: " + destination + "..."
        create_html_list(destination)
        print ".copying files..."
        copy_files(['index.html', 'bootstrap.css', 'style.css'], destination)
        print ".done"
    else:
        print "Too much arguments!"
        usage()

Скрипт сканирует вложенные директории, считывает заголовок каждого PDF и создает в целевой папке файл index.html. Для пущей красоты я еще добавил к нему немножко CSS, но это уже детали…
Как оказалось, среди документации встречаются зашифрованные файлы, которые хоть и открываются нормально любым PDF ридером, но почему-то не позволяют прочитать свой заголовок с помощью getDocumentInfo().title. В таком случае ссылкой у нас будет всё-таки имя файла.
Для генерации HTML кода прекрасно подошел markup, с ним все просто и красиво, например:

    page = markup.page( )
    page.init( 
        title="Pdf File List", 
        css=( 'bootstrap.css', 'style.css' ), 
        script={ 'script.js':'javascript' } 
        )

    page.div(class_='wrapper')
    ...
    page.div.close()
    print page


Часть 3. Куда податься

Пусть приведенный код и не использует концепций ООП, изученных в курсе Interactive Programming in Python, но именно этот курс подстегнул во мне интерес к использованию новых языков и изучению современных паттернов программирования. В данный момент на очереди у меня вот такие курсы:


И это только на Coursera, а ведь есть еще Udacity, фантастический Сode School, edX с потрясающими курсами BerkeleyX и MIT, и этот список можно продолжать бесконечно.
Нельзя не упомянуть также инициативу русскоговорящих товарищей из стартапа «Свободный университет» Hexlet University. Желаю этому проекту развития взрывными темпами!
Теперь основной проблемой стало найти свободное время для всей этой учебы, а также мучительный выбор лучшего из нескольких курсов, которые идут одновременно.
Tags:
Hubs:
+18
Comments 4
Comments Comments 4

Articles