Показаны сообщения с ярлыком Программирование. Показать все сообщения
Показаны сообщения с ярлыком Программирование. Показать все сообщения

вторник, октября 17, 2017

Переписал сайт planetgo.ru на Go

Наконец-то дошли руки переписать свой агрегатор на Go. Давно уже хотел этим заняться, но всё руки не доходили. Было несколько идей по улучшению работы сайта, по загрузке данных с ресурсов и пр., но внедрять их используя те технологии, на которых изначально было написан сайт(Perl, Mojolicious), не хотелось. Вот тут я немного описал по какой причине мне не хотелось дальше работать с моджо.
В итоге парсер ресурсов был переписан на питоне, а бэкенд сайта переписан на Go.
Что хотелось бы отметить про разработку на go после опыта на динамически типизированном языке? В первую очередь - это непривычность работы со строгой типизацией. Когда пишешь функцию/метод ты должен чётко значть, что у тебя будет на входе и на выходе. Динамически типизированные языки проще в этом плане.
Немного но сильно побесил встроенный шаблонизатор html/template. Чтобы скомпилировать шаблон из нескольких файлов, нужно предварительно корректно задать имя получившегося шаблона:
import (
 "html/template"
 "path/filepath"
)

files := []string{"base.tmpl", "index.tmpl"}
path := "root_path"
for i, file := range files {
 files[i] = filepath.Join(path, file)
}
tmpl := template.Must(template.New("index").ParseFiles(files...))
Поначалу, с непривычки никак не мог вкурить в некоторые моменты работы шаблонизатора. Пришлось лезть в исходники чтобы разобраться. Также пришлось разбираться с пакетом net/http, т.к. при написании кода хотелось по макисмуму использовать стандартную библиотеку языка чтобы лучше с ним позакомиться. Некоторое время потратил на создание
промежуточного обработчика запросов.
Сейчас сайт уже запущен и работает. Допиливаю небольшую админку, тоже на Go, вожусь с обработкой json для rest api.
В целом, язык очень годный, разрабатывать на нём приятно. Go fmt вообще крутая вещь.
В будущем постараюсь написать статьи по различным компонентам стандартной библиотеки, с которыми мне пришлось столкнуться в процессе разработки.

вторник, мая 23, 2017

Пробую свои силы в python и go

Расширяю свой кругозор и пробую для себя новые технологии.
Не так давно дошли руки до книги "Простой Python. Современный стиль программирования" которую я купил себе на день рождения в прошлом году.
Решил переписать сайт planetgo.ru с перла на питон и go. С фреймворком Mojolicious всё по-прежнему очень печально. Не так давно там опять сломали обратную совместимость в минорной версии. После этого я окончательно решил для себя, что иметь дело я с ним больше не хочу.
Сейчас дописываю парсер на питоне. Веб-сервер будет работать на гошке. Может быть в будущем запилю статейку о том как сделать простенький веб-сервер на стандартном net/http с использованием tamplate'ов на go. Статей в рунете об этом не так уж и много.

четверг, октября 22, 2015

Perl. Получить ссылку на скачивание дистрибутива по имени модуля.

На работе запонадобилось накачать модулей используя их канонические имена вида 'Foo::Bar'. Лазить на cpan и вручную качать, понятное дело, неправильно. К тому же, часть модулей содержалась в дистрибутиве других модулей, как например, Catalyst находится в составе Catalyst::Runtime.
Конечной моей задачей был скрипт, которому я на вход даю имя модуля, а он мне на выходе отдаёт ссылку на скачивание данного модуля с cpan.
Недолгое гугление вывело меня на модуль MetaCPAN::Client, который позволяет работать с metacpan через API.
В итоге, для скачивания модуля имеем такой код:
#!/usr/bin/env perl

use 5.014;
use strict;
use warnings;

use MetaCPAN::Client;

my $module_name = $ARGV[0] or die "Can't get module name";

