File Coverage

lib/Function/Version.pm
Criterion Covered Total %
statement 37 37 100.0
branch 12 12 100.0
condition n/a
subroutine 11 11 100.0
pod 0 5 0.0
total 60 65 92.3


line stmt bran cond sub pod time code
1             package Function::Version;
2             # Define and use different function versions
3 1     1   75850 use strict; use warnings; use utf8; use 5.10.0;
  1     1   2  
  1     1   28  
  1     1   5  
  1         2  
  1         25  
  1         5  
  1         1  
  1         7  
  1         38  
  1         4  
4             our $VERSION = '0.0001';
5 1     1   7 use Carp;
  1         2  
  1         521  
6              
7             # 2D Dispatch table
8             my $DISPATCH = {};
9              
10             ## CLASS CONSTRUCTORS
11             sub def {
12 18     18 0 6104 my ($class,$fname,$ver,$sub) = @_;
13              
14             # Create dispatch with $fname as key if needed
15             $DISPATCH->{$fname} = {}
16 18 100       43 unless exists $DISPATCH->{$fname};
17              
18             # Store the sub into the dispatch table
19 18         55 $DISPATCH->{$fname}{$ver} = $sub;
20              
21 18         64 return $class;
22             }
23              
24 7     7 0 19 sub new { bless _init(@_[1..$#_]), $_[0] }
25             sub _init {
26             return {
27 7     7   27 ver => undef, # Selected version
28             fname => undef, # Selected function
29             dispatch => $DISPATCH # 2D Dispatch Table
30             }
31             }
32             sub ver {
33 7     7 0 32 my ($self,$ver) = @_;
34              
35             # Guard: Caller should be an object
36 7 100       102 croak "Error. You have not selected a function."
37             unless ref $self eq 'Function::Version';
38              
39 6         9 my ($fname) = ($self->{fname});
40              
41             # Guard: The selected version of the function must be defined
42             croak "Error. Version '$ver' of '$fname' not in definition."
43 6 100       84 unless exists $self->{dispatch}{$fname}{$ver};
44              
45 5         7 $self->{ver} = $ver;
46 5         11 return $self;
47             }
48             sub func {
49 8     8 0 23 my ($self,$fname) = @_;
50              
51 8 100       17 if ($self eq 'Function::Version') {
52 7         14 $self = Function::Version->new; # Convert the class into an object
53             } else {
54 1         93 croak "Error: Assigned to '".$self->{fname}."' already.";
55             }
56              
57             # Guard: Selected function must be defined
58             croak "Error. Selected function '$fname' not in definition."
59 7 100       109 unless exists $self->{dispatch}{$fname};
60              
61 6         9 $self->{fname} = $fname;
62 6         19 return $self;
63             }
64             sub with {
65 4     4 0 16 my ($self,@args) = @_;
66              
67             # Guard: Caller should be an object
68 4 100       202 croak "Error. You have not selected a function."
69             unless ref $self eq 'Function::Version';
70              
71 3         6 my ($fname,$ver) = ($self->{fname},$self->{ver});
72              
73 3         9 $self->{dispatch}{$fname}{$ver}(@args);
74             }
75              
76             1;
77              
78             =encoding utf-8
79             =cut
80             =head1 NAME
81              
82             Function::Version - Define and use different function versions
83              
84             =cut
85             =head1 SYNOPSIS
86              
87             use Function::Version;
88              
89             # Define two versions of load() and dump()
90             my $defn = Function::Version
91             ->def('load', '1.5', sub { "load v1.5: $_[0]" })
92             ->def('load', '1.6', sub { "load v1.6: $_[0]" })
93             ->def('dump', '1.5', sub { "dump v1.5: $_[0]" })
94             ->def('dump', '1.6', sub { "dump v1.6: $_[0]" })
95             ;
96              
97             my $load = $defn->func('load') # Select load() v1.5
98             ->ver('1.5');
99             my $dump = $defn->func('dump') # Select dump() v1.6
100             ->ver('1.6');
101              
102             # Call with arguments
103             say $load->with('vista'); # load v1.5: vista
104             say $dump->with('gems'); # dump v1.6: gems
105              
106             say $load->ver('1.6') # Use other versions
107             ->with('hobbits'); # load v1.6: hobbits
108              
109             # Version does not revert
110             say $load->with('ring'); # load v1.6: ring
111              
112             say $dump->func('load') # Using other function dies
113             ->with('hobbits'); # Error: Assigned to dump()
114              
115             =cut
116             =head1 DESCRIPTION
117              
118             This module provides a simple way to define and use different function
119             versions.
120              
121             One use case is when deploying changes to an application. Being able to
122             select the function based on a version number is useful to roll-back or
123             roll-forward changes.
124              
125             =cut
126             =head1 AUTHOR
127              
128             Hoe Kit CHEW Ehoekit@gmail.comE
129              
130             =cut
131             =head1 COPYRIGHT
132              
133             Copyright 2021- Hoe Kit CHEW
134              
135             =cut
136             =head1 LICENSE
137              
138             This library is free software; you can redistribute it and/or modify
139             it under the same terms as Perl itself.
140              
141             =cut
142