Group
Extension

MOP4Import-Declare/Base/CLI_JSON.pod

=encoding utf-8

=head1 NAME

MOP4Import::Base::CLI_JSON - Base class for rapidly building testable CLI modules with JSON I/O

=head1 SYNOPSIS

=for code perl

  #!/usr/bin/env perl
  package MyScript;

  use MOP4Import::Base::CLI_JSON -as_base,
      [fields =>
        [verbose => doc => "Enable verbose output", json_type => 'bool'],
        [config  => doc => "Config file path", json_type => 'string']
      ];

  MY->cli_run(\@ARGV) unless caller;

  # Official CLI command - handles its own output
  sub cmd_status : Doc("Show system status") {
    my ($self) = @_;
    print "System OK\n";
  }

  # Regular method - output handled by CLI_JSON
  sub query {
    my ($self, $sql) = @_;
    # Returns data structure that will be JSON-encoded
    return {result => "data from $sql"};
  }

  1;

From shell:

=for code sh

  # Show help
  $ ./MyScript.pm --help

  # Call official command
  $ ./MyScript.pm status
  System OK

  # Call regular method (output as NDJSON by default)
  $ ./MyScript.pm query "SELECT * FROM users"
  {"result":"data from SELECT * FROM users"}

  # Use different output format
  $ ./MyScript.pm --output=yaml query "test"
  ---
  result: data from test

  # Pass complex data structures as arguments
  $ ./MyScript.pm process '{"key":"value"}' '[1,2,3]'

=head1 DESCRIPTION

MOP4Import::Base::CLI_JSON enables rapid development of Perl modules by making
any method immediately testable from the command line. It provides automatic
JSON serialization for inputs and outputs, making it ideal for exploratory
development and debugging.

Key features:

=over 4

=item * Instant CLI access to any module method

=item * Automatic JSON encoding/decoding of arguments and return values

=item * Multiple output formats (ndjson, json, yaml, tsv, dump, raw)

=item * Direct integration with debugger (C<perl -d>) and profiler

=item * Type checking via C<json_type> field declarations

=back

For conceptual background, see L<OO Modulino Pattern|https://github.com/hkoba/perl-mop4import-declare/blob/master/docs/OO_Modulino.md>.

=head1 USAGE

=head2 Creating a CLI_JSON Module

To create a module that can be used both as a library and CLI tool:

=for code perl

  package MyModule;
  use MOP4Import::Base::CLI_JSON -as_base;

  MY->cli_run(\@ARGV) unless caller;

  # Your methods here
  1;

The C<unless caller> idiom ensures C<cli_run> only executes when the file is
run directly, not when it's loaded as a module.

=head2 Command Resolution Rules

When invoked from CLI, the first argument is treated as the command name:

=over 4

=item C<cmd_$COMMAND>

If a method C<cmd_$COMMAND> exists, it's treated as an official CLI command.
The method is responsible for all output and exit handling.

=item C<$COMMAND>

If a method matching the command name exists, it's invoked and its return
value is automatically serialized according to the C<--output> option.

=item Unknown commands

If no matching method exists, C<cli_unknown_subcommand> is called, which
by default shows an error message and help.

=back

=head2 Field Declarations

Fields can be declared with type information and documentation:

=for code perl

  use MOP4Import::Base::CLI_JSON -as_base,
    [fields =>
      [dbfile =>
        doc => "Database file path",
        default => ":memory:",
        json_type => 'string'
      ],
      [limit =>
        doc => "Result limit",
        json_type => 'integer',
        validator => sub { $_[0] > 0 }
      ]
    ];

=head3 Field Options

=over 4

=item C<doc>

Documentation string shown in help output

=item C<default>

Default value for the field

=item C<json_type>

JSON Schema type for validation. Supported types:
C<string>, C<bool>, C<boolean>, C<int>, C<integer>, C<number>

=item C<validator>

Code reference for custom validation. Receives the value and should
return true if valid.

=back

=head1 CORE METHODS

=head2 cli_run(\@ARGV, \%shortcuts)

  MY->cli_run(\@ARGV) unless caller;

  # With option shortcuts
  MY->cli_run(\@ARGV, {h => 'help', v => 'verbose'}) unless caller;

