Пишем клиента для OData на Python

Open Data Protocol

Что это такое и для чего создан очень хорошо рассказано в этом видео: http://www.msteched.com/2010/NorthAmerica/DEV208

Python

Одним из аргументов в пользу OData звучит то, что данный протокол не зависит от платформы, и это очевидно (AtomPub), а так же не привязан к конкретному вендору. Но всё же я решил набросать небольшой пример, в котором эмулировать привычный .NET API для работы с OData

Lets code it

import odata

url = "http://odata.netflix.com/Catalog/"

service = odata.service(url)

service.Languages

languages = service.execute()

print languages

Давайте разбираться, что же написано выше.

http://odata.netflix.com/Catalog/ - netflix является одним из официальных поставщиков OData

Итак, мы импортируем наш модуль OData, который мы реализуем чуть позже, далее создаем сервис, для получения данных и читаем какие языки будет предоставлять нам netflix.

odata.py

import urllib2
import feedparser

version = '0.1'

feedparser — не входит в набор стандартных библиотек python, поэтому её надо будет скачать и установить, как видно из нахвания библиотека предоставляет гибкий API для доступа к различным лентам данных, а следовательно отлично подходит для нашей будущей реализации

class service(interceptor):
    def __init__(self, url):
        self.url = url

Реализация класса service (фактически data-proxy), который будет основной точкой доступа для работы с данными.

Очевидно, что для запроса Languages, это свойство должно присутствовать в нашей реализации, но так же не менее очевидно, что каждая реализация OData ленты может предоставлять свои собственные данные, в связи с этим мы реализуем некоторый механизм формирования запросов на основе полученных от пользователя вызовах.

Внимательный читатель мог заметить, что service наследует от некоторого класса interceptor, вот он:

class interceptor(object):
    def __getattribute__(self, name):
        try:
            return object.__getattribute__(self, name)
        except:
            self.property = name

Из реализации видно, что наш класс занимается тем, что отлавливает вызов несуществующих свойств, к примеру наш Languages и записывает последний в поле property.

Следующей итерацией необходимо имплементировать вызов метода получения данных execute()

class service(interceptor):
    def __init__(self, url):
        self.url = url

    def execute(self):
        proc_url = self.url + "/" + self.property
        result = feedparser.parse(proc_url)
        for entry in result.entries: print entry.title

В данном методе мы формируем url-строку для запроса ленты данных, в последствии пробегаемся по результату и выводим значения клиенту.

Это лишь начальная стадия реализации, многие вопросы не учтены (фильтрация данных, построение запросов и прочее), однако данный пример наглядно указывает на общеупотребимость Open Data Protocol в повседневных нуждах разработки.

Что почитать

Adventures in Meta programming in Python: im_class, __import__, __getattribute__ http://www.lostechies.com/blogs/rssvihla/archive/2010/01/08/adventures-in-meta-programming-in-python-im-class-import-getattribute.aspx

Introducing a Ruby OData Client Library http://blogs.visoftinc.com/archive/2010/06/12/Introducing-a-Ruby-OData-Client-Library.aspx

LINQPad теперь тоже понимает OData http://www.linqpad.net/Beta.aspx

Создание OData API для StackOverflow включая XML и JSON за 30 минут http://blog.zzlab.ru/perevod/sozdanie-odata-api-dlya-stackoverflow-vklyuchaya-xml-i-json-za-30-minut.html

Что такое API данных Google? http://code.google.com/intl/ru-RU/apis/gdata/

Реклама

Как забыть про ярлыки на рабочем столе?

Введение

image Раньше у меня довольно часто возникала проблема захламления рабочего стола огромным количеством ярлыков, и я начинал теряться в них, соответственно терять время при поиске необходимых мне приложений. В дальнейшем я научился пользоваться сочетанием клавиш win+r, создавая ярлыки с короткими именами в system32. С приходом Windows Vista (7) теперь только кнопки win, однако гибкость и настройка данных методов весьма ограниченна. Имеется так же огромное количество hotkey-менеджеров, однако не с одним из них я так и не сдружился.

Лаунчеры

Недавно (по-моему после прочтения книги «Продуктивный программист. Как сделать сложное простым, а невозможное – возможным» Нила Форда) мой интерес пал на launcher’ы. Для windows-платформы я нашёл несколько:

Ну и герой этого поста:

Немного истории

enso_321[1]

