Perl 交互环境

简介: =head1 NAMEPerl 交互环境(REPL read eval print loop)=head1 DESCRIPTIONPython 带有一个 REPL 可以很方便的做计算器,或者做点稍微复杂的事情,作为 Perler很是羡慕。
=head1 NAME

Perl 交互环境(REPL read eval print loop)

=head1 DESCRIPTION

Python 带有一个 REPL 可以很方便的做计算器,或者做点稍微复杂的事情,作为 Perler
很是羡慕。Perl 源代码中带有个 psh 但是功能太简单了,就像它说的是“穷人的REPL”。
至于 perl -d 也不喜欢。于是搜了下 CPAN 结果没有找到合适的就自动动手写了个,
很简单。


=head2 Loop

REPL 最核心的就是 eval 函数和循环,Perl 都有只需要写个美化的界面如提示符什么的。直接看代码:

        sub prompt {
            my $pat = '[%03d]=> ';
            state $cnt = 0;
            printf $pat, $cnt++;
        }

这个是打印提示符的,带了行号。顺便 show 了下 state 关键字的用法。

        sub main {
            chdir 'd:/' or die $!;
            no strict;
            for(prompt; ; prompt) {
                chomp;
                my @output = eval;
                say "\n=> ", @output if @output;
                print $@ if $@;
                say '';
            }
        }

主函数,首先切换到默认 文件夹这个看个人喜欢我觉得挺方便。因为REPL中我们都懒得
声明变量,而且正常情况下都用全局变量所以就关闭了 strict。这里关于变量作用域
的问题很多,搞不懂的看仙子的教程。

循环很简单,打印提示符-> 读取一行代码-> list context eval -> B。
至于这里的“一行代码”其实是由 $/ 决定的,所以不用担心要输入多行代码的问题。
只打印出返回值,所以下面的命令可以返回字符串来做命令提示。


=head2 辅助工具

上面是 psh 的全部了,我们还要添加些辅助功能否则和直接写 C 就没
多少区别了。

首先解决读入多行代码的问题:

        sub ml { $/ = "\n\n"; '[multi line mode ok]'  }
        sub sl { $/ = "\n";   '[line mode ok]'        }

在 REPL 中直接输入 ml 就切换为了多行模式就可以输入多行代码,最后用连续2个换行
就表示程序结束了。

改变当前目录也很常用,加上:

        sub ls { print "\n", `ls`; ''} # win 下用 dir 或自己写个 ls
        sub cd { chdir shift; cwd }

基本的提示信息:

        sub h { 'bla bla bla' }
        sub help { h() }


=head2 数据可视化

进行RE匹配的时候,构建复杂数据结构的时候经常需要将数据结果打印出来,但是
Perl 不会自动展开 reference 所以 Data::Dumper 就成了我的最爱。

        use Data::Dumper ();
        *D = \&Data::Dumper::Dumper;

这里把 Data::Dumper::Dumper 在 package main 中取了个别名,用一个字母 D 表示
是因为它实在太常用了。同样道理 yaml 格式有时也很常用,特别是很多匿名 hashref
的时候用 Data::Dumper 打印出来太长太乱了,这时候用 YAML 就非常舒服了。

        use YAML ();
        sub yaml { return "---- yaml ----\n", YAML::Dump @_ }

很简单,这里不用别名是为了打印输出时排版更漂亮。

有兴趣 hack Perl 内部数据结构的同学肯定很熟悉 Devel::Peek::Dump 同样默认加入。

        use Devel::Peek ();
        *DD = \&Devel::Peek::Dump;


=head2 测试模块

配合上面的辅助功能很容易测试 Perl 语言特性或者陷阱,但是有时候我们想要测试
类或者包的特性的时候就有点力不从心了,因为一般都需要个文件来帮忙。否则在
REPL 中反复输入都要累死了,但是 REPL 有点好处就是交互方便比 Test::More 简单
太多了。

下面我们有了 .pm 文件比如叫 T.pm 吧。放到当前目录用 use T; 来加载它,发现功能
不完善修改下,再 use T; 却发现不行了,提示说已经加载,头大啊难道还要再启用新
进程?

其实这是 Perl 的 require 加载机制决定了,加载的文件会放到 %INC 中,每次再
use 或 require 会检查加载没有,大家明白所在了吧(带有 XS 扩展的模块不行)。

