免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 13322 | 回复: 20
打印 上一主题 下一主题

Perl 交互环境 [复制链接]

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-06-08 16:58 |只看该作者 |倒序浏览
本帖最后由 zhlong8 于 2011-06-08 16:59 编辑
=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<perl -E CODE> 就没
多少区别了。

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

        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<^$module(?=[./])>) { #并不只删除此模块,是一系列模块
                    $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(blessed 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 函数前声明了上面这些辅助函数,调用的时候就不需要
带括号了,更像命令了。


有兴趣的朋友自己把代码拼起来就可以用了。代码中用了 5.10 的 say 和 state 特性,不过非常简单就可以迁移到 5.8 因为 state 只有开始一处

论坛徽章:
0
2 [报告]
发表于 2011-06-08 17:16 |只看该作者
不错啊~~鼓励原创,代码和注释都很清楚。

论坛徽章:
0
3 [报告]
发表于 2011-06-08 17:29 |只看该作者
写的很好,就是吧,我现在的水平,看不懂啊。
好在我现在也用不着。

论坛徽章:
0
4 [报告]
发表于 2011-06-08 17:35 |只看该作者
这个好得很呐。

论坛徽章:
0
5 [报告]
发表于 2011-06-08 18:42 |只看该作者
先收藏了{:3_189:}

论坛徽章:
0
6 [报告]
发表于 2011-06-08 19:02 |只看该作者
Devel::REPL 如何?

论坛徽章:
0
7 [报告]
发表于 2011-06-08 19:10 |只看该作者
高手
收藏了以后看

论坛徽章:
0
8 [报告]
发表于 2011-06-08 21:10 |只看该作者
本帖最后由 lokchungk 于 2011-06-08 21:14 编辑

這個先收下了



懶人做法:
  1. perl -d -e ''
复制代码
另外
  1. return "---- B::Deparse ----\n", `perl -MO=Deparse -E "$code"`;
复制代码
  1. return "---- B::Terse ----\n", `perl -MO=Terse -E "$code"`;
复制代码
建議直接
  1. use O (...);
复制代码
以減少調用另一個perl解譯器所浪費的資源
詳參 perldoc O

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
9 [报告]
发表于 2011-06-08 22:10 |只看该作者
Devel::REPL 如何?
redicaps 发表于 2011-06-08 19:02



    当初写的时候应该找到过这个,不过想不起来为什么不采纳了,可能当时太水了吧。自己写的心里有底,那个模块功能完善,看依赖功能有很多相通的地方,果然大家的需求都类似啊

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
10 [报告]
发表于 2011-06-08 22:30 |只看该作者
這個先收下了



懶人做法:另外和建議直接以減少調用另一個perl解譯器所浪費的資源
詳參 perldoc O
lokchungk 发表于 2011-06-08 21:10



    这里怎么 use O; ?我只会命令行的用法,或者在文件里面 use O; 然后整个文件都被 B 处理了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP