2014-01-16 6 views
0

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

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

Вот суть сценария (воспользовавшись селеном):

#!/usr/bin/perl 
use strict; 
use warnings; 

use Getopt::Long; 
use WWW::Selenium; 

my @changepass; 
my $addsub  = ''; 
my $add2sub = ''; 

GetOptions (
    "changepass|cp=s{3}" => \@changepass, 
    "addsub|as=s" => \$addsub, 
    "add2sub|a2s=s" => \$add2sub, 
    "help|h" => \&do_help 
) or die(&do_help); 


sub login { 
    my $sel = WWW::Selenium->new(
     host => "localhost", 
     port => 4444, 
     browser => "*googlechrome", 
     browser_url => "example.com", 
); 
    $sel->start; 
    $sel->open("/login.php"); 
    $sel->wait_for_page_to_load("5000"); 
    $sel->type("id=loginSection-username", "username"); 
    $sel->type("id=loginSection-password", "password"); 
    $sel->click("name=send"); 
    $sel->wait_for_page_to_load("30000"); 
    sleep(2); 

    return $sel; 
} 


sub do_changepass { 
    my $email = $changepass[0]; 
    my $oldpass = $changepass[1]; 
    my $newpass = $changepass[2]; 
    my ($sel) = @_; 
    $sel->click("css=#my-webspaces-container .more > a"); 
    $sel->wait_for_page_to_load("30000"); 
    ...MORE COMMANDS... 
} 


if (@changepass) { 
    print "Changing password...\n"; 
    my $sel = do_changepass(); 
    print "Finished!\n"; 
} 

Так что я хотел бы, чтобы иметь возможность повторно использовать определенные блоки кода, такие как переменная my $sel. Но я понимаю, что это объект. Если бы я мог как-то просто сохранить его в виде обычного текста, а затем импортировать его в функцию. (Не через внешний файл, если это возможно.)

+2

Пожалуйста, не полностью меняйте свой вопрос. Он ставит ответы и комментарии, которые вы получили до изменения вне контекста. Одной из основных функций Stack Overflow является предоставление многоразовых решений для доступа других людей, и вы должны избегать всего, что делает сообщение менее понятным для всех. Вы всегда можете * добавить * к своему ответу, чтобы уточнить, что вы имеете в виду. – Borodin

ответ

0

Чтобы получить работу, что вы пытаетесь достичь, вы должны заботиться о масштабах в $ Селе объекта:

... 

if (@commands){ 
    my $sel = login(); 
    do_changepass($sel); 
} 

sub login { 
    my $sel = WWW::Selenium->new(host => "localhost", 
            port => 4444, 
            browser => "*googlechrome", 
            browser_url => "example.com", 
           ); 
    $sel->start; 
    $sel->open("/login.php"); 
    $sel->wait_for_page_to_load("5000"); 
    $sel->type("id=loginSection-username", "username"); 
    $sel->type("id=loginSection-password", "password"); 
    $sel->click("name=send"); 
    $sel->wait_for_page_to_load("30000"); 
    sleep(2); 

    return $sel; 
} 

sub do_changepass { 
    my $email = $changepass[0]; my $oldpass = $changepass[1]; my $newpass = $changepass[2]; 
    my ($sel) = @_; 
    $sel->click("css=#my-webspaces-container .more > a"); 
    $sel->wait_for_page_to_load("30000"); 
    ...MORE COMMANDS... 
} 
... 

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

или вы можете использовать login -subroutine непосредственно в do_changepass

... 
    sub do_changepass { 
     my $email = $changepass[0]; my $oldpass = $changepass[1]; my $newpass = $changepass[2]; 
     my ($sel) = login(); # <--- login used here!!! 
     $sel->click("css=#my-webspaces-container .more > a"); 
     $sel->wait_for_page_to_load("30000"); 
     ...MORE COMMANDS... 
    } 
... 
+0

Второй вариант - именно то, что я искал. Это работает. Спасибо! Два вопроса, однако, можете ли вы уточнить, что скобка означает при определении переменной? И было бы возможно добавить больше функций в ... i.e. My ($ sel) = login(). go2page(); ' – Brandon

+0

Каждая подпрограмма принимает список (НЕ массив!) аргументов и также возвращает список. '(listitem0, listitem1, ...) = подпрограмма (listitem0, listitem1, ...)'. когда я назначаю список скаляру ('$ somthing'), он по умолчанию устанавливает первый список. Поэтому, когда вы возвращаете только один скаляр из подкаталога, 'my $ xyz = lala()' эквивалентно 'my ($ xyz) = lala()'. Когда вы возвращаете больше значений: 'my ($ val1, $ val2) = lala()' – marderh