Изложу настолько, насколько я сумел разобраться в ней. Первоначально Enso был строго коммерческим проектом, разрабатываемым компанией Humanized (основанной Джеффри Раскиным, в котрой в последующем работал его сын). В дальнейшем компания начала работу над Mozilla Ubiquity (аналог Enso, являющийся плагином для FireFox), что позволило ей сделать Enso бесплатным.

Enso

Лучше 1 раз увидеть, чем 7 раз прочитать, базовые возможности представлены в следующих роликах:

На настоящий момент на сайте компании есть две версии продукта:

удобна в эксплуатации, но умеет делать лишь базовые вещи.

настройка (как и во второй версии) происходит через embeded веб-сервер

в данной версии появилось огромное количество очень полезных плагинов (к примеру поиск в google, генерация объектов-карт по выделенному адресу) однако юзабили немного упало (с моей точки зрения) в плане того, что после ввода команды начала открываться отдельная строка для ввода параметров, на что уходило время, и приходилось нажимать лишний раз enter

Все отлично, за исключением того, что проект на данном сайте вроде как заброшен, что не совсем воодушевляло к использованию, однако слазив внутрь и посмотрев реализацию, обнаружилось, что всё написано на Python (межплатформенность?), а так же исходники доступны в свободном доступе, что немного приободрило.

В дальнейших поисках упоминаний о Enso я наткнулся на коммунити http://www.ensowiki.com, а так же (самое главное) хостинг нынешей версии Enso https://launchpad.net/enso, итак, что же изменилось с тех времен:

  • настройка больше не через веб-сервер
  • межплатформенность (Windows, Linux, Mac OS X, etc)
  • интерфейс первой версии
  • практически все плагины из второй версии

Используем Enso

Для установки существует инсталлер, поэтому трудности вряд ли могут встретиться. Далее у меня возникла необходимость в настройке (теперь для совершения настроек существует файл enso\config.py) “основной” клавиши (Caps Lock) в режим залипания (Sticky в терминологии создателей программы), для этого я проделал следующее:

# Whether the Quasimode is actually modal («sticky»).

IS_QUASIMODE_MODAL = True

Расширяем Enso

Классно, мой питомец (Enso) теперь стал послушным и ласковым, однако хочется научить его понимать новые команды, ну что ж, пускай это будет Enso hello world.

Я отправился в папку commands в корне, куда добавил файл butaji.py со следующим содержимым:

import enso.config

from enso.messages import displayMessage

def cmd_butaji(ensoapi, cmd):

if cmd == «time»:

ensoapi.display_message(«Hello world»)

cmd_butaji.valid_args = [‘time’]

И у меня получилось следующее:

image

image

Великолепно! я думаю, что мы с Enso очень сдружимся.


Анализ рынка ноутбуков с помощью Python

Введение

В этой статье я расскажу о состоянии на сегодняшнем российском рынке ноутбуков. Всю аналитику мы будем проводить с помощью кода на python. Думаю она будет полезна как тем, кто ищет ноутбук, так и тем, кто хочет потренироваться написанию на python.

Начнём

diy-03-425[1] Для анализа нам необходим набор данных, к сожалению я не смог обнаружить веб-сервисы у российских он-лайн магазинов ноутбуков, поэтому мне пришлось скачать прайс-лист одного из них (я не стану называть его) и вытащить из него цены и основные параметры (по-моему мнению таковыми являются: частота процессора, диагональ монитора, объем оперативной памяти, размер жесткого диска и объем памяти на видео-карточке). Далее я провёл некоторый анализ по следующим вопросам:

  1. Средняя стоимость ноутбука
  2. Усредненные параметры железа на ноутбуках
  3. Самая дорогая/дешевая конфигурация ноутбука
  4. Какой из параметров конфигурации больше всего влияет на его цену
  5. Прогнозирование цены указанной конфигурации
  6. График распределения конфигураций и цен

Lets code

Прайс-лист, который мне удалось заполучить я сохранил в формате CVS, для работы с ним необходимо подключить модуль cvs:

import csv
import re
import random

Так же подключим модуль для работы со случайными числами и регулярными выражениями, которые в последствии нам понадобятся.

Далее создадим метод для чтения и получения ноутбуков:

def get_notebooks():
    reader = csv.reader(open(‘data.csv’), delimiter=‘;’, quotechar=‘|’)
    return filter(lambda x: x != Nonemap(create_notebook, reader))

здесь всё просто, мы читаем на файл с данными data.csv и фильтруем по результату функции create_notebook, т.к. не все позиции в прайсе являются ноутбуками, а вот кстати и она:

