Perl6 的 YAML::Dumper 模块使用详解
這兩天決定試一把 Perl6,因為扶凱兄已經把還沒有正式發(fā)行 Rakudo Star 包的 MoarVM 編譯打包好了,所以可以跳過這步直接進入模塊安裝。當然,源碼編譯本身也沒有太大難度,只不過從 github 下源碼本身耗時間比較久而已。
既然木有 Star 包,那么安裝好 MoarVM 上的 Rakudo 后我們就有必要先自己把 panda 之類的工具編譯出來。這一步需要注意一下你的 @*INC 路徑和實際的 $PERL6LIB 路徑,已經編譯之后的 panda 存在的 $PATH 是不是都正確,如果不對的修改一下 ~/.bashrc 就好了。
我的嘗試遷移對象是一個很簡單的 Puppet 的 ENC 腳本,只涉及 SQLite 的讀取,以及 YAML 格式的輸出。通過 panda install DBIish 命令即可安裝好 DBIish 模塊。
腳本本身修改起來難度不大,結果如下:
#!/usr/bin/env perl6 
use v6; 
use DBIish; 
use YAML; 
my $base_dir = "/etc/puppet/webui"; 
# 函數(shù)在 Perl6 中依然使用 sub 關鍵字定義,不過有個超酷的特性是 multi sub 
# 腳本中沒有用到,但是在 YAML::Dumper 中遍地都是,這里也提一句。 
# MAIN 函數(shù)在 Perl6 里可以直接用 :$opt 命令參數(shù)起 getopt 的作用 
# 不過 ENC 腳本就是直接傳一個主機名,用不上這個超酷的特性 
sub MAIN($node) { 
# connect 方法接收參數(shù)選項是 |%opts,所以可以把哈希直接平鋪寫 
# 這個 | 的用法一個月前在《Using Perl6》里看到過 
	my $dbh = DBIish.connect( 'SQLite', database => "{$base_dir}/node_info.db" ); 
	my $sth = $dbh.prepare("select * from node_info where node_fqdn = ?"); 
	$sth.execute("$node"); 
	my $ret = $sth.fetchrow_hashref; 
	my $res; 
	if ( !$ret ) { 
		$res = { 
# Perl5 的 qw() 在 Perl6 里直接寫成  。也不用再通過 [] 來指明是引用 
			classes     => , 
			environment => 'testing', 
		}; 
	} 
	else { 
		$res = { 
			environment => $ret{'environment'}, 
			parameters  => { role => $ret{'role'} }, 
			classes     => {}, 
		}; 
# 這個 for 的用法,在 Perl5 的 Text::Xslate 模板里就用過 
		for split(',', $ret{'classes'}) -> $class { 
			if ( $class eq 'nginx' ) { 
# 這個  寫這行 
# 如果不習慣這種流向操作符的,可以用,號,反正不能跟 Perl5 那樣啥都不寫 
# 這里比較怪的一點是我試圖把這么長的一句分成多行寫,包括每行后面加,我看到 YAML 代碼里就用分行了,但是我這就會報錯 
# Perl6 的正則變化較大,這里 /^#/ 要寫成 /^'#'/ 或者 /^x23/ 
# 正則 // 前面不加 m// 不會立刻開始匹配 
# 原先的 s///g 可以寫作 s:g///,也可以寫作對象式的 .subst(m//, '', :g),. 前面為空就是默認的 $_ 
# 捕獲的數(shù)據(jù)存在 @() 數(shù)組里,也可以用 $/[i] 的形式獲取 
# 字符串內插時,不再寫作 ${*},而是 {$*} 的形式 
# 命名捕獲這里沒用上,寫個示例: 
#     $str ~~ /^(w+?)$=(w ** 4)w$/; 
#     $/.chomp.say; 
# 注意里面的 w{4} 變成了 w ** 4 
				my @needs <== map { .subst(m/^(.+):(d+)$/, "{$/[0]} max_fails=30 weight={$/[1]}", :g) } <== grep { !m/^x23/ } <== split(',', $ret{'extstr'}); 
				$res{'classes'}{'nginx'}{'iplist'} = @needs; 
			} 
			else { 
# Perl5 的 undef 不再使用,可以使用 Nil 或者 Any 對象 
				$res{'classes'}{$class} = Nil; 
			} 
		} 
	}; 
	$dbh.disconnect(); 
# 這個 dump 就是 YAML 模塊導出的函數(shù) 
# Perl6 的模塊要導出函數(shù)不再需要 Exporter 那樣,直接用 our sub dump($obj) {} 就可以了 
	say dump($res); 
};
登錄后復制
但是麻煩的是 YAML 模塊本身,這個模塊是 ingydotnet 在好幾年前草就,后來就沒管了,實際現(xiàn)在壓根跑不起來,花了半天時間,一邊學習一邊修改,總算修改正常了,主要涉及了 Attribute 對象,Nil 對象,twigls 前綴符,:exists 定義幾個概念,以及 YAML 格式本身的處理邏輯.
YAML模塊修改對比如下:
diff --git a/lib/YAML/Dumper.pm b/lib/YAML/Dumper.pm 
index d7a7981..ec47341 100644 
--- a/lib/YAML/Dumper.pm 
+++ b/lib/YAML/Dumper.pm 
@@ -2,16 +2,16 @@ use v6; 
 class YAML::Dumper; 
 has $.out = []; 
