File Coverage

lib/Synapse/CLI/Config.pm
Criterion Covered Total %
statement 44 57 77.1
branch 7 20 35.0
condition 4 9 44.4
subroutine 9 9 100.0
pod 5 5 100.0
total 69 100 69.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Synapse::CLI::Config - configure and manage your application objects in a terminal
4              
5              
6             =head1 About Synapse's Open Telephony Toolkit
7              
8             L is a part of Synapse's Wholesale Open Telephony
9             Toolkit.
10              
11             As we are refactoring our codebase, we at Synapse have decided to release a
12             substantial portion of our code under the GPL. We hope that as a developer, you
13             will find it as useful as we have found open source and CPAN to be of use to
14             us.
15              
16              
17             =head1 What is L all about
18              
19             We strongly believe that prior to building graphical front ends, it is
20             necessary to build a robust and reliable command line interface in order to
21             configure software packages.
22              
23             The goal of this module is to provide something that will allow you to interact
24             with your application objects and classes using the command line, and make
25             object changes persistent on disk.
26              
27              
28             =head1 SYNOPSIS
29              
30             Say you create a MyAPP::User object.
31              
32              
33             =head2 Step 1
34              
35             Make MyAPP::User inherit from L:
36              
37             use base qw /Synapse::CLI::Config::Object/;
38              
39             Doing this means that your class will inherit L methods.
40              
41              
42             =head2 Step 2
43              
44             Write your own methods, for example in MyAPP::User, these could be something in
45             the lines of:
46              
47             sub password {
48             my $self = shift;
49             @_ and $self->{password} = shift;
50             return $self->{password};
51             }
52            
53             sub email {
54             my $self = shift;
55             @_ and $self->{email} = shift;
56             return $self->{email};
57             }
58              
59              
60             Create a simple script, say myapp-cli, which declares aliases for your objects
61             and calls the Synapse::CLI::Config::execute() method.
62              
63             #!/usr/bin/perl
64             # this is myapp-cli. It should be installed in /usr/local/bin/myapp-cli
65             use Synapse::CLI::Config;
66             use YAML::XS;
67             use warning;
68             use strict;
69             $Synapse::CLI::Config::BASE_DIR = "/etc/myapp";
70             $Synapse::CLI::Config::ALIAS->{type} = 'Synapse::CLI::Config::Type';
71             $Synapse::CLI::Config::ALIAS->{user} = 'MyAPP::User';
72             print Dump (Synapse::CLI::Config::execute (@ARGV));
73              
74              
75             =head2 Step 3, congrats, you've built your own CLI interface!
76              
77             Now let's create a user and use these fancy methods.
78              
79             # create user 'foo' with label 'Foo Bar'
80             myapp-cli type user create foo "Foo Bar"
81            
82             # change password and email
83             myapp-cli user foo email example@example.com
84             myapp-cli user foo password "very hard to remember"
85            
86             # view result
87             myapp-cli user foo show
88            
89             # rename foo
90             myapp-cli user foo rename bar
91            
92             # get rid of it now
93             myapp-cli user bar remove
94            
95              
96             =head1 API
97              
98             =cut
99             package Synapse::CLI::Config;
100 4     4   319282 use YAML::XS;
  4         17478  
  4         395  
101 4     4   35 use warnings;
  4         8  
  4         105  
102 4     4   26 use strict;
  4         34  
  4         3826  