my $mclient = MetaCPAN::Client->new;
my $module  = $mclient->module( $module_name );

say $mclient->release( $module->distribution )->download_url;
Проверяем:
% perl load_module.pl List::Util
https://cpan.metacpan.org/authors/id/P/PE/PEVANS/Scalar-List-Utils-1.42.tar.gz
Что и требовалось.

пятница, октября 09, 2015

Сравнение скорости работы Perl 5 и Perl 6. Считаем сумму чисел Фибоначчи

Стало интересно, насколько последний релиз ракуды быстр в сравнении с пятым перлом. До этого ранее ради интереса сравнивал быстродействие перла 5 в сравнении с питоном и руби. Сравнивал рассчётом суммы первых 30-ти чисел Фибоначчи. Перловка там проигрывала питону с рубями.
Теперь вот решил сравнить насколько шестёрка хороша в данной задаче.

Итак, что имеем:
% perl -v
This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux-gnu-thread-multi

% perl6 -v
This is perl6 version 2015.09 built on MoarVM version 2015.09

Код на perl 5:
#!/usr/bin/perl

use strict;
use warnings;

sub fib {
    my $n = shift;
    if ( $n < 3 ) {
        return 1;
    }

    return fib($n-1) + fib($n-2);
}

print fib(30) . "\n";

Код на perl 6:
#!/usr/bin/env perl6

sub fib ( Int $n ) {
    if ( $n < 3 ) {
        return 1;
    }

    return fib($n-1) + fib($n-2);
}

fib(30).say;
результаты:
% time perl fib.pl
832040

real 0m0.757s
user 0m0.756s
sys  0m0.000s

% time perl6 fib.pl6
832040

real 0m8.946s
user 0m8.912s
sys  0m0.028s
Что-то как-то совсем не быстро и с большой нагрузкой на проц(в случае с перлом 6). Разница в скорости работы почти в 12 раз!
Понятно, что перл 6 - это виртуальная машина, которая медленно запрягает но быстро едет, но как-то цифры всё-равно не радуют. Другое дело что раньше разница в работе была ещё более впечатляющей, разрабы оптимизируют код, ускоряют работу интерпретатора Rakudo и это не может не радовать.
Буду надеяться, что к стабильному релизу p6 мощЕй ещё добавят. Может даже что-нибудь напишу для себя на нём.

среда, июля 02, 2014

Perl. Добавляем инкапсуляцию методам класса

Перл - замечательный язык с очень простой и понятной ООП-парадигмой. Из коробки мы имеем полиморфизм и наследование, но, к сожалению, не можем похвастаться инкапсуляцией.
Инкапсуляция, для тех кто не знаком с терминами, это сокрытие методов класса от посторонних лиц. Другими словами, мы в классе создаём различные методы, часть из которых доступна для вызова другими модулями/скриптами. Другая часть не должна быть вызвана нигде, кроме как в самом классе(private-метод) или в классе, который наследуется от данного класса(protected-метод).
В перле, как и в питоне, нельзя штатными средствами перекрыть доступ к методам класса. Применяется негласное соглашение, по которому методы(или функции), имена которых начинаются с нижнего подчёркивания, считаются приватными.

С этим в принципе можно мириться и ваять код на pure-перл, не прибегая к ООП-фреймворкам типа Moose, что я в принципе всегда и делал - меня слегка пугает перспектива тянуть в своё приложение 100500 модулей ради одного функционала.
К счастью, благодаря статье в журнале pragmaticperl я узнал о модуле Attribute::Protected. Данный модуль написал Tatsuhiko Miyagawa, очень известный разработчик в мире Perl.
Модуль достаточно легковесный и имеет в зависимостях только Attribute::Handlers, который давно является модулем ядра perl.
Рассмотрим на примере, как можно с помощью указанного модуля добавить в наш класс инкапсуляцию.
Для наглядности создадим 2 модуля и один скрипт, который будет вызывать оба модуля. Один модуль будет наследоваться от другого.