def create_notebook(raw):
    try:
        notebook = Notebook()
        notebook.vendor = raw[0].split(‘ ’)[0]
        notebook.model = raw[0].split(‘ ’)[1]
        notebook.cpu = getFloat(r»(\d+)\,(\d+)\s\Г», raw[0].split(‘/’)[0])
        notebook.monitor = getFloat(r»(\d+)\.(\d+)\»», raw[0].split(‘/’)[1])
        notebook.ram = getInt(r»(\d+)\Mb», raw[0].split(‘/’)[2])
        notebook.hdd = getInt(r»(\d+)Gb», raw[0].split(‘/’)[3])
        notebook.video = getInt(r»(\d+)Mb», raw[0].split(‘/’)[4])
        notebook.price = getInt(r»(\d+)\s\руб.», raw[1])
        return notebook
    except Exception, e:
        return None

Как вы можете заметить, я решил не обращать внимания на вендора, модель и тип процессора (здесь конечно не всё так просто, но тем не менее), а и ещё — в данном методе присутствуют мои кастомные функции-помощники:

def getFloat(regex, raw):
    m = re.search(regex, raw).groups()
    return float(m[0+ ‘.’ + m[1])

def getInt(regex, raw):
    m = re.search(regex, raw).groups()
    return int(m[0])

Хочу заметить, что писать для питона лучше всего в стиле наборов данных, а не ООП структур, в связи с тем, что язык больше располагает к такому стилю, однако для наведения некоторого порядка в нашей доменной области (ноутбуки), я ввёл класс, как вы могли заметить выше (notebook = Notebook())

class Notebook:
   pass

Отлично, теперь у нас есть структура в памяти и она готова для анализа (2005 различных конфигураций и их стоимость), что же начнём:

Средняя стоимость ноутбука:

def get_avg_price():
    print sum([n.price for n in get_notebooks()])/len(get_notebooks())

Исполняем код и видим, что 1K$, как стандарт для компьютера всё ещё в силе:

>> get_avg_price()
34574

Усредненные параметры железа на ноутбуках

def get_avg_parameters():
    print «cpu {0}».format(sum([n.cpu for n in get_notebooks()])/len(get_notebooks()))
    print «monitor {0}».format(sum([n.monitor for n in get_notebooks()])/len(get_notebooks()))
    print «ram {0}».format(sum([n.ram for n in get_notebooks()])/len(get_notebooks()))
    print «hdd {0}».format(sum([n.hdd for n in get_notebooks()])/len(get_notebooks()))
    print «video {0}».format(sum([n.video for n in get_notebooks()])/len(get_notebooks()))

Та-да, и в наших руках усредненная конфигурация:

>> get_avg_parameters()
cpu 2.0460798005
monitor 14.6333167082
ram 2448
hdd 243
video 289

Самая дорогая/дешевая конфигурация ноутбука:

Функции идентичны, за исключением функций min/max

def get_max_priced_notebook():
    maxprice = max([n.price for n in get_notebooks()])
    maxconfig = filter(lambda x: x.price == maxprice, get_notebooks())[0]
    print «cpu {0}».format(maxconfig.cpu)
    print «monitor {0}».format(maxconfig.monitor)
    print «ram {0}».format(maxconfig.ram)
    print «hdd {0}».format(maxconfig.hdd)
    print «video {0}».format(maxconfig.video)
    print «price {0}».format(maxconfig.price)
>> get_max_priced_notebook()
cpu 2.26
monitor 18.4
ram 4096
hdd 500
video 1024
price 181660
>> get_min_priced_notebook()
cpu 1.6
monitor 8.9
ram 512
hdd 8
video 128
price 8090

Какой из параметров конфигурации больше всего влияет на его цену

Очень интересно было бы узнать, за какой из параметров конфигурации мы платим больше всего денег. Прикинув, я предположил, что скорее всего это диагональ монитора и частота процессора, ну что же, думаю, что стоит проверить это.

Для начала наш набор параметров конфигурации стоит немного модифицировать. В связи с тем, что единицы измерения различных параметров различны в своём порядке, нам необходимо привести их к одному знаменателю, т.е. нормализовать их. Итак, приступим:

def normalized_set_of_notebooks():
    notebooks = get_notebooks()
    cpu = max([n.cpu for n in notebooks])
    monitor = max([n.monitor for n in notebooks])
    ram = max([n.ram for n in notebooks])
    hdd = max([n.hdd for n in notebooks])
    video = max([n.video for n in notebooks])
    rows = map(lambda n : [n.cpu/cpu, n.monitor/monitor, float(n.ram)/ram, float(n.hdd)/hdd, float(n.video)/video, n.price], notebooks)
    return rows

В данной функции я нахожу максимальные значения для каждого из параметров, после этого формирую результирующий список ноутбуков, в котором каждый из параметров представлен в виде коэффициента (его значение будет колебаться от 0 до 1), показывающего отношение его параметра к максимальному значению в наборе, к примеру память в 2048Mb даст конфигурации коэффициент в ram = 0.5 (2048/4056).

Вклад каждого из параметров мы будем считать в рублях, для наглядности, хранить эти веса мы будет в наборе:

#cpu, monitor, ram, hdd, video
koes = [00000]

Я предлагаю исчислять эти коэффициенты для каждой конфигурации, а после этого определить среднюю величину всех коэффициентов, что даст нам усредненные данные о весе каждого из элементов конфигурации.

def analyze_params(parameters):
    koeshistory = []
    #наши ноутбуки
    notes = normalized_set_of_notebooks()
    for i in range(len(notes)):
        koes = [00000]
        #устанавливаем коэффициенты
        set_koes(notes[i], koes)
        #сохраняем историю коэффициентов
        koeshistory.extend(koes)
        #показываем прогресс выполнения
        if (i % 100 == 0):
            print i
            print koes

Как же мы будет устанавливать коэффициенты для каждого элемента конфигурации? Мой способ заключается в следующем:

  • нам необходимо в случайном порядке наращивать, либо уменьшать значение одного из коэффициентов
  • после чего анализировать, приблизились ли мы к цене за конфигурацию, при умножении вектора параметров на вектор коэффициентов (напомню, что в нашем случае это рубли)
  • если приближение состоялось, ты мы повторяем данное действие, если же нет, то отменяем его
  • повторять данный порядок до той степени, пока не приблизимся к нашей цене с установленной нами точностью

Вот реализация данного алгоритма:

def set_koes(note, koes, error=500):
    price = get_price(note, koes)
    lasterror = abs(note[5 price)
    while (lasterror > error):
        k = random.randint(0,4)
        #изменяем коэффицинт
        inc = (random.random()*2  1* (error*(1  error/lasterror))
        koes[k] += inc
        #не даём коэффициенту стать меньше нуля
        if (koes[k] < 0): koes[k] = 0
        #получаем цену при учёте коэффициентов
        price = get_price(note, koes)
        #получаем текущую ошибку
        curerror = abs(note[5 price)
        #проверяем, приблизились ли мы к цене, казанной в прайсе
        if (lasterror < curerror):
            koes[k] -= inc
        else:
            lasterror = curerror

inc – переменная отвечающая за цвеличение/уменьшение коэффициента, способ её вычисления объесняется тем, что данное значение должно быть тем больше, чем больше разница в ошибке, для быстрого и более точного приближения к желаемому результату.

Умножение векторов для получения цены выглядит следующим образом:

def get_price(note, koes):
    return sum([note[i]*koes[i] for i in range(5)])

Пришла пора выполнить анализ:

>> analyze_params()
cpu, monitor, ram, hdd, video

[15455.6067566768420980.56048381136112782.53527030428117819.90462958586114677.889529808042]

Данный набор мы получили, благодаря усреднению коэффициентов, полученных для каждой из конфигураций:

def get_avg_koes(koeshistory):
    koes = [00000]
    for row in koeshistory:
        for i in range(5):
            koes[i] += koeshistory[i]
    for i in range(5):
        koes[i] /= len(koeshistory)
    return koes

Итак, у нас получился желаемый набор, что же мы можем сказать из этих цифр, а можем мы составить рейтинг параметров:

  1. Диагональ монитора
  2. Объем жесткого диска
  3. Частота процессора
  4. Объем видео-карточки
  5. Объем оперативной памяти

Хотелось бы отметить, что это далеко не идеальный вариант, и у вас могут получится иные результаты, однако, моё предположение, о том, что частота процессора и диагональ дисплея наиболее важные параметры в конфигурации, частично подтвердились.

Прогнозирование цены указанной конфигурации

Классно бы было, имея такой богатый набор данных, уметь прогнозировать цену на заданную конфигурацию. Этим мы и займемся.

Для начала преобразуем нашу коллекцию ноутбуков в список:

def get_notebooks_list():
    return map(lambda n: [n.cpu, n.monitor, n.ram, n.hdd, n.video, n.price], get_notebooks())

Далее нам понадобиться функция, способная определить расстояние между двумя векторами, хорошим вариантом я вижу функцию эвклидова расстояния:

def euclidean(v1, v2):
    d = 0.0
    for i in range(len(v1)):
        d+=(v1[i]  v2[i])**2;
    return math.sqrt(d)

Корень из суммы квадратов разностей довольно таки наглядно и эффективно показывает нам насколько один вектор различен от другого. Чем же полезна для нас данная функция? Всё просто, когда мы получим вектор, с интересующими нас параметрами, мы пробежимся по всей коллекции нашего набора и найдём ближайшего соседа, а его стоимость мы уже знаем, отлично! Вот как мы это сделаем:

def getdistances(data, vec1):
    distancelist=[]
    for i in range(len(data)):
        vec2 = data[i]
        distancelist.append((euclidean(vec1,vec2),i))
    distancelist.sort()
    return distancelist

Далее, можно немного усложнить задачу, а так же точность предоставляемых данных. Для этого мы введем функцию, использующую классификацию методом k взвешенных ближайших соседей:

K взвешенных ближайших соседей — это метрический алгоритм классификации, основанный на оценивании сходства объектов. Классифицируемый объект относится к тому классу, которому принадлежат ближайшие к нему объекты обучающей выборки.

Ну и взять среднее значение среди некоторого количества ближайших соседей, что сведет на нет влияние цен вендора, либо специфичности конфигурации:

def knnestimate(data,vec1,k=3):
    dlist = getdistances(data, vec1)
    avg = 0.0
    for i in range(k):
        idx = dlist[i][1]
        avg +=data[idx][5]
    avg /= k
    return avg

*последние 3 алгоритма взяты из книги Сегерана Тоби “Программируем коллективный разум”

И что же мы получаем:

>> knnestimate(get_notebooks_list(), [2.4173062250512])
31521.0

>> knnestimate(get_notebooks_list(), [2.0152048160256])
27259.0
>> knnestimate(get_notebooks_list(), [2.0152048160128])
20848.0

Цены рыночные и этого вполне достаточно, хотя мы абсолютно не учитываем в этой реализации, к примеру частоту процессора и диагональ монитора (для этого нам необходимо добавить в функцию сравнения векторов их веса , которые мы вычисляли в предыдущем пункте)

График распределения конфигураций и цен

Хочется объять картину распределения целиком, т.е. нарисовать распределение конфигураций и цен на рынке. Ок, сделаем это.

Для начала надо поставить библиотеку matplotlib. Далее подключить её к нашему проекту:

from pylab import *

Так же нам понадобится создать два набора данных, для оси абсцисс и ординат:

def power_of_notebooks_config():
    return map(lambda x: x[0]*x[1]*x[2]*x[3]*x[4], normalized_set_of_notebooks())
def config_prices():
    return map(lambda x: x[5], normalized_set_of_notebooks())

И функцию, в которой мы построим график распределения:

def draw_market():
    plot(config_prices(),power_of_notebooks_config(),‘bo’, linewidth=1.0)

    xlabel(‘price (Rub)’)
    ylabel(‘config_power’)
    title(‘Russian Notebooks Market’)
    grid(True)
    show()

И что же мы получаем:

notes

В завершение

Итак, у нас получилось провести небольшой анализ российского рынка ноутбуков, а так же немного проиграться с python.

Исходный код проекта доступен по адресу:

http://code.google.com/p/runm/source/checkout


Ruby|Python в браузере, сделай сам

Зачем?

sidebar_gestaltКлиентскую часть в веб-приложениях принято создавать на JavaScript. Я считаю, что большинство разработчиков с огромным удовольствием бы отошли от этого правила и воспользовались своим любимым server-side языком. Ну что же, команда MIX Online предоставила любителям динамических языков такую возможность, подробнее об этом можно прочитать в “Проект Gestalt – пишите на Ruby, Python и XAML прямо в HTML на стороне клиента”. Ниже я предлагаю создать нечто подобное, но уже своими силами.

С помощью чего?

Посмотрев несколько примеров мне стало ясно, что реализован Gestalt на Silverlight + Dynamic Languages Runtime. Далее я прикинул, а на сколько сложно создать нечто своими руками? И сразу же решение: Silverlight умеет  взаимодействовать с DOM – значит я смогу получить код и интерпритировать его – дело за малым – реализация.

Приступим

Нам понадобятся:

  • Visual Studio >2008SP1 (при желании можно и другие IDE или средства редактирования текста)
  • Silverlight >2.0 Tools
  • Dynamic Languages SDK >0.5.0 (download)
  • 10 мин времени

Lets code

image

Открываем Visual Studio, создаём Silverlight Application, я назову проект “mygestalt”. Теперь я осознаю, что писать та надо будет совсем не много, мне понадобится экспериментальный Client-Script и его интерпритатор. Открываем страничку, на которой будет хоститься наш Silverlight, в моём случаем это mygestaltTestPage.aspx и добавляем туда наш client-side python code. Выглядеть это должно примерно так:

  1. <script type="python">
  2. def func():
  3.     HtmlPage.Window.Alert("Hello world!")
  4.    
  5. func()
  6. </script>

* This source code was highlighted with Source Code Highlighter.

Далее отправляемся в MainPage.xaml.cs, где будем заниматься поисками нашего скрипта:

  1. using System.Linq;
  2. using System.Windows.Browser;
  3.  
  4. namespace mygestalt
  5. {
  6.   public partial class MainPage
  7.   {
  8.     public MainPage()
  9.     {
  10.       InitializeComponent();
  11.       FindAndRunScript();
  12.     }
  13.  
  14.     private void FindAndRunScript()
  15.     {
  16.       var scripts = HtmlPage.Document.GetElementsByTagName("script");
  17.       var pythonScript = scripts.Where(x => x.GetProperty("type").ToString() == "python").First();
  18.       PythonEngine.Run(pythonScript.GetProperty("innerHtml").ToString());
  19.     }
  20.   }
  21. }

* This source code was highlighted with Source Code Highlighter.

Ну и реализация PythonEngine:

  1. using Microsoft.Scripting;
  2. using Microsoft.Scripting.Hosting;
  3. using Microsoft.Scripting.Silverlight;
  4.  
  5. namespace mygestalt
  6. {
  7.   public static class PythonEngine
  8.   {
  9.     public static ScriptScope Run(string source)
  10.     {
  11.       var setup = Configuration.LoadFromAssemblies(Package.GetManifestAssemblies());
  12.       setup.HostType = typeof(BrowserScriptHost);
  13.       setup.DebugMode = true;
  14.       var runtime = new ScriptRuntime(setup);
  15.       var engine = runtime.GetEngine("IronPython");
  16.       var scope = engine.CreateScope();
  17.       const string init = @"
  18. import clr
  19. clr.AddReference('System.Windows.Browser')
  20.  
  21. from System.Windows.Browser import *
  22.  
  23. "
  24. ;

  25.  
  26.       ScriptSource initSource = engine.CreateScriptSourceFromString(init, SourceCodeKind.Statements);
  27.       initSource.Execute(scope);
  28.       var script = engine.CreateScriptSourceFromString(source, SourceCodeKind.Statements);
  29.       script.Execute(scope);
  30.  
  31.       return scope;
  32.     }
  33.   }
  34. }

* This source code was highlighted with Source Code Highlighter.

Запускаем приложение и видим:

image

 

 

 

 

В заключение

Вот у нас и получился свой собственный Gestalt, самое интересное в том, что я посмотрел его исходники и нашёл там примерно такую же реализацию.

Мой проект можно найти на http://code.google.com/p/mygestalt/.

Всем спасибо!


Языки предметной области Domain-Specific Languages (DSL)

Что это?

Это некоторая форма компьютерных языков, разрабатываемых для специфичной предметной области. Это то, что позволяет вам (разработчикам ПО) лучше взаимодействовать с носителями “доменных знаний”. А так же позволяет более лаконично оформлять бизнес-логику. Это то, что представляет собой, к примеру, SQL, Linq, многое из синтаксиса Ruby On Rails.

Зачем мне это?

Если вы согласны с утверждением: “Языки общего назначения порой слишком красноречивы”, вы разрабатываете на .NET, либо сильно интересуетесь программированием, то наш доклад будет вам интересен.

Что я узнаю?

Ответы на следующие вопросы:

  • Что такое DSL?
  • Откуда это понятие пришло к нам?
  • Какие бывают DSL?
  • Какие “языки общего употребления (GPL)”  предоставляют возможности построения DSL? Какие из них есть на .NET?
  • Почему я должен использовать DSL? Какие плюсы от этого?
  • Какие шаблоны используются при построении DSL?
  • А можно увидеть примеры?

Материалы нашего выступления

Слайды презентации

Building DSLs on CLR and DLR (.NET)

Видео:

http://video.yandex.ru/users/thecoffee/collection/1/

Видео в более пригодном к рассматриванию надписей на доске качестве можно слить по ссылкам ниже:

http://narod.ru/disk/9278634000/01.wmv.html

http://narod.ru/disk/9279885000/02.wmv.html

Все рассмотренные примеры доступны здесь:

http://spbalt.net/Content/Baum_Moiseev_DSL.zip


Звучит заманчиво: Django на IronPython

def Introduce():

Дорогие мальчики и девочки, меня (как позже оказалось не только меня) интересует веб-индустрия и всё, что с ней связано, соответственно хочется вкусить разнообразных технологий, одной из них является известный фреймворк DjangoimageИм и хочется заняться. Думаю, не стоит говорить, о том, что я .NET-разработчик, в связи с чем Python в чистом виде использовать не очень хочется, но хочется попробовать IronPython в деле. Тогда вполне очевидно, что Django на .NET должен являться ASP.NET приложением.

def WSGI():

Здесь нам нужно знать, что такое WSGI:

WSGI (англ. Web Server Gateway Interface, произносится виски) — стандарт взаимодействия между Python-программой, выполняющейся на стороне сервера, обычно из каталога cgi-bin, и самим веб-сервером, например, Apache.

Дополнительная информация: PEP 333

И нам безусловно повезло, т.к. есть готовая имплементация WSGI для ASP.NET: NWSGI – выполнена как ASP.NET 2.0 HttpHandler на IronPython.

Что примечательно, мало того, что NWSGI интегрируется с IIS и позволяет работать с сессиями, кешем и управлением пользователями, он интегрируется даже с графической средой управления IIS 7!

Это ещё не всё, NWGSI умеет также работать с Cassini (веб-сервер Visual Studio).

Думаю Вам, ровно как и мне, не терпится поработать с этим.

def PrepareIIS():

Итак, что нам необходимо:

  • IronPython 2.0
  • NWSGI 1.0
  • Огромное желание сделать что-нибудь особенное на этом.

Для установки из пакета NWSGI копируем пример HelloWorld в папку C:\inetpub\wwwroot\HelloWorld (либо другой путь для ваших IIS приложений). Из этого же пакета копируем NWSGI.dll в папочку HelloWorld\bin (если пользовались инсталлятором, то в этом нет необходимости, т.к. она уже в GAC’е).

Далее из пакета IronPython 2.0 копируем в каталог HelloWorld\bin следующие сборки:

  • IronPython.dll
  • IronPython.Modules.dll
  • Microsoft.Scripting.Core.dll
  • Microsoft.Scripting.dll

Наша папочка HelloWorld должна выглядеть следующим образом:

HelloWorld\

  • bin\
    • NWSGI.dll (optional)
    • IronPython.dll
    • IronPYthon.Modules.dll
    • Microsoft.Scripting.Core.dll
    • Microsoft.Scripting.dll
  • hello.wsgi
  • Web.Classic.config
  • Web.Integrated.config

Далее, если у нас ISS 7.0, то тогда копируем Web.Integrated.config в Web.config, иначе Web.Classic.config в Web.config.

Далее добавляем приложение на IIS, это можно сделать, как через графическое меню, так и воспользоваться консолью:

%systemroot%\system32\inetsrv\appcmd add app /site.name:"Default Web Site" /path:/hello /physicalPath:C:\inetpub\wwwroot\HelloWorld

Если же у вас IIS 6, то путь один – через графическое меню, а так же необходимо будет ассоциировать *.wsgi с ASP.NET ISAPI фильтром (по аналогии с *.aspx)

Теперь идём по адресу http://localhost/hello/hello.wsgi. И видим грациозное: "Hello, World!", yeah!

def InstallDjango():

Установить Django можно с помощью команды:

ipy setup.py install

Далее можно добавить проект и сгенерировать приложения:

ipy manage.py startapp AppName

ipy manage.py startproject ProjName

К сожалению, мне не хватило навыков для того, чтобы запустить django-приложение под NWSGI.

def SqlServer():

Подключить Django к Microsft SQL Server 2005 и выше можно с помощью следующей библиотеки:

http://code.google.com/p/django-mssql/

Так же можно почитать о подключении здесь: http://blogs.msdn.com/dinoviehland/archive/2008/03/17/ironpython-ms-sql-and-pep-249.aspx

def GetGratitude():

Огромную благодарность за выполненную работу хочу выразить Jeff Hardy и советую ознакомиться с его работами:


Обзор языка Boo! – как средства организации DSL Вашего приложения

boo-logo-128_med

Одна из вещей, как известно, способная помочь вам стать лучше в качестве разработчика, заключается в изучении нового языка. Даже если Вы никогда не будете пользоваться этим языком в Вашей повседневной трудовой деятельности, он поможет Вам лучше понять языки, с которыми Вы работаете.

В последнее время меня так и тянет насесть на какой-нибудь новенький язык программирования, особенно что-нибудь на типа Ruby или Python, но в связи с моей привязанностью среде разработки (Visual Studio, неверно это не очень хорошо – зависеть от IDE ;)) и затруднительной ситуацией с разработкой на ней на динамических языках (надеюсь это временное затруднение) от них пока пришлось отказаться. В то же время меня интересуют такие области как метапрограммирование и реализация DSL (Domain-Specific Language == проблемно-ориентированный язык приложения), и в этой связи видится мне, что Boo является весьма интересным языком. К тому же Boo — язык CLR, что очень даже не плохо для изучения.

Поэтому я решил, что когда я узнаю Boo и когда почувствую уверенность в Boo, я попробую реализовать DSL и реализовать именно на Boo для своего ближайшего проекта.

Что такое Boo?

Boo представляет собой open-source объектно-ориентированный статически типизированный язык программирования для CLR с Python’о-подобным синтаксисом, язык увидел свет в 2004 году из-под рук Rodrigo B. de Oliveira. В настоящее время последняя версия 0.8.2, но даже если нет еще версии 1.0, это действительно очень стабильной и зрелый язык, который можно использовать на производстве.

Основные концепции в Boo:

  1. Дать компилятору сделать большую часть работы, для того чтобы помочь языку выглядеть более динамическим с автоматическим объявлением переменных, выводом и приведением типов.
  2. В то же время он предоставляет возможности для выполнения статической компиляции, проверку ошибок во время компиляции.
  3. Boo также предоставляет функциональную составляющую в том, что функции могут использоваться в качестве возвращаемого значения, как аргументы, хранимые в переменных, а так же как объекты.
  4. Boo имеет первоклассные генераторы, это конструкций, способные производить более одного значения при использовании итерации цикла (“return a for a in apples if a.IsRipe”).
  5. Boo также поддерживает утиную типизацию (Duck Typing), которая позволяет отказаться от обеспечения безопасности статических типов и принимать любой объект, который просто имеет соответствующие методы и свойства, определяемые во время выполнения.
  6. Boo также имеет расширения методов и свойств (extension methods and extension properties).

Одним из наиболее интересных функций Boo является расширяемость процесса компиляции, которая позволяет управлять компиляцией и изменять или добавлять функции. Можно добавить подпрограмм для проверки конвенции кода, генерирования отчётов или преобразовывания кода. То, что Вы сможете сделать в C# с помощью тулзы посткомпиляции такой, как PostSharp и только ограниченный набор действий. В Boo Вы могли бы например автоматически преобразовать класс в одноэкземплярный (pattern Singleton), просто добавив атрибут следующим образом:

[singleton]
class MySingleton: pass

PostSharp просто не смог бы сделать этого, свойство экземпляра было бы обработано поздно. Это действительно открывает множество возможностей и Вы ограничиваетесь только Вашим пониманием внутренней функциональности компилятора и набора его возможностей.

В Boo пробелы имеют важное значение как в python, но есть возможность включить режим “Whitespace Agnostic”, позволяющий оканчивать выражение с помощью “end”, который избавит Вас от возможных проблем с пробелами.

Что нужно для начала работы с Boo?

Главным образом если Вы хотите узнать Boo, достаточно иметь последнюю версию Boo . В папке bin, Вы найдете файл “Booish.exe”, являющийся интерпретатором командной строки Boo, которая позволяет проиграться с синтаксисом языка.image

Для разработки нам необходима IDE, и следовательно у нас два варианта.

Большинство Boo разработчиков работают с SharpDevelop , и если Вы скачаете последнюю версию, в ней будет Boo полностью готовый к использованию. Эта IDE имеет преимущество, с точки зрения создания DSL, так как в ней легче добавить функции автозавершения кода и подсветки синтаксиса, в Visual Studio же потребуются написать лексер и парсер; в SharpDevelop можно сделать это с помощью XML-файла.

Но с другой стороны Visual Studio является зрелой IDE, и с BooLangStudio вы получите Boo интегрированный в Visual Studio. Люди жалуются, что проект является нестабильным и это лишь альфа выпуск, так же я встретился в нём с проблемами уникода (UTF8), которые пока не смог разрешить, но у меня пока нет весомых замечаний.

В настоящее время я буду пользоваться Visual Studio в силу привычки, но я могу изменить свой взгляд при продолжении этой статьи.

При написании данного поста я руководствовался данной работой, можно даже сказать переводил, но перевод очень личный и свободный.

Продолжение следует…