Skip to content
This repository has been archived by the owner on Jan 16, 2021. It is now read-only.

pub_obj

till-varoquaux edited this page Dec 20, 2011 · 4 revisions

Pub Objects

Pub objects are a lot like JSON objects: they can be dictionaries, arrays, scalars, or compositions of these three data types. The main Pub documentation shows how to access these objects from HTML and Pub modes, and also a little bit from C++ code. This document is a further investigation of how to access and manipulate pub objects from C++ code.

pub3::obj_t

The most general object type is, and its most commonly-used methods are:

namespace pub3 {
    class obj_t { ... }; 
}

As defined in libpub/pub3obj.h The cool thing about this object is that it will act like a scalar, a list or a dictionary, depending on how you use it. You can also make some interesting JSON-y type objects without much work. So for instance, you can do this:

pub3::obj_t o;
o("foo")[1]("bar")[0] = 10;

Which will output a JSON object like:

{ "foo" : [ null, { "bar" : [ 10 ] } ] }

In general, the most recent assignment wins. If you have a pub3::obj_t, use it like a list, but then assign it to a scalar, you've lost all of the stuff in your list, and you only have a scalar. That is, if one did this:

pub3::obj_t o;
o("foo")[1]("bar")[0] = 10;
o = "bah";

Then o is just the object

"bah"

More specific documentation follows.

Class Definition (Abridged)

namespace pub3 {
     class obj_t { // note that some of these methods are implemented in const_obj_t
    
        // treat this object like a **list**
        obj_t push_back ();
        void push_back (obj_t o);
        obj_t operator[] (size_t s);
        const_obj_t operator[] (size_t s) const;
        
        // treat this object like a **dictionary**
        void insert (const str &n, obj_t o);
        obj_t operator() (const str &s);
        const_obj_t operator() (const str &s) const;
        void remove_key (str k);
        ptr<vec<str> > keys () const;
        
        // Useful on strings, lists or dictionaries
        size_t size () const;
        
        // assign this object to something else
        obj_t &operator= (int i);
        obj_t &operator= (const str &s);
        obj_t &operator= (obj_t o);
        void clear ();
        
        // access the internal pub objects that this class is wrapping
        ptr<expr_dict_t> dict ();
        ptr<const expr_dict_t> dict () const;
        ptr<expr_t> obj ();
        ptr<const expr_t> obj () const;
        ptr<expr_list_t> list ();
        ptr<const expr_list_t> list () const;
        
        // Access the scalars hidden in this object:
        bool to_bool () const;
        str to_str () const;
        int to_int () const;
    };
};

Scalars

To assign a pub3::obj_t to a scalar value, simply do this:

pub3::obj_t o;
o = 10;
o = "bah";
o = true;

If you are expecting an object as a scalar, you can use methods like to_int, to_str and to_bool to get data back out:

pub3::obj_t o; 
o = 10; assert (o.to_int() == 10);
o = "bye"; assert (o.to_str () == "bye");
o = true; assert (o.to_bool ());

There are also similar versions of the above methods that let you know if the conversion worked (rather than just giving you default values like 0, "", or false if it didn't).

pub3::obj_t o; int i; str s; bool b;
o = 10; assert (o.to_int (&i) && i == 10);
o = "foo"; assert (o.to_str (&s) && s == "foo" && !o.to_int (&i));

Lists

To make a pub3::obj_t a list, just start using it like one:

pub3::obj_t o;
o.push_back (10);
o[1] = "bye";

This will yield a JSON object of the form:

[ 10, "bye" ]

To access data that's in a list, the following methods are useful:

pub3::obj_t o; o.push_back (10); o[1] = "bye";
assert (o.size () == 2);
assert (o[0] == 10);

Also, other methods will naturally fail if you're dealing with a list:

int i;
assert (!o.to_int (&i));

When an object in a list state, you can access the underlying list object as follows:

pub3::obj_t o;
o[0] = 10;
ptr<pub3::expr_list_t> l = o.list ();
assert (l);

Dictionaries

To make a pub3::obj_t a dictionary, start using it like one:

pub::obj_t o;
o("bar") = 10;
o("jam") = "foo";
o(1) = "bar";

This will yield a JSON object of the form:

{ "bar" : 10, "jam" : "foo", "1" : "bar" }

Convenient access methods now include:

pub3::obj_t::keys

Get a list of all keys that have corresponding values:

pub3::obj_t o;
o ("a") = 2;
ptr<vec<str> > k = o.keys ();
assert (k); // k will be NULL if o wasn't a dictionary
assert ((*k)[0] == "a"); // keys will be populate in random order.

pub3::obj_t::size

Return the number of name-value pairs stored in the dictionary:

pub3::obj_t o; o ("a") = 2;
assert (o.size() == 1);

pub3::obj_t::remove_key

Remove a key/value pair from the dictionary:

pub3::obj_t o;
o("a") = 2;
o("b") = 1;
assert (o.size () == 2);
o.remove_key ("a");
assert (o.size () == 0);

Other Access

When an object is in a dictionary state, you can access its internals like so:

pub3::obj_t o;
o("blah") = 10;
ptr<pub3::expr_dict_t> d = o.dict ();
assert (d);

pub3::obj_list_t

A pub3::obj_list_t is much like a pub3::obj_t, except that it is initialized to an empty list:

pub3::obj_list_t l;
assert (l.list ());

pub3::obj_dict_t

A pub3::obj_dict_t is much like a pub3::obj_t, except that it is initialized to an empty dictionary:

pub3::obj_dict_t d;
assert (d.dict ());

Under the Hood

Under the hood, a pub3::obj_t (and its associated base classes like pub3::obj_list and pub3::obj_dict_t) are simple wrapper structs that contain four pointers:

ptr<expr_t> _obj;
ptr<obj_ref_t> _ref;
ptr<expr_list_t> _list;
ptr<expr_dict_t> _dict;
ptr<expr_t> _scalar;

Depending on whatever the obj_t is acting as, that ptr will be set, and the others will be NULL. The only one that isn't object is an obj_ref_t, which will be set to non-null if this object is referring to another object. For instance:

pub3::obj_t o;
pub3::obj_list_t l;
o.refer_to (l.push_back());
o = 10;

After this code, the list l will be:

[10]

In turn, objects like pub3:expr_t, pub3::expr_list_t and pub3::expr_dict_t are the underlying Pub3 types that are the basic building blocks of the pub system. In this sense, the pub3::obj_t's are just wrappers around those building blocks.

Common Issues

Pub3 v. Tame

Something that might come up is populating a pub3-list as you loop through a tamed list. For this, the easier approach is refer_to:

tamed void
myfn ()
{
   tvars {
       pub3::obj_list_t l;
       pub3::obj_t row;
   }
   while (/* some condition */) {
       twait { /* some fn */ ; }
       row.refer_to (l.push_back ());
       row("foo") = 1;
   }
}

Pass by Value v. Pass by Reference

(talk about why sometimes passing pub3::obj_t's by value will work, and sometimes not...)