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.
>

Reply via email to