I have following tree-like structure where each level is represented by separate class:
Book ------ Page ------ Line
1 n 1 n
Each class has a property that holds all its members (e/g/ Book::pages, as array of blessed refs), some properties specific to the level (e.g. Book::author) as well as some methods to add/remove its members.
Now I want to save/load all the data to/from a single file. It's not going to be a relational DB (most probably YAML will be used), so basically what I need to get at some point is something like:
my $book = {
author => "Fred Flinstone",
name => "My Favorite Stones",
pages => [
{
number => 1,
footer => "Dedicated to Wilma",
lines => [ ],
},
{
number => 2,
lines => [
{ text => "Preface", style => "h1" },
{ text => "This book is about my favorite stones:" },
{ text => "Marble" },
# ...
]
},
# ...
]
};
Should there be one smart pair of methods in Book that knows about all member classes? Or should each class implement part of it so that e.g. Line::save returned something like { text => "Marble" }?
What is the correct way to implement this? I would like solution that is as least as possible bounded to the actual data. What if I decide tomorrow to add Page::bookmarks and want to save Bookmarks as well?
Oh, and I'm using Moose, although that should not make much difference.
If you're using Moose, I would recommend looking at MooseX::Storage to handle this. You would use this module inside your package then add with Storage('format' => 'YAML', 'io' => 'File');.
This quick example may get you started:
package Book;
use Moose;
use MooseX::Storage;
with Storage('format' => 'YAML', 'io' => 'File');
...
1;
my $book = Book->new();
...
# to store object
$book->store('book.yml');
# to get object back
my $book2 = Book->load('book.yml');
Related
With the following Code I can fetch Data stored in a Hash from a Database and print it out:
use Data::Dumper;
my $fdx = $s->field(); # get Hashreference from Database
print Dumper($fdx); # print out Hash
The (important part of the) Output looks like this:
$VAR1 = bless( {
'selectable' => 'true',
'_PARENT_OBJECT' => bless( {
'dirtyFlag' => 1,
'path' => undef,
'testItems' => [],
'data' => {
'TEST_10' => {
'atm_rundatahistory' => {
'1523964918' => {
'atm_prid' => {
'content' => '',
'label' => 'Problem Report IDs',
'raw' => ''
}, ...
'1523964410' => {
'atm_prid' => {
'label' => 'Problem Report IDs',
'raw' => '23361234',
'content' => '23361234'
}, ...
'Test_10' is one of hundreds of Tests, '1523964918' is one of many unix timestamps, so basically its a 32 Bit Integer, but I dont know which numbers the timestamps contain.
How do I print out / access the values for 'content' (in this case '23361234') of the most inner Hashes, for all Tests and unix timestamps, if they exist?
from here on I will describe my thoughts and what I have tried, its not necessary to read any further for this question.
I think the code I am looking for is something like:
foreach my $val($fdx{_PARENT_OBJECT}{data}{"TEST_*"}{atm_rundatahistory}{"********"}{atm_prid}{content})
print("\n$val");
However I don't know the exact Syntax, and neither do I know which placeholders to set for "Test_10", since there are many tests numbers, e.g. "...Test_132...Test_134" and the Unix timestamps can be any 32 Bit Integer, so I guess I can use start as a placeholder? e.g. "********".
After some hours of searching on the web, I haven't found a understandable tutorial on how to access values from complex Perl hash structures, I guess there are some simple syntax-rules to know and you can get any value of even very complex data structures without to much effort.
I've already read perldoc_perlreftut. If there is any other easy to understandable tutorial for these kind of problems, please recommend them to me. I don't really know how I can learn to handle such complex data structures in Perl myself.
I'd like to ask you for an advice regarding attribute accessors' naming.
I started to develop a project that is supposed to have quite a ramified hierarchy of classes, for example, the SomeFramework class, a bunch of classes like SomeFramework::Logger and, let's say, classes similar to SomeFramework::SomeSubsystem::SomeComponent::SomeAPI classes.
My goal is to design the most efficient communication between all these classes. I'll explain how I'm doing it now, so maybe you would like to share some opinions on how to make it better.
When I initialize the SomeFramework class, I have an object reference which I use from my application.
my $someframework = SomeFramework->new(parameter => 'value');
The SomeFramework class has some attributes, such as logger, configuration, etc, here are some examples of their definitions:
has 'logger' => (
is => 'ro',
isa => 'SomeFramework::Logger',
reader => 'get_logger',
writer => '_set_logger',
builder => '_build_logger',
lazy => 1
);
sub _build_logger {
my $self = shift;
SomeFramework::Logger->new(someframework => $self);
}
I'm passing the reference to the parent object to the child object, because I need the child to have access to the parent and its methods & accessors. So in the SomeFramework::Logger I have such attribute:
has 'someframework' => (
is => 'ro',
isa => 'SomeFramework',
reader => 'get_someframework',
writer => '_set_someframework',
required => 1
);
It lets me to have access to any object from within the SomeFramework::Logger class, usually it looks something like that:
my $configuration =
$self->
get_someframework->
get_configuration->
get_blah_blah;
To extrapolate it, let's look into the SomeFramework::SomeSubsystem::SomeComponent::SomeAPI class. This class has its own "parent" attribute (let's call it somecomponent) which is supposed to have a reference to a SomeFramework::SomeSubsystem::SomeComponent object as the value. The SomeFramework::SomeSubsystem::SomeComponent class has the attribute for its own parent attribute (we can call it somesubsystem) which is supposed to contain a reference to a SomeFramework::SomeSubsystem object. And, finally, this class has the attribute for its own parent too (someframework), so it contains the reference to a SomeFramework object.
It all makes it possible to have something like that inside of the SomeFramework::SomeSubsystem::SomeComponent::SomeAPI class:
my $configuration =
$self->
get_someframework->
get_somesubsystem->
get_somecomponent->
get_configuration->
get_blah_blah;
The first thing I'd like to know: is it a good practice? I hope, it is, but maybe you would advice me to go some more smooth way?
The second question is a bit more complicated (as for me), but I hope you'll help me with it. :) I like canonical names of accessors recommended by D.Conway in his "Perl Best Practices", but I'd like to do something like that:
my $configuration = $self->sc->ss->sf->conf->blah_blah;
Surely I can name all readers in this laconical manner:
has 'some_framework' => (
is => 'ro',
isa => 'SomeFramework',
reader => 'sf',
writer => '_set_someframework',
required => 1
);
But I don't like the idea of managing without the "standard" accessors names. :(
Also I can use MooseX::Aliases, it works fine for something like that:
has 'some_framework' => (
is => 'ro',
isa => 'SomeFramework',
reader => 'get_someframework',
writer => '_set_someframework',
required => 1,
alias => 'sf'
);
It looks fine, but there's an issue with attributes which names do NOT needed to be shortened. For example:
has 'api' => (
is => 'ro',
isa => 'SomeFramework::SomeSubsystem::SomeComponent::API',
reader => '_get_api',
writer => '_set_api',
required => 1,
alias => 'api'
);
In this case Moose throws an exception: Conflicting init_args: (api, api) at constructor. :( As I understand, MooseX::Aliases tries to create an attribute with the same value of the init_args parameter, so it fails. By the way, sometimes it happens, but sometimes it works fine, I haven't discovered when exactly it doesn't work.
Maybe I should have something like that:
has 'api' => (
is => 'ro',
isa => 'SomeFramework::SomeSubsystem::SomeComponent::API',
reader => '_get_api',
writer => '_set_api',
required => 1,
handles => {
api => 'return_self' # It's supposed to have some method that only
# returns the reference to its own object
}
);
? But it doesn't seem to be the best option too, because it helps me only if the attribute contains a reference some object for which I can define the return_self method. If the attribute contains a reference to some "foreign" object or some other value (e.g., a hash), it won't be possible to call that method. :(
Ugh... Sorry for such a long rant! I hope, you have managed to read to here. :)
I'll be very happy to get to know what do you thing and what would you suggest to do. Feel free to share any your ideas on this topic, any fresh ideas will be very appreciated!
Updated on 25.10.2015
As for the bigger question, let me see if I understood. There are an Apple and a Banana. The Fridge has both of them inside. But you want the Apple to know about the Fridge, and the Worm should know about the Apple, so that it can go from Worm up to Apple up to Fridge and turn the $fridge->light off when it wants to sleep. Is that correct? Sounds like a horrible idea that breaks all kinds of design patterns
Well, to be frank, I didn't think it's horrible. As for me, it's quite good when it's possible to have access from some class to some other class within the same framework. Why not? For example, let's imagine we have some class for the jobs-queue runner (let's call it SomeFramework::JobsQueue::Executor) and some class for jobs. Is it really bad to do something like:
package SomeFramework::JobsQueue::Executor;
use Moose;
use MooseX::Params::Validate;
has queue {
isa => 'SomeFramework::JobsQueue',
required => 1,
reader => 'get_queue',
writer => '_set_queue'
}
# This attribute is being set by the framework when the framework
# creates the SomeFramework::JobsQueue::Executor-based object
sub execute {
my($self, $job, $options) = validated_hash(
\#_,
job => { isa => 'SomeFramework::JobsQueue::Job' },
options => { isa => 'HashRef' }
);
my $queue = $self->get_queue;
$queue->mark_as_running($job->get_id);
$job->execute(options => $options);
$queue->mark_as_completed($job->get_id);
}
? So, our queue-runner object is aware about the queue object it "belongs" to, so it can call some methods of this queue object.
Or let's look at much more simple example:
package SomeFramework::SomeSubsystem;
use Moose;
has 'some_framework' => {
isa => 'SomeFramework',
required => 1,
reader => 'get_some_framework',
writer => '_set_some_framework'
}
sub some_method {
my $self = shift;
$self->get_some_framework->get_logger->log_trace("Hello, world!");
}
So, our object knows how to call methods of the framework's object that has initialized that object, moreover it can call some methods of the framework's object and even some methods of other objects initialized and stored by the framework's object.
If it's really bad, would you be so kind as to help me to understand why? Thank you!
So I'm trying use Rose::HTML::Form and I want my fields to appear based on 'rank' rather than by name (the default) .
I've written a comparator subroutine:
sub _order_by_rank {
my ($self, $one, $two) = #_;
return $one->rank <=> $two->rank;
};
and referenced it in my form constructor:
Rose::HTML::Form->new(method => 'post', compare_fields => \&_order_by_rank);
But I am then left with:
Can't call method "name" on unblessed reference at /usr/lib/perl5/site_perl/5.8.8/Rose/HTML/Form/Field/Collection.pm line 405.
It seems to call the comparator before I've added anything.
After constructing the form object, I add some fields and then call init_fields:
$form->add_fields(
id => { type => 'hidden', value => "", rank => 0 },
number => { type => 'int', size => 4, required => 1, label => 'Plant Number', rank => 1 },
name => { type => 'text', size => 25, required => 1, label => 'Plant Name', rank => 2 },
...
);
$form->init_fields;
According to the documentation this is something people usually do. What it doesn't explain is how to do it.
Hopefully someone can explain this to me before I have to buy a new keyboard :)
From the documentation it looks as though, rather than passing in a subroutine reference, you need to subclass Rose::HTML::Form and override the compare_fields method.
The default comparison method is Rose::HTML::Form::compare_fields. You have to create subclasses if you want different sorting methods for different forms.
It would help me to explain further if you showed your full code.
i was wondering, what is the best way to store Hash of Hashes in Moose. Lets take for example a Hash like this:
my %hash = ('step1' => {'extraction' => \$object1,
'analysis' => \$object2},
'step2' => {'extraction' => \$object3,
'analysis' => \$object4});
but i want to save this one in a moose attribute. How should i organize the access (reading, writing) on this. Examples on the net are mostly for "flat" hashes. But then you can use helpers like Moose::Meta::Attribute::Native::Trait::Hash. Is there something similar for hash of hashes?
Reason for this is, that i want to iterate over the step-keys and access the object-instances in that. Or is there a better, more Moose-like way to do this?
Thanks in advance!!!
You can store a hash of hashes in a Moose object in pretty much the same way as you would store any other hash:
has steps => ( is => 'ro', isa => 'HashRef' );
You can, however, be more specific to declare it as the specific kind of hash you need to store as a way to verify that anything stored in that slot is the right kind of thing:
has steps => ( is => 'ro', isa => 'HashRef[HashRef[Object]]' );
Depending on the data, I might also change Object here to the class name. You can get even fancier and use MooseX::Types and MooseX::Types::Structured to specify an even more exacting structure.
As for helpers to to step over your structure, I don't know of anything in Moose or MooseX to do that. If you know the structure of your data, it's probably best to just implement a subroutine to do what you need yourself. Your code will likely perform better and do what you need better than any generic traversal.
Edit/Additional Info: Each Moose attribute creates an accessor method no your class which returns the stored value, so accessing the data is:
# Assuming we put the attribute in a package named StepTool
my $step_tool = StepTool->new(
steps => { 'step1' => {'extraction' => \$object1,
'analysis' => \$object2},
'step2' => {'extraction' => \$object3,
'analysis' => \$object4} },
);
# To do something one of the values
do_something($step_tool->steps->{step1}{extraction});
# To iterate over the structure, could be done in a method on StepTool
for my $step_name (keys %{ $step_tool->steps }) {
my $step = $step_tool->steps->{ $step_name };
for my $action_name (keys %$step) {
my $object = $step->{ $action_name };
do_something($object);
}
}
# If doing the above as a method, $self is the Moose object, so...
sub traverse_steps {
my ($self) = #_;
for my $step_name (keys %{ $self->steps }) {
... # just like above
}
}
And one other note, you could still use traits => [ 'Hash' ] and add some handles to give yourself some additional helpers, if you want.
If the data structure is more free form than that, you might want to look into something like Data::Visitor to iterate over your structure in your subroutine. (I have had some difficult to debug, weird problems with Data::Visitor, so I try to avoid it when I can.)
There is also a type-safe approach inspired by Moose: How to get an array of objects? Traits?
There is a class to hold the outer hash (StepTool::Steps) that has traits => ['Hash']. This approach can be nested infinitely deep using e.g. Arrays and Hashes:
package StepTool;
use Moose;
has 'steps' => (
'is' => 'rw',
'isa' => 'StepTool::Steps',
'default' => sub { StepTool::Steps->new() },
);
package StepTool::Steps;
use Mouse;
has '_steps' => (
is => 'ro',
isa => 'HashRef[StepTool::Step]',
traits => ['Hash'],
default => sub { {} },
handles => {
# You'll probably want a fuller set here...
get => 'get',
set => 'set',
keys => 'keys',
}
);
package StepTool::Step;
use Mouse;
has 'extraction' => (
is => 'rw',
);
has 'analysis' => (
is => 'rw',
);
package main;
my $object1 = bless {}, 'Foobar1';
my $object2 = bless {}, 'Foobar2';
my $object3 = bless {}, 'Foobar3';
my $object4 = bless {}, 'Foobar4';
my $stepTool = StepTool->new();
# set up step1 one field at a time.
$stepTool->steps->set('step1', StepTool::Step->new());
# I have no idea why the OP wants references to objects
# everywhere but he does...
$stepTool->steps->get('step1')->extraction(\$object1);
$stepTool->steps->get('step1')->analysis(\$object2);
# set up step2 all at once
$stepTool->steps->set('step2', StepTool::Step->new(
extraction => \$object3,
analysis => \$object4
));
# or, less elegantly, initialize an entire StepTool:
my $stepTool2 = StepTool->new(
steps => StepTool::Steps->new(
_steps => {
step1 => StepTool::Step->new(
extraction => \$object1,
analysis => \$object2
),
step2 => StepTool::Step->new(
extraction => \$object3,
analysis => \$object4
),
}
),
);
printf "step1->analysis is a ref to an instance of class: %s\n",
ref(${$stepTool->steps->get('step1')->analysis});
When I define(?) a resource e.g. to ensure dir structure, are there any loops available?
Like that:
for X in [app1,app2] do:
file { '/opt/app/' + X:
ensure => directory,
owner => 'root',
group => 'root',
mode => '0644',
}
I have tens of directories and I am really tired with declaring it in puppet.. It would take 15 LOC of bash.
Any ideas?
Older versions of the puppet language have no support for loops.
But you can use an array instead of a simple string for the title and declare several resources at the same time with the same params:
$b = '/opt/app'
file { [ "$b/app1", "$b/app2" ]:
ensure => directory,
owner => 'root',
group => 'root',
mode => 0644,
}
You can also declare many resources of the same type with different params by ending each resource with a ;, which is a bit more compact than repeating the file and the {s and }s:
file {
[ "$b/app1", "$b/app2" ]:
ensure => directory,
owner => 'root',
group => 'root',
mode => 0755;
[ "$b/app1/secret", "$b/app2/secret" ]:
ensure => directory,
owner => 'root',
group => 'root',
mode => 0700;
}
In the specific case of files, you can set up a source and use recursion:
file { "/opt/app":
source => "puppet:///appsmodule/appsdir",
recurse => true;
}
(that would require having a source of that directory structure for puppet to use as the source)
You can define a new resource type to reuse a portion of the param multiple times:
define foo {
file {
"/tmp/app/${title}":
ensure => directory,
owner => 'root',
mode => 0755;
"/tmp/otherapp/${title}":
ensure => link,
target => "/tmp/app/${title}",
require => File["/tmp/app/${title}"]
}
}
foo { ["app1", "app2", "app3", "app4"]: }
Starting with Puppet 2.6, there's a Ruby DSL available that has all the looping functionality you could ask for: http://www.puppetlabs.com/blog/ruby-dsl/ (I've never used it, however). In Puppet 3.2, they introduced some experimental loops, however those features may change or go away in later releases.
As of version 3.2 there are lambdas
You must set parser = future in puppet.conf.
$a = [1,2,3]
each($a) |$value| { notice $value }
Another option for declaring multiple defined types is create_resources. Pass it a hash of hashes:
create_resources(file, {
'/tmp/test1' => {
ensure => directory,
owner => 'root',
group => 'root',
mode => '0644',
},
'/tmp/test2' => {
ensure => directory,
owner => 'www-data',
group => 'www-data',
mode => '0755',
},
})
As of Puppet 4 (and the "future parser" of late versions of Puppet 3) the Puppet DSL has iteration functions similar in form and function to some of the methods of Ruby arrays and hashes:
each - evaluates a block of code (formally, a lambda) for each element of an array or hash
filter - applies a lambda to each element of an array or hash and returns an array or hash of those for which the lambda evaluated to true
map - applies a lambda to each element of an array or hash, and returns an array of the results
reduce - applies a lambda to each element of an array or hash to build up a single result, which it returns
There is no indexed for loop along the lines of C's or Java's, but you can combine array sectioning with any of the functions above to achieve iteration over a subset of a data structure. There is no indefinite iteration along the lines of a C or Java while loop.
Of course, you can still use the resource-centric approaches described in other answers, and sometimes one of those is indeed the best available approach. You cannot any longer use Ruby DSL, however; it is removed altogether from Puppet 4. Among the iteration functions, the ability to define custom functions, the ascension of data-centric approaches into favor, and all Puppet's historic standard features, Ruby DSL seems not much missed.
Yes. "Ruby DSL" could help, just use file extension ".rb" instead of ".pp" in manifest and you can define puppet "type" like this:
define 'myapps::structure', :applist do
#applist.each do |app|
file( #name+'/'+app,
:ensure => directory,
:owner => 'root',
:group => 'root',
:mode => '0644')
end
end
Classes and nodes also can be defined in similar way. Notice however that this feature is deprecated since release 3