File Coverage

blib/lib/Math/SymbolicX/Calculator/Interface/Web.pm
Criterion Covered Total %
statement 24 77 31.1
branch 0 32 0.0
condition 2 8 25.0
subroutine 7 14 50.0
pod 5 5 100.0
total 38 136 27.9


line stmt bran cond sub pod time code
1             package Math::SymbolicX::Calculator::Interface::Web;
2 1     1   25926 use 5.006;
  1         4  
  1         192  
3 1     1   7 use strict;
  1         2  
  1         47  
4 1     1   5 use warnings;
  1         1  
  1         53  
5              
6             our $VERSION = '0.01';
7              
8 1     1   949 use Params::Util qw/_INSTANCE/;
  1         7611  
  1         82  
9 1     1   1014 use Math::SymbolicX::Calculator;
  1         225351  
  1         41  
10 1     1   9 use base 'Math::SymbolicX::Calculator::Interface';
  1         3  
  1         1126  
11              
12             # For convenience, we extend the Math::Symbolic parser.
13             # This will become the shortcut derive() => partial derivative.
14             $Math::Symbolic::Operator::Op_Symbols{derive} = Math::Symbolic::ExportConstants::U_P_DERIVATIVE;
15             $Math::Symbolic::Parser = Math::Symbolic::Parser->new();
16             $Math::Symbolic::Parser->Extend(<<'GRAMMAR');
17             function_name: 'derive'
18             GRAMMAR
19              
20             # Matches identifiers
21             my $Ident = $Math::SymbolicX::Calculator::Identifier_Regex;
22              
23             =head1 NAME
24              
25             Math::SymbolicX::Calculator::Interface::Web - An AJAXy web interface to the calculator
26              
27             =head1 SYNOPSIS
28              
29             # simplest form of usage:
30             use Math::SymbolicX::Calculator::Interface::Web;
31             my $interface = Math::SymbolicX::Calculator::Interface::Web->new();
32             # But you probably want to use
33             # Math::SymbolicX::Calculator::Interface::Web::Server instead!
34              
35             =head1 DESCRIPTION
36              
37             This module implements an AJAX-enabled web interface to the
38             Math::SymbolicX::Calculator.
39              
40             B
41              
42             You probably want to look at the C
43             script or the L
44             module which come with this distribution instead!
45              
46             =head1 METHODS
47              
48             =cut
49              
50              
51             # defined or
52             sub _dor {
53 0     0   0 foreach (@_) {
54 0 0       0 return $_ if defined $_;
55             }
56 0         0 return(undef);
57             }
58              
59              
60             =head2 new
61              
62             Returns a new web interface object.
63              
64             Optional parameters: (default in parenthesis)
65              
66             calc => a Math::SymbolicX::Calculator object to use
67              
68             =cut
69              
70             sub new {
71 1     1 1 3 my $proto = shift;
72 1   33     11 my $class = ref($proto)||$proto;
73              
74 1         4 my %args = @_;
75              
76 1   33     15 my $self = {
77             calc => $args{calculator}
78             || Math::SymbolicX::Calculator->new(),
79             };
80 1         65 bless $self => $class;
81              
82 1         4 return $self;
83             }
84              
85             =head2 execute_expression
86              
87             Runs a single expression.
88              
89             =cut
90              
91             sub execute_expression {
92 0     0 1   my $self = shift;
93              
94 0           my $expr = shift;
95 0           my $out;
96            
97             my $cmd;
98             # What type of command?
99 0 0         if ($expr =~ /=~~?/) {
    0          
100 0           $cmd = $self->_parse_transformation($expr);
101             }
102             elsif ($expr =~ /=/) {
103 0           $cmd = $self->_parse_assignment($expr);
104             }
105             else {
106 0           $cmd = $self->_parse_command($expr);
107             }
108            
109 0 0         if (not defined $cmd) {
    0          
    0          
110 0           return("ERROR: Invalid expression. Neither assignment, replacement, nor command.");
111             }
112             elsif (_INSTANCE($cmd, 'Math::SymbolicX::Calculator::Command')) {
113 0           my @output = $self->calc->execute($cmd);
114 0           $out .= $self->_generic_out(@output);
115             }
116             elsif (ref($cmd) eq 'ARRAY') {
117 0 0         if ($cmd->[0] eq 'print') {
118 0           $out .= $self->_generic_out(@{$cmd}[1..$#$cmd]);
  0            
119             }
120             }
121             else {
122            
123             }
124              
125              
126 0           return($out);
127             }
128              
129             =head2 calc
130              
131             Returns the Calculator object of this Web Interface.
132              
133             =cut
134              
135             sub calc {
136 0     0 1   my $self = shift;
137 0           return $self->{calc};
138             }
139              
140             =head2 exit_hook
141              
142             Call this before stopping the web interface. It runs all cleanup actions
143             such as those needed for a possible persistance.
144              
145             This method doesn't actually kill your script, but returns after
146             doing the cleanup.
147              
148             =cut
149              
150             sub exit_hook {
151 0     0 1   my $self = shift;
152 0           return();
153             }
154              
155              
156             =head2 error
157              
158             Used to issue a warning to the user. First argument must be an error
159             message to display. This is currently ignored for the web
160             interface. Investigating methods to pass this to the client in
161             a reliable fashion.
162              
163             =cut
164              
165             sub error {
166 0     0 1   my $self = shift;
167 0           my $message = shift;
168             # print "!!! $message\n";
169             }
170              
171             =head2 _parse_command
172              
173             Parses generic commands such as exit and print.
174              
175             This might change. (Name and implementation)
176              
177             First argument: Expression to parse.
178              
179             =cut
180              
181             sub _parse_command {
182 0     0     my $self = shift;
183 0           my $expr = shift;
184              
185 0 0         if ($expr =~ /^\s*exit\s*$/i) {
    0          
    0          
    0          
    0          
186 0           return 'exit';
187             }
188             elsif ($expr =~ /^\s*print\s+($Ident)\s*$/) {
189 0           my $id = $1;
190             return [
191 0           'print', $id, "==", _dor($self->calc->stash($id), '/Undefined/')
192             ];
193             }
194             elsif ($expr =~ /^\s*apply_deriv\s+($Ident)(?:\s*|\s+(\d+))$/) {
195 0   0       my $level = $2||undef;
196 0           my $id = $1;
197 0           my $cmd = $self->calc->new_command(
198             type => 'DerivativeApplication', symbol => $id,
199             level => $level,
200             );
201 0           return $cmd;
202             }
203             elsif ($expr =~ /^\s*insert\s+($Ident|\*)\s+in\s+($Ident)\s*$/) {
204 0           my $what = $1;
205 0           my $where = $2;
206 0           my $cmd = $self->calc->new_command(
207             type => 'Insertion', symbol => $where,
208             what => $what
209             );
210 0           return $cmd;
211             }
212             elsif ($expr =~ /^\s*$/) {
213 0           return();
214             }
215             else {
216 0           $self->error("Could not parse command '$expr'.");
217 0           return();
218             }
219              
220 0           die "Sanity check";
221             }
222              
223             =head2 _generic_out
224              
225             Generic output routine: Print Formulas and messages alike
226              
227             Subject to change and refactoring.
228              
229             =cut
230              
231             sub _generic_out {
232 0     0     my $self = shift;
233 0           my @out = @_;
234 0 0         if (not @out) {
235 0           return("\n");
236             }
237              
238             my $str = join ' ',
239             map {
240 0 0         if (not defined) {
  0 0          
241 0           "\n"
242             }
243             # insert special cases here...
244             elsif (_INSTANCE($_, 'Math::Symbolic::Custom::Transformation')) {
245 0           $_->to_string();
246             }
247             else {
248 0           "$_"
249             }
250             } @out;
251              
252 0 0         $str .= "\n" if not $str =~ /\n$/;
253 0           return($str);
254             }
255              
256             1;
257              
258             __END__