Xpoint
   [напомнить пароль]

Структура модулей

Метки: [без меток]
2009-01-16 10:05:57 [обр] Artie Kh![досье]

Здравствуйте!

Я начинающий программист на Perl и столкнулся со следующей проблемой: пишу движок для сайта, до этого у меня была некоторая CMS, которая представляла из себя два файла — первый - администраторский интерфейс, второй - клиентская часть.

И вот недавно в моём воспалённом мозгу родилась идея сделать новый проект по-новому — используя модульную структуру, а так с этим я совсем не знаком перед встал один большой вопрос:

Как построить структуру каталога с модулями?

Решил сделать так:

+ App.pm
+ App/
 \
 | - Auth/
 | - Module1/
 | - Auth.pm
 | - Module1.pm

Я смотрел как была организованная структура в movable type и решил сделать что-то вроде этого, НО я не могу понять как мне объединить все эти модули, и вообще может я себе не правильно это представляю?

спустя 18 минут [обр] Иванов Михаил aka Ivanych(0/70)[досье]
Структура правильная. А что за проблема с объединением? Что, собственно, не получается?
спустя 1 час 2 минуты [обр] Artie Kh![досье]

ну вот есть у меня головной модуль - App.pm и есть модуль Auth.pm в папке Auth/ есть файлы Auth/Basic.pm
есть скрипт app.cgi в котором написано

use lib("./lib");
use App.pm;

в App.pm
должна быть функция что-то вроде run_app { ... }
которая разбирает query_string и передает результат в роутер - функцию типа route { ... }
которая запускает модуль необходимый.

Вот! Что нужно сделать что бы в главном модуле и не перечислять все существующие на данный момент модули в приложении?
т.е. если я в файле приложения - app.cgi пишу use App.pm у меня подгружались все модули которые есть в папке App/...
или я чего не понимаю...
а ещё мне кажется я как-то непонятно всё объясняю. ):
как это сделать?

я немного непонимаю, тут это всё как-то завязано на наследовании или как?

спустя 1 час 35 минут [обр] Алексей Севрюков(61/1292)[досье]
Artie Kh![досье] модули сами по себе не загрузятся, их нужно загружать руками.
спустя 18 минут [обр] Artie Kh![досье]
Алексей Севрюков[досье] это понятно, потому я всё и спрашиваю. я вот смотрел модули CGI::Simple например, но там я нигде не нашёл явно строки в которой подключались бы подмодули, например CGI::Simple::Cookie.
И прямого обращения, например, CGI::Simple::Cokie->somefunc... тоже не видел.
Мне нужно в главном модуле просто перечислиить подмодули или обращаться напрямую?
не могу понять именно этот момент, потому и топчусь на месте.
спустя 13 минут [обр] Алексей Севрюков(61/1292)[досье]
сообщение промодерировано
Artie Kh![досье] Зависит от архитектуры и от содержимого подключаемых модулей. Вообще можно сделать как угодно. Например, Вы можете подключить CGI::Simple::Cookie, но все его методы (или функции) будут вызываться через CGI::Simple.
Теоритически, судя по Вашему описанию, Вам достаточно будет подключить все вспомогательные пакеты в основном. Попробуйте, это не страшно.
спустя 12 минут [обр] Artie Kh![досье]
Алексей Севрюков[досье] скорее всего так и поступлю.
И если не трудно, подскажите какие ещё есть варианты и где можно об этом почитать?
спустя 15 минут [обр] Алексей Севрюков(61/1292)[досье]
Artie Kh![досье] Вариантов огромное множество. Все зависит от Ваших задач. Что почитать даже не подскажу. Сам я до всех этих вариантов доходил самостоятельно, создавая свой код и читая чужой.
Я могу попробовать ответить на Ваш вопрос, если Вы конкретно опишите какая у Вас задача.
спустя 22 минуты [обр] Artie Kh![досье]

Алексей Севрюков[досье] Задача: написать модульный движок для интернет-сайта.
Может быть и не стоило бы делать модулями, но вот только очень хочется, и очень уж это интересно.

Посмотрел я сейчас исходники MovableType... сделаю я так, как посоветовали Вы, всё равно я сам к этому шёл. Только решение это, как мне кажется не самое лучшее.

Спасибо за помощь.

спустя 5 часов [обр] Nuclon(0/22)[досье]
ну, если сильно хочется динамическую загрузку - посмотрите в сторону Module::Find например
спустя 19 часов [обр] Алексей Севрюков(61/1292)[досье]
сообщение промодерировано
Artie Kh![досье] Есть три основных причины делать модульную структуру:
  1. Разбить код на более менее логически связанные части. В результате получится набор модулей "по действиям", Вы будете легко ориентироваться в наборе модулей, упростится поиск ошибок, ускорится процесс доработки/апгрейда, появится возможность работать в команде над отдельными частями.
  2. Подгружать ТОЛЬКО необходимые для формирования результата модули, экономя при этом память, время загрузки, время на компиляцию.
  3. Повторное использование. Единожды написав модули - Вы избавите себя от необходимости писать их каждый раз для нового проекта. За счет этого многократно возрастет скорость создания проектов.
