[Linux-aus] Moose, JSON Question

Daniel Pittman daniel at rimspace.net
Sat Jan 3 20:19:19 EST 2009

David Lloyd <lloy0076 at adam.com.au> writes:

> At the recent OSDC I heard about Moose so I thought I'd take the Moose
> out on the hunting range to see what I could come up with.

Your question isn't actually Moose related, but a generic Perl question,
as far as I can tell.

> Now, I also wanted to fiddle a bit with JSON so I thought, well, let's
> do some TDD as practice and see what happens. Here's a cut down
> version of TestJSON.pm:


>     sub json2perl {
>         my ($self, $perl) = @_;
>         return from_json($perl);
>     }

This will call from_json with only one argument, the '$perl' value.


>       DB<5> david-lloyds-imac:TestJSON lloy0076$ perl -Ilib -MTestJSON -d -e 0
>     Loading DB routines from perl5db.pl version 1.28
>     Editor support available.
>     Enter h or `h h' for help, or `man perldebug' for more help.
>     main::(-e:1): 0
>     DB<1> $tj = TestJSON->new();
>     DB<2> $tj->from_json('{"event":"suiteStart","suite":"ArrayTest","tests":2}');
>     malformed JSON string, neither array, object, number, string or atom, at character
>     offset 0 ["TestJSON=HASH(0xbbd9..."] at /Library/Perl/5.8.8/JSON.pm line 154.
>     ^^^ BTW, that is valid JSON, see below
> It appears that "from_json" is being interpreted as an object method and then
> dispatched to JSON::from_json like this:
>     JSON::from_jason($object_hash, $json);

Yes, it is — because you explicitly called it that way.  The '->'
operator passes the object on the left to the function on the right as
the first argument.

This has nothing to do with Moose, and would work the same way in any
object / package you created.

> Take careful note that the object hash is now in the array. The
> function then reads the very first argument passed to it and then
> balks.
> In another session I managed this:
>     DB<3> $tj->to_json({a => 'b'});
>     Can't locate object method "a" via package "JSON" at /Library/Perl/5.8.8/JSON.pm
>     line 136.

The JSON package to_json treats the hash keys in the second argument as
local method calls, resulting in this error.

> So, a few questions:
>  1. If one uses a module in Perl 5.8.10 inside an object, but more
>     specifically a Moose based object, and it imports functions into
>     the module's namespace, it appears that the functions really are
>     in the namespace and can be called


>      1. But the caveat is that they don't do what you expect them to
>         do...

They don't do what *you* expect them to do — your examples did exactly
what I expected. ;)  More seriously, this is the standard Perl
behaviour, not anything to do with Moose or otherwise.

>  2. Interestingly if I remove the perl2json or json2perl class, the class methods
>     "to_json" and "from_json" respectively (or both) throw a "can't be found in
>     namespace error", i.e. Moose/Perl can't find them
>      1. Which implies they're being loaded because they're used in the module...
>      2. I've looked into JSON's source code and it seems to be doing some funky stuff
>         to figure out which backend JSON:: one is using but other than that it looks
>         like a standard Exporter to me, it just has rolled its own export and import
>         functions

They should show up in the namespace... and a quick test here shows that
they do:

    perl -e 'package Test; use JSON; package main; \
        print UNIVERSAL::can("Test", "to_json") ? "imported\n" : "missing\n"'

>  3. As a matter of OO style, is it "nice" to expose "used" package's
>     imports in the class one is making even though the behaviour if
>     you use them as a class method appears to be strange

Generally, no, you wouldn't expect to import a random class into your
object and have it add methods.

With Moose this is even less common: the 'Role' type is used for the
purpose of class extension, in a cleaner fashion than random exports
into your namespace.

>      1. That is, in this case I did "use JSON;" and caused "from_json"
>         and "to_json" to materialise - if I have an actual object
>         (TestJSON->new()) I can call them but as shown the behaviour
>         is suboptimal

Your calling convention is wrong: the JSON methods need to have their
data as the first argument, and calling them as methods means that they

The summary is, don't do that.  Use your wrapper methods. ;)


More information about the linux-aus mailing list