+0

Что вы имеете в виду, добавляя больше функций? Как в боксе? 'my $ sel = go2page (login());' – marderh

3

Обратите внимания, что вы должны никогда не положенных прототипы на подпрограммах Perl (в () после идентификатора подпрограммы). Вы также должны добавить use strict и use warnings наверху всякий программа. (use warnings предпочтительнее -w в хижину линии.)

Вы можете вернуть $sel объект, который вы создали в одной подпрограмме и использовать его в дальнейшем в другом. Пока не ясно, какие вещи вы хотите сделать, как ваши две подпрограммы кажутся идентичными друг от комментария в конце второго, но это может помочь

#!/usr/bin/perl 
use strict; 
use warnings; 

use WWW::Selenium; 

sub login { 
    my $sel = WWW::Selenium->new(
     host => "localhost", 
     port => 4444, 
     browser => "*googlechrome", 
     browser_url => "example.com", 
); 
    $sel->start; 
    $sel->open("/login.php"); 
    $sel->wait_for_page_to_load("5000"); 
    $sel->type("id=username", "usernamehere"); 
    $sel->type("id=password", "passwordhere"); 
    $sel->click("name=send"); 
    $sel->wait_for_page_to_load("30000"); 
    sleep(2); 

    return $sel; 
} 

sub some_function { 
    my ($sel) = @_; 
    # ....MORE COMMANDS HERE.... 
} 

my $sel = login(); 
some_function($sel); 

Update

Что у вас не так с кодом, так это то, что вы никогда не звоните login. Если вы посмотрите на мой пример выше, вызывается login для входа в систему и возвращает значение $sel, которое затем передается в some_function.

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

if (@changepass) { 
    print "Changing password...\n"; 
    my $sel = login(); 
    do_changepass($sel); 
    print "Finished!\n"; 
} 

Я также полагаю, что вы не вызывать login внутри каждой подпрограммы. Его лучше всего вызвать из того же кода, который вызывает do_changepass и т. Д., Как указано выше.

+0

Бородин, я обновил свой код, чтобы быть более точным из того, что я пытаюсь выполнить. И, как вы можете видеть, я также пробовал, что вы предлагаете, но он не работает. Ошибка при вызове метода «Невозможно вызвать метод», потому что он не набирает значение '$ sel'. – Brandon

+0

В принципе, каждая функция должна включать эту «процедуру входа в систему», прежде чем продолжить навигацию на странице. Поэтому 'do_changepass()' должен сначала выполнить процедуру входа в систему, а затем выполнить собственные шаги. – Brandon

+0

@Brandon: Вы неправильно поняли мое первоначальное решение и внедрили его неправильно. Я добавил к своему ответу, чтобы объяснить. – Borodin

0

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

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

В моем тестовом скрипте:

my $driver = Custom::WebApp::setup_selenium(undef, undef, \%desired_capabilities); 

В моем WebApp.pm:

sub setup_selenium { 

    my $self   = shift; 
    my $browser  = shift; 
    my $capabilities = shift; 
    my $driver; 
    my %desired_capabilities; 

    if ($capabilities) { 
     %desired_capabilities = %$capabilities; 
    } 

    # Start selenium with capabilities if passed in from test script 
    unless (keys %desired_capabilities == 0) { 

     $driver = eval { 
      Selenium::Remote::Driver->new(%desired_capabilities); 
     }; 
     return [email protected] if [email protected]; # Return with error if capability not matched 
    } 

    # Or just start it with default settings 
    else { 
     $driver = eval { 
      Selenium::Remote::Driver->new(browser_name => $browser, 
              proxy => { proxyType => 'system' }); 
     }; 
     return [email protected] if [email protected]; # Return with error if capability not matched 
    } 
    return $driver; 

} 

Водитель, который возвращается setup_selenium, затем может использоваться на протяжении всего сценария, пока вы не позвоните $driver->quit;

Если вы заметили, в приведенном выше решении используется привязка Selenium :: Remote :: Driver, но вы можете легко заменить WWW :: Selenium, если хотите (хотя я рекомендую S: R: D в основном потому, что он активно поддерживается на Git и CPAN).

 Смежные вопросы

  • Нет связанных вопросов^_^