Rinci-1.1.78/0000755000175000017500000000000012571643014010307 5ustar s1s1Rinci-1.1.78/README0000644000175000017500000000000012571643014011155 0ustar s1s1Rinci-1.1.78/lib/0000755000175000017500000000000012571643014011055 5ustar s1s1Rinci-1.1.78/lib/Rinci.pod0000644000175000017500000004446712571643014012644 0ustar s1s1package Rinci; # just to make PodWeaver happy # VERSION 1; # ABSTRACT: Language-neutral metadata for your code entities __END__ =pod =encoding UTF-8 =head1 NAME Rinci - Language-neutral metadata for your code entities =head1 VERSION This document describes version 1.1.78 of Rinci (from Perl distribution Rinci), released on 2015-09-03. =head1 SPECIFICATION VERSION 1.1 =head1 ABSTRACT This document describes B, a set of extensible, language-neutral metadata specifications for your code (functions/methods, variables, packages, classes, and so on). Rinci allows various helper tools, from code generator to web middleware to documentation generator to other protocols, to act on your code, making your life easier as a programmer. Rinci also allows better interoperability between programming languages. Rinci is geared towards dynamic scripting languages like Perl, Python, Ruby, PHP, JavaScript, but is not limited to those languages. =head1 STATUS The 1.1 series does not guarantee full backward compatibility between revisions, so caveat implementor. However, major incompatibility will bump the version to 1.2 or 2.0. =head1 TERMINOLOGIES The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. B is a set of specifications of metadata for your code entities. Each different type of code entity, like function/method, variable, namespace, etc, has its own metadata specification. B is a defhash (see L). Each specification will specify what B should be supported. So the L specification will describe metadata for functions/methods, L will describe metadata for namespace/package, and so on. Rinci defines properties pertaining to documentation (like C, C, C, C), function argument and return value validation (C and C), dependencies (C), standardized feature description (C), also a few conventions/protocols for doing stuffs like undo (others like callback/progress report will follow). Basically anything that can describe the code entity. The specification is extensible: you can define more properties, or more deps, or more features. Since defhash can contain keys that are ignored (those that start with underscore, C<_>), extra information can be put here. =head1 WHAT ARE THE BENEFITS OF RINCI? By adding Rinci metadata to your code, you can write/use tools to do various things to your program. Rinci is designed with code generation and function wrapping in mind. At the time of this writing, in Perl there exists several tools (mostly modules under L namespace) to do the following: =over 4 =item * L Wrap functions with a single generated function that can do the following: validate input (using information from the C property), validate return value (the C property), add execution time-limiting (C), add automatic retries (C), interactive confirmation, logging, and more. =item * L A replacement for L or L if your functions are equipped with Rinci metadata. Automatically provide export tags (using information in the C property). Can automatically wrap functions using Perinci::Sub::Wrapper when exporting. =item * Perinci::To::* modules Convert metadata to various other documents, for example L to generate documentation. =item * L L command-line client. Call local/remote functions. Automatically convert command-line options/arguments to function arguments. Generate help/usage message (for C<--help>). Check dependencies (e.g. you can specify that in order to run your functions, you need some executables/other functions to exist, an environment variable being set, and so on), perform bash shell completion (using L). =item * L A L application (a set of PSGI middlewares, really) to serve metadata and function call requests over HTTP, according to the L protocol. =item * L An alternative for L for REST-style service. =item * L Use remote packages and import their functions/variables transparently like you would use local Perl modules. The remote server can be any Riap-compliant service, even when implemented in other languages. =item * C Since Rinci metadata are just normal data structure, they can be easily generated. The Perinci::Sub::Gen::* Perl modules can generate functions as well as their metadata, for example to access table data (like from a regular array or from a SQL database). =back More tools will be written in the future. =head1 RINCI VS ... Some features offered by Rinci (or Rinci tools) are undoubtedly already offered by your language or existing language libraries. For example, for documentation Perl already has POD and Python has docstrings. There are numerous libraries for argument validation in every language. Python has decorators that can be used to implement various features like argument validation and logging. Perl has subroutine attributes to stick additional metadata to your subroutines and variables. And so on. The benefits that Rinci offer include richer metadata, language neutrality, extensibility, and manipulability. B. Rinci strives to provide enough metadata for tools to do various useful things. For example, the C and C properties support translations. Argument specification is pretty rich, with a quite powerful and flexible schema language. B. You can share metadata between languages, including documentation and rules for argument validation. Perl 6 allows very powerful argument validation, for example, but it is language-specific. With Rinci you can easily share validation rules and generate validators in Perl and JavaScript (and other target languages). B. Being a normal data structure, your Rinci metadata is easier to manipulate (clone, merge, modify, export, what have you) as well as access (from your language and others). Perl's POD documentation is not accessible from the language (but Perl 6's Pod and Python docstrings are, and there are certainly tools to parse POD). On the other hand, Python docstrings are attached in the same file with the function, while with Rinci you can choose to separate the metadata into another file more easily. B. If you stack multiple decorators in Python, for example, it usually results in wrapping your Python function multiple times, which can add overhead. A single wrapper like L, on the other hand, uses a single level of wrapping to minimize subroutine call overhead. B. There is no reason why Rinci metadata has to compete against existing features from language/libraries. A code generator for Rinci metadata can generate code that utilize those features. For example, the C property can be implemented in Python using decorator, if you want. Rinci basically just provides a way for you to express desired properties/constraints/behaviours, separate from the implementation. A tool is free to implement those properties using whatever technique is appropriate. =head1 SPECIFICATION Note: Examples are usually written in Perl, but this does not mean they only apply to a particular language. =head2 Terminologies B, or just B for short, are elements in your code that can be given metadata. Currently supported entities are function/method, namespace/package, and variable. Other entities planned to be supported: class, object, library, application. =head2 Specification common to all metadata This section describes specification common to all kinds of Rinci metadata. B. The specification does not specify where to put metadata in: it might be put alongside the code, separated in another source code, encoded in YAML/JSON, put in database, or whatever. It is up to the tools/implementations to provide the mechanism. If you use L in Perl, there is a great deal of flexibility, you basically can do all of the above, even split the metadata in several files. See its documentation for more details. B. Below are properties common to all metadata: =head3 Property: v => FLOAT (required) From DefHash. Declare specification version. This property is required. It should have the value of 1.1. If C is not specified, it is assumed to be 1.0 and metadata is assumed to be the old, Sub::Spec 1.0.x metadata. Example: v => 1.1 =head3 Property: entity_v => STR Specify entity version (like package or function version). This is version as in software implementation version, not to be confused with C which is the metadata specification version (1.1). Example: entity_v => 0.24 In Perl, modules usually put version numbers in package variable called C<$VERSION>. If not set, tools like L automatically fills this property from that variable, to relieve authors from manually setting this property value. =head3 Property: default_lang => STR From DefHash. Specify default language used in the text properties like C and C. Default is 'en_US'. To specify translation texts in other languages, you can use C, e.g.: summary => "Perform the foo ritual", "summary.alt.lang.id_ID" => "Laksanakan ritual foo", =head3 Property: name => STR From DefHash. The name of the entity. Useful when aliasing entity (and reusing the metadata) and wanting to find out the canonical/original entity. Examples: name => 'foo' name => '$var' # only in languages where variables have prefix =head3 Property: summary => STR From DefHash. A one-line summary. It should be plain text without any markup. Please limit to around 72 characters. Example: # in variable metadata for $Answer summary => 'The answer to the question: what is the meaning of life' # in function metadata foo summary => 'Perform the foo ritual', For variable metadata, it should describe what the variable contain. You do not need to say "Contains ..." or "A variable that ..." since that is redundant; just say directly the content of the variable (noun). You also do not need to say what kinds of values the variable should contain, like "An integer, answer to the ..." or "..., should be between 1..100" since that should go to the C property. For function metadata, it should describe what the function does. Suggestion: use active, bare infinitive verb like in the example (not "Performs ..."). Avoid preamble like "This function ..." or "Function to ..." since that is redundant. Also avoid describing the arguments and its values like "..., accepts a single integer argument" as that should go to the C property. To specify translations in other language, use the L. Or change the C property. Examples: # default language is 'en_US' summary => 'Perform the foo ritual', "summary.alt.lang.id_ID" => 'Laksanakan ritual foo', # change default language to id_ID, so all summaries are in Indonesian, except # when explicitly set otherwise default_lang => 'id_ID', summary => 'Laksanakan ritual foo', "summary.alt.lang.en_US" => 'Perform the foo ritual', =head3 Property: tags => ARRAY OF (STR OR HASH) From DefHash. A list of tags, useful for categorization. Can also be used by tools, e.g. L in Perl uses the C property of the function metadata as export tags. Tag can be a simple string or a tag metadata hash. Example: # tag a function as beta tags => ['beta'] # the second tag is a detailed metadata tags => ['beta', { name => 'category:filtering', summary => 'Filtering', "summary.alt.lang.id_ID" => 'Penyaringan', } ] =head3 Property: description => STR From DefHash. A longer description text. The text should be in marked up in format specified by C and is suggested to be formatted to 78 columns. To avoid redundancy, you should mentioning things that are already expressed as properties, for example: return value of function (specify it in C property instead), arguments that the function accepts (C), examples (C), function's features (C) and dependencies/requirements (C). For function, description should probably contain a more detailed description of what the function does (steps, algorithm used, effects and other things of note). Example: { name => 'foo', summary => 'Perform the foo ritual', description => <, to specify translations in other language, use the L property. =head3 Property: links => ARRAY OF HASHES List to related entities or resources. Can be used to generate a SEE ALSO and/or LINKS sections in documentation. Each link is a defhash with the following keys: =over 4 =item * url => STR (required) URI is used as a common syntax to refer to resources. If URI scheme is not specified, tools can assume that it is a C URI (see L). =item * caption => STR From DefHash. A short plaintext title for the link. =item * description => STR From DefHash. A longer marked up text description for the link. Suggested to be formatted to 76 columns. =item * tags => ARRAY OF (STR OR HASH) From DefHash. Can be used to categorize or select links. For generating SEE ALSO sections, use the tag 'see'. =back Example: # links in the Bar::foo function metadata links => [ { url => "http://example.org/foo-with-bar-algo.html", caption => "Article describing foo using Bar algorithm", }, { url => "../Bar2/", caption => "Another implementation of the Bar algorithm", tags => ['see'], }, ], =head3 Property: x => ANY From DefHash. This property is used to store extended (application-specific) attributes, much like the C prefix in HTTP or email headers. This property can be used as an alternative to using underscore prefix (e.g. C<_foo>). Some processing tools strip properties/attributes that begin with underscores, so to pass extended metadata around, it might be more convenient to use the C property. It is recommended that you put an application prefix. Example: "x.myapp.foo" => "some value", Another example: "x.dux.strip_newlines" => 0, =head2 Entity-specific specifications Each entity-specific specification is described on a separate subdocument. Currently these specifications are defined: =over 4 =item * L - Metadata for functions/methods =item * L - Metadata for namespaces/packages =item * L - Metadata for variables =item * L - Function/method result metadata =back These specifications are planned or considered, but not yet defined: =over 4 =item * L - Metadata for classes =item * L - Metadata for objects =item * L - Metadata for applications =item * L - Metadata for libraries =item * L - Metadata for software distribution =item * L - Metadata for programming languages =item * L - Metadata for software authors =item * L - Metadata for software projects =item * L - Metadata for code repository (like git, svn) =back =head1 FAQ =head2 What does Rinci mean? Rinci is taken from Indonesian word B or B, meaning: specification, detail. =head2 Why use Sah for data schema? Sah is a flexible and extensible schema language, while still not being language-specific, making it easy for code generator tools to generate validator code in various target languages (Perl, Ruby, etc). =head1 HISTORY Below is the general history of the project and major changes to the specifications. For more detailed changes between releases, see the B file in the distribution. =head1 1.1 (Jan 2012) To clearly separate specification from implementation, rename specification from C to C (the namespace C is now used for the Perl implementation). Support code entities other than functions/methods. Bump specification version from 1.0 to 1.1 due to several incompatibilities like changed C and C properties, terminologies, defaults. Versioning property (C) now required. =head2 1.0 (Aug 2011) First release version of Sub::Spec. =head2 0.x (Feb-Aug 2011) Series of Sub::Spec drafts. =head2 Spanel project (2009-2010) I started using some metadata for API functions, calling them spec and putting them in %spec instead of in POD, so I can list and grab all the summaries easily as a single dump for API catalog (instead of having to parse POD from my source code files). Later on I kept adding more and more stuffs to this, from argument specification, requirements, and so on. =head1 SEE ALSO =head2 Related specifications L Sah schema language, L L =head2 Related ideas/concepts B<.NET attributes>, http://msdn.microsoft.com/en-us/library/z0w1kczw.aspx B, http://www.python.org/dev/peps/pep-0318/ , http://wiki.python.org/moin/PythonDecorators =head2 Other related links L, http://www.acmeism.org/ =head1 HOMEPAGE Please visit the project's homepage at L. =head1 SOURCE Source repository is at L. =head1 BUGS Please report any bugs or feature requests on the bugtracker website L When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 AUTHOR perlancar =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2015 by perlancar@cpan.org. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Rinci-1.1.78/lib/Rinci/0000755000175000017500000000000012571643014012121 5ustar s1s1Rinci-1.1.78/lib/Rinci/variable.pod0000644000175000017500000000341012571643014014410 0ustar s1s1package Rinci::variable; # just to make PodWeaver happy # VERSION 1; # ABSTRACT: Metadata for your variables __END__ =pod =encoding UTF-8 =head1 NAME Rinci::variable - Metadata for your variables =head1 VERSION This document describes version 1.1.78 of Rinci::variable (from Perl distribution Rinci), released on 2015-09-03. =head1 SPECIFICATION VERSION 1.1 =head1 INTRODUCTION This document describes metadata for variables. This specification is part of L. Please do a read up on it first, if you have not already done so. =head1 SPECIFICATION There is currently no metadata properties specific to variables. =head2 Property: schema => SCHEMA Specify the Sah schema that the variable's value must validate to. This can be used by a variable wrapper (getter/setter generator) tool to make sure that variable always contains valid values. Example: # metadata for variable $Meaning_Of_Life { ... summary => 'The meaning of life', schema => [int => {between => [1, 100]}, } =head1 FAQ =head1 SEE ALSO L =head1 HOMEPAGE Please visit the project's homepage at L. =head1 SOURCE Source repository is at L. =head1 BUGS Please report any bugs or feature requests on the bugtracker website L When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 AUTHOR perlancar =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2015 by perlancar@cpan.org. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Rinci-1.1.78/lib/Rinci/FAQ.pod0000644000175000017500000001411712571643014013240 0ustar s1s1package Rinci::FAQ; # just to make PodWeaver happy # DATE # VERSION 1; # ABSTRACT: Metadata for your functions/methods __END__ =pod =encoding UTF-8 =head1 NAME Rinci::FAQ - Metadata for your functions/methods =head1 VERSION This document describes version 1.1.78 of Rinci::FAQ (from Perl distribution Rinci), released on 2015-09-03. =head1 FAQ =head2 Rinci::function =over =item * Why do you make enveloped result an arary instead of hash? For example, a hash-based enveloped result can be something like: {status=>200, message=>"OK", result=>42, meta1=>..., meta2=>...} This has the benefit of a single container, but I picked array because of the brevity for simple cases (which are the majority), e.g.: [200] # versus {status=>200} [200, "OK"] # versus {status=>200, message=>"OK"} When handling enveloped result, the array version is also shorter: if ($res->[0] == 200) { ... } # versus: if ($res->{status} == 200) { ... } print "Error $res->[0] - $res->[1]"; # versus: print "Error $res->{status} - $res->{message}"; The hash version is more obvious for first-time reader, but after just some amount of time, C<< $res->[0] >>, C<< $res->[1] >> will become obvious if you use it consistently. As a bonus, arrays are faster and more space-efficient than hashes. =item * How do you indicate transient/temporary vs permanent errors? Some protocols, like SMTP or POP, defines 4xx codes as temporary errors and 5xx as permanent ones. This gives clue to clients whether to retry or not. HTTP, which Rinci is modelled after, does not provide such distinction to its status codes. However, Rinci defines a C result metadata that can be used for such purpose, e.g.: [500, "Can't submit mail, we are being blocked by RBL", undef, {perm_err=>0}] [500, "Can't submit mail, destination address does not exist", undef, {perm_err=>1}] =item * How to handle binary data? To accept binary data, you can set one or more arguments as having the schema type C (instead of C): args => { data => { schema => 'buf*', req=>1 }, } To return binary data, you can set result's schema type to C, e.g.: result => { schema => 'buf*' } For handling binary data when writing Perl-based command-line applications, see L. =item * How to accept partial data? First, set an argument property C to true to signify that this argument accept partial value. You can then call with special arguments C<-arg_len>, C<-arg_part_start>, C<-arg_part_len>. See L for more details. L can also do this via HTTP Content-Range. =item * How to accept streaming input? Many program environments (like in Unix) have the concept of standard input. Rinci provides a thin abstraction over this. You can set the argument property C to true. This way, in most implementation like in Perl, your function will receive the argument value as filehandle which it can then read from. See C property in C function metadata property in L for an example. Your function can also read from standard input directly, but this means you cannot use conveniences like the C, where the command-line framework can supply an argument value for you from various sources including standard input and/or files. =item * How to produce streaming output? Many program environments (like in Unix) have the concept of standard output. To produce output stream, you can set result metadata property C to true. And then in the result you can put a filehandle or an object that responds to getline/getitem methods. =item * What is the difference between accepting partial data and streaming input? If a function accepts partial data, to send a large data without taking up too much memory, a caller needs to break the data into several parts and call the function several times, each with a different part. If a function accepts a stream input, to send a large data a caller can send a filehandle/iterator object from which the function can read the data iteratively. Stream input is easier and simpler for the function writer to write. A caller also only needs to call the function once instead of multiple times. However, there is no resume capability. On the other hand, partial input data is easier to implement with Riap::HTTP, as it maps rather closely to HTTP Content-Range. If you are uploading a large data over a network to a function, partial input data is preferred because of its ease to work with HTTP and its resume ability. However, if input is really a stream (i.e. unknown/infinite length), then streaming input is the option to use. =item * What is the difference between returning partial result and streaming output? If a function can return partial result, to retrieve a large result from a function a caller can calls several times and each time request to retrieve parts of result. If a function returns output stream, a caller can then retrieve data from the stream iteratively. Output stream is easier to handle by the caller. The caller also only needs to call once instead of multiple times. However, there is no resume capability. On the other hand, partial result is easier to implement with Riap::HTTP, as it maps rather closely to HTTP Content-Range. If you are retrieving a large data over a network from a function, partial result is preferred because of its ease to work with HTTP =back =head1 HOMEPAGE Please visit the project's homepage at L. =head1 SOURCE Source repository is at L. =head1 BUGS Please report any bugs or feature requests on the bugtracker website L When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 AUTHOR perlancar =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2015 by perlancar@cpan.org. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Rinci-1.1.78/lib/Rinci/Undo.pod0000644000175000017500000002206412571643014013536 0ustar s1s1package Rinci::Undo; # just to make PodWeaver happy # VERSION 1; # ABSTRACT: (DEPRECATED) Protocol for undo operations in functions __END__ =pod =encoding UTF-8 =head1 NAME Rinci::Undo - (DEPRECATED) Protocol for undo operations in functions =head1 VERSION This document describes version 1.1.78 of Rinci::Undo (from Perl distribution Rinci), released on 2015-09-03. =head1 SPECIFICATION VERSION 1.1 =head1 STATUS This protocol (riundo for short) is now deprecated in favor of L (ritx for short) for several reasons: =over 4 =item * riundo is inherently unreliable Undo information is returned by function I the function has performed the action. If function dies in the middle of action, client does not have the information to undo the (partially completed) action. That is why in ritx, the TM asks the function first for undo information before asking the function to perform its action. =item * ritx does not limit using the same function for undo In riundo, we must call the same function (passing the previously obtained undo data from the that function) to undo the information. This is sometimes slightly cumbersome. The undo action might be provided by other functions, but we still have to go through the same function first. =item * ritx can also implement undo/redo So there is no need for maintaining two specifications. =back =head1 SPECIFICATION This document describes the Rinci undo protocol. This protocol must be followed by functions that claim that they support undo (have their C C set to true). Such functions are from here on called I (or just function, unless when ambiguous). The protocol is basically the non-OO version of the command pattern, a design pattern most commonly used to implement undo/redo functionality. In this case, each function behaves like a command object. You pass a special argument C<-undo_action> with the value of C and C to execute or undo a command, respectively. For C and C, the same set of arguments are passed. =head2 Requirements Function MUST check special argument C<-undo_action> before it checks other arguments. Function MUST at least support the following undo action: C, C. On unsupported/unknown undo action, function MUST return status 400, with message like "Unsupported undo action". If C<-undo_action> is not set, it means caller does not care about undo. Undoable function should execute as any normal function. =head2 Performing 'do' To indicate that we need undo, we call function by passing special argument C<-undo_action> with the value of C. Function should perform its operation and save undo data along the way. If C<-undo_action> is not passed or false/undef, function should assume that caller does not need undo later, so function need not save any undo data. After completing operation successfully, function should return status 200, the result, and undo data. Undo data is returned in the result metadata (the fourth element of result envelope), example: [200, "OK", $result, {undo_data=>$undo_data}] Undo data should be serializable so it is easy to be made persistent if necessary (e.g. by some undo/transaction manager). =head2 Performing 'undo' To perform an undo, caller must call the function again with the same previous arguments, except C<-undo_action> should be set to C and C<-undo_data> set to undo data previously given by the function. Function should perform the undo operation using the undo data. Upon success, it must return status 200, the result, and an undo data (in other words, redo data, since it can be used to undo the undo operation). =head2 Performing 'redo' To perform redo, caller can call the function again with <-undo_action> set to C and C<-undo_data> set to the redo data given in the undo step. Or, alternatively, caller can just perform a normal do (see above). An example: $SPEC{setenv} = { v => 1.1, summary => 'Set environment variable', args => { name => {req=>1, schema=>'str*'}, value => {req=>1, schema=>'str*'}, }, features => {undo=>1}, }; sub setenv { my %args = @_; my $name = $args{name}; my $value = $args{value}; my $undo_action = $args{-undo_action} // ''; my $undo_data = $args{-undo_data}; my $old; if ($undo_action) { # save original value and existence state $old = [exists($ENV{$name}), $ENV{$name}]; } if ($undo_action eq 'undo') { if ($undo_data->[0]) { $ENV{$name} = $undo_data->[1]; } else { delete $ENV{$name}; } } else { $ENV{$name} = $value; } [200, "OK", undef, $undo_action ? {undo_data=>$old} : {}]; } The above example declares an undoable command C to set an environment variable (C<%ENV>). To perform command: my $res = setenv(name=>"DEBUG", value=>1, -undo_action=>"do"); die "Failed: $res->[0] - $res->[1]" unless $res->[0] == 200; my $undo_data = $res->[3]{undo_data}; To perform undo: $res = setenv(name=>"DEBUG", value=>1, -undo_action="undo", -undo_data=>$undo_data); die "Can't undo: $res->[0] - $res->[1]" unless $res->[0] == 200; After this undo, DEBUG environment variable will be set to original value. If it did not exist previously, it will be deleted. To perform redo: my $redo_data = $res->[3]{undo_data}; $res = setenv(name=>"DEBUG", value=>1, -undo_action="undo", -undo_data=>$redo_data); or you can just do: $res = setenv(name=>"DEBUG", value=>1, -undo_action="do"); =head2 Saving undo data in external storage Although the complete undo data can be returned by the function in the C result metadata property, sometimes it is more efficient to just return a pointer to said undo data, while saving the actual undo data in some external storage. For example, if a function deletes a big file and wants to save undo data, it is more efficient to move the file to trash directory and return its path as the undo data, instead of reading the whole file content and its metadata to memory and return it in C result metadata. Functions which require undo trash directory should specify this in its metadata, through the C dependency clause. For example: deps => { ... trash_dir => 1, } When calling function, caller needs to provide path to undo trash directory via special argument C<-trash_dir>, for example: -trash_dir => "/home/.trash/2fe2f4ad-a494-0044-b2e0-94b2b338056e" =head2 What about non-undoable actions? Like in real life, not all actions are undoable. Examples of undoable/irreversible actions include wiping a file/directory (more generally speaking, any action to permanently delete/destroy something, without backing up the data first), sending an email (more generally speaking, any action that is sent to an external entity beyond our control, unless that external entity provides a way to undo the action). An undoable function MUST NOT mix undoable and non-undoable actions. For example: safe_delete(file=>'/path/to/file'); # puts file into Trash, undoable action safe_delete(file=>'/path/to/file', permanent=>1); # deletes file, non-undoable The C function above mixes undoable action (putting a file into Trash directory) and non-undoable action (permanently deleting a file without putting it in Trash). Without domain knowledge of the function, a caller cannot know whether a call will be undoable or not. This will also prevent the function from participating in a transaction, because transaction requires function call to always be undoable, for rollback purpose. The solution is to separate non-undoable action in another function, for example: trash(file=>'/path/to/file'); # undoable, can execute inside transaction delete(file=>'/path/to/file'); # non-undoable, executes outside transaction empty_trash(); # non-undoable, executes outside transaction The non-undoable function is also non-transactional (it operates outside the scope of a transaction). But it can still be idempotent. And it can manipulate the transactions if it needs too. In the example, the empty_trash() function instructs the transaction manager to discard the trash() transactions, since after the trash is emptied, the trash() transactions cannot be undone anyway. =head1 SEE ALSO Related specifications: L =head1 HOMEPAGE Please visit the project's homepage at L. =head1 SOURCE Source repository is at L. =head1 BUGS Please report any bugs or feature requests on the bugtracker website L When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 AUTHOR perlancar =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2015 by perlancar@cpan.org. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Rinci-1.1.78/lib/Rinci/resmeta.pod0000644000175000017500000001373712571643014014300 0ustar s1s1package Rinci::resmeta; # just to make PodWeaver happy # DATE # VERSION 1; # ABSTRACT: Function/method result metadata __END__ =pod =encoding UTF-8 =head1 NAME Rinci::resmeta - Function/method result metadata =head1 VERSION This document describes version 1.1.78 of Rinci::resmeta (from Perl distribution Rinci), released on 2015-09-03. =head1 SPECIFICATION VERSION 1.1 =head1 INTRODUCTION This document describes metadata for function/method result. This specification is part of L. Please do a read up on it first, if you have not already done so. =head1 SPECIFICATION There are currently several properties being used: =head2 Property: undo_data => ANY (DEPRECATED) Explained in C feature section in L. =head2 Property: perm_err => bool Indicate that error is permanent (instead of temporary/transient). This is to provide a feature like that found in SMTP/POP protocol, where 4xx codes indicate transient errors and 5xx permanent ones. =head2 Properties: func.* => ANY These properties allow function to return extra stuffs. Usually done to avoid breaking format of existing result (to maintain API compatibility). The attributes after C is up to the respective function. An example is the C function in the L Perl module. The function returns C<$args> but from v0.26 it also wants to give hints about whether or not there are missing arguments. It can do this via C result metadata. =head2 Properties: cmdline.* Interpreted by L. See its documentation for more detail. =head2 Property: logs => ARRAY OF HASH Store log of events happening to this result, stored chronologically (older first). Each log should be a hash which should have at least the following keys: C