トピックは人間の怠inessを引き起こしました:)
繰り返し、複数の構成に現れるパラメーター(例えば、インターフェースのIPアドレス)を変更する必要がある場合に対処する必要がありました。 また、推測するのが論理的であるため、どのようなファイルが「すぐに」思い出すことは困難であることが判明しました。
このアイデアは新しいものではなく、テンプレートの使用に基づいています。 言語はルビーです。
初期構成ファイルのタイプとして
XMLを選択することにしましたが、これは非常に適しています。
YAMLなどに目を向けることができます。
<xml>
<構成名= 'rc.conf'>
<インターフェース>
<iface name = 're0' tag = 'internal'>
<ip> 172.16.0.1 </ ip>
<netmask> 255.255.255.240 </ netmask>
<media> 1000baseTX </ media>
<mediaopt>全二重</ mediaopt>
<opts>ポーリング</ opts>
</ iface>
<iface name = 're1' tag = 'external'>
<ip> 172.16.0.17 </ ip>
<netmask> 255.255.255.228 </ netmask>
</ iface>
<iface name = 'fxp0'>
<dhcp> true </ dhcp>
<opts>ポーリング</ opts>
</ iface>
<エイリアスiface = 're0' num = '0'>
<ip> 10.0.0.1 </ ip>
<netmask> 255.255.255.0 </ netmask>
</エイリアス>
<クローン>
vlan101
vlan110
vlan111
</ cloned>
</ interfaces>
</ config>
</ xml>
LibXMLを使用してより速く解析し、それを選択しました。 類似として、
REXML、またはXMLファイルからハッシュを作成する
XmlSimpleの既製の代替手段を
検討できますが、より遅くなります。この点については以下で説明します。
テンプレートでの作業には、
erubisを選択し
ました 。
テストによると
、 ERBや
erubyよりも速いよう
です 。
実際にはコード自体:
「rubygems」が必要
「エルビス」が必要
「xml」が必要
def xml2hash(xml = nil)
xml.nilの場合、「missed 'xml' param」を発生しますか?
v = []; h = {}
ループする
xml.read
break if(xml.node_type == XML :: Reader :: TYPE_END_ELEMENT || xml.empty_element?)
if(xml.node_type == XML :: Reader :: TYPE_ELEMENT)
名前= xml.name
h [名前] || = []
attrib = {}
if(xml.attribute_count> 0)then
カウント= xml.attribute_count
while(count> 0)do
カウント-= 1
xml.move_to_attribute(カウント)
attrib.merge!({xml.name => xml.value})
終わり
終わり
r = xml2hash(xml)
ケースr
ハッシュするとき
r.merge!(attrib)attrib.emptyでない限り?
h [名前] .push(r)
とき配列
h [name] .push(attrib)attrib.emptyでない限り?
h [名前] .push(* r)
他に
h [name] .push(attrib)attrib.emptyでない限り?
h [名前] .push(r)
r.nilでない限り終了しますか?
elsif(xml.node_type == XML :: Reader :: TYPE_TEXT &&!xml.value.nil?)
xml.value.split( "\ n")。各{| i | i.gsub!(/ ^ \ s *?(\ S +)\ s * $ /、 '\ 1'); v.push(i)except(i.empty?|| i =〜/ ^ \ s * $ /); }
終わり
終わり
r = []
r.push(h)(h.nil?|| h.empty?)でない限り
r.push(* v)(v.nil?|| v.empty?)以外
リターン* r
レスキュー=> e
puts "#{e.class}:#{e}(method:xml2hash)"
終わり
始める
xml = XML :: Reader.file( 'params.xml')
r = xml2hash(xml)
xml.close
r ['xml']。最初の['config']。各do | i |
テンプレート= File.read(i ['name'] + ".eruby")
eruby = Erubis :: Eruby.new(テンプレート)
File.open(i ['name']、 "w"){| file | file.puts eruby.evaluate({:list => i})}
終わり
レスキュー=> e
puts "#{e.class}:#{e}(method:main)"
終わり
コードの詳細は説明しません。xml2hashメソッドの再帰呼び出しが使用されているとだけ言います。ブロックの始まりであれば、さらに深く、ブロックの終わりまたは空の要素/ブロックであれば、上に戻ります。
テンプレートファイルはxml + '.eruby'のconfig_nameです。 私の場合、rc.conf.eruby。
出力はconfig_name(rc.conf)にあります。
テンプレートコンテンツ:
<% for item in @list['interfaces'].first['iface'] %>
ifconfig_<%= item['name'] %>="<% unless item['dhcp'] %>inet <%= item['ip'].first %> netmask <%= item['netmask'].first %><% else %>DHCP<% end %><% unless (item['media'].nil? || item['media'].empty?) %> media <%= item['media'].first %><% end %><% unless (item['mediaopt'].nil? || item['mediaopt'].empty?) %> mediaopt <%= item['mediaopt'].first %><% end %><% unless (item['opts'].nil? || item['opts'].empty?) %> <%= item['opts'].first %><% end %>"
<% end %>
<% for item in @list['interfaces'].first['alias'] %>
ifconfig_<%= item['iface'] %>_alias<%= item['num'] %>="inet <%= item['ip'].first %> netmask <%= item['netmask'].first %>"
<% end %>
<% if @list['interfaces'].first.key?('cloned') && !@list['interfaces'].first['cloned'].empty? %>cloned_interfaces="<%= @list['interfaces'].first['cloned'].join(' ') %>"<% end %>
はい、それはやや読めないように見えますが、これは一見しただけです:)
約束どおり、「上記のコード」とXmlSimpleのテストに移りましょう。
xml_test.rb:
「rubygems」が必要
「xml」が必要
「ベンチマーク」が必要
def xml2hash(xml = nil)
#メソッド定義上記参照
終わり
始める
xml = ''
Benchmark.bm do | x |
x.report {100.times do
xml_read = XML :: Reader.file( 'params.xml')
xml = xml2hash(xml_read)
xml_read.close
終了}
終わり
p xml
レスキュー=> e
puts "#{e.class}:#{e}(method:main)"
終わり
ezhik @ pollux:〜$ time ruby xml_test.rb
ユーザーシステムの総実数
0.210000 0.010000 0.220000(0.253391)
{"xml" => [{"config" => [{"name" => "rc.conf"、 "interfaces" => [{"alias" => [{"netmask" => ["255.255.255.0 "]、" num "=>" 0 "、" ip "=> [" 10.0.0.1 "]、" iface "=>" re0 "}]、" iface "=> [{" name "=>" re0 "、" netmask "=> [" 255.255.255.240 "]、" opts "=> [" polling "]、" tag "=>" internal "、" mediaopt "=> ["全二重 "]、"メディア"=> [" 1000baseTX "]、" ip "=> [" 172.16.0.1 "]}、{" name "=>" re1 "、" netmask "=> [" 255.255.255.228 "]、" tag "= > "external"、 "ip" => ["172.16.0.17"]}、{"name" => "fxp0"、 "opts" => ["polling"]、 "dhcp" => ["true"] }]、 "クローン" => ["vlan101"、 "vlan110"、 "vlan111"]}]}}}}]}}
実数0m0.447s
ユーザー0m0.344s
sys 0m0.036s
xml_simple.rb:
「rubygems」が必要
「xmlsimple」が必要
「ベンチマーク」が必要
xml = ''
Benchmark.bm do | x |
x.report {100.times do
xml = XmlSimple.xml_in( 'params.xml')
終了}
終わり
p xml
ezhik @ pollux:〜$ time ruby xml_simple.rb
ユーザーシステムの総実数
1.770000 0.100000 1.870000(1.956282)
{"config" => [{"name" => "rc.conf"、 "interfaces" => [{"alias" => [{"netmask" => ["255.255.255.0"]、 "num" = > "0"、 "ip" => ["10.0.0.1"]、 "iface" => "re0"}]、 "iface" => [{"netmask" => ["255.255.255.240"]、 " name "=>" re0 "、" opts "=> [" polling "]、" tag "=>" internal "、" mediaopt "=> ["全二重 "]、"メディア "=> [" 1000baseTX " ]、 "ip" => ["172.16.0.1"]}、{"netmask" => ["255.255.255.228"]、 "name" => "re1"、 "tag" => "external"、 "ip "=> [" 172.16.0.17 "]}、{" name "=>" fxp0 "、" opts "=> [" polling "]、" dhcp "=> [" true "]}]、" clone "= > ["\ n vlan101 \ n vlan110 \ n vlan111 \ n"]}]}]}}
実際の0m2.279s
ユーザー0m2.012s
sys 0m0.124s
はい、それはまさにxmlを解析した後のハッシュの外観です。
時間差はありますが、このタスクにはそれほど重要ではないと思うので、選択はあなた次第です。
その結果、私は得た:
ifconfig_re0 = "inet 172.16.0.1ネットマスク255.255.255.240メディア1000baseTX mediaopt全二重ポーリング"
ifconfig_re1 = "inet 172.16.0.17 netmask 255.255.255.228"
ifconfig_fxp0 = "DHCPポーリング"
ifconfig_re0_alias0 = "inet 10.0.0.1 netmask 255.255.255.0"
clone_interfaces = "vlan101 vlan110 vlan111"
終わり。