MyModuleParent.pm :
package MyModuleParent;

use strict;
use warnings;
use Attribute::Protected;

sub new {
    my $class = shift;

    return bless {}, $class;
}

sub _private_method : Private {
    print "This is private method in package " . __PACKAGE__ . "\n";
}

sub _protected_method : Protected {
    print "This is protected method in package " . __PACKAGE__ . "\n";
}

sub public_method {
    print "This is public method in package " . __PACKAGE__ . "\n";
}

1;

MyModule.pm :
package MyModule;

use strict;
use warnings;

use parent 'MyModuleParent';

sub mymethod {
    print "This is simple method in package " . __PACKAGE__ . "\n";
}

sub call_protect_method {
    my $self = shift;
    $self->_protected_method;
}

sub call_private_method {
    my $self = shift;
    $self->_private_method;
}

1;

script.pl :
#!/usr/bin/perl

use strict;
use warnings;

use MyModule;
use MyModuleParent;

my $parent_object = MyModuleParent->new;
my $object = MyModule->new;

$object->public_method;         # OK
$object->mymethod;              # OK
$object->call_protect_method;   # OK
$object->call_private_method;   # NOT OK

$parent_object->public_method;       # OK
$parent_object->_protected_method;   # NOT OK
$parent_object->_private_method;     # NOT OK
Объект "$object" может вызвать публичный метод класса "MyModuleParent", т.к. от него наследуется класс "MyModule". Также, данный объект вызывает методы "call_protect_method" и "call_private_method", вызывающие в свою очередь protect и private методы класса "MyModuleParent" соответственно. Вызов метода "call_private_method" завершится с ошибкой _private_method() is a private method of MyModuleParent!, вызов метода "call_protect_method" завершится успешно. Прямой вызов из скрипта private и protected методов класса "MyModuleParent"(через объект $parent_object) завершится с ошибкой.

Таким образом, мы получаем малой кровью(а оверхед там действительно ничтожный, проверенно в дебаггере) надёжную инкапсуляцию методов, очень похожую на сишную и явовску, да к тому же сделанную почти полностью на базовых средствах языка. Модулю Attribute::Protected уже 13 лет, удивитильно, что его так мало используют.

воскресенье, июня 29, 2014

yet another conference server

Начал пилить демона для управления аудио-конференциями на базе ip-pbx FreeSWITCH. Сам демон будет выступать прослойкой между пользователями и сервером PBX.
В бытность свою работы с ip-телефонией вцелом и астериском в частности, не раз собирался заняться фрисвичом, да всё как-то руки не доходили и задач соответствующих не было. Зато теперь, в чине разработчика, полёт фантазий в плане приложений для телефонии уносит меня за дальние горизонты)) Специально для этих целей даже c++ начал изучать.
Но пока что пишу на перле и anyevent. Проект ещё в начальной стадии, готово процентов 20.
Думаю, что к осени будет готова хотя бы альфа-версия.

суббота, июня 28, 2014

Perl. Получить в модуле полный путь до файла модуля

Возник давеча такой вопрос: надо было в модуле, в не зависимости от того, кто и откуда его запускает, получать текущий PATH данного модуля.
Инструменты типа FindBin и Cwd не работали, т.к. они показывали путь до скрипта, который использовал данный модуль. Недолгое гугление выдало вот такое решение:
use File::Spec;

my $mod_dir = (File::Spec->splitpath( __FILE__ ))[1];
Вызов
File::Spec->splitpath( __FILE__ )
возвращает массив, в котором первым аргументом является имя файла, а вторым как раз будет полный путь от "/" до модуля.

четверг, апреля 18, 2013

Perl. Сортировка ключей хеш-массива по значениям этих ключей



