Поддерево Parslet не стреляет
Возобновить (я сократил следующую длинную историю до простой проблемы)
tree = {:properties => [{:a => 'b'}, {:c => 'd'}]}
big_tree = {:properties => [{:a => 'b'}, {:c => 'd'}], :moves => [{:a => 'b'}, {:c => 'd'}]}
trans = Parslet::Transform.new do
rule(:properties => subtree(:nested)) do
out = {}
nested.each {|pair| out = out.merge pair}
{:properties => out}
end
end
pp tree
pp trans.apply(tree)
pp big_tree
pp trans.apply(big_tree)
# OUTPUT
{:properties=>[{:a=>"b"}, {:c=>"d"}]}
{:properties=>{:a=>"b", :c=>"d"}} # Worked with small tree
{:properties=>[{:a=>"b"}, {:c=>"d"}], :moves=>[{:a=>"b"}, {:c=>"d"}]}
{:properties=>[{:a=>"b"}, {:c=>"d"}], :moves=>[{:a=>"b"}, {:c=>"d"}]} # Didn't work with bigger tree
========================= ПОЛНАЯ ИСТОРИЯ (Не так актуально после заголовка)
Я делаю парсер файлов SGF с помощью Parslet.
Сейчас я на стадии, чтобы сделать Трансформер.
От парсера я уже получаю такие структуры:
[{: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...
Набор правил, который я использую для преобразования:
# Rewrite player: COLOR, place: X to COLOR: X
rule( player: simple(:p), place: simple(:pl)) do
if p == 'W'
{ 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
С такими правилами я получаю следующую структуру:
[{: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...
Все отлично. Единственная моя проблема заключается в том, что: свойства Array of Hashes.
В конце концов я хочу иметь
[{: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...
Ты видишь? Объедините все массивные хэши внутри: properties, потому что после предыдущих преобразований у них теперь есть уникальные ключи. Также немного сгладьте структуру.
Привет! Я могу сделать это вручную. Я имею в виду запустить отдельный метод, как
merged_stuff = {}
tree.first[:properties].each {|pair| pair.each {|k, v| merged_stuff[k] = v}}
tree.first[:properties] = merged_stuff
Но почему я не могу сделать это с аккуратными правилами преобразования, чтобы все логики преобразования были в одном месте?
Дело в том, что rule( properties: subtree(:props) )
не уволен вообще. Даже если я просто верну ноль из блока, это ничего не изменит. Так, кажется, что это subtree
не ловит вещи, или я не ловлю.
2 ответа
Проблема в том, что :properties
а также :moves
ключи в том же хеше, и subtree
очевидно, не хочет совпадать с частью хэша. Если вы удалите :moves
, правило будет выполнено. Это как-то объясняется в документации:
Слово о моделях
Учитывая хеш PORO
{ :dog => 'terrier', :cat => 'suit' }
можно предположить, что следующее правило соответствует
:dog
и заменяет его на'foo'
:rule(:dog => 'terrier') { 'foo' }
Это, честно говоря, невозможно. Как бы
'foo'
жить кроме:cat => 'suit'
внутри хеша? Это не может. Вот почему хэши либо полностью совпадают, либо вообще не совпадают.
хотя я должен признать, что это не очень четкий пример.
Таким образом, правило проблемы должно выглядеть так:
rule( properties: subtree(:props), moves: subtree(:m) ) do
out = {}
props.each {|pair| pair.each {|k, v| out[k] = v}}
{ properties: out , moves: m}
end
Правила преобразования соответствуют целому узлу и заменяют его, поэтому вам нужно сопоставить весь хэш, а не только один ключ.
rule( properties: subtree(:props), moves: subtree(:moves) )
Если вы преобразовали {:name=>"GM", :values=>[{:value=>"1"}]}
вводить вещи в объекты (скажем, используя OpenStruct), тогда вам не нужно использовать subtree
, ты можешь использовать sequence
,