File Coverage

lib/Inline/CLIPS.pm
Criterion Covered Total %
statement 40 84 47.6
branch 6 30 20.0
condition 2 11 18.1
subroutine 13 16 81.2
pod 0 5 0.0
total 61 146 41.7


line stmt bran cond sub pod time code
1             package Inline::CLIPS;
2              
3 2     2   176737 use strict;
  2         4  
  2         69  
4 2     2   16 use warnings;
  2         3  
  2         152  
5              
6 2     2   11 use Carp qw(croak);
  2         3  
  2         101  
7 2     2   9 use File::Spec;
  2         5  
  2         59  
8 2     2   2363 use File::Temp qw(tempfile);
  2         40736  
  2         140  
9 2     2   838 use IPC::Open3 qw(open3);
  2         4720  
  2         103  
10 2     2   11 use Symbol qw(gensym);
  2         3  
  2         1374  
11              
12             our $VERSION = '0.001';
13              
14             sub new {
15 3     3 0 120998 my ($class, %args) = @_;
16             my $self = bless {
17             executable => $args{executable},
18             library => $args{library},
19 3         13 }, $class;
20 3         8 return $self;
21             }
22              
23             sub executable {
24 1     1 0 2 my ($self) = @_;
25 1 50       3 return $self->{executable} if defined $self->{executable};
26              
27             $self->{executable} = $ENV{INLINE_CLIPS_EXECUTABLE}
28 1   0     4 || _path_executable('clips')
29             || _alien_executable()
30             || q{};
31              
32 1         4 return $self->{executable};
33             }
34              
35             sub library {
36 1     1 0 523 my ($self) = @_;
37 1 50       6 return $self->{library} if defined $self->{library};
38              
39             $self->{library} = $ENV{INLINE_CLIPS_LIB}
40 1   50     5 || _alien_library()
41             || q{};
42              
43 1         7 return $self->{library};
44             }
45              
46             sub run_program {
47 0     0 0 0 my ($self, $program, @commands) = @_;
48 0 0       0 croak 'program text is required' if !defined $program;
49              
50 0         0 my ($fh, $tmp) = tempfile('inline-clips-XXXX', SUFFIX => '.clp', UNLINK => 1);
51 0         0 print {$fh} "(clear)\n";
  0         0  
52 0         0 print {$fh} $program;
  0         0  
53 0 0       0 print {$fh} "\n" if $program !~ /\n\z/;
  0         0  
54 0         0 print {$fh} "(reset)\n";
  0         0  
55 0         0 print {$fh} "$_\n" for @commands;
  0         0  
56 0         0 print {$fh} "(exit)\n";
  0         0  
57 0         0 close $fh;
58              
59 0         0 return $self->run_file($tmp);
60             }
61              
62             sub run_file {
63 1     1 0 3 my ($self, $file) = @_;
64 1 50 33     5 croak 'file path is required' if !defined $file || $file eq q{};
65 1 50       239 croak "CLIPS file not found: $file" if !-f $file;
66              
67 0         0 my $exe = $self->executable;
68 0 0       0 croak 'CLIPS executable is not available; set INLINE_CLIPS_EXECUTABLE or install CLIPS/Alien::CLIPS'
69             if !$exe;
70              
71 0         0 my $err = gensym;
72 0         0 my $pid = open3(my $in, my $out, $err, $exe, '-f2', $file);
73 0         0 close $in;
74              
75 0         0 local $/ = undef;
76 0   0     0 my $stdout = <$out> // q{};
77 0   0     0 my $stderr = <$err> // q{};
78 0         0 waitpid($pid, 0);
79 0         0 my $status = $? >> 8;
80              
81             return {
82 0         0 status => $status,
83             stdout => $stdout,
84             stderr => $stderr,
85             };
86             }
87              
88             sub _path_executable {
89 0     0   0 my ($name) = @_;
90 0         0 for my $dir (File::Spec->path) {
91 0         0 my $candidate = File::Spec->catfile($dir, $name);
92 0 0       0 return $candidate if -x $candidate;
93             }
94 0         0 return;
95             }
96              
97             sub _alien_executable {
98 0 0   0   0 my $alien = _load_alien() or return;
99 0 0       0 my @bins = $alien->can('bin_dir') ? $alien->bin_dir : ();
100 0         0 for my $dir (@bins) {
101 0         0 my $candidate = File::Spec->catfile($dir, 'clips');
102 0 0       0 return $candidate if -x $candidate;
103             }
104 0         0 return;
105             }
106              
107             sub _alien_library {
108 1 50   1   3 my $alien = _load_alien() or return;
109 0 0       0 my @libs = $alien->can('dynamic_libs') ? $alien->dynamic_libs : ();
110 0 0       0 return $libs[0] if @libs;
111 0         0 return;
112             }
113              
114             sub _load_alien {
115 1     1   1 my $ok = eval {
116 1         402 require Alien::CLIPS;
117 1         10 Alien::CLIPS->import();
118 0         0 1;
119             };
120 1 50       661 return if !$ok;
121 0           return 'Alien::CLIPS';
122             }
123              
124             1;
125              
126             __END__