φ(.. ) 備忘録
   
  
ラベル perl の投稿を表示しています。 すべての投稿を表示
ラベル perl の投稿を表示しています。 すべての投稿を表示

2014年6月7日土曜日

hubot-loggerを設定する

hubot-loggerを設定する。文字化け対策もやる。対策に使うnkf.plは本ブログの過去記事を参照すること。ログの保存はutf-8になる。noticeでもログはとる。設定は以下。
(1)~/tools/hubot/package.jsonを修正。青字追加。
   :
  "dependencies": {
    "hubot": "~2.5.1",
    "hubot-scripts": ">= 2.1.0",
    "optparse": "1.0.3",
    "hubot-irc": "0.1.x",
    "hubot-logger": "~0.0.11"  },
   :
(2)~/tools/hubot/external-scripts.jsonを以下の内容で作成。
["hubot-logger"]
(3)% npm install
(4)~/tools/hubot/node_modules/hubot-logger/scripts/hubot-logger.coffeeを修正。
        :
log_message = (root, date, type, channel, meta) ->
  mkdirp(path.resolve root, channel)
  log_file = path.resolve root, channel, date.toString("%Y-%m-%d") + '.txt'
  meta.date = date
  meta.channel = channel
  meta.type = type
  if meta.message
    cmd = "~/tools/hubot/perl/nkf.pl -in " + escape(meta.message)
    exec = require('child_process').exec
    exec cmd, (err,stdout,stderr) ->
      meta.message=stdout
      fs.appendFile log_file, JSON.stringify(meta) + '\n', (err) ->
        if err
          throw err
  else

    fs.appendFile log_file, JSON.stringify(meta) + '\n', (err) ->
      if err
        throw err
        :
    robot.adapter.bot.on 'message', (nick, to, text, message) ->
      result = (text + '').match(/^\x01ACTION (.*)\x01$/)
      if !result
        log_message(logs_root, new Tempus(), "message", to, {nick: nick, message: text, raw: message })
      else
        log_message(logs_root, new Tempus(), "action", to, {nick: nick, action: result[1], raw: message })
    robot.adapter.bot.on 'notice', (nick, to, text, message) ->
      result = (text + '').match(/^\x01ACTION (.*)\x01$/)
      if !result
        log_message(logs_root, new Tempus(), "message", to, {nick: nick, message: text, raw: message })
      else
        log_message(logs_root, new Tempus(), "action", to, {nick: nick, action: result[1], raw: message }) 

        :
(5) ~/tools/hubot/runbot.shに以下の設定追加。
export IRCLOGS_PORT=3001 #expressがlistenするポート番号
export IRCLOGS_FOLDER="chatlogs" #ログの保存先
以上を設定すると、http://localhost:3001/irclogsでログを参照することができる。

2014年6月5日木曜日

hubotのbotスクリプトをperlで書く

hubotのbotスクリプトはcoffeescriptで書かれていて、ところどころ非同期動作となり初心者には難しく感じた。ある程度勉強してそれなりにかけるようになったが、複雑な処理をやらせようとするといつも私は壁に当たってしまう。めんどくさくなったので使い慣れたperlで書くことにした。
perlで書くといってもircとの接続部分はhubotを使うのでperlを起動し結果をircに渡す最低限の箇所だけcoffeescriptで書き、あとはperlで実装する方式を採用する。
実際、やってみたがあっさりできた。DB連携でき文字化けもせず今のところ問題ない。
やり方を公開しとく。
1.まず最初にやるのは本ブログで紹介したirc.coffeeの文字化け対策。詳細はこちら
2.次にbotをircに接続するため、以下の内容で
  ~/tools/hubot/node_modules/hubot-scripts/src/scripts/tellme.coffeeを作成。
# tellme.coffee
module.exports = (robot) ->
  robot.hear /^(tellme_del|tellme_add|tellme)(\ | ).+/i, (msg) ->
    cmd = "~/tools/hubot/perl/dbbot.pl "+escape('tellme')+" "+ escape(msg.match[0])
    exec = require('child_process').exec
    exec cmd, (err,stdout,stderr) ->
      msg.send stdout
