File Coverage

blib/lib/Dancer2/Plugin/Sixpack.pm
Criterion Covered Total %
statement 52 52 100.0
branch 11 16 68.7
condition 7 10 70.0
subroutine 9 9 100.0
pod 1 1 100.0
total 80 88 90.9


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::Sixpack;
2              
3 2     2   1048748 use 5.006;
  2         12  
  2         102  
4 2     2   11 use strict;
  2         4  
  2         82  
5 2     2   11 use warnings FATAL => 'all';
  2         8  
  2         94  
6              
7 2     2   1416 use Dancer2;
  2         1024579  
  2         14  
8 2     2   170616 use Dancer2::Plugin;
  2         8003  
  2         16  
9 2     2   22476 use WWW::Sixpack;
  2         172638  
  2         3520  
10              
11             our $VERSION = '0.02';
12              
13             my $conf;
14              
15             =head1 NAME
16              
17             Dancer2::Plugin::Sixpack - Dancer2's plugin for WWW::Sixpack
18              
19             =head1 DESCRIPTION
20              
21             This plugin gives you the ability to do A/B testing within Dancer2 easily,
22             using L.
23              
24             It handles the client_id transparantly through Dancer2's Session plugin.
25              
26             =head1 SYNOPSIS
27              
28             use Dancer2;
29             use Dancer2::Plugin::Sixpack;
30              
31             get '/route' => sub {
32             my $variant = experiment 'decimal_dot_comma', [ 'comma', 'dot' ];
33              
34             $price =~ s/\.(?=[0-9]{2})$/,/
35             if( $variant eq 'comma' );
36             # ...
37             };
38              
39             get '/some_click' => sub {
40             convert 'decimal_dot_comma', 'click';
41             redirect $somewhere;
42             };
43              
44             get '/confirmation' => sub {
45             convert 'decimal_dot_comma';
46             # ...
47             };
48              
49              
50             =head1 CONFIGURATION
51              
52             There are no mandatory settings.
53              
54             plugins:
55             Sixpack:
56             host: http://localhost:5000
57             experiments:
58             decimal_dot_comma:
59             - comma
60             - dot
61             beer:
62             - duvel
63             - budweiser
64              
65             The experiments can be generated on the fly without defining them. See below
66             for more information.
67              
68             =head1 KEYWORDS
69              
70             =head2 experiment
71              
72             Fetch the alternative used for the experiment name passed in.
73              
74             The experiment and its' alternatives may be defined in the configuration. If
75             they're not defined, the experiment will be created (if you provided the
76             alternatives arrayref).
77              
78             Examples:
79              
80             # experiment defined in config:
81             my $variant = exeriment 'known-experiment';
82              
83             # experiment not defined
84             my $variant = experiment 'on-the-fly', [ 'alt-1', 'alt-2' ];
85              
86             The client_id will be fetched from session, or generated if needed.
87              
88             The client's IP address and user agent string are automatically
89             added to the request for bot detection.
90              
91             Alternatives can be forced by params like "sixpack-force-$experiment=$alt"
92              
93             Returns the alternative name chosen.
94              
95             =cut
96              
97             register experiment => sub {
98 2     2   210101 my ($dsl, $name, $alternatives) = @_;
99              
100 2         22 my $sixpack = $dsl->get_sixpack();
101              
102             # stored alternatives?
103 2 100 66     2168 if( !$alternatives && defined $conf->{experiments}{$name} ) {
104 1         3 $alternatives = $conf->{experiments}{$name};
105             }
106              
107             # user info
108 2         6 my %options = ();
109 2 50       34 $options{ip_address} = $dsl->request->address
110             if $dsl->request->address;
111 2 50       39 $options{user_agent} = $dsl->request->agent
112             if $dsl->request->agent;
113              
114             # force if requested
115 2 50       2070 $options{force} = $dsl->param("sixpack-force-$name")
116             if $dsl->param("sixpack-force-$name");
117              
118 2         111 my $alt = $sixpack
119             ->participate( $name, $alternatives, \%options );
120              
121 2   100     19009 my $experiments = $dsl->session('sixpack_experiments') || { };
122 2         929 $experiments->{$name} = $alt->{alternative}{name};
123              
124 2         9 $dsl->session->write('sixpack_id', $alt->{client_id});
125 2         40139 $dsl->session->write('sixpack_experiments', $experiments);
126              
127 2         1521 return $alt->{alternative}{name};
128             };
129              
130             =head2 convert
131              
132             Convert a user.
133              
134             Provide the experiment and (optional) a KPI to track conversion on.
135             If the KPI doesn't exist yet, it will be created.
136              
137             When no experiment name is given, we try to fetch the experiments
138             from the user's session and convert on all of the found experiments.
139              
140             Returns a hashref with { 'experiment' => 'status' }
141              
142             =cut
143              
144             register convert => sub {
145 2     2   36019 my ($dsl, $experiment, $kpi) = @_;
146              
147 2         4 my %return;
148 2         9 my $sixpack = $dsl->get_sixpack();
149              
150 2 100       1878 if( $experiment ) {
151             # specific experiment given
152 1         8 my $res = $sixpack->convert($experiment, $kpi);
153 1         1527 $return{$experiment} = $res->{status};
154             } else {
155             # no experiments given, look them up
156 1   50     5 my $experiments = $dsl->session('sixpack_experiments') || { };
157 1         665 for my $exp (keys %{$experiments}) {
  1         6  
158 2         9 my $res = $sixpack->convert($exp);
159 2         2567 $return{$exp} = $res->{status};
160             }
161             }
162              
163 2         20 return \%return;
164             };
165              
166             =head2 get_sixpack
167              
168             Internal method to construct the L object.
169              
170             =cut
171              
172             sub get_sixpack {
173 4     4 1 9 my $dsl = shift;
174              
175 4   66     23 $conf ||= plugin_setting();
176              
177 4         135 my %options;
178 4         33 my $client_id = $dsl->session('sixpack_id');
179              
180             # need to pass info on to the sixpack object?
181 4 50       7858 $options{host} = $conf->{host} if( defined $conf->{host} );
182 4 100       22 $options{client_id} = $client_id if( defined $client_id );
183 4 50       23 $options{ua} = $conf->{ua} if( defined $conf->{ua} );
184              
185 4         43 return WWW::Sixpack->new(%options);
186             }
187              
188             =head1 AUTHOR
189              
190             Menno Blom, C<< >>
191              
192             =head1 BUGS
193              
194             Please report any bugs or feature requests to C, or through
195             the web interface at L. I will be notified, and then you'll
196             automatically be notified of progress on your bug as I make changes.
197              
198             =head1 LICENSE AND COPYRIGHT
199              
200             Copyright 2013 Menno Blom.
201              
202             This program is free software; you can redistribute it and/or modify it
203             under the terms of either: the GNU General Public License as published
204             by the Free Software Foundation; or the Artistic License.
205              
206             See L for more information.
207              
208             =cut
209              
210             register_plugin for_versions => [ 2 ] ;
211              
212             1; # End of Dancer2::Plugin::Sixpack