root/lang/perl/R-Writer/trunk/lib/R/Writer.pm @ 7162

Revision 7162, 4.9 kB (checked in by daisuke, 5 years ago)

docs

  • Property svn:keywords set to Id
RevLine 
[7121]1# $Id$
2
3package R::Writer;
4use strict;
5use warnings;
6use base qw(Class::Accessor::Fast);
[7128]7use R::Writer::Encoder;
[7121]8use R::Writer::Range;
[7128]9use R::Writer::Var;
10use R::Writer::Util;
[7121]11
[7128]12__PACKAGE__->mk_accessors($_) for qw(encoder);
13
[7121]14our $VERSION = '0.00001';
15use Sub::Exporter -setup => {
16    exports => [ 'R' ]
17};
18
19my $base;
20
21sub append {
22    my $self = shift;
23
[7128]24    if ( R::Writer::Util::__IN_RWRITER_PACKAGES__ ) {
[7121]25        push @{ $self->{statements} }, { code => shift };
26        return $self;
27    }
28
29    return $self->call("append", @_);
30}
31
32
33sub R
34{
[7128]35    my $R = R::Writer::Util::__R();
[7121]36    my ($obj) = @_;
37
38    if (defined $R) {
39        $R->{object} = $obj if defined $obj;
40        return $R;
41    }
42
43    $base = R::Writer->new(@_) unless defined $base;
44    $base->{object} = $obj if defined $obj;
45    return $base;
46}
47
48sub new
49{
50    my $class = shift;
51    my $self = $class->SUPER::new({
[7128]52        encoder    => R::Writer::Encoder->new,
[7121]53        @_,
54        statements => [],
55        delimiter  => undef,
56    });
57    return $self;
58}
59
60sub call
61{
62    my ($self, $function, @args) = @_;
63
64    push @{$self->{statements}}, {
65        object => delete $self->{object} || undef,
66        call   => $function,
67        args   => \@args,
68        end_of_call_chain => ! defined wantarray
69    };
70    return $self;
71}
72
73# XXX - This looks fishy
74sub range
75{
76    my ($self, $start, $end) = @_;
77    my $obj = R::Writer::Range->new($start, $end);
78#    $self->append($obj->as_string, delimiter => "");
79    $obj;
80}
81
82sub obj_as_string
83{
84    my ($self, $obj) = @_;
85
86    my $ref = ref($obj);
87
88    if ($ref eq 'CODE') {
89        return $self->function($obj);
90    }
91    elsif ($ref =~ /^R::Writer/) {
92        return $obj->as_string
93    }
94    elsif ($ref eq "SCALAR") {
95        return $$obj
96    }
97    elsif ($ref eq 'ARRAY') {
98        my @ret = map {
99            $self->obj_as_string($_)
100        } @$obj;
101
102        return "[" . join(",", @ret) . "]";
103    }
104    elsif ($ref eq 'HASH') {
105        my %ret;
106        while (my ($k, $v) = each %$obj) {
107            $ret{$k} = $self->obj_as_string($v)
108        }
[7128]109        return "{" . join (",", map { $self->encoder->encode($_) . ":" . $ret{$_} } keys %ret) . "}";
[7121]110    }
111    else {
[7128]112        return $self->encoder->encode($obj)
[7121]113    }
114}
115
116sub as_string
117{
118    my $self = shift;
119    my $ret = "";
120
121    for my $s (@{$self->{statements}}) {
122        # If {call} is present, then this is a function call
123        if (my $f = $s->{call}) {
124            my $delimiter =
125                defined($s->{delimiter}) ? $s->{delimiter} : ($s->{end_of_call_chain} ? ";" : ".");
126            my $args = $s->{args};
127            $ret .= ($s->{object} ? "$s->{object}." : "" ) .
128                "$f(" .
129                    join(",",
130                         map {
131                             $self->obj_as_string( $_ );
132                         } @$args
133                     ) . ")" . $delimiter . "\n"
134        }
135        elsif (my $c = $s->{code}) {
136            my $delimiter = defined $s->{delimiter}  ? $s->{delimiter} : ";";
137            $c .= $delimiter unless $c =~ /$delimiter\s*$/s;
138            $ret .= $c ."\n";
139        }
140    }
141    return $ret;
142}
143
144sub var
145{
146    my ($self, $var, $value) = @_;
147
[7128]148    my $obj = R::Writer::Var->new($var, $value, $self);
149    $self->append($obj->as_string());
[7121]150    return $self;
151}
152
153sub save
154{
155    my ($self, $file) = @_;
156
157    open(my $fh, '>', $file) or die "Failed to open $file for writing: $!";
158    print $fh, $self->as_string;
159    close($fh);
160}
161
1621;
163
164__END__
165
166=head1 NAME
167
168R::Writer - Generate R Scripts From Perl
169
170=head1 SYNOPSIS
171
172  use R::Writer;
173
174  {
175    # x <- 1;
176    # y <- x + 1;
177    # cat(y);
178
179    my $R = R();
180    $R->var(x => 1)
181      ->var(y => 'x + 1')
182      ->call(cat => \'y')
183    ;
184
185    print $R->as_string;
186    # or save to a file
187    $R->save('file');
188  }
189
190=head1 DISCLAIMER
191
192** THIS SOFTWARE IS IN ALPHA ** Patches, comments, and contributions are
193very much welcome. I'm not really a statistics guy. I just happen to write
194Perl code to do it.
195
[7162]196I'm sure there are bunch of bugs lurking, but I'd like this module to be
197useful, so please let me know if there are problems or missing features.
[7121]198
199=head1 DESCRIPTION
200
201R::Writer is a tool to generate R scripts for the "R" Statistical Computing
202Tool from within Perl.
203
204Implementation details heavily borrow from JavaScript::Writer. Without it,
205this module wouldn't have been possible (I'm not insan... smart enough to
206fiddle with DB package on my own. gugod++)
207
208=head1 TODO
209
210=over 4
211
212=item Remove JavaScript-ness
213
214JSON and what not are probably not needed.
215
216=item Add Proper Documentation
217
218=item Document Way To Feed The Script To "R"
219
220=back
221
222=head1 AUTHOR
223
224Copyright (c) 2008 Daisuke Maki C<< <daisuke@endeworks.jp> >>
225
226Much of the code is gratuitously taken from JavaScript::Writer,
227which is by Kang-min Liu C<< <gugod@gugod.org> >>
228
229=head1 LICENSE
230
231This program is free software; you can redistribute it and/or modify it
232under the same terms as Perl itself.
233
234See http://www.perl.com/perl/misc/Artistic.html
235
236=cut
Note: See TracBrowser for help on using the browser.