LimeLexerTransformAnnotations.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <?php
  2. /*
  3. * This file is part of the Lime test framework.
  4. *
  5. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  6. * (c) Bernhard Schussek <bernhard.schussek@symfony-project.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. /**
  12. * Transforms annotated code in a file into functions.
  13. *
  14. * The created function names are returned by the function parse(), indexed
  15. * by annotation name.
  16. *
  17. * <code>
  18. * $lexer = new LimeLexerTransformAnnotations('path/to/transformed/file.php', array('First', 'Second'));
  19. * $functions = $lexer->parse('/path/to/original/file.php');
  20. *
  21. * // => array('First' => array(...), 'Second' => array(...))
  22. * </code>
  23. *
  24. * The annotated source file for the above code could look like this:
  25. *
  26. * <code>
  27. * $test = 'nothing';
  28. *
  29. * // @First
  30. * $test = 'First';
  31. *
  32. * // @Second
  33. * $test = 'Second';
  34. *
  35. * // @First
  36. * echo $test;
  37. * </code>
  38. *
  39. * You can include the transformed file and execute a certain subset of
  40. * annotations:
  41. *
  42. * <code>
  43. * include 'path/to/transformed/file.php';
  44. *
  45. * foreach ($functions['First'] as $function)
  46. * {
  47. * $function();
  48. * }
  49. *
  50. * // => First
  51. * </code>
  52. *
  53. * @package Lime
  54. * @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
  55. * @version SVN: $Id: LimeLexerTransformAnnotations.php 23701 2009-11-08 21:23:40Z bschussek $
  56. * @see LimeLexerAnnotationAware
  57. */
  58. class LimeLexerTransformAnnotations extends LimeLexerAnnotationAware
  59. {
  60. protected static
  61. $annotations = array('Test', 'Before', 'After', 'BeforeAll', 'AfterAll');
  62. protected
  63. $fileName,
  64. $file,
  65. $variables,
  66. $functions,
  67. $functionCount,
  68. $initialized,
  69. $testVariable,
  70. $classBuffer,
  71. $classNotLoaded,
  72. $firstAnnotation;
  73. /**
  74. * Constructor.
  75. *
  76. * @param string $targetFile The file where the transformed code
  77. * will be written.
  78. * @param array $allowedAnnotations The allowed annotations.
  79. */
  80. public function __construct($targetFile)
  81. {
  82. parent::__construct(self::$annotations);
  83. $this->fileName = $targetFile;
  84. }
  85. /**
  86. * Transforms the annoated code in the given file and writes it to the
  87. * target file.
  88. *
  89. * @see LimeLexer#parse($content)
  90. */
  91. public function parse($content)
  92. {
  93. if (is_readable($content))
  94. {
  95. $content = file_get_contents($content);
  96. }
  97. $lexer = new LimeLexerVariables($this->getAllowedAnnotations(), array('Before'));
  98. $this->variables = $lexer->parse($content);
  99. $lexer = new LimeLexerTestVariable();
  100. $this->testVariable = $lexer->parse($content);
  101. $this->initialized = false;
  102. $this->functionCount = 0;
  103. $this->functions = array();
  104. $this->classBuffer = '';
  105. $this->classNotLoaded = false;
  106. $this->firstAnnotation = true;
  107. foreach ($this->getAllowedAnnotations() as $annotation)
  108. {
  109. $this->functions[$annotation] = array();
  110. }
  111. // backup the contents for the case that the path == filename
  112. $this->file = fopen($this->fileName, 'w');
  113. $result = parent::parse($content);
  114. if ($this->inAnnotation())
  115. {
  116. fwrite($this->file, "\n}");
  117. }
  118. fclose($this->file);
  119. return $result;
  120. }
  121. /**
  122. * Returns the name of the first global variable that contains an instance
  123. * of LimeTest or any subclass.
  124. *
  125. * If no such variable could be detected, NULL is returned.
  126. *
  127. * @return string
  128. */
  129. public function getTestVariable()
  130. {
  131. return $this->testVariable;
  132. }
  133. /**
  134. * (non-PHPdoc)
  135. * @see LimeLexer#process($text, $id)
  136. */
  137. protected function process($text, $id)
  138. {
  139. if (!$this->inClassDeclaration())
  140. {
  141. $this->classBuffer = '';
  142. }
  143. if (!$this->inClass())
  144. {
  145. $this->classNotLoaded = false;
  146. }
  147. // Some classes are automatically loaded when the script is opened, others
  148. // are not. These other classes need to be left in the source code,
  149. // otherwise they cannot be instantiated later.
  150. // This functionality is covered in LimeAnnotationSupportTest 11+12
  151. if ($this->inClassDeclaration())
  152. {
  153. if ($this->getCurrentClass() && !class_exists($this->getCurrentClass()) && !interface_exists($this->getCurrentClass()))
  154. {
  155. $this->classNotLoaded = true;
  156. $text = $this->classBuffer.$text;
  157. $this->classBuffer = '';
  158. }
  159. else
  160. {
  161. $this->classBuffer .= $text;
  162. }
  163. }
  164. if ($id == T_OPEN_TAG && !$this->initialized)
  165. {
  166. if (count($this->variables))
  167. {
  168. $text .= 'global '.implode(', ', $this->variables).';';
  169. }
  170. $this->initialized = true;
  171. }
  172. else if ($this->inClass() && $this->classNotLoaded)
  173. {
  174. // just print
  175. }
  176. else if ($this->inClass() || $this->inFunction())
  177. {
  178. $text = str_repeat("\n", count(explode("\n", $text)) - 1);
  179. }
  180. else if ($this->inAnnotationDeclaration())
  181. {
  182. $functionName = '__lime_annotation_'.($this->functionCount++);
  183. $this->functions[$this->getCurrentAnnotation()][] = array($functionName, $this->getCurrentAnnotationComment());
  184. $text = $this->firstAnnotation ? '' : '} ';
  185. $this->firstAnnotation = false;
  186. $variables = count($this->variables) ? sprintf('global %s;', implode(', ', $this->variables)) : '';
  187. $text .= sprintf("function %s() { %s\n", $functionName, $variables);
  188. }
  189. fwrite($this->file, $text);
  190. }
  191. /**
  192. * (non-PHPdoc)
  193. * @see LimeLexer#getResult()
  194. */
  195. protected function getResult()
  196. {
  197. return $this->functions;
  198. }
  199. }