Main entry point for CLI execution. Parses arguments, creates an instance,
and invokes the appropriate method. Options before the command become
constructor arguments, remaining arguments are passed to the method.

Option format: C<--name> or C<--name=value> (no space between name and value).

JSON values in options and arguments are automatically decoded:

=for code sh

  $ ./MyScript.pm --config='{"port":8080}' process '[1,2,3]'

=head2 Command Methods

=head3 Official Commands (cmd_*)

Methods prefixed with C<cmd_> are official CLI commands:

=for code perl

  sub cmd_import : Doc("Import data from file") {
    my ($self, $file) = @_;
    # Handle own output
    print "Importing $file...\n";
    # Handle own exit code if needed
    exit($success ? 0 : 1);
  }

=head3 Regular Methods

Regular methods have their return values automatically serialized:

=for code perl

  sub calculate {
    my ($self, $x, $y) = @_;
    return {result => $x + $y};  # Will be JSON-encoded
  }

=head2 Output Control Methods

=head3 cli_output(\@results)

Called automatically to output method results. Can be overridden
for custom output handling.

=head3 cli_write_fh($filehandle, @data)

Low-level output method that respects the C<--output> format option.

=head1 OPTIONS

These options control CLI behavior and are processed by C<cli_run>:

=over 4

=item C<--help>

Show help message and exit

=item C<--quiet>

Suppress normal output

=item C<--scalar>

Evaluate methods in scalar context (default is list context)

=item C<--output=FORMAT>

Output format: C<ndjson> (default), C<json>, C<yaml>, C<tsv>, C<dump>, C<raw>

=item C<--flatten>

Flatten array results (useful with C<--output=tsv>)

=item C<--undef-as=STRING>

How to represent undef in TSV output (default: "null")

=item C<--no-exit-code>

Don't set exit code based on results

=item C<--binary>

Keep STDIN/STDOUT/STDERR in binary mode (no UTF-8 encoding)

=back

=head1 OUTPUT FORMATS

=head2 ndjson (default)

Newline Delimited JSON - one JSON object per line. Ideal for:

=over 4

=item * Large result sets (human readable without pretty-printing)

=item * Pipeline processing with grep, awk, etc.

=item * Streaming output

=back

=head2 json

Standard JSON format with pretty-printing

=head2 yaml

YAML format (requires YAML::Syck)

=head2 tsv

Tab-separated values, useful for spreadsheet import

=head2 dump

Perl Data::Dumper output for debugging

=head2 raw

No serialization, raw string output

=head1 UTILITY METHODS

These methods are available for use in your modules:

=head2 cli_decode_json($json_string)

Decode a JSON string to Perl data structure

=head2 cli_encode_json($data)

Encode Perl data structure to JSON string

=head2 cli_read_file($filename)

Read and parse a file based on its extension (.json, .yml, .txt)

=head1 DEVELOPMENT WORKFLOW

CLI_JSON is designed to accelerate development through immediate feedback:

=for code perl

  # 1. Create minimal module
  package MyModule;
  use MOP4Import::Base::CLI_JSON -as_base;
  MY->cli_run(\@ARGV) unless caller;
  1;

=for code sh

  # 2. Check syntax
  $ perl -wc MyModule.pm

  # 3. Add a method and test immediately
  $ ./MyModule.pm my_method "arg1" "arg2"

  # 4. Debug interactively
  $ perl -d ./MyModule.pm my_method "test"

  # 5. Profile performance
  $ perl -d:NYTProf ./MyModule.pm heavy_method

=head1 SEE ALSO

=over 4

=item * L<OO Modulino Pattern|https://github.com/hkoba/perl-mop4import-declare/blob/master/docs/OO_Modulino.md>

=item * L<CLI_JSON Rationale|https://github.com/hkoba/perl-mop4import-declare/blob/master/docs/CLI_JSON_rationale.md>

=item * L<MOP4Import::Base::CLI> - Base CLI class without JSON features

=item * L<App::Cmd> - Full-featured CLI framework for production applications

=back

=head1 LICENSE

Copyright (C) Kobayasi, Hiroaki.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=head1 AUTHOR

Kobayasi, Hiroaki E<lt>buribullet@gmail.comE<gt>

=cut

Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.