I've been trying to find a Perl module that converts a YAML file into moose objects without having to pre-declare the structure as you seem to need to do when using MooseX::YAML. Does anyone know of such a module (or script)?
views:
99answers:
2If you don't want to do anything special in your YAML, you can just set up the
proper coercions for your Moose classes and then pass the loaded data to
new()
. For example:
package My::Types;
use Moose::Util::TypeConstraints;
class_type 'My::Related::Class';
coerce 'My::Related::Class', from 'HashRef',
via { My::Related::Class->new(%$_) };
package My::Class;
use Moose;
has name => (is => 'ro', isa => 'Str');
has related => (is => 'ro', isa => 'My::Related::Class', coerce => 1);
package My::Related::Class;
use Moose;
has flavor => (is => 'ro', isa => 'Str');
Then, in some YAML:
name: "An instance of My::Class"
related:
flavor: "Dangerberry!"
Then, in some code:
my $obj = My::Class->new(Load($yaml_data));
print ref $obj->related; # My::Related::Class
print $obj->related->flavor; # Dangerberry!
This isn't roundtrippable, obviously, without some more customization of your Moose classes -- it's just for constructing objects. Also, you need to know what classes the root objects are.
That's probably enough for a lot of simple uses, though.
Don't.
Moose classes, their attributes, and whatever else belongs to them, have a lot of meta-data attached to them. You can't infer all of that meta-data from the data of a single instance.
I'm assuming, given a yaml document as
---
foo: 42
bar: ['moo', 'kooh']
you'd expect and object back that responds to calls to a foo
and a bar
method, returning the respective values. But how should those accessors behave? Should they be simple reader-methods, or also allow writing? Should they validate against any kind of typeconstraint? etc.
If all you really need is something that makes some unblessed data-structure accessible like an object, have a look at Data::Hive
, Hash::AsObject
, and similar modules instead.
If you really want to build proper Moose classes, and are either alright with the guesswork that'd be involved, or happen to have the necessary meta-data available somewhere, you can just use the meta-protocol.
my $class = Moose::Meta::Class->create_anon_class(
attributes => [map {
# your particular set of assumptions here
Moose::Meta::Attribute->new($_ => (is => 'ro', ...))
} keys %{ $deserialized_yaml }],
);
my $instance = $class->name->new($deserialized_yaml);
$instance->$some_key_in_the_yaml_document;