В процессе выполнения тестовых заданий для новой работы столкнулся с задачей вывода сортированных данных.
Итак, имеем структуру:
$VAR1 = bless( {
                 'DOMAINS' => {
                                'yandex.ru' => 1,
                                'INVALID' => 5,
                                'rambler.ru' => 1,
                                'vk.com' => 1,
                                'mail.ru' => 2
                              }, 
               }, 'MyModule' );
необходимо выводить данные хеш-массива DOMAINS, отсортированные по значениям(values) данного массива.
Недолго думая обратился за ответом к замечательной книге Perl: изучаем глубже, в которой было найдено решение:
foreach my $domain (sort { $self->{DOMAINS}->{$b} cmp $self->{DOMAINS}->{$a} } 
                keys $self->{DOMAINS}) {
        print $domain . "\t" . $self->{DOMAINS}->{$domain} . "\n";
    }
В результате получаем то, что требовалось:
INVALID 5
mail.ru 2
yandex.ru 1
rambler.ru 1
vk.com 1

Perl. Перехват warn'ов и carp'ов



Сейчас немного про перл.
В перле есть замечательная функция eval, которая умеет перехватывать критические ошибки, которые были вызваны die и/или croak. Но эта функция не умеет работать с предупреждениями, которые генерируются с помощью функций warn и carp. Ну и что такого, спросите вы, предупреждения для того и существуют, чтобы информировать пользователя/разработчика о некорректной работе скрипта или модуля. Но порой всё-же требуется, чтобы наш скрипт, написанный на перле, умел перехватывать подобные сообщения, сгенерированные модулями или функциями, чтобы, например, обрабатывать подобные сообщения особым образом.

четверг, июня 14, 2012

K&R Язык программирования C. Упражнение 1.19. Напишите функцию reverse(s), которая переписывает свой строковый аргумент в обратном порядке

Занялся на досуге изучением языка си по книжке K&R. Дошёл до задания 1.19. По итогу выполнения решил написать данное сообщение, как памятку себе. Итак, программа выглядит следующим образом:
/* программа, реверсирующая входные строки */
#include <stdio.h>
#define MAXLINE 1000

void reverse(char s[]);
int my_getline(char s[], int);

int main()
{
    int len;
    char line[MAXLINE];

    while((len = my_getline(line, MAXLINE)) > 0) {
        printf("Исходная строка выглядит так: %s", line);
        reverse(line);
        printf("Реверсированная строка выглядит так: %s", line);
    }
    return 0;
}

int my_getline(char s[], int lim)
{
    int i, c;

    for(i = 0; i < lim -1 && (c = getchar()) != EOF && c != '\n'; ++i) {
        s[i] = c;
    }
    if(c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

/* функция reverse: переписывает строки в обратном порядке. Суть работы в следующем:
 т.к. мы знаем, что любая строка заканчивается символом '\0', можно на время удалить
 из строки данный символ и занять его место первым элементом массива. После этого можно
 осуществить последовательный перенос всех элементов. В последствии необходимо будет
 "сдвинуть" полученную строку влево */
void reverse(char s[])
{
    int n, i, c, j;

    c = n = 0;
    while(s[n] != '\0') {
        ++n;
    }
    if(s[n-1] == '\n') {
        c = s[n-1]; //c теперь содержит символ перехода на новую строку
        n = n - 2; //не будем подставлять в качестве первого символа переход на новую строку
    }
    /* выясняем, какое у нас число символов в строке: чётное или нечётное */
    if((n%2) == 0) {
        j = n/2;
    } else {
        j = n/2 + 1;
    }
    /* переносим крайние элементы в массиве */
    s[n+1] = s[0];
    s[0] = s[n];
    /* переносим остальные элементы */
    for(i = 0; i < j; ++i) {
        s[i] = s[n-i];
        s[n-i] = s[i+1];
    }
    /* нужно "сдвинуть" символы влево, начиная с середины */
    for(i = j; i < n + 1; ++i) {
        s[i] = s[i+1];
    }
    if(c == '\n') {
        n = n + 1;
        s[n] = '\n';
    }
    s[n+1] = '\0';
}