-
Notifications
You must be signed in to change notification settings - Fork 38
pub_obj
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.
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.
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;
};
};
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));
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);
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:
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.
Return the number of name-value pairs stored in the dictionary:
pub3::obj_t o; o ("a") = 2;
assert (o.size() == 1);
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);
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);
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 ());
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, 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.
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;
}
}
(talk about why sometimes passing pub3::obj_t's by value will work, and sometimes not...)