спустя 1 день 22 часа [обр] Artie Kh![досье]

хм... и наверное самый главный вопрос, который я потерял из виду изначально: как объявить переменную которую смогут видеть все модули?

нагуглил только одно решение: экспортировать эти переменные, но мне не нравится это решение.
как минимум мне надо будет три глобальные переменные объявленные в главном модуле: это $q от модуля CGI, $dbh от DBI и $tt от TT (=

спустя 6 минут [обр] Алексей Севрюков(61/1292)[досье]
Artie Kh![досье] В частности с базой данных я этот вопрос решил модулем-singleton. Модуль подключается в основном скрипте, там же ему передаются данные коннекта. Далее все просто — функция Database::dbh() возвращает дескриптор подключенной базы данных, если подключения не было, то сперва происходит подключение, а затем возвращается идентификатор. Это гарантирует что я буду использовать один и тот дескриптор во всех модулях и файлах. Что касается модулей CGI и TT — я бы инициализировал бы их непосредственно там, где нужно.
Дело в том, что глобальные переменные ухудшают читаемость кода и ими лучше не пользоваться.
спустя 54 минуты [обр] Artie Kh![досье]
Алексей Севрюков[досье] а можно посмотреть как выглядит ваш модуль?
спустя 16 минут [обр] Алексей Севрюков(61/1292)[досье]

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

# Database.pm
package Database;

use strict;
use DBI ();
use DBD::mysql ();

END
 {
  Database::disconnect() if( defined($Database::dbh) && ref($Database::dbh) );
 }



sub connected
 {
  return 1 if(defined $Database::dbh && ref($Database::dbh));
  undef;
 }


sub data
 {
  $Database::_DSN=$_[0];
  $Database::_LOGIN=$_[1];
  $Database::_PASSWORD=$_[2];
 }

sub dbh
 {
  unless(defined($Database::dbh) && ref($Database::dbh))
   {
    $Database::dbh=DBI->connect($Database::_DSN,$Database::_LOGIN,$Database::_PASSWORD, {PrintError=>0,RaiseError=>0});
    return undef if($DBI::err);
   }
  return $Database::dbh;
}


sub disconnect
 {
  if(defined($Database::dbh) && ref($Database::dbh))
   {
    $Database::dbh->disconnect();
    undef $Database::dbh;
   }
}

1;
__END__

использование достаточно так же простое:

#!/usr/bin/perl

use strict;
use Database;

Database::data("DBI:mysql:db:host","user","password");

{
 my $dbh=Database::dbh();
 my $sth=$dbh->prepare('...');
 ....
}

подключение к базе произойдет в момент первого обращения к Database::dbh(), во время второго и последующих обращений будет возвращаться один и тот же дескриптор БД. Обращаться можно откуда угодно, в том числе и из модулей, причем необязательно объявлять этот пакет и в модулях, т.к. он использует процедурный интерфейс и ничего не экспортирует в вызывающую программу/модуль.

спустя 24 минуты [обр] Artie Kh![досье]
Алексей Севрюков[досье] спасибо!
спустя 1 день [обр] Artie Kh![досье]

После долгих мучений с модулем Exporter и прочей ерундой, решил всё-таки воспользоваться вашим, Алексей Севрюков[досье] модулем. Но что-то он у меня не заработал.

Решил "переписать":

package Database;

use strict;
use warnings;

use DBI;

our ($dsn, $login, $password, $dbh);

END {
    Database::disconnect() if (defined($dbh) && ref($dbh));
}

sub set_handle {
    my $self = shift;

    ($dsn, $login, $password) = @_;
}

sub get_handle {
    unless (defined($dbh) && ref($dbh)) {
        $dbh = DBI->connect($dsn, $login, $password);

        return undef if ($DBI::err);
    }

    return $dbh;
}

sub disconnect {
    if (defined($dbh) && ref($dbh)) {
        $dbh->disconnect();
        undef $dbh;
    }
}

1;

__END__
спустя 36 минут [обр] Алексей Севрюков(61/1292)[досье]

Artie Kh![досье] понятия "не заработал" в программировании нет. Что конкретно не получается? Как минимум ошибка у Вас тут:

sub set_handle {
    ($dsn, $login, $password) = @_;
}

строка:

my $self = shift;

лишняя. Тут же процедурный подход, а не ОО.

А у Вас скорее всего выдается ошибка из-за неверных данных коннекта, потому что shift съедает первый параметр.

спустя 18 часов [обр] Artie Kh![досье]
Алексей Севрюков[досье] вообще-то у меня не заработал именно ваш вариант, потому что первым параметром у меня выступало имя модуля, после его выдёргивания всё встало на свои места и сейчас разработка уже идёт полным ходом.
спустя 1 час 54 минуты [обр] Алексей Севрюков(61/1292)[досье]

Artie Kh![досье] Вы неправильно делали вызов. Т.е. нужно вызывать функцию как функцию:

Database::dbh()

, а не как метод:

Database->dbh()

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

Powered by POEM™ Engine Copyright © 2002-2005