Cookbook
Some quick answers to common needs.
Define the application structure in JSON
It might be a good idea to define the application's structure through a JSON file. In this case, there are several ways to use it, all through the run
command.
If the specification is inside a standalone JSON file, just pass the path to the file:
run('/path/to/app.json', \@ARGV);
If the specification is in a variable as a string, pass a reference to that string:
run(\$app_definition_in_json, \@ARGV);
Partition code into multiple files
If your application definition grows a lot, it can make sense to break it into multiple files, especially the implementation parts. This can be done out of the box in App::Easer, even though there are some tricks that can make the process smoother.
We will concentrate on an example about the execute
callback, but this is generally applied to all other executables as well.
An executable can be a string, in which case it is resolved into a function. At a basic level, it's sufficient to provide the name of a package, and App::Easer will do the heavy-lifting:
my $app = {
commands => {
foo => {
execute => 'MyApp::Foo',
}
}
};
By default, App::Easer will look for a function that matches the specific callback it is resolving:
Callback name | Searched function
--------------+------------------
collect | collect
commit | commit
dispatch | dispatch
execute | execute
fallback | fallback
merge | merge
validate | validate
It is possible to set a different name like this:
my $app = {
commands => {
foo => {
execute => 'MyApp::Foo#execute_this',
}
}
};
It is also possible to simplify the specification by setting a prefix expansion, like the following example:
my $app = {
factor => { prefixes => { '@' => 'MyApp::' } },
commands => {
foo => {
execute => '@Foo',
}
}
};
Try to avoid the +
prefix because it is already used by App::Easer.
The two can be put together, of course:
my $app = {
factor => { prefixes => { '@' => 'MyApp::' } },
commands => {
foo => {
execute => '@Foo#execute_this',
}
}
};
Partition the definition into multiple files
To keep the definition parts together with the implementation, the configuration specfetch
instructs App::Easer about where to find the specifications (in addition to the specification hash):
my $app = {
configuration => {
specfetch => '+SpecFromHashOrModule',
...
}
};
To trigger loading the command specification from an external module, set the children
with hints to get the specification, e.g.:
my $app = {
...
commands => {
MAIN => {
children => [qw< MyApp::Foo MyApp::Bar >],
...
},
}
};
In the examples above, sub-command foo
is defined inside MyApp::Foo
, in particular inside its function spec
:
package Foo;
# get the command specification, built according to App::Easer rules
# for commands inside the commands hash.
sub spec {
return {
supports => [qw< foo Foo FOO >],
...
}
}
1;
When configuration specfetch
is set to +SpecFromHashOrModule
(which is actually a shortcut for App::Easer's own internal function stock_SpecFromHashOrModule
), for all matters the child name is treated as an executable unless there's already a definition in the commands
sub-hash. As such, it's possible to use all tricks explained in Partition code into multiple files, like setting a custom name for the function to be called, or ease life through prefixes.