103              
104              
105             =head2 GLOBALS
106              
107             =over 4
108              
109             =item $Synapse::CLI::Config::VERSION - library version number
110              
111             =item $Synapse::CLI::Config::BASE_DIR - points to the directory where object
112             configuration files live.
113              
114             =item $Synapse::CLI::Config::ALIAS - alias => package name mapping.
115              
116             =item @Synapse::CLI::Config::BUFFER - where execute() commands are logged prior to
117             flushing() everything to disk.
118              
119             =back
120              
121             =cut
122             our $VERSION = 0.1;
123             our $BASE_DIR = $ENV{CLI_CONFIG_BASEDIR} || "/etc/cli-config";
124             our $ALIAS = {
125             type => 'Synapse::CLI::Config::Type',
126             };
127              
128              
129              
130             =head2 Synapse::CLI::Config::base_dir()
131              
132             Returns $BASE_DIR
133              
134             =cut
135             sub base_dir {
136 19     19 1 91 return $BASE_DIR;
137             }
138              
139              
140              
141             =head2 Synapse::CLI::Config::debug($msg)
142              
143             Debug hook. Sends messages to STDERR.
144              
145             =cut
146             sub debug($) {
147 1     1 1 2 my $msg = shift;
148 1         13 print STDERR ' -- ';
149 1         5 print STDERR scalar gmtime;
150 1         2 print STDERR ' -- ';
151 1         12 print STDERR $msg;
152 1         11 print STDERR "\n";
153             }
154              
155              
156             =head2 Synapse::CLI::Config::parse($file)
157              
158             Turns a YAML file into a Perl structure and returns it.
159              
160             =cut
161             sub parse {
162 1     1 1 2 my $file = shift;
163 1 0       18 -e $file || return;
164 1 0       7 open FILE, "<$file" or do {
165 1         2 debug ("cannot read open $file");
166 1         15 return;
167             };
168 0         0 my $yaml = join '', ;
169 0         0 close FILE;
170 0         0 return Load $yaml;
171             }
172              
173              
174             =head2 Synapse::CLI::Config::dump($file, $scalar)
175              
176             Turns Perl $scalar (which will most often be a reference) into a YAML file.
177              
178             =cut
179             sub dump {
180 0     1 1 0 my $file = shift;
181 0         0 my $obj = shift;
182 0 0       0 -e $file || return;
183 0 0       0 open FILE, ">file" or do {
184 0         0 debug ("cannot write open $file");
185 0         0 return;
186             };
187 0         0 print FILE Dump $obj;
188 0         0 close FILE;
189             }
190              
191              
192             =head2 Synapse::CLI::Config::execute (@args)
193              
194             Executes command, and saves it in the corresponding file if object is changed.
195              
196             For instance:
197              
198             $Synapse::CLI::Config::ALIASES->{foo} = "My::Foo";
199             Synapse::CLI::Config::execute ("My::Foo", "bar", "baz");
200              
201             Is like saying:
202              
203             My::Foo->new ('bar')->baz();
204              
205             On the cli it should look like this:
206              
207             myapp-cli foo bar baz
208              
209             =cut
210             sub execute {
211 9   50 9 1 2439 my $type = shift || die "usage: $0 arg1 ... argN";
212            
213 9   33     51 my $package = $Synapse::CLI::Config::ALIAS->{$type} || $type;
214 9     2   1163 eval "use $package";
  2         33  
  2         4  
  2         29  
215            
216 9         24 my $name = shift;
217 9 50       29 defined $name || die "object name unspecified";
218            
219 9   50     40 my $object = $package->new ($name) || die "$name does not exist";
220 9   50     30 my $method = shift || die "method unspecified";
221 9         26 $method =~ s/-/_/g;
222 9 50       37 $object->can ($method) || die "no such method";
223            
224 9         683 my $before = YAML::XS::Dump ($object);
225 9         28 my $res;
226 9         15 eval { $res = $object->$method (@_) };
  9         142  
227 9 50       35 $@ and die $@;
228 9         294 my $after = YAML::XS::Dump ($object);
229            
230 9         32 my $FORCE_SAVE = $method . "_FORCE_SAVE";
231 9         16 my $FORCE_NOSAVE = $method . "_FORCE_NOSAVE";
232            
233             # if $object->method_FORCE_SAVE() exists, always logs
234 9 50       58 if ($object->can ($FORCE_SAVE)) {
    100          
235 0         0 $object->__save__ ($method => @_);
236             }
237            
238             # if $object->method_FORCE_NOSAVE() exists, never logs
239             elsif ($object->can ($FORCE_NOSAVE)) {
240             }
241            
242             # otherwise, logs only if object has changed
243             else {
244 8 50       25 $before ne $after and do { $object->__save__ ($method => @_) }
  0         0  
245             }
246            
247 9         53 return $res;
248             }
249              
250              
251             1;
252              
253              
254             __END__