File Coverage

blib/lib/Text/Hunspell/FFI.pm
Criterion Covered Total %
statement 30 30 100.0
branch 4 6 66.6
condition n/a
subroutine 9 9 100.0
pod n/a
total 43 45 95.5


line stmt bran cond sub pod time code
1             package Text::Hunspell::FFI;
2              
3 10     10   1095650 use strict;
  10         104  
  10         321  
4 10     10   58 use warnings;
  10         18  
  10         266  
5 10     10   265 use 5.020;
  10         35  
6 10     10   7078 use FFI::Platypus 1.00;
  10         85620  
  10         367  
7 10     10   5119 use FFI::CheckLib 0.27 ();
  10         27257  
  10         384  
8 10     10   5348 use experimental qw( postderef );
  10         34070  
  10         59  
9              
10             # ABSTRACT: Perl FFI interface to the Hunspell library
11             our $VERSION = '0.03'; # VERSION
12              
13             sub _lib
14             {
15 6677     6677   1213909 my @args = (lib => '*', verify => sub { $_[0] =~ /hunspell/ }, symbol => "Hunspell_create");
  11     11   85  
16 11         62 my @libs = FFI::CheckLib::find_lib @args;
17 11 50       6822 my($first) = @libs
18             ? @libs
19             : FFI::CheckLib::find_lib @args, alien => 'Alien::Hunspell';
20 11 50       356 die "unable to find libs" unless $first;
21 11         214 $first;
22             }
23              
24             my $ffi = FFI::Platypus->new(
25             api => 1,
26             lib => _lib(),
27             );
28              
29             $ffi->attach(['Hunspell_create'=>'new'] => ['string','string'] => 'opaque', sub
30             {
31             my($xsub, $class, $aff, $dic) = @_;
32             my $ptr = $xsub->($aff, $dic);
33             bless \$ptr, $class;
34             });
35              
36              
37             $ffi->attach(['Hunspell_destroy'=>'DESTROY'] => ['opaque'] => 'void', sub
38             {
39             my($xsub, $self) = @_;
40             $xsub->($$self);
41             });
42              
43             foreach my $try (qw( Hunspell_add_dic _ZN8Hunspell7add_dicEPKcS1_ ))
44             {
45             eval {
46             $ffi->attach([$try=>'add_dic'] => ['opaque','string'] => 'void', sub
47             {
48             my($xsub, $self, $dpath) = @_;
49             $xsub->($$self, $dpath);
50             });
51             };
52             last unless $@;
53             }
54              
55             unless(__PACKAGE__->can('add_dic'))
56             {
57             # TODO: fallback on Perl implementation ?
58             die "unable to find add_dic";
59             }
60              
61             $ffi->attach(['Hunspell_spell'=>'check'] => ['opaque','string'] => 'int', sub
62             {
63             my($xsub, $self, $word) = @_;
64             $xsub->($$self, $word);
65             });
66              
67             $ffi->attach(['Hunspell_free_list',=>'_free_list'] => ['opaque','opaque*','int'] => 'void');
68              
69             sub _string_array_and_word
70             {
71 2     2   680 my($xsub, $self, $word) = @_;
72 2         5 my $ptr;
73 2         284 my $count = $xsub->($$self, \$ptr, $word);
74 2         28 my @result = map { $ffi->cast('opaque','string',$_) } $ffi->cast('opaque',"opaque[$count]", $ptr)->@*;
  4         683  
75 2         226 _free_list($self, $ptr, $count);
76 2 100       17 wantarray ? @result : $result[0]; ## no critic (Freenode::Wantarray)
77             }
78              
79             $ffi->attach(['Hunspell_suggest'=>'suggest'] => ['opaque','opaque*','string'] => 'int', \&_string_array_and_word);
80             $ffi->attach(['Hunspell_analyze'=>'analyze'] => ['opaque','opaque*','string'] => 'int', \&_string_array_and_word);
81              
82             $ffi->attach(['Hunspell_generate'=>'generate'] => ['opaque','opaque*','string','string'] => 'int', sub {
83             my($xsub, $self, $word, $word2) = @_;
84             my $ptr;
85             my $count = $xsub->($$self, \$ptr, $word, $word2);
86             my @result = map { $ffi->cast('opaque','string',$_) } $ffi->cast('opaque',"opaque[$count]", $ptr)->@*;
87             _free_list($self, $ptr, $count);
88             wantarray ? @result : $result[0]; ## no critic (Freenode::Wantarray)
89             });
90              
91             $ffi->attach(['Hunspell_generate2'=>'generate2'] => ['opaque','opaque*','string','string[]','int'] => 'int', sub
92             {
93             my($xsub, $self, $word, $suggestions) = @_;
94             my $n = scalar @$suggestions;
95             my $ptr;
96             my $count = $xsub->($$self, \$ptr, $word, [@$suggestions], 1);
97             my @result = map { $ffi->cast('opaque','string',$_) } $ffi->cast('opaque',"opaque[$count]", $ptr)->@*;
98             _free_list($self, $ptr, $count);
99             wantarray ? @result : $result[0]; ## no critic (Freenode::Wantarray)
100             });
101              
102             1;
103              
104             __END__