Skip to content

Instantly share code, notes, and snippets.

@perlpunk
Last active February 7, 2018 20:16
Show Gist options
  • Save perlpunk/79891288fc07a6593f4c3ff35d9ba20d to your computer and use it in GitHub Desktop.
Save perlpunk/79891288fc07a6593f4c3ff35d9ba20d to your computer and use it in GitHub Desktop.
---
a:
b: &1
abcde: &2
- fghi
- jklm
- &3
nopq: rstu
c:
- *1
d: *2
e: *3
f:
test: 1
test2: 2
g:
test: 1
test2: 3
#!/usr/bin/env perl
# Usage: perl detect-same.pl filename
# WARNING: experimental and ugly!
use strict;
use warnings;
use 5.010;
use lib "lib";
use YAML::PP::Parser;
use YAML::PP::Emitter;
use YAML::PP::Writer;
use Data::Dumper;
my %seen;
my @events;
my @event_data;
my $writer = YAML::PP::Writer->new;
my $emitter = YAML::PP::Emitter->new();
$emitter->set_writer($writer);
my $parser = YAML::PP::Parser->new(
receiver => sub {
my ($self, @args) = @_;
my $str = YAML::PP::Parser->event_to_test_suite(\@args);
push @event_data, \@args;
push @events, $str;
},
);
my $yaml = do { open my $fh, $ARGV[0] or die $!; local $/; <$fh> };
$parser->parse($yaml);
my @emit;
my $anchor_index = 0;
my $i = -1;
while (my $event = shift @events) {
$i++;
my $original_event = $event_data[ $i ];
push @emit, $original_event;
if ($event !~ m/^[+]/ or $event =~ m/^\+STR/) {
next;
}
my $exists = $seen{ $event } ? ($event) : ();
my $list = $seen{ $event } ||= { index => {}, events => {} };
$list->{index}->{ $i }++;
my $duplicate_count = 0;
my $last_index;
my $ref = \$list->{events};
my $level = 1;
my $last_level = $level;
for my $e (@events) {
if ($e =~ m/^\+/) {
$level++;
}
elsif ($e =~ m/^-/) {
$level--;
}
if ($$ref->{ $e } and $exists) {
if ($level >= 0) {
my $test = $$ref->{ $e };
$last_index = (keys %{ $$ref->{ $e }->{index} })[0];
$last_level = $level;
$duplicate_count++;
}
}
else {
$exists = 0;
}
$$ref->{ $e } ||= { index => {}, events => {} };
$$ref->{ $e }->{index}->{ $i }++;
$ref = \$$ref->{ $e }->{events};
}
if ($duplicate_count > 1 and $last_level == 0) {
# We've found a duplicate, no need to analyze the following events
splice @events, 0, $duplicate_count, ();
$i += $duplicate_count;
my $same_event = $event_data[ $last_index ];
$same_event->[1]->{anchor} = ++$anchor_index;
# we remove this event and put an alias at its place
my $delete = pop @emit;
push @emit, [ alias_event => { value => $anchor_index } ];
}
}
$emitter->init;
for my $event (@emit) {
my ($type, $info) = @$event;
# my $str = YAML::PP::Parser->event_to_test_suite([$type, $info]);
$emitter->$type($info);
}
my $out = $emitter->writer->output;
say $out;
---
a:
b:
abcde:
- fghi
- jklm
- nopq: rstu
c:
- abcde:
- fghi
- jklm
- nopq: rstu
d:
- fghi
- jklm
- nopq: rstu
e:
nopq: rstu
f:
test: 1
test2: 2
g:
test: 1
test2: 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment