initial commit
[namibia] / public / min / lib / MrClay / Cli / Arg.php
1 <?php
2
3 namespace MrClay\Cli;
4
5 use BadMethodCallException;
6
7 /**
8  * An argument for a CLI app. This specifies the argument, what values it expects and
9  * how it's treated during validation.
10  *
11  * By default, the argument will be assumed to be an optional letter flag with no value following.
12  *
13  * If the argument may receive a value, call mayHaveValue(). If there's whitespace after the
14  * flag, the value will be returned as true instead of the string.
15  *
16  * If the argument MUST be accompanied by a value, call mustHaveValue(). In this case, whitespace
17  * is permitted between the flag and its value.
18  *
19  * Use assertFile() or assertDir() to indicate that the argument must return a string value
20  * specifying a file or directory. During validation, the value will be resolved to a
21  * full file/dir path (not necessarily existing!) and the original value will be accessible
22  * via a "*.raw" key. E.g. $cli->values['f.raw']
23  *
24  * Use assertReadable()/assertWritable() to cause the validator to test the file/dir for
25  * read/write permissions respectively.
26  *
27  * @method \MrClay\Cli\Arg mayHaveValue() Assert that the argument, if present, may receive a string value
28  * @method \MrClay\Cli\Arg mustHaveValue() Assert that the argument, if present, must receive a string value
29  * @method \MrClay\Cli\Arg assertFile() Assert that the argument's value must specify a file
30  * @method \MrClay\Cli\Arg assertDir() Assert that the argument's value must specify a directory
31  * @method \MrClay\Cli\Arg assertReadable() Assert that the specified file/dir must be readable
32  * @method \MrClay\Cli\Arg assertWritable() Assert that the specified file/dir must be writable
33  *
34  * @property-read bool mayHaveValue
35  * @property-read bool mustHaveValue
36  * @property-read bool assertFile
37  * @property-read bool assertDir
38  * @property-read bool assertReadable
39  * @property-read bool assertWritable
40  * @property-read bool useAsInfile
41  * @property-read bool useAsOutfile
42  *
43  * @author Steve Clay <steve@mrclay.org>
44  * @license http://www.opensource.org/licenses/mit-license.php  MIT License
45  */
46 class Arg {
47     /**
48      * @return array
49      */
50     public function getDefaultSpec()
51     {
52         return array(
53             'mayHaveValue' => false,
54             'mustHaveValue' => false,
55             'assertFile' => false,
56             'assertDir' => false,
57             'assertReadable' => false,
58             'assertWritable' => false,
59             'useAsInfile' => false,
60             'useAsOutfile' => false,
61         );
62     }
63
64     /**
65      * @var array
66      */
67     protected $spec = array();
68
69     /**
70      * @var bool
71      */
72     protected $required = false;
73
74     /**
75      * @var string
76      */
77     protected $description = '';
78
79     /**
80      * @param bool $isRequired
81      */
82     public function __construct($isRequired = false)
83     {
84         $this->spec = $this->getDefaultSpec();
85         $this->required = (bool) $isRequired;
86         if ($isRequired) {
87             $this->spec['mustHaveValue'] = true;
88         }
89     }
90
91     /**
92      * Assert that the argument's value points to a writable file. When
93      * Cli::openOutput() is called, a write pointer to this file will
94      * be provided.
95      * @return Arg
96      */
97     public function useAsOutfile()
98     {
99         $this->spec['useAsOutfile'] = true;
100         return $this->assertFile()->assertWritable();
101     }
102
103     /**
104      * Assert that the argument's value points to a readable file. When
105      * Cli::openInput() is called, a read pointer to this file will
106      * be provided.
107      * @return Arg
108      */
109     public function useAsInfile()
110     {
111         $this->spec['useAsInfile'] = true;
112         return $this->assertFile()->assertReadable();
113     }
114
115     /**
116      * @return array
117      */
118     public function getSpec()
119     {
120         return $this->spec;
121     }
122
123     /**
124      * @param string $desc
125      * @return Arg
126      */
127     public function setDescription($desc)
128     {
129         $this->description = $desc;
130         return $this;
131     }
132
133     /**
134      * @return string
135      */
136     public function getDescription()
137     {
138         return $this->description;
139     }
140
141     /**
142      * @return bool
143      */
144     public function isRequired()
145     {
146         return $this->required;
147     }
148
149     /**
150      * Note: magic methods declared in class PHPDOC
151      *
152      * @param string $name
153      * @param array $args
154      * @return Arg
155      * @throws BadMethodCallException
156      */
157     public function __call($name, array $args = array())
158     {
159         if (array_key_exists($name, $this->spec)) {
160             $this->spec[$name] = true;
161             if ($name === 'assertFile' || $name === 'assertDir') {
162                 $this->spec['mustHaveValue'] = true;
163             }
164         } else {
165             throw new BadMethodCallException('Method does not exist');
166         }
167         return $this;
168     }
169
170     /**
171      * Note: magic properties declared in class PHPDOC
172      *
173      * @param string $name
174      * @return bool|null
175      */
176     public function __get($name)
177     {
178         if (array_key_exists($name, $this->spec)) {
179             return $this->spec[$name];
180         }
181         return null;
182     }
183 }