Transform rules match a whole node and replace it, so you need to match the
whole hash, not just one key.
rule( properties: subtree(:props), moves: subtree(:moves) )
If you converted the {:name=>"GM", :values=>[{:value=>"1"}]} type things
into objects (using OpenStruct say) then you don't need to use subtree, you
can use sequence.
---
"No man is an island... except Philip"
On Mon, May 13, 2013 at 3:14 AM, Alexey Skoblikov <[email protected]> wrote:
> Hello all.
>
> Actually it is a copy of the question at
> http://stackoverflow.com/questions/16509369/parslet-subtree-doesnt-fire
>
> I am making an SGF files parser with Parslet.
>
> Now I am at the stage to make a Transformer.
>
> From the Parser I already get the structs like that:
>
> [{:properties=>
> [{:name=>"GM"@2, :values=>[{:value=>"1"@5}]},
> {:name=>"FF"@7, :values=>[{:value=>"4"@10}]},
> {:name=>"SZ"@12, :values=>[{:value=>"19"@15}]},
> {:name=>"AP"@18, :values=>[{:value=>"SmartGo Kifu:2.2"@21}]},
> {:name=>"GN"@40, :values=>[{:value=>"2013-05-11g"@43}]},
> {:name=>"PW"@57, :values=>[{:value=>"Dahan"@60}]},
> {:name=>"PB"@68, :values=>[{:value =>"SmartGo"@71}]},
> {:name=>"DT"@81, :values=>[{:value=>"2013-05-11"@84}]},
> {:name=>"KM"@97, :values=>[{:value=>"6.5"@100}]},
> {:name=>"RE"@106, :values=>[{:value=>"W+R"@109}]},
> {:name=>"RU"@115, :values=>[{:value=>"AGA (Area)"@118}]},
> {:name=>"ID"@129, :values=>[{:value=>"ch0"@132}]}],
> :moves=>
> [{:player=>"B"@137, :place=>"oq"@139},
> {:player=>"W"@143, :place=>"dd"@145},
> {:player=>"B"@149, :place=>"oo"@151},
> ...etc...
> The ruleset I am using to Transform:
>
> # Rewrite player: COLOR, place: X to COLOR: X
> rule( player: simple(:p), place: simple(:pl)) do
> if p == 'W'
> &nbs p; { white: pl }
> elsif p == 'B'
> { black: pl }
> end
> end
> # Un-nest single-value hash
> rule( value: simple(:v)) { v }
> # Rewrite name: KEY, values: SINGLE_VALUE to KEY: SINGLE_VALUE
> rule( name: simple(:n), values: [ simple(:v) ]) { {n.to_sym => v} }
> # A Problem!!!
> rule( properties: subtree(:props) ) do
> out = {}
> props.each {|pair| pair.each {|k, v| out[k] = v}}
> { properties: out }
> end
> With such rules I get the following struct:
>
> [{:properties=>
> [{:GM=>"1"@5},
> &n bsp; {:FF=>"4"@10},
> {:SZ=>"19"@15},
> {:AP=>"SmartGo Kifu:2.2"@21},
> {:GN=>"2013-05-11g"@43},
> {:PW=>"Dahan"@60},
> {:PB=>"SmartGo"@71},
> {:DT=>"2013-05-11"@84},
> {:KM=>"6.5"@100},
> {:RE=>"W+R"@109},
> {:RU=>"AGA (Area)"@118},
> {:ID=>"ch0"@132}],
> :moves=>
> [{:black=>"oq"@139},
> {:white=>"dd"@145},
> {:black=>"oo"@151},
> ...etc...
> Everything is perfect. The only Problem of mine is that :properties Array
> of Hashes.
>
> In the end I want to have
>
> [{:properties=>
> {:GM=>"1"@5,
> :FF=>"4"@10,
> :SZ=>"19"@15,
> :AP=>"SmartGo Kifu:2.2"@21,
> :GN=>"2013-05-11g"@43,
> :PW=>"Dahan"@60,
> :PB=>"SmartGo"@71,
> :DT=>"2013-05-11"@84,
> :KM=>"6.5"@100,
> :RE=>"W+R"@109,
> :RU=>"AGA (Area)"@118,
> :ID=>"ch0"@132},
> :moves=>
> [{:black=>"oq"@139},
> {:white=>"dd"@145},
> {:black=>"oo"@151},
> ...etc...
> You see? Merge all arrayed hashes inside :properties, because after the
> previous transformations they now have unique keys. Also flatten the struct
> a bit.
>
> Hey! I can do it manually. I mean to run a separate method like
>
> merged_stuff = {}
> tree.first[:properties].each { |pair| pair.each {|k, v| merged_stuff[k] =
> v}}
> tree.first[:properties] = merged_stuff
> But Why I Cannot Do That With The Neat Transform Rules, To Have All
> Transformation Logic In One Place?
>
> The point is that rule( properties: subtree(:props) ) does not get fired
> at all. Even if I just return nil from the block, it doesn't change
> anything. So, seems, that this subtree doesn't catch the things, or I don't.
>