目标就是删除 %INC 中的 'T.pm'。

        sub re_use {
            my $module = shift;
            $module =~ s/\s//g;
            $module =~ s/::/\//g;
       
            return if $module eq '';
       
            my $count = 0;
            my @packages;
       
            while (my($k, $v) = each %INC) {
       
                if ($k =~ m) { #并不只删除此模块,是一系列模块
                    $count ++;
                    push @packages, $k;
                    delete $INC{$k};
                }
            }
            return "delete $count package\n\n", join "\n", @packages;
        }

注释那里这么说其实是因为模块命名都是有规律的,比如 Moose 所有辅助模块都在
Moose 文件夹下,这里一并删除就全部更新了。

这样我们就可以方便的写个模块,加载测试下-> 修改-> re_use 'Module_name' ->
加载继续测试。


=head2 来点高级的

Perl 的语法有时让人很迷惑,默认变量、作用域什么的,论坛上很多同学都问题多多。
用 B::Deparse 有时不失为一种很好的解决办法。这里只是简单封闭下,引号问题很多,
如果内容比较多还是老老实实用命令行解决吧。

        sub terse {
            my $code = shift;
            return "---- B::Terse ----\n", `perl -MO=Terse -E "$code"`;
        }
       
        sub deparse {
            my $code = shift;
            return "---- B::Deparse ----\n", `perl -MO=Deparse -E "$code"`;
        }


=head2 完善我们的计算器

为了方便做计算或测试,我们可以随意导入模块。有些不常用的也可以在 REPL 中动态
加载 比如 use LWP; 之类的。这里贴出最有用的

        use List::Util qw(first max maxstr min minstr reduce shuffle sum);
        use Scalar::Util qw(bles sed dualvar isweak weaken refaddr reftype
        looks_like_number);

让退出更友善点

        $SIG{INT} = sub {say "\n*** goodbye ***"; sleep 0.5; exit};


=head1 总结

厌倦了总是在命令行 perl -E 就写了这么个小工具,慢慢的添加了很多小工具,这里
介绍了大部分有助于学习 Perl 语言的功能。因为只是简单的 eval 而且用的时候
经常是全局变量,如果遇到什么离奇的事我只能祝你 good luck 了。

至于 应用其实它不仅仅是个简单的计算器、语言测试工具。因为可以动态加载模块,
我们完全可以创建一个文件,处理数据,输出;用 LWP 下载网页,处理,打印想要的
内容等等。配合着 Perl 完整的 系统调用封闭和大量模块,它就是个 shell

给小鸟们提示下如果在 main 函数前声明了上面这些辅助函数,调用的时候就不需要
带括号了,更像命令了。



目录
相关文章
|
9天前
|
数据挖掘 测试技术 开发工具
python 以及集成环境的安装
python 以及集成环境的安装
|
7月前
|
关系型数据库 MySQL Apache
kali配置python开发环境支持+apache2+cgi支持
kali配置python开发环境支持+apache2+cgi支持
90 0
|
10月前
|
算法 程序员 PHP
|
算法 Linux PHP
PHP是如何和Linux的CPU交互的?生命周期是怎样的?底层原理是什么?
PHP是如何和Linux的CPU交互的?生命周期是怎样的?底层原理是什么?
|
Python
Python自动化实现web页面UI差异对比
以自动化或工具的方式实现页面UI与标准UI图对比并输出可视结果
978 0
Python自动化实现web页面UI差异对比
|
XML JavaScript 前端开发
在FreeSWITCH中执行长期运行的嵌入式脚本–Lua语言例子
众所周知,FreeSWITCH中可以使用嵌入式的脚本语言javascript、lua等来控制呼叫流程。而更复杂一点操作可能就需要使用Event Socket了。其实不然,嵌入式的脚本也可以一直运行,并可以监听所有的Event,就像使用Event Socket起一个单独的Daemon一样。
|
数据可视化 Linux
借助第三方工具,在Linux中快速搭建LAMP环境
本文章意在介绍一种,快速搭建Linux中Web环境的配置方式,以降低LAMP环境的搭建门槛。
94 0
借助第三方工具,在Linux中快速搭建LAMP环境
|
数据安全/隐私保护 Shell 网络安全
借助URLOS快速安装swoole环境
环境需求 最低硬件配置:1核CPU,1G内存(1+1)提示:如果你的应用较多,而主机节点的硬件配置较低,建议在部署节点时开通虚拟虚拟内存; 生产环境建议使用2G或以上内存; 推荐安装系统:Ubuntu-16.
874 0