File Coverage

blib/lib/DBGp/Client/Parser.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package DBGp::Client::Parser;
2              
3 22     22   8079 use strict;
  22         27  
  22         538  
4 22     22   68 use warnings;
  22         25  
  22         505  
5              
6 22     22   7131 use XML::Parser;
  0            
  0            
7             use XML::Parser::EasyTree;
8              
9             use DBGp::Client::Response::Init;
10             use DBGp::Client::Response::Error;
11             use DBGp::Client::Response::InternalError;
12             use DBGp::Client::Response::Notification;
13             use DBGp::Client::Response::Stream;
14              
15             my $parser = XML::Parser->new(Style => 'XML::Parser::EasyTree');
16              
17             my %response_map;
18             BEGIN {
19             %response_map = (
20             'status' => 'DBGp::Client::Response::Step',
21             'step_into' => 'DBGp::Client::Response::Step',
22             'step_over' => 'DBGp::Client::Response::Step',
23             'run' => 'DBGp::Client::Response::Step',
24             'step_out' => 'DBGp::Client::Response::Step',
25             'detach' => 'DBGp::Client::Response::Step',
26             'stop' => 'DBGp::Client::Response::Step',
27             'stack_depth' => 'DBGp::Client::Response::StackDepth',
28             'stack_get' => 'DBGp::Client::Response::StackGet',
29             'eval' => 'DBGp::Client::Response::Eval',
30             'expr' => 'DBGp::Client::Response::Eval',
31             'exec' => 'DBGp::Client::Response::Eval',
32             'typemap_get' => 'DBGp::Client::Response::Typemap',
33             'context_names' => 'DBGp::Client::Response::ContextNames',
34             'context_get' => 'DBGp::Client::Response::ContextGet',
35             'breakpoint_get' => 'DBGp::Client::Response::BreakpointGetUpdateRemove',
36             'breakpoint_set' => 'DBGp::Client::Response::BreakpointSet',
37             'breakpoint_update' => 'DBGp::Client::Response::BreakpointGetUpdateRemove',
38             'breakpoint_remove' => 'DBGp::Client::Response::BreakpointGetUpdateRemove',
39             'breakpoint_list' => 'DBGp::Client::Response::BreakpointList',
40             'feature_set' => 'DBGp::Client::Response::FeatureSet',
41             'feature_get' => 'DBGp::Client::Response::FeatureGet',
42             'property_get' => 'DBGp::Client::Response::PropertyGet',
43             'property_value' => 'DBGp::Client::Response::PropertyValue',
44             'property_set' => 'DBGp::Client::Response::PropertySet',
45             'source' => 'DBGp::Client::Response::Source',
46             'stdout' => 'DBGp::Client::Response::Redirect',
47             'stderr' => 'DBGp::Client::Response::Redirect',
48             'stdin' => 'DBGp::Client::Response::Redirect',
49             'break' => 'DBGp::Client::Response::Break',
50             'interact' => 'DBGp::Client::Response::Interact',
51             );
52              
53             my $load = join "\n", map "require $_;", values %response_map;
54             eval $load or do {
55             die "$@";
56             };
57             }
58              
59             sub _nodes {
60             my ($nodes, $node) = @_;
61              
62             return grep $_->{type} eq 'e' && $_->{name} eq $node, @{$nodes->{content}};
63             }
64              
65             sub _node {
66             my ($nodes, $node) = @_;
67              
68             return (_nodes($nodes, $node))[0];
69             }
70              
71             sub _text {
72             my ($nodes) = @_;
73             my $text = '';
74              
75             for my $node (@{$nodes->{content}}) {
76             $text .= $node->{content}
77             if $node->{type} eq 't';
78             }
79              
80             return $text;
81             }
82              
83             sub parse {
84             return undef unless defined $_[0];
85              
86             my $tree = $parser->parse($_[0]);
87             require Data::Dumper, die "Unexpected return value from parse(): ", Data::Dumper::Dumper($tree)
88             if !ref $tree || ref $tree ne 'ARRAY';
89             die "Unexpected XML"
90             if @$tree != 1 || $tree->[0]{type} ne 'e';
91              
92             my $root = $tree->[0];
93             if ($root->{name} eq 'init') {
94             return bless $root->{attrib}, 'DBGp::Client::Response::Init';
95             } elsif ($root->{name} eq 'response') {
96             if (ref $root->{content} && (my $error = _node($root, 'error'))) {
97             return bless [$root->{attrib}, $error], 'DBGp::Client::Response::Error';
98             }
99              
100             my $cmd = $root->{attrib}{command};
101             if (my $package = $response_map{$cmd}) {
102             return bless $root, $package;
103             } else {
104             require Data::Dumper;
105              
106             die "Unknown command '$cmd' " . Data::Dumper::Dumper($root);
107             }
108             } elsif ($root->{name} eq 'stream') {
109             return bless $root, 'DBGp::Client::Response::Stream';
110             } elsif ($root->{name} eq 'notify') {
111             return bless $root, 'DBGp::Client::Response::Notification';
112             } else {
113             require Data::Dumper;
114              
115             die "Unknown response '$root' " . Data::Dumper::Dumper($root);
116             }
117             }
118              
119             1;