3.runbot.shで上記スクリプトが読み込まれるよう
  ~/tools/hubot/hubot-scripts.jsonに以下青字を追加
["redis-brain.coffee", "shipit.coffee", "tellme.coffee"]
4.perlスクリプトを以下内容で~/tools/hubot/perl/dbbot.plに作成。mysqlのアカウントとパスワードは環境により修正要!
#!/usr/bin/perl
use utf8;
use DBI;
use Encode;
use URI::Escape;
exit if($#ARGV < 1);
$maxcnt=5; # 最大表示レコード数
$tbl=uri_unescape(decode("utf-8",$ARGV[0]));
$tbl=~s/%u([0-9a-fA-F]{4})/pack("U",hex($1))/ego;
$str=uri_unescape(decode("utf-8",$ARGV[1]));
$str=~s/%u([0-9a-fA-F]{4})/pack("U",hex($1))/ego;
$str=~s/\ /\ /g;$pos=index($str,' ');
exit if($pos == -1);
$exeid=substr($str,0,$pos);$key=substr($str,$pos+1);$exeid=~tr/A-Z/a-z/;
if($exeid =~ /.+_add$/){
    $pos=index($key,' ');
    if($pos == -1){print "内容がないよぅ\n";exit;}
    $val=substr($key,$pos+1);$key=substr($key,0,$pos);
}
if($key eq "help"||$key eq "?"||$key eq "?"){
    $exeid =~ tr/A-Za-z//;
    print "■".$exeid."マクロの使い方\n";
    print "\t登録・・・『 ".$exeid."_add <key> <val> 』\n";
    print "\t削除・・・『 ".$exeid."_del <key> 』\n";
    print "\t参照<完全一致>・・・『 ".$exeid." <key> 』\n";
    print "\t参照<部分一致>・・・『 ".$exeid." %<key>% 』\n";
    print "\t参照<前方一致>・・・『 ".$exeid." <key>% 』\n";
    print "\t参照<後方一致>・・・『 ".$exeid." %<key> 』\n";
    print " ※情報が複数ある場合は最大".$maxcnt."つまで表示する\n";
    exit;
}
if($exeid =~/.+_add/ || $exeid =~ /.+_del/){
    $dbh=DBI->connect('DBI:mysql:hubot', 'root', 'root');
    $dbh->do("set names utf8");
    $sql='SELECT * FROM `'.$tbl.'` WHERE `key` = '.$dbh->quote($key);%rows=();
    $sth=$dbh->prepare($sql);$sth->execute;
    while ($row = $sth->fetchrow_hashref()){$rows{$row->{key}}=$row->{val};}
    $sth->finish;
    if(scalar(keys(%rows)) == 0){
        if($exeid =~ /.+_del/){
            $dbh->disconnect;print "そんなキーワードないよ!!\n";exit;
        }
        $sql='INSERT INTO `hubot`.`'.$tbl.'` (`key`, `val`) VALUES ('.
            $dbh->quote($key).', '.$dbh->quote($val).');';
        $val="追加しました!!";
    }
    else{
        if($exeid =~ /.+_del/){
            $sql='DELETE FROM `hubot`.`'.$tbl.'` WHERE `'.$tbl.'`.`key` = '.
                $dbh->quote($key).';';
            $val="削除しました!!";
        }
        else{
            $sql='UPDATE `hubot`.`'.$tbl.'` SET `val` = '.$dbh->quote($val).
                ' WHERE `'.$tbl.'`.`key` = '.$dbh->quote($key).';';
            $val="更新しました!! 旧->".decode("utf-8",$rows{encode("utf-8",$key)});
        }
    }
    $sth=$dbh->prepare($sql);$sth->execute;
    if($sth->err){print "ERROR! ".$sth->errstr."\n";}else{print $val."\n";}
    $sth->finish;$dbh->disconnect;
}
else{
    $dbh=DBI->connect('DBI:mysql:hubot', 'root', 'root');
    $dbh->do("set names utf8");
    if($key =~ /.*%.*/){$ope="LIKE";}else{$ope="=";}
    $sql='SELECT * FROM `'.$tbl.'` WHERE `key` '.$ope.' '.$dbh->quote($key);
    $sth=$dbh->prepare($sql);$sth->execute;%rows=();
    while ($row = $sth->fetchrow_hashref()){$rows{$row->{key}}=$row->{val};}
    $sth->finish;$dbh->disconnect;
    if(scalar(keys(%rows)) == 0){print "そんなキーワードないですよ!!\n";exit;}
    foreach $key(keys(%rows)){
        print "%u0016".$key."%u000f ".$rows{$key}."\n" if($ope eq "LIKE");
        print $rows{$key}."\n" if($ope eq "=");
        $maxcnt--;last if($maxcnt < 1);
    }
    print "・・・以下省略。ほかにもあるよ!!\n" if(scalar(keys(%rows)) > 5)
}
5.DB準備。
 (1)MySqlインストール
 (2)DB作成。名前は「hubot」
 (3)テーブル作成。名前は「tellme」。カラム数は2
 (4)テーブルの構造設定。
   1カラム目:名前「key」データ型「char」長さ「255」照合順序「utf8-bin」
   2カラム目:名前「val」データ型「char」長さ「255」照合順序「utf8-bin」

これで準備完了。cd ~/tools/hubot ; ./runbot.shで起動するとmybot君がチャットに登場する。
使い方は、
 tellme_add キーワード 内容
でDBに情報登録
 tellme キーワード
でDBの情報をチャットに出力
 tellme_del キーワード
でDBのレコードを削除
ちなみに、tellme.coffeeの robot.hearの行を
 robot.hear /^(なんとか_del|なんとか_add|なんとか)(\ | ).+/i, (msg) ->
にかえると、「なんとか」でbotが反応するようになる。
また
    cmd = "~/tools/hubot/perl/dbbot.pl "+escape('tellme')+" "+ escape(msg.match[0])
のtellmeを「なんとか」にかえるとテーブル名「なんとか」でDB登録参照するようになる。

ゼロからわかる Perl言語超入門
高橋 順子
技術評論社
売り上げランキング: 81,545

2014年5月31日土曜日

hubot文字化け対策

会社のchatbotが調子悪そうなので、新しいマシンにhubotをインストールして構築しなおしている。チャットの文字コードはISO-2022-JPだが、hubotがutf-8しか対応していないので結構文字化けに悩まされた。
ちまたでは、ZNCなどのプロキシを使うのが常套手段らしいがメンテするツールが増えるのがいやだったので、coffeescriptの改版で乗り切ったので備忘録を残しておく。
改版するスクリプトはこれ。
 hubot/node_modules/hubot-irc/src/irc.coffee

■変更箇所①sendするところでutf-8からISO-2022-JPに変換するperlを起動する。
      8   send: (envelope, strings...) ->
      9     mybot = @bot
     10     # Use @notice if SEND_NOTICE_MODE is set
     11     return @notice envelope, strings if process.env.HUBOT_IRC_SEND_NOTICE_MODE?
     12
     13     target = @_getTargetFromEnvelope envelope
     14
     15     unless target
     16       return console.log "ERROR: Not sure who to send to. envelope=", envelope
     17
     18     for str in strings
     19       cmd = "hubot/perl/nkf.pl -out " + escape(str)
     20       exec = require('child_process').exec
     21       exec cmd, (err,stdout,stderr) ->
     22         mybot.say target, stdout

■変更箇所②message受信時にISO-2022-JPからutf-8に変換するperlを起動する。
    215     bot.addListener 'message', (from, to, message) ->
    216       cmd = "hubot/perl/nkf.pl -in " + escape(message)
    217       exec = require('child_process').exec
    218       exec cmd, (err,stdout,stderr) ->
    219         message = stdout
    220         if options.nick.toLowerCase() == to.toLowerCase()
    221           # this is a private message, let the 'pm' listener handle it
    222           return
    223
    224         if from in options.ignoreUsers
    225           console.log('Ignoring user: %s', from)
    226           # we'll ignore this message if it's from someone we want to ignore
    227           return
    228
    229         console.log "From #{from} to #{to}: #{message}"
    230
    231         user = self.createUser to, from
    232         if user.room
    233           console.log "#{to} <#{from}> #{message}"
    234         else
    235           unless message.indexOf(to) == 0
    236             message = "#{to}: #{message}"
    237           console.log "msg <#{from}> #{message}"
    238
    239         self.receive new TextMessage(user, message)
以上、2箇所。noticeもかえたければ上記を参考に変更する。220行目以降は変更はないが、インデントを2文字ずつ後ろにする必要がある。これをやらないとうまくうごかないぞ!
次は文字コード変換perl。
※ここはperlのnkfモジュールを使うように以前の投稿から変更する。以前はファイル出力しnkfコマンドを使っていたがモジュールを使うことにする。
perlのnkfモジュールは sudo apt-get install libnkf-perlでインストールできる。
■hubot/perl/nkf.pl
#!/usr/bin/perl
use utf8;use NKF;use URI::Escape;
exit if($#ARGV < 1);
$str=uri_unescape($ARGV[1]);
if($ARGV[0] eq "-in"){print nkf("--oc=utf-8 --ic=ISO-2022-JP",$str);}
else{
    $str=~s/%u([0-9a-fA-F]{4})/pack("U",hex($1))/ego;
    print nkf("--ic=utf-8 --oc=ISO-2022-JP",$str);
}

chmod 755 nkf.pl を忘れずに!。
これでほぼ文字化けは回避できた。ポイントは文字をescapeしてからperlに渡しているところで、これをしないと「Д」とか「:」が入力されたとき動作がおかしくなる。


つくって覚えるCoffeeScript入門
飯塚直
アスキー・メディアワークス
売り上げランキング: 292,335

2014年2月1日土曜日

Cygwin perlで発生するwarningを消す

Cygwinのperlで作成したデスクトップ操作用スクリプトだが、起動時に以下のようなwarningが発生する。
「cygwin warning: MS-DOS style path detected:~」
スクリプト動作上はなにも影響ないようにみえるが、うざいので消した。
やり方は以下。
  1. コンピュータ→プロパティ→システムの詳細設定→詳細設定タブ→環境変数を選択。
  2. システム環境変数に新規で以下を追加。
     変数名:CYGWIN 変数値:nodosfilewarning

これでwarningはでなくなる。快適快適。

新版Perl言語プログラミングレッスン入門編
結城浩
ソフトバンククリエイティブ
売り上げランキング: 13,118

2013年12月20日金曜日

Cygwin perlでクリップボード操作

前回、Cygwin(32bit)のperl環境がある程度整ったので、今日はクリップボードと連携したperlのツールを作成する。
本ツールはモジュールの「Win32::Clipboard」と「Encode」を使用する。インストールしていない人は、32bit Cygwinでperl設定を参考にしてほしい。
以下の内容をclipboard_sort_uniq.plというファイル名で適当なとこに配置し、デスクトップにショートカットを作成する。
    #!/usr/bin/perl
    #----------------------------------------
    # [Windows用]
    # クリップボードのデータをユニークソートし、
    # 結果をクリップボードに設定する。
    use utf8;
    use Encode;
    use Win32::Clipboard;
    my $clip = Win32::Clipboard();
    exit 1 unless $clip->IsText(); # テキスト以外なら終了する
    my $text = decode("cp932",$clip->GetText()); # テキスト取得
    # 連想配列を使ってユニーク
    my %hash=();
    foreach $rec (split(/\n/,$text)){
        $rec=~s/\r//g;       # LFを削除
        next if($rec eq ""); # スペースは除外
        $hash{$rec}="";
    }
    $text="";
    foreach $key (sort keys(%hash)){
        $text.=$key."\r\n";
    }
    $clip->Set(encode("cp932",$text)); # テキスト設定
    exit;
    #----------------------------------------
    
使い方は、
  1. ユニークソートしたい単語配列をコピー。例)excelの縦列を選択しCtrl+C
  2. clipboard_sort_uniq.plのショートカットをダブルクリック
  3. メモ帳やエクセルに貼り付けCtrl+v
クリップボードをIO媒体として使うので、後始末もなく手軽で便利。

2013年12月19日木曜日

32bit Cygwinでperl設定

  • 前回、64bit版CygwinをUninstallして、32bit版Cygwinをinstallした。本日はperlの設定を試みる。
  • まずは、cpanの設定。設定方法は以前の記事「perlのcpan設定」を参照。
  • 次に、64bit版Cygwinでは失敗したperlのWin32::OLEをインストールする。
  1. Cygwin Terminal起動
  2. cpan ⏎
  3. cpan[1]> install Win32::OLE
今回は問題なくmakeできた。やっぱり64bit版をinstallしたのがいけなかったのか。。。
まぁ、とりあえずinstallできたのでよしとする。
ついでに環境整備。
  1. cpan[2]> install Encode
  2. cpan[3]> install Win32::Clipboard
  3. cpan[4]> q
ん。いい感じ。
次回は、デスクトップ周りを便利にするスクリプトをためす。

初めてのPerl 第6版
初めてのPerl 第6版
posted with amazlet at 13.12.19
Randal L. Schwartz brian d foy Tom Phoenix
オライリージャパン
売り上げランキング: 27,108

2013年12月13日金曜日

perlのcpan設定

cygwinのperl環境を整えている。最近、台湾のcpanサイトがつながらないせいで、cpanコマンドが失敗する。この際、cpanのサイトを変えることにした。google先生に教えてもらって、以下をすれば変更できることがわかった。
  1. Cygwinターミナル起動
  2. cpan
  3. cpan[1]> o conf urllist →これで今設定されているurlのリストが見える
        urllist
            0 [http://cpan.cs.pu.edu.tw/]
    Type 'o conf' to view all configuration items
    1. cpan[2]> o conf urllist pop →これで削除
    Please use 'o conf commit' to make the config permanent!
    1. cpan[3]> o conf urllist →消えたか確認
        urllist
    Type 'o conf' to view all configuration items
    1. cpan[4]> o conf urllist push http://ftp.jaist.ac.jp/pub/CPAN/ →サイト追加
    Please use 'o conf commit' to make the config permanent!
    1. cpan[5]> o conf urllist →追加できたか確認
        urllist
            0 [http://ftp.jaist.ac.jp/pub/CPAN/]
    Type 'o conf' to view all configuration items
    1. cpan[6]> o conf commit →設定保存
    2. cpan[7]> q →終了
    日本には、ほかにもcpanサイトがあるので、追加してもよいかも。
    Perl CPANモジュールガイド
    冨田尚樹
    ワークスコーポレーション
    売り上げランキング: 125,210

    2013年12月9日月曜日

    Cygwinでperl環境を整える

    最近は、rubyのほうが主流だが、perlを先に覚えたためなかなか手放せない。
    なので、Windows7でもperlをインストールする。
    まずは、CygwinのSetup.exeからperlをインストール。 次にモジュールをインストール。
    モジュールインストールはcpanを使う。 cpanは、install ほげほげとすれば、
    モジュールのコンパイルとインストール できる優れもの。 やり方はこう。
    1. Cygwin Terminal起動
    2. 「cpan」と入れてリターン。するといろいろ聞かれるかもしれないが、ほとんどの場合そのままリターンすればOK。proxyを使っている人は注意がいるかも。
    3. 「cpan[1]>」のプロンプトが出力されたら、「install モジュール名」 といれるだけ。
    4. 「Connection timed out.」がでるようならCtrl+cでスキップすると他サイトからインストール可能。
    5. インストールがおわったら「quit」で終了
    とりいそぎ、使いそうなのをピックアップしていれておこう。まぁ、あとから追加できるから
    あとでもよいが・・・
      install Encode文字コードトラブル回避要
      install Win32::ClipboardWindowsのクリップボードが操作できる
      install Win32::OLEWindowsのアプリケーション操作可能
      ん。なんかmake NOとかいわれるな。後で調べよう
      ⚠️12/15追記
      もしかしたら64bitのCygwinだからかも。
    とりあえず、こんなもんか。

    続・初めてのPerl 改訂第2版
    Randal L. Schwartz brian d foy Tom Phoenix
    オライリージャパン
    売り上げランキング: 109,219