-has $.seen is rw = {}; 
+has $.seen = {}; 
 has $.tags = {}; 
 has $.anchors = {}; 
 has $.level is rw = 0; 
-has $.id is rw = 1; 
+has $.id = 1; 
 has $.info = []; 
 method dump($object) { 
	 $.prewalk($object); 
-    $.seen = {}; 
+    $!seen = {}; 
	 $.dump_document($object); 
	 return $.out.join(''); 
 } 
@@ -45,11 +45,11 @@ method dump_collection($node, $kind, $function) { 
 method check_special($node) { 
	 my $first = 1; 
-    if $.anchors.exists($node.WHICH) { 
-    if $.anchors.exists($node.WHICH) { 
+    if $.anchors{$node.WHICH}:exists { 
		 push $.out, ' ', '&' ~ $.anchors{$node.WHICH}; 
		 $first = 0; 
	 } 
-    if $.tags.exists($node.WHICH) { 
+    if $.tags{$node.WHICH}:exists { 
		 push $.out, ' ', '!' ~ $.tags{$node.WHICH}; 
		 $first = 0; 
	 } 
@@ -64,7 +64,7 @@ method indent($first) { 
			 return; 
		 } 
		 if $.info[*-1] eq 'seq' && $.info[*-2] eq 'map' { 
-            $seq_in_map = 1; 
+            $seq_in_map = 0; 
		 } 
	 } 
	 push $.out, "n"; 
@@ -155,7 +155,8 @@ method dump_object($node, $type) { 
	 $.tags{$repr.WHICH} = $type; 
	 for $node.^attributes -> $a { 
		 my $name = $a.name.substr(2); 
-        my $value = pir::getattribute__PPs($node, $a.name);     #RAKUDO 
+        #my $value = pir::getattribute__PPs($node, $a.name);     #RAKUDO 
+        my $value = $a.get_value($node);                         #for non-parrot 
		 $repr{$name} = $value; 
	 } 
	 $.dump_node($repr);
登錄后復制
這里的 $.seen 和 $!seen 是不是暈掉了?其實 $.seen 就相當于先聲明了 $!seen 后再自動創(chuàng)建一個 method seen() { return $!seen }。
另一處是 pir::getattribute__PPs() 函數(shù),pir 是 parrot 上的語言,而 MoarVM 和 JVM 上都是先實現(xiàn)了一個 nqp 再用 nqp 寫 Perl6,不巧的是這個 pir 里的 getattribute__PPs() 剛好至今還沒有對應的 nqp 方法。(在 pir2nqp.todo 文件里可見)
所以只能用高級的 Perl6 語言來做了。
總的來說,這個 yaml-pm6 代碼里很多地方都是試來試去,同樣的效果不同的寫法,又比如 .WHICH 和 .WHAT.perl 也是混用。 而且我隨手測試了一下,即使在 parrot 上,用 pir::getattribute__PPs 的速度也比 Attribute.get_value 還差點點。
最后提一句,目前 ENC 腳本在 perl5、perl6-m、perl6-p、perl6-j 上的運行時間大概分別是 0.13、1.5、2.8、12s。MoarVM 還差 Perl5 十倍,領先 parrot 一倍。不過 JVM 本身啟動時間很長,這里不好因為一個短時間腳本說它太慢。
另外還試了一下如果把我修改過的 YAML::Dumper 類直接寫在腳本里運行,也就是不編譯成 moarvm 模塊,時間大概是 2.5s,比 parrot 模塊還快點點。
不過如何把 perl6 腳本本身編譯成 moarvm 的 bytecode 格式運行還沒有研究出來,直接 perl6-m --target=mbc --output=name.moarvm name.pl6 得到的文件運行 moar name.moarvm 的結果運行會內存報錯。
本文地址:
轉載隨意,但請附上文章地址:-)
總結
以上是生活随笔為你收集整理的Perl6 的 YAML::Dumper 模块使用详解的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: FreeMaker+Xml导出word(
- 下一篇: 带新风的空调怎么样
