File Coverage

blib/lib/Global/Context.pm
Criterion Covered Total %
statement 45 45 100.0
branch 10 12 83.3
condition n/a
subroutine 14 14 100.0
pod 3 3 100.0
total 72 74 97.3


line stmt bran cond sub pod time code
1 3     3   28402 use strict;
  3         7  
  3         90  
2 3     3   13 use warnings;
  3         5  
  3         130  
3             package Global::Context;
4             {
5             $Global::Context::VERSION = '0.003';
6             }
7             # ABSTRACT: track the global execution context of your code
8              
9 3     3   14 use Carp ();
  3         5  
  3         40  
10 3     3   1807 use Global::Context::Env::Basic;
  3         9  
  3         127  
11 3     3   2069 use Global::Context::StackFrame::Basic;
  3         12  
  3         111  
12 3     3   2686 use Sub::Exporter::GlobExporter ();
  3         2500  
  3         146  
13              
14              
15 3         16 use Sub::Exporter -setup => {
16             exports => [
17             ctx_init => \'_build_ctx_init',
18             ctx_push => \'_build_ctx_push',
19             ],
20             collectors => {
21             '$Context' => Sub::Exporter::GlobExporter::glob_exporter(
22             Context => \'common_globref',
23             )
24             },
25 3     3   17 };
  3         5  
26              
27              
28 4     4 1 519 sub common_globref { \*Object }
29              
30              
31 1     1 1 14 sub default_context_class { 'Global::Context::Env::Basic' }
32 4     4 1 1755 sub default_frame_class { 'Global::Context::StackFrame::Basic' }
33              
34             sub _build_ctx_init {
35 2     2   312 my ($class, $name, $arg, $col) = @_;
36              
37 2 50       12 Carp::croak("can't import $name without importing \$Context")
38             unless $col->{'$Context'};
39              
40             return sub {
41 2     2   2867 my ($arg) = @_;
42              
43 2         3 my $ref = *{ $col->{'$Context'} }{SCALAR};
  2         9  
44 2 100       201 Carp::confess("context has already been initialized") if $$ref;
45              
46 1         9 $$ref = $class->default_context_class->new($arg)->with_pushed_frame(
47             $class->default_frame_class->new({
48             description => Carp::shortmess("context initialized"),
49             ephemeral => 1,
50             }),
51             );
52              
53 1         3436 return $$ref;
54 2         12 };
55             }
56              
57             sub _build_ctx_push {
58 2     2   44 my ($class, $name, $arg, $col) = @_;
59              
60 2 50       9 Carp::croak("can't import $name without importing \$Context")
61             unless $col->{'$Context'};
62              
63             return sub {
64 5     5   4661 my ($frame) = @_;
65              
66 5         263 Carp::croak("Can't push frame onto uninitialized context")
67 5 100       9 unless defined ${ *{ $col->{'$Context'} }{SCALAR} };
  5         10  
68              
69 4 100       14 $frame = { description => $frame } unless ref $frame;
70              
71 4 100       24 $frame = $class->default_frame_class->new($frame)
72             unless Scalar::Util::blessed($frame);
73              
74 4         2640 return ${ *{ $col->{'$Context'} }{SCALAR} }->with_pushed_frame($frame);
  4         6  
  4         22  
75             }
76 2         10 }
77              
78             1;
79              
80             __END__
81              
82             =pod
83              
84             =head1 NAME
85              
86             Global::Context - track the global execution context of your code
87              
88             =head1 VERSION
89              
90             version 0.003
91              
92             =head1 OVERVIEW
93              
94             B<WARNING!> This code is B<very> young and experimental. Its interface may
95             change drastically as it is proven.
96              
97             Global::Context is a system for tracking the context under which a program is
98             currently running. It establishes a globally-accessible object that tracks the
99             current user, authentication information, request originator, and execution
100             stack.
101              
102             This object can be replaced locally (within dynamic scopes) to affect pushes
103             and pops against is stack, but is otherwise meant to be immutable once created.
104              
105             use Global::Context -all, '$Context';
106              
107             ctx_init({
108             terminal => Global::Context::Terminal::Basic->new({ uri => 'ip://1.2.3.4' }),
109             auth_token => Global::Context::AuthToken::Basic->new({
110             uri => 'websession://1234',
111             agent => 'customer://abcdef',
112             }),
113             });
114              
115             sub eat_pie {
116             my ($self) = @_;
117              
118             local $Context = ctx_push("eating pie");
119            
120             ...;
121             }
122              
123             eat_pie;
124              
125             =head2 Exports
126              
127             If C<$Context> is requested as an import, a package variable is added, aliasing
128             a shared global. It can be localized as needed, affecting the global value.
129             This feature is provided by L<Sub::Exporter::GlobExporter>.
130              
131             The shared globref is provided by the C<common_globref> method, which can
132             return a different globref in other subclasses to allow multiple global
133             contexts to exist in one interpreter.
134              
135             The C<ctx_init> and C<ctx_push> routines are exported by request or as part of
136             the C<-all> group.
137              
138             C<ctx_init> takes the same arguments as the constructor for the default context
139             class (by default L<Global::Context::Env::Basic>) and sets up the initial
140             environment. If C<ctx_init> is called after the environment has already been
141             configured, it is fatal.
142              
143             C<ctx_push> takes either a stack frame (something that does
144             L<Global::Context::StackFrame>), the arguments to a construct a new
145             Global::Context::StackFrame::Basic, or a stack frame description. It returns a
146             new global context object, just like the current but with an extra stack frame.
147             It's meant to be called like this:
148              
149             {
150             local $Context = ctx_push("preferences subsystem");
151              
152             ...
153             }
154              
155             =head1 METHODS
156              
157             =head2 common_globref
158              
159             This returns the globref in which the context object is stored. This method
160             can be replaced in subclasses to allow multiple global contexts to operate in
161             one program.
162              
163             =head2 default_context_class
164              
165             =head2 default_frame_class
166              
167             These methods name the default classes for new context objects and stack
168             frames. They default to Global::Context::Env::Basic and
169             Global::Context::StackFrame::Basic, by default.
170              
171             =head1 AUTHOR
172              
173             Ricardo Signes <rjbs@cpan.org>
174              
175             =head1 COPYRIGHT AND LICENSE
176              
177             This software is copyright (c) 2010 by Ricardo Signes.
178              
179             This is free software; you can redistribute it and/or modify it under
180             the same terms as the Perl 5 programming language system itself.
181              
182             =cut