Permalink
Browse files

Allow callback to attain the root object

  • Loading branch information...
1 parent 454a1e5 commit 72712d665e0b669c124030c69211721cf2230085 @mnunberg committed Apr 5, 2013
Showing with 100 additions and 1 deletion.
  1. +1 −0 MANIFEST
  2. +49 −0 SL.xs
  3. +11 −1 lib/JSON/SL.pm
  4. +3 −0 perl-jsonsl.h
  5. +36 −0 t/60-rootcb.t
View
@@ -44,6 +44,7 @@ t/40-tuba_basic.t
t/41-tuba_accum_all.t
t/b100-gh1.t
t/b100-gh2.t
+t/60-rootcb.t
eg/bench.pl
eg/synopsis.pl
View
@@ -618,6 +618,23 @@ static int error_callback(jsonsl_t jsn,
return 0;
}
+static void invoke_root_cb(PLJSONSL *pjsn)
+{
+ PLJSONSL_dTHX(pjsn);
+ if (!pjsn->options.root_callback) {
+ return;
+ }
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newRV_inc(pjsn->root)));
+ PUTBACK;
+ call_sv(pjsn->options.root_callback, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+}
+
static void initial_callback(jsonsl_t jsn,
jsonsl_action_t action,
struct jsonsl_state_st *state,
@@ -635,6 +652,10 @@ static void initial_callback(jsonsl_t jsn,
die("Found type %s as root element", jsonsl_strtype(state->type));
}
+ if (pjsn->options.root_callback) {
+ invoke_root_cb(pjsn);
+ }
+
state->sv = pjsn->root;
jsn->action_callback = NULL;
jsn->action_callback_PUSH = body_push_callback;
@@ -1484,6 +1505,33 @@ PLJSONSL_reset(PLJSONSL *pjsn)
pjsn->curhk = NULL;
pjsn->jsn->action_callback_PUSH = initial_callback;
+SV*
+PLJSONSL_root_callback(PLJSONSL *pjsn, SV *callback)
+ CODE:
+ RETVAL = pjsn->options.root_callback;
+ if (RETVAL) {
+ SvREFCNT_inc(RETVAL);
+ } else {
+ RETVAL = &PL_sv_undef;
+ }
+
+ if (SvTYPE(callback) == SVt_NULL) {
+ if (pjsn->options.root_callback) {
+ SvREFCNT_dec(pjsn->options.root_callback);
+ pjsn->options.root_callback = NULL;
+ }
+ } else {
+ if (SvTYPE(callback) != SVt_RV ||
+ SvTYPE(SvRV(callback)) != SVt_PVCV) {
+ die("Second argument must be undef or a CODE ref");
+ }
+ if (pjsn->options.root_callback) {
+ SvREFCNT_dec(pjsn->options.root_callback);
+ }
+ pjsn->options.root_callback = newRV_inc(SvRV(callback));
+ }
+
+ OUTPUT: RETVAL
void
PLJSONSL_DESTROY(PLJSONSL *pjsn)
@@ -1495,6 +1543,7 @@ PLJSONSL_DESTROY(PLJSONSL *pjsn)
REFDEC_FIELD(pjsn, root);
REFDEC_FIELD(pjsn, results);
REFDEC_FIELD(pjsn, buf);
+ REFDEC_FIELD(pjsn, options.root_callback);
} /* else, it's a mortal and shouldn't be freed */
jsonsl_jpr_match_state_cleanup(pjsn->jsn);
if (pjsn->jprs) {
View
@@ -16,7 +16,7 @@ use base qw(Exporter);
our @EXPORT_OK = qw(decode_json unescape_json_string);
BEGIN {
- $VERSION = '1.0.0';
+ $VERSION = '1.0.1';
require XSLoader;
XSLoader::load(__PACKAGE__, $VERSION);
}
@@ -248,6 +248,16 @@ croak if you try so with an 'attempted modification of read-only value' error.
Nevertheless it is useful to get a glimpse of the 'rest' of the JSON document
not returned via the feed method
+B<NOTE> This method is deprecated. Use the L</root_callback> method instead.
+
+=head3 root_callback($cb)
+
+Invoked when the root object is first created. It is passed a reference to the
+root object. Use this method instead of C<root>, as the root object will no
+longer be available via C<root()> once the parsing of the current tree is
+completed. Using a callback oriented mechanism proviedes a better guarantee
+of being able to keep a reference to the root.
+
=head3 referrent_is_writeable($ref)
Returns true if the object pointed to by C<$ref> has the C<SvREADONLY> flag
View
@@ -154,6 +154,9 @@ typedef struct {
/* ignore the jsonpointer settings and allow an 'iv-drip' of
* objects to be returned via feed */
int object_drip;
+
+ /** Callback to invoke when root object is about to be destroyed */
+ SV *root_callback;
} options;
/**
View
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use JSON::SL;
+use Test::More;
+use Data::Dumper;
+
+my $jsn = JSON::SL->new();
+my @root_objs = ();
+
+sub rootcb {
+ push @root_objs, $_[0];
+}
+
+my $prev_cb;
+
+$prev_cb = $jsn->root_callback( \&rootcb );
+is($prev_cb, undef);
+$prev_cb = $jsn->root_callback(undef);
+is($prev_cb, \&rootcb);
+
+eval {
+ $jsn->root_callback("meh");
+}; like($@, '/CODE ref/', "Got error on passing non CODE-ref");
+
+is($jsn->root_callback(\&rootcb), undef);
+
+
+# Now see if the thing actually works
+
+my $txt = '[1], [2], [3], [4]';
+
+$jsn->feed($txt);
+is_deeply(\@root_objs, [[1],[2],[3],[4]]);
+
+done_testing();

0 comments on commit 72712d6

Please sign in to comment.