2014年12月20日星期六

[PerlChina] PerlChina Advent Day 20: cpanfile

# cpanfile

传统的 Perl 风格,是将依赖模块写在 Makefile.PL 里。无奈这个单词实在给人太大精神压力,而且在一些项目应用中,我们也不需要除了依赖关系以外其他的 Makefile 内容。所以 modern perl 从 Ruby 学来了 Gemfile 的方式,叫做 [cpanfile](https://metacpan.org/pod/cpanfile)。

cpanfile 写法示例如下:

    requires 'perl', '5.20.0';
    requires 'Plack', '1.0'; # 1.0 or newer
    requires 'JSON', '>= 2.00, < 2.80';

    recommends 'JSON::XS', '2.0';
    conflicts 'JSON', '< 1.0';

    on 'test' => sub {
      requires 'Test::More', '>= 0.96, < 2.0';
      recommends 'Test::TCP', '1.12';
    };

支持 cpanfile 格式的安装工具,目前有两个:[cpanm](https://metacpan.org/pod/cpanm) 和 [carton](https://metacpan.org/pod/carton)。

cpanm 在之前的 advent 已经介绍过,可以说是目前最推荐的 cpan 客户端命令了。在有 cpanfile 存在的目录下,执行如下命令即可安装 cpanfile 里列出的全部依赖模块:

    $ cpanm --installdeps .

而 carton 则是学习 Ruby 的 bundle 命令。了解 bundle 的,基本可以直接照着习惯用 carton 就好了。如果不了解的,继续往下看。

## carton 用法

### 安装依赖

同样是在有 cpanfile 存在的目录下,执行如下命令安装依赖模块:

    $ carton install

和采用 cpanm 方式不同的是,这个命令会在目录下新生成一个文件叫 `cpanfile.snapshot`。这个文件里会记录你这次安装的时候的模块的确切版本,这样你通过 github 等方式共享给其他人、发布到服务器等的时候,再用下面的命令安装就可以同样做到安装完全一致的版本的模块了:

    $ carton install --deployment

### 执行

carton 和 cpanm 的另一个不同, cpanm 默认是把模块安装到系统目录里,用 -L 参数指定才会到指定目录。而 carton 默认是安装到当前目录的 **local/** 子目录下。所以,就需要利用 carton 命令来启动应用才能找到正确的路径:

    $ carton exec hypnotoad ./script/myapp

### 打包

carton 有专门的一个 bundle 命令。把之前 install 在 **local/** 里的模块,复制到 **vendor/cache** 目录下。然后通过下面命令来安装:

    $ carton install --cached

看起来似乎有点多此一举,分发的时候发哪个目录不都一样么?要点在于:carton 复制到 **vendor/cache** 目录下的,不是安装好的模块,而是各模块的 .tar.gz 包。这样,对于跨不同平台和系统环境的部署,这个会重新走一遍编译的过程,有些 XS 就不会有问题了。

好了,大家快给自己的项目加上 cpanfile 吧~

--
您收到此邮件是因为您订阅了Google网上论坛上的"PerlChina Mongers 讨论组"群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到perlchina+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至perlchina@googlegroups.com
访问此群组:http://groups.google.com/group/perlchina
要查看更多选项,请访问https://groups.google.com/d/optout

2014年12月19日星期五

[PerlChina] PerlChina Advent Day 19: 客户端来源 IP 信息处理

=encoding utf8

=for advent_year 2014

=for advent_title 客户端来源 IP 信息处理

=for advent_author fukai

=head2 前言

我们进行日志处理, 常有的一个需求就是需要日志中来源的 IP 变成指定的信息来进行分析, 也有可能有一种需求, 就是需要给所有用户的请求转换成 "ISP, 省市, 城市", 然后在排序分析用户来源相关的信息, 如省市排名, 运营商排名, 更加复杂的还有可能, 根据这些信息来做基础信息来判断用户的体验, 比如那个地区, 那个 ISP 的用户访问速度最快等等.
另外, 对于象视频, 大文件下载, 这种应用, 目前很多是基于 HTTP 之类的更加高级的调度, 这时我们就需要更加给请求过来的用户 IP , 也转换成相应的地区, 然后查询自己的全网调度系统中, 是否存在相应最优节点.

基于以上二点, 我们需要非常非常快速的 IP 转换成城市信息的模块. 在 08 年的时候, 我就想过各种方式, 使用过 Geo::IP 之类的库, 当年的 QQway.bat 的结构,还有比如给 IP 段折开, 存到数据之类的地方, 然后有了 IP , 根据这个信息来查询段是什么 ISP 和地区, 试过各种方式, 但速度和效率都不太理想.

比如日志 cat 出来后进行二次分析和清洗的时候, 这个查询和转换是最占用时间的, 真到我找到了 Net::IP::Match::Trie 这个模块, 这个速度快到可以不影响你 cat 的速度, 直接线性的处理 IP 到信息的转换.

当年这个模块还是刚出来的时候我关注到的, 非常好用, 非常想推荐给其它人. 但一直没有发布正式版本, 就这样用了几年, 因为不是正式版本, 所以 cpanm 一直找不到这个模块, 要指定 url 才能安装. 直到去年末, 我发了个邮件给作者, 提醒他, 这个模块几年还没 release , 作者接到邮件后立即就更新, 所以现在正式接这个机会推荐给有相应需求的朋友 ( 注: cpan 作者都非常热情, 有问题直接联系作者哦 ). 注: 我自己的调度系统中一直使用这个模块, 很多年了.

=head2 原始 IP 段和地址信息的加入

进行 IP 信息处理, 我们需要先收集 IP 段是哪个运营商. 目前网络上这种数据很多, 可以下载任何一个数据来加入到这个模块当中.

  use Net::IP::Match::Trie;
  my $matcher = Net::IP::Match::Trie->new;
  $matcher->add(CNC-ZJ-ZJ => [qw(66.249.64.0/19 74.125.0.0/16)]);
  $matcher->add(CNC-ZJ-ZJ  => [qw(69.147.64.0/18 209.191.64.0/18 209.131.32.0/19)]);


我是直接给对应的信息写成了一个如下的文件结构, 然后使用上面的方式导入.


上面 add 的 key 就是后面的 CNC,ZJ-ZJ. 然后在加上网段.


=head2 来源 IP 的查询

查询非常简单, 只需要给 IP 放到 match_ip 的方法中就搞定了.

  say $matcher->match_ip("66.249.64.1"); # => "CNC-ZJ-ZJ"


=head2 样例

下面是一个简单的管道传送过来的日志进行 IP 地址翻译的小程序.

  use strict;
  use 5.010;

  use Net::IP::Match::Trie;
  my $matcher = Net::IP::Match::Trie->new;

  open my $fh, "<", 'isp_ip.csv' or die "print $!";
  while (<$fh>) {
      my ($CIDRS, $isp, $region) = split(/,/, $_);
      chomp $region;
      my $name  = "$isp-$region";
      $matcher->add( $name , [$CIDRS] );
  }

  while(<>){
      chomp;
      my $ISP = $matcher->match_ip($_);
      print "$_, $ISP\n";
  }

=head2 使用

象上面, 可以用于日常的日志处理, 让信息读进来一次, 给 IP 以流的方式 cat 进去就好了, 象日志处理什么之类就非常好用了.

  # echo 202.106.0.20 |perl check.pl
  202.106.0.20, CNC-BJ-BJ

=head2 IP 段的整理

象上面的 IP 段, 因为运营商信息不断的变化, 所以你的 IP 数据库也会跟着不断的变化, 当运营商给你一堆 IP 时, 你对很多重复的段要合并, 有些小的段要折分, 这样手工操作很累, 同样, 也推荐一个模块, 叫 Net::IP::RangeCompare , 小小包装和处理一下, 配合起来使用, 非常合适.

=head2 作者

fukai, L<mail://iakuf@163.com>

=cut


--
您收到此邮件是因为您订阅了Google网上论坛上的"PerlChina Mongers 讨论组"群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到perlchina+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至perlchina@googlegroups.com
访问此群组:http://groups.google.com/group/perlchina
要查看更多选项,请访问https://groups.google.com/d/optout

2014年12月18日星期四

Re: [PerlChina] PerlChina Advent Day 18: Time::Piece 模块

cool~ ;-)

于 14/12/18 下午9:58, chenlin rao 写道:
巧合的是今天日本Perl协会的advent发的是 Time::Piece::Iterator 模块,http://t.cn/Rz3HWiy 大家可以一块看看~

在 2014年12月18日 下午9:56,chenlin rao <rao.chenlin@gmail.com>写 道:
# Time::Piece

时间处理是一个有时候蛮麻烦的事情。很多 Perl 程序员可能还习惯于使用下面这样的写法:

    my ($sec, $min, $hour, $mday, $mon, $year_off, $wday, $yday, $isdat) = localtime;

或者稍微简单一点的地方,可以:

    use POSIX qw/strftime/;
    print strftime('%F %T', localtime);

但是涉及到时间运算的时候,就麻烦多了。常见的是换算到秒做加减乘除,或者安装沉重的 DateTime 模块。

## Time::Piece 示例

其实,从 Perl v5.9.5 版本开始,就随内核分发一个时间模块,叫 [Time::Piece](https://metacpan.org/pod/Time::Piece)。在 通常情况下,都足够好用了。

    use 5.010;
    use Time::Piece;
    my $t = localtime() - localtime()->tzoffset;
    say $t->datetime;                              # 2014-12-14T16:06:06
    say localtime()->datetime;                     # 2014-12-15T00:06:06
    say $t->date;                                  # 2014-12-14
    say $t->mdy('/');                              # 12/14/2014
    say $t->time;                                  # 00:06:06
    say $t->hms('.');                              # 00.06.06
    say $t->epoch;                                 # 1418573166
    say $t->month;                                 # Dec
    say $t->add_months(1)->year;                   # 2015

Time::Piece 会覆盖 CORE 里提供的 **localtime** 和 **gmtime** 函数,自动返回 Time::Piece 对象。这点类似的还有 [File::stat](https://metacpan.org/pod/File::stat) 模块,注意是小写的,这个也是 Perl5 现在的内核分发模块。在 `use File::stat` 以后,**stat** 函数也会自动返回 File::stat 对象而不是那个复杂的数组!

## Time::Seconds 示例

上面示例代码里有个隐藏的地方,`localtime->tzoffset` 事实上是返回了一个 [Time::Seconds](https://metacpan.org/pod/Time::Seconds) 对象。这个类是 Time::Piece 模块里一起提供的,不用单独安装。

一个 Time::Piece 对象加减一个 Time::Seconds 对象,得到的还是 Time::Piece 对象。而两个 Time::Piece 对象相加减,得到的则是 Time::Seconds 对象了:

    my $s = $t - localtime();
    say $s->days;                                  # 31

Time::Seconds 如果你单独导入的话,他会导出一系列常量,比如我们再重复一次前面那个加一个月的操作,就可以写成:

    use Time::Seconds;
    $t += ONE_MONTH;                               # 继续用前面的 $t 变量
    say $t->month;                                 # Feb

## 缺陷

Time::Piece 虽然也实现了 `strptime` 方法,但是实现的不是很全面(不支持时区)。如果有很强的从字符串转换成时间对象的需求,可以参考 [Time::Moment](https://metacpan.org/pod/distribution/Time-Moment/lib/Time/Moment.pod) 模块的 `->from_string` 方法。Time::Moment 模块也提供了类似的一些属性方法。


--
您收到此邮件是因为您订阅了Google网上论坛上的"PerlChina Mongers 讨论组"群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到perlchina+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至perlchina@googlegroups.com
访问此群组:http://groups.google.com/group/perlchina
要查看更多选项,请访问https://groups.google.com/d/optout

Re: [PerlChina] PerlChina Advent Day 18: Time::Piece 模块

巧合的是今天日本Perl协会的advent发的是 Time::Piece::Iterator 模块,http://t.cn/Rz3HWiy 大家可以一块看看~

在 2014年12月18日 下午9:56,chenlin rao <rao.chenlin@gmail.com>写道:
# Time::Piece

时间处理是一个有时候蛮麻烦的事情。很多 Perl 程序员可能还习惯于使用下面这样的写法:

    my ($sec, $min, $hour, $mday, $mon, $year_off, $wday, $yday, $isdat) = localtime;

或者稍微简单一点的地方,可以:

    use POSIX qw/strftime/;
    print strftime('%F %T', localtime);

但是涉及到时间运算的时候,就麻烦多了。常见的是换算到秒做加减乘除,或者安装沉重的 DateTime 模块。

## Time::Piece 示例

其实,从 Perl v5.9.5 版本开始,就随内核分发一个时间模块,叫 [Time::Piece](https://metacpan.org/pod/Time::Piece)。在通常情况下,都足够好用了。

    use 5.010;
    use Time::Piece;
    my $t = localtime() - localtime()->tzoffset;
    say $t->datetime;                              # 2014-12-14T16:06:06
    say localtime()->datetime;                     # 2014-12-15T00:06:06
    say $t->date;                                  # 2014-12-14
    say $t->mdy('/');                              # 12/14/2014
    say $t->time;                                  # 00:06:06
    say $t->hms('.');                              # 00.06.06
    say $t->epoch;                                 # 1418573166
    say $t->month;                                 # Dec
    say $t->add_months(1)->year;                   # 2015

Time::Piece 会覆盖 CORE 里提供的 **localtime** 和 **gmtime** 函数,自动返回 Time::Piece 对象。这点类似的还有 [File::stat](https://metacpan.org/pod/File::stat) 模块,注意是小写的,这个也是 Perl5 现在的内核分发模块。在 `use File::stat` 以后,**stat** 函数也会自动返回 File::stat 对象而不是那个复杂的数组!

## Time::Seconds 示例

上面示例代码里有个隐藏的地方,`localtime->tzoffset` 事实上是返回了一个 [Time::Seconds](https://metacpan.org/pod/Time::Seconds) 对象。这个类是 Time::Piece 模块里一起提供的,不用单独安装。

一个 Time::Piece 对象加减一个 Time::Seconds 对象,得到的还是 Time::Piece 对象。而两个 Time::Piece 对象相加减,得到的则是 Time::Seconds 对象了:

    my $s = $t - localtime();
    say $s->days;                                  # 31

Time::Seconds 如果你单独导入的话,他会导出一系列常量,比如我们再重复一次前面那个加一个月的操作,就可以写成:

    use Time::Seconds;
    $t += ONE_MONTH;                               # 继续用前面的 $t 变量
    say $t->month;                                 # Feb

## 缺陷

Time::Piece 虽然也实现了 `strptime` 方法,但是实现的不是很全面(不支持时区)。如果有很强的从字符串转换成时间对象的需求,可以参考 [Time::Moment](https://metacpan.org/pod/distribution/Time-Moment/lib/Time/Moment.pod) 模块的 `->from_string` 方法。Time::Moment 模块也提供了类似的一些属性方法。


--
您收到此邮件是因为您订阅了Google网上论坛上的"PerlChina Mongers 讨论组"群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到perlchina+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至perlchina@googlegroups.com
访问此群组:http://groups.google.com/group/perlchina
要查看更多选项,请访问https://groups.google.com/d/optout

[PerlChina] PerlChina Advent Day 18: Time::Piece 模块

# Time::Piece

时间处理是一个有时候蛮麻烦的事情。很多 Perl 程序员可能还习惯于使用下面这样的写法:

    my ($sec, $min, $hour, $mday, $mon, $year_off, $wday, $yday, $isdat) = localtime;

或者稍微简单一点的地方,可以:

    use POSIX qw/strftime/;
    print strftime('%F %T', localtime);

但是涉及到时间运算的时候,就麻烦多了。常见的是换算到秒做加减乘除,或者安装沉重的 DateTime 模块。

## Time::Piece 示例

其实,从 Perl v5.9.5 版本开始,就随内核分发一个时间模块,叫 [Time::Piece](https://metacpan.org/pod/Time::Piece)。在通常情况下,都足够好用了。

    use 5.010;
    use Time::Piece;
    my $t = localtime() - localtime()->tzoffset;
    say $t->datetime;                              # 2014-12-14T16:06:06
    say localtime()->datetime;                     # 2014-12-15T00:06:06
    say $t->date;                                  # 2014-12-14
    say $t->mdy('/');                              # 12/14/2014
    say $t->time;                                  # 00:06:06
    say $t->hms('.');                              # 00.06.06
    say $t->epoch;                                 # 1418573166
    say $t->month;                                 # Dec
    say $t->add_months(1)->year;                   # 2015

Time::Piece 会覆盖 CORE 里提供的 **localtime** 和 **gmtime** 函数,自动返回 Time::Piece 对象。这点类似的还有 [File::stat](https://metacpan.org/pod/File::stat) 模块,注意是小写的,这个也是 Perl5 现在的内核分发模块。在 `use File::stat` 以后,**stat** 函数也会自动返回 File::stat 对象而不是那个复杂的数组!

## Time::Seconds 示例

上面示例代码里有个隐藏的地方,`localtime->tzoffset` 事实上是返回了一个 [Time::Seconds](https://metacpan.org/pod/Time::Seconds) 对象。这个类是 Time::Piece 模块里一起提供的,不用单独安装。

一个 Time::Piece 对象加减一个 Time::Seconds 对象,得到的还是 Time::Piece 对象。而两个 Time::Piece 对象相加减,得到的则是 Time::Seconds 对象了:

    my $s = $t - localtime();
    say $s->days;                                  # 31

Time::Seconds 如果你单独导入的话,他会导出一系列常量,比如我们再重复一次前面那个加一个月的操作,就可以写成:

    use Time::Seconds;
    $t += ONE_MONTH;                               # 继续用前面的 $t 变量
    say $t->month;                                 # Feb

## 缺陷

Time::Piece 虽然也实现了 `strptime` 方法,但是实现的不是很全面(不支持时区)。如果有很强的从字符串转换成时间对象的需求,可以参考 [Time::Moment](https://metacpan.org/pod/distribution/Time-Moment/lib/Time/Moment.pod) 模块的 `->from_string` 方法。Time::Moment 模块也提供了类似的一些属性方法。


--
您收到此邮件是因为您订阅了Google网上论坛上的"PerlChina Mongers 讨论组"群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到perlchina+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至perlchina@googlegroups.com
访问此群组:http://groups.google.com/group/perlchina
要查看更多选项,请访问https://groups.google.com/d/optout

[PerlChina] Re: 发起两个学习小组:大数据和TDD

发现一个很棒的程序,采用了PDL::stats ,Web 采用的是 Mojolicious构架。

效果演示 :http://gitinsight.mudler.pm/

代码:https://github.com/mudler/GitInsight

Web界面 :https://github.com/mudler/WebApp-GitInsight

对于学习PDL和Mojolicious 都有很好的学习价值。

On Tuesday, December 16, 2014 11:14:28 AM UTC+8, BlackJack wrote:
在上周日上海Perl聚会后,考虑发起两个学习小组:大数据和TDD来活跃和丰富Perl的应用领域。
大数据小组主要分支一是学习PDL ,专注于 计算可视化 ,即数据挖掘,2D/3D演示。主要应用场景是 生物医药统计和计算,金融证券数据分析,电商CRM客户行为建模和挖掘。是不是非常高大上。
大数据小组的另一分支是海量日志收集和分析系统,包括分布式计算和存储。


TDD(即Test-Driven Development )小组主要专注这样开发模式的应用和普及,比如基于Test:Mojo开发网站压力和安全测试,以及普及Perl测试技术和流程。

欢迎有兴趣的Monks来邮件交流和参加对应的小组共同学习和实践。

Xu.hejun@163.com

--
您收到此邮件是因为您订阅了Google网上论坛上的"PerlChina Mongers 讨论组"群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到perlchina+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至perlchina@googlegroups.com
访问此群组:http://groups.google.com/group/perlchina
要查看更多选项,请访问https://groups.google.com/d/optout

2014年12月17日星期三

[PerlChina] PerlChina Advent Day 17: File::ChangeNotify

# File::ChangeNotify

[File::ChangeNotify](https://metacpan.org/pod/File::ChangeNotify)通过系统事件通知来获悉文件的变化,所以其性能较好,CPU占用率也低。

我们可以使用[File::ChangeNotify](https://metacpan.org/pod/File::ChangeNotify)监测文件/目录的变化,来达到某些自动化操作。

例如:

1. nginx -s reload

当然[File::ChangeNotify](https://metacpan.org/pod/File::ChangeNotify)也有表现不正常的时候,正如我最近用Vagrant+VirtualBox搭建的Debian 7开发环境,经Host修改的文件,在Guest中用File::ChangeNotify就因为整个环境的问题,修改过的文件,Guest系统并没有发出notify事件,所以[File::ChangeNotify](https://metacpan.org/pod/File::ChangeNotify)无法被通知到。当然这不能算是[File::ChangeNotify](https://metacpan.org/pod/File::ChangeNotify)的问题了

下面是我工作场景的一个示例,监测一些目录的文件变化,并执行drush来清除Drupal Cache操作:

#!perl

# 监控drupal sites下的module文件,有改变则用drush cc清除cache
# 此脚本需要在drupal_site_path对应的目录下执行
# usage:
# 1. cd the_drupal_site_path
# 2. perl $0 path1 path2 path..n

use strict;

use File::ChangeNotify;

sub usage
{
die "perl $0 path1 path2 path..n\n";
}

my @site_path = @ARGV;
if (!@site_path)
{
&usage();
}

my $watcher = File::ChangeNotify->instantiate_watcher(
directories => [@site_path],
filter => qr/\.(?:module|inc|info|php)$/,
sleep_interval => 1,
);

print "monitor @site_path, wait for events\n\n";

while (my @events = $watcher->wait_for_events())
{
print "\nclear cache at: " . scalar(localtime()) . "\n";
system('drush cc all');
print "\n";
}

## 作者
[Beckheng Lam](http://blog.yixinit.com/)

--
您收到此邮件是因为您订阅了Google网上论坛上的"PerlChina Mongers 讨论组"群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到perlchina+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至perlchina@googlegroups.com
访问此群组:http://groups.google.com/group/perlchina
要查看更多选项,请访问https://groups.google.com/d/optout