louie_45 has asked for the wisdom of the Perl Monks concerning the following question:

Howdy,

We plan to use Yaml as the config parser in our tool.
But we need figure out the solution for below concern.

1> data structure deeply merge and include
==> I think it’s doable as we could use some modules link Yaml::AppConfig, Hash::Merge etc
2> External command call with variable substitution
==> No sure how to do this part as if the setting is: cmd: date +%W
And other var depends on it.
3> Dynamically load anonymous sub with mutable arguments
==> For instance:
exe_cmd: anonymous_sub
Then when the program running, we want to load the setting as: &$anonymous_sub(args) for call back
Is it doable?

Thanks in advance,

Replies are listed 'Best First'.
Re:yaml dynamically load in perl
by shmem (Chancellor) on Nov 01, 2015 at 16:22 UTC
    Is it doable?

    Yes, of course. How would you do it? Do you have some thoughts about how this might be done? Code?

    I think that this tasks amounts to having config values treated as macros. A distinction between literal values, macros and referenced YAML keys has to be established. Macro values would be turned into an anonymous subs, so retrieving a value would be done like this (shown here with a hash):

    my $val = ref $yaml{$key} eq 'CODE' ? $yaml{$key}->() : $yaml{$key};

    or the like. You'd be inventing a macro language for your config files. The node tied hash for data munging is based on that. You should be very careful if you are going to shell out to get a value, since typos or mischief can be disastrous. Always run such code under -T (taint checks - see perlrun)!

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      Thanks a lot for your inputs. Would check tied hash later.

      And could you show my how to call the 'CODE' or 'ref' in Yaml.

      For instance, Here is Yaml format: cmd:!perl/ref my_print

      Perl Code:
      $my_print = sub { print "howdy"; };
      How do I make 'cmd' to call $my_print after load the Yaml file into $conf like:
      &{ $conf->{"cmd"} }
      To make it run and print "howdy".

        Not sure if this answers your general question, but here are some specific alternatives:

        c:\@Work\Perl\monks>perl -wMstrict -le "my $my_print = sub { print qq{howdy @_}; }; ;; my $conf = { 'cmd' => $my_print }; ;; &{ $conf->{'cmd'} }; $conf->{'cmd'}->('there'); $conf->{cmd}('doody'); " howdy howdy there howdy doody


        Give a man a fish:  <%-{-{-{-<

Re: yaml dynamically load in perl
by Your Mother (Archbishop) on Nov 01, 2015 at 19:44 UTC

    For #1 you might look into Hash::MultiValue or, as you already mentioned, Hash::Merge. For the rest… it kind of sounds like a mess that would be better addressed by abstracting out each part/tool to Perl that can also be configured via #1.

    As shmem said, yes, of course it's doable. Pretty complicated problem with a pretty terse description. Break it into pieces with real examples of what you have and what you want it to become.

      Thanks for your comments. And how could I make the tag type work? I tried to define a class like: Foo::myPrint
      test: !!perl/Foo::myPrint - strings_to_print
      Then, I want to call the Print method in the Foo.pm like:
      $conf-{'test'}->myPrint("strings_to_print");
      It does not work...

        I'm suggesting that you build a data model module in Perl to be configured with your data; the module and its methods are not in config. just its data. This is one of the things I think Catalyst does very well. It's too complicated, for the time I have today, to write a working demo. This is the idea in a Catalyst idiom.

        # Load application. Application loads its data models. # Instantiate model(s) with conf. String::Thing: strings: - one - two, etc # Use models via application or bare if you prefer. # This $conf-{'test'}->myPrint("strings_to_print") beomes $app->model("StringThing")->strings;

        It might not be the right approach for your problem but might be good. You have a complicated problem that is a little under described.