wproot 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -0
- data/bin/wproot +7 -0
- data/lib/wproot.rb +11 -0
- data/lib/wproot/cli.rb +35 -0
- data/lib/wproot/compass.rb +15 -0
- data/lib/wproot/haml.rb +15 -0
- data/lib/wproot/version.rb +3 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/wproot_spec.rb +59 -0
- data/vendor/HamlPHP.php +7 -0
- data/vendor/HamlPHP/.gitignore +6 -0
- data/vendor/HamlPHP/MIT-LICENSE +22 -0
- data/vendor/HamlPHP/README.mkd +39 -0
- data/vendor/HamlPHP/src/HamlPHP/CommentNode.php +92 -0
- data/vendor/HamlPHP/src/HamlPHP/Compiler.php +109 -0
- data/vendor/HamlPHP/src/HamlPHP/ContentEvaluator/ContentEvaluator.php +16 -0
- data/vendor/HamlPHP/src/HamlPHP/ContentEvaluator/DefaultContentEvaluator.php +22 -0
- data/vendor/HamlPHP/src/HamlPHP/DoctypeNode.php +47 -0
- data/vendor/HamlPHP/src/HamlPHP/Element.php +618 -0
- data/vendor/HamlPHP/src/HamlPHP/ElementNode.php +222 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/CssFilter.php +31 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/Filter.php +18 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/FilterContainer.php +34 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/JavascriptFilter.php +29 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/PhpFilter.php +24 -0
- data/vendor/HamlPHP/src/HamlPHP/Filter/PlainFilter.php +46 -0
- data/vendor/HamlPHP/src/HamlPHP/FilterNode.php +29 -0
- data/vendor/HamlPHP/src/HamlPHP/HamlNode.php +75 -0
- data/vendor/HamlPHP/src/HamlPHP/HamlPHP.php +191 -0
- data/vendor/HamlPHP/src/HamlPHP/Helpers.php +136 -0
- data/vendor/HamlPHP/src/HamlPHP/Interpolation.php +71 -0
- data/vendor/HamlPHP/src/HamlPHP/NodeFactory.php +80 -0
- data/vendor/HamlPHP/src/HamlPHP/RootNode.php +133 -0
- data/vendor/HamlPHP/src/HamlPHP/Storage/DontEvaluateStorage.php +68 -0
- data/vendor/HamlPHP/src/HamlPHP/Storage/FileStorage.php +74 -0
- data/vendor/HamlPHP/src/HamlPHP/Storage/Storage.php +24 -0
- data/vendor/HamlPHP/src/HamlPHP/TagNode.php +125 -0
- data/vendor/HamlPHP/src/HamlPHP/Util/BaseException.php +340 -0
- data/vendor/HamlPHP/src/HamlPHP/Util/BaseObject.php +94 -0
- data/vendor/HamlPHP/src/HamlPHP/Util/StringScanner.php +989 -0
- data/wproot.gemspec +21 -0
- metadata +126 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
<?php
|
2
|
+
|
3
|
+
require_once 'Storage/Storage.php';
|
4
|
+
require_once 'Compiler.php';
|
5
|
+
require_once 'ContentEvaluator/DefaultContentEvaluator.php';
|
6
|
+
|
7
|
+
class HamlPHP
|
8
|
+
{
|
9
|
+
private $_compiler = null;
|
10
|
+
private $_storage = null;
|
11
|
+
private $_contentEvaluator = null;
|
12
|
+
private $_nodeFactory = null;
|
13
|
+
private $_filterContainer = null;
|
14
|
+
private $_cacheEnabled = true;
|
15
|
+
|
16
|
+
// Placeholder until config gets properly implemented
|
17
|
+
public static $Config = array(
|
18
|
+
'escape_html' => false
|
19
|
+
);
|
20
|
+
|
21
|
+
public function __construct(Storage $storage)
|
22
|
+
{
|
23
|
+
$this->_compiler = $this->getCompiler();
|
24
|
+
$this->_storage = $storage;
|
25
|
+
|
26
|
+
if ($this->_storage instanceof ContentEvaluator) {
|
27
|
+
$this->setContentEvaluator($this->_storage);
|
28
|
+
} else {
|
29
|
+
$this->setContentEvaluator(new DefaultContentEvaluator());
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Sets a content evaluator.
|
35
|
+
*
|
36
|
+
* @param ContentEvaluator $contentEvaluator
|
37
|
+
*/
|
38
|
+
public function setContentEvaluator(ContentEvaluator $contentEvaluator)
|
39
|
+
{
|
40
|
+
$this->_contentEvaluator = $contentEvaluator;
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Sets a filter container and updates the node factory to use it.
|
45
|
+
*
|
46
|
+
* @param FilterContainer $container
|
47
|
+
*/
|
48
|
+
public function setFilterContainer(FilterContainer $container)
|
49
|
+
{
|
50
|
+
$this->_filterContainer = $container;
|
51
|
+
$this->getNodeFactory()->setFilterContainer($this->getFilterContainer());
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Returns a filter container object. Initializes the filter container with
|
56
|
+
* default filters if it's null.
|
57
|
+
*
|
58
|
+
* @return FilterContainer
|
59
|
+
*/
|
60
|
+
public function getFilterContainer()
|
61
|
+
{
|
62
|
+
if ($this->_filterContainer === null) {
|
63
|
+
$filterContainer = new FilterContainer();
|
64
|
+
$filterContainer->addFilter(new CssFilter());
|
65
|
+
$filterContainer->addFilter(new PlainFilter());
|
66
|
+
$filterContainer->addFilter(new JavascriptFilter());
|
67
|
+
$filterContainer->addFilter(new PhpFilter());
|
68
|
+
|
69
|
+
$this->_filterContainer = $filterContainer;
|
70
|
+
}
|
71
|
+
|
72
|
+
return $this->_filterContainer;
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* Sets a node factory.
|
77
|
+
*
|
78
|
+
* @param NodeFactory $factory
|
79
|
+
*/
|
80
|
+
public function setNodeFactory(NodeFactory $factory)
|
81
|
+
{
|
82
|
+
$this->_nodeFactory = $factory;
|
83
|
+
$this->getNodeFactory()->setFilterContainer($this->getFilterContainer());
|
84
|
+
}
|
85
|
+
|
86
|
+
/**
|
87
|
+
* Returns a node factory object.
|
88
|
+
*
|
89
|
+
* @return NodeFactory
|
90
|
+
*/
|
91
|
+
public function getNodeFactory()
|
92
|
+
{
|
93
|
+
if ($this->_nodeFactory === null) {
|
94
|
+
$this->setNodeFactory(new NodeFactory());
|
95
|
+
}
|
96
|
+
|
97
|
+
return $this->_nodeFactory;
|
98
|
+
}
|
99
|
+
|
100
|
+
/**
|
101
|
+
* Sets a compiler.
|
102
|
+
*
|
103
|
+
* @param Compiler $compiler
|
104
|
+
*/
|
105
|
+
public function setCompiler(Compiler $compiler)
|
106
|
+
{
|
107
|
+
$this->_compiler = $compiler;
|
108
|
+
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* Returns a compiler object.
|
112
|
+
*
|
113
|
+
* @return Compiler
|
114
|
+
*/
|
115
|
+
public function getCompiler()
|
116
|
+
{
|
117
|
+
if ($this->_compiler === null) {
|
118
|
+
$this->_compiler = new Compiler($this);
|
119
|
+
}
|
120
|
+
|
121
|
+
return $this->_compiler;
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Enables caching.
|
126
|
+
*/
|
127
|
+
public function enableCache()
|
128
|
+
{
|
129
|
+
$this->_cacheEnabled = true;
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* Disables caching.
|
134
|
+
*/
|
135
|
+
public function disableCache()
|
136
|
+
{
|
137
|
+
$this->_cacheEnabled = false;
|
138
|
+
}
|
139
|
+
|
140
|
+
/**
|
141
|
+
* Returns true if caching is enabled.
|
142
|
+
*
|
143
|
+
* @return bool
|
144
|
+
*/
|
145
|
+
public function isCacheEnabled()
|
146
|
+
{
|
147
|
+
return $this->_cacheEnabled;
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Parses a haml file and returns a cached path to the file.
|
152
|
+
*
|
153
|
+
* @param string $fileName
|
154
|
+
*/
|
155
|
+
public function parseFile($fileName, array $templateVars = array())
|
156
|
+
{
|
157
|
+
$content = $this->getContentFromStorage($fileName);
|
158
|
+
|
159
|
+
return $this->_contentEvaluator->evaluate(
|
160
|
+
$content, $templateVars, $this->generateFileId($fileName));
|
161
|
+
}
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Returns content from a storage
|
165
|
+
*
|
166
|
+
* @param string $fileName
|
167
|
+
* @return string
|
168
|
+
*/
|
169
|
+
public function getContentFromStorage($fileName)
|
170
|
+
{
|
171
|
+
$fileId = $this->generateFileId($fileName);
|
172
|
+
|
173
|
+
if ($this->_storage === null) {
|
174
|
+
throw new Exception('Storage not set');
|
175
|
+
}
|
176
|
+
|
177
|
+
if ($this->isCacheEnabled()
|
178
|
+
&& $this->_storage->isFresh($fileId)) {
|
179
|
+
return $this->_storage->fetch($fileId);
|
180
|
+
}
|
181
|
+
|
182
|
+
// file is not fresh, so compile and cache it
|
183
|
+
$this->_storage->cache($fileId, $this->_compiler->parseFile($fileName));
|
184
|
+
return $this->_storage->fetch($fileId);
|
185
|
+
}
|
186
|
+
|
187
|
+
private function generateFileId($filename)
|
188
|
+
{
|
189
|
+
return str_replace(array(':','/','\\'), '_', ltrim($filename, '/\\'));
|
190
|
+
}
|
191
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
<?php
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Returns a double or single quoted string. whatever works without changing the content of the string.
|
5
|
+
* Example:
|
6
|
+
* @code
|
7
|
+
* quote("McDonald's") # -> "\"McDonad's\""
|
8
|
+
* quote("You \"win\", looser") # -> "'You \"win\", looser'"
|
9
|
+
* @endcode
|
10
|
+
*
|
11
|
+
* If it can't be done. It will return false.
|
12
|
+
*
|
13
|
+
* @param $str
|
14
|
+
* @return mixed The quoted string or false
|
15
|
+
*/
|
16
|
+
function quote($str)
|
17
|
+
{
|
18
|
+
if(strpos($str, '"') === false)
|
19
|
+
return "\"$str\"";
|
20
|
+
|
21
|
+
if(strpos($str, "'") === false)
|
22
|
+
return "'$str'";
|
23
|
+
|
24
|
+
return false;
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* Prints a list of attributes specified by an array of (att_name => att_value)
|
29
|
+
*
|
30
|
+
* @param array $atts
|
31
|
+
* @param bool $echo [optional] Wheter to echo the result or not (default: true)
|
32
|
+
*
|
33
|
+
* @return string The list of attributes
|
34
|
+
*/
|
35
|
+
function atts($atts, $echo=true)
|
36
|
+
{
|
37
|
+
$str = '';
|
38
|
+
$flatten = array();
|
39
|
+
|
40
|
+
foreach ($atts as $name => $value)
|
41
|
+
{
|
42
|
+
if((string)$name != 'id' && (string)$name != 'class' && is_array($value))
|
43
|
+
{
|
44
|
+
foreach($value as $k => $v)
|
45
|
+
{
|
46
|
+
// TODO: if we found an Id or a Class attribute here. What should we do? For now, it will replace the original ones instead of append
|
47
|
+
$flatten[$k] = $v;
|
48
|
+
}
|
49
|
+
unset($atts[$name]);
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
$atts = array_merge($atts, $flatten);
|
54
|
+
|
55
|
+
foreach ($atts as $name => $value)
|
56
|
+
{
|
57
|
+
if($value === false)
|
58
|
+
continue;
|
59
|
+
|
60
|
+
if($value === true)
|
61
|
+
{
|
62
|
+
$str .= " $name=\"$name\"";
|
63
|
+
}
|
64
|
+
else
|
65
|
+
{
|
66
|
+
if('id' == (string)$name && is_array($value))
|
67
|
+
{
|
68
|
+
$str .= ' id="'.join('_', $value);
|
69
|
+
}
|
70
|
+
elseif ('class' == (string)$name && is_array($value))
|
71
|
+
$str .= ' class="'.join(' ', $value);
|
72
|
+
else
|
73
|
+
$str .= " $name=".quote($value);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
if($echo)
|
78
|
+
echo $str;
|
79
|
+
|
80
|
+
return $str;
|
81
|
+
}
|
82
|
+
|
83
|
+
/**
|
84
|
+
* Returns an id generated by joining the class of $obj and the id of $obj, joined by a underscore (_), and prefixing it with $prefix.
|
85
|
+
* To get the class, this method will call the class_for() helper.
|
86
|
+
* To get the id, this method first check if the \c $id variable is set, if not, it checks for a \c getId()
|
87
|
+
* method. If none of them is found, it will use an internal, class specific, object counter.
|
88
|
+
*
|
89
|
+
* @param object $obj
|
90
|
+
* @param string $prefix [Optional]
|
91
|
+
*/
|
92
|
+
function id_for($obj, $prefix = '')
|
93
|
+
{
|
94
|
+
static $counter = array();
|
95
|
+
|
96
|
+
if(!empty($prefix))
|
97
|
+
$prefix .= '_';
|
98
|
+
|
99
|
+
$klass = class_for($obj).'_';
|
100
|
+
|
101
|
+
if(isset($obj->id))
|
102
|
+
return $prefix.$klass.$obj->id;
|
103
|
+
|
104
|
+
if(method_exists($obj, 'getId'))
|
105
|
+
return $prefix.$klass.$obj->getId();
|
106
|
+
|
107
|
+
if(!isset($counter[$klass]))
|
108
|
+
$counter[$klass] = 0;
|
109
|
+
|
110
|
+
$counter[$klass]++;
|
111
|
+
|
112
|
+
return $prefix.$klass.$counter[$klass];
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
* Returns the class name of an object to be used in the class attribute.
|
117
|
+
* This behaviour can be overloaded by implement a haml_obj_ref (or hamlObjRef) method.
|
118
|
+
* Which MUST return a string. If such method isn't present, it will use php's get_class() function.
|
119
|
+
* If prefix is not empty, both, the object's class and the prefix, will be returned separated by one space.
|
120
|
+
*
|
121
|
+
* @param object $obj
|
122
|
+
* @param string $prefix [Optional]
|
123
|
+
*/
|
124
|
+
function class_for($obj, $prefix = '')
|
125
|
+
{
|
126
|
+
if(!empty($prefix))
|
127
|
+
$prefix .= ' ';
|
128
|
+
|
129
|
+
if(method_exists($obj, 'haml_obj_ref'))
|
130
|
+
return $prefix.$obj->haml_obj_ref();
|
131
|
+
|
132
|
+
if(method_exists($obj, 'hamlObjRef'))
|
133
|
+
return $prefix.$obj->hamlObjRef();
|
134
|
+
|
135
|
+
return $prefix.get_class($obj);
|
136
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<?php
|
2
|
+
|
3
|
+
class Interpolation
|
4
|
+
{
|
5
|
+
const REGEXP = '/(?:\#\{([^\}]+)\})+/';
|
6
|
+
const REPLACEMENT = '<?php echo $1; ?>';
|
7
|
+
|
8
|
+
private $_text = null;
|
9
|
+
|
10
|
+
public function __construct($text)
|
11
|
+
{
|
12
|
+
$this->_text = $text;
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @todo Refactor!
|
17
|
+
* @throws LogicException
|
18
|
+
*/
|
19
|
+
public function render()
|
20
|
+
{
|
21
|
+
$interpolationStarted = false;
|
22
|
+
$content = "";
|
23
|
+
$interpolationContent = "";
|
24
|
+
$len = strlen($this->_text);
|
25
|
+
$i = 0;
|
26
|
+
|
27
|
+
while ($i < $len) {
|
28
|
+
$currentChar = $this->_text[$i];
|
29
|
+
$nextChar = ($i + 1 <= $len - 1) ? $this->_text[$i + 1] : null;
|
30
|
+
|
31
|
+
if ($interpolationStarted) {
|
32
|
+
if ($currentChar === '}') {
|
33
|
+
$interpolationStarted = false;
|
34
|
+
|
35
|
+
if (empty($interpolationContent)) {
|
36
|
+
throw new LogicException("Empty interpolation: " . $this->_text);
|
37
|
+
}
|
38
|
+
|
39
|
+
$content .= "<?php echo " . $interpolationContent . "; ?>";
|
40
|
+
$interpolationContent = '';
|
41
|
+
$i++;
|
42
|
+
continue;
|
43
|
+
}
|
44
|
+
|
45
|
+
if (null !== $nextChar && '#{' === $currentChar . $nextChar) {
|
46
|
+
throw new LogicException(
|
47
|
+
"Nested interpolation not allowed: " . $this->_text);
|
48
|
+
}
|
49
|
+
|
50
|
+
$interpolationContent .= $currentChar;
|
51
|
+
$i++;
|
52
|
+
continue;
|
53
|
+
}
|
54
|
+
|
55
|
+
if (null !== $nextChar && '#{' === $currentChar . $nextChar) {
|
56
|
+
$interpolationStarted = true;
|
57
|
+
$i += 2;
|
58
|
+
continue;
|
59
|
+
}
|
60
|
+
|
61
|
+
$content .= $currentChar;
|
62
|
+
$i++;
|
63
|
+
}
|
64
|
+
|
65
|
+
if ($interpolationStarted) {
|
66
|
+
throw new LogicException("Unclosed interpolation: " . $this->_text);
|
67
|
+
}
|
68
|
+
|
69
|
+
return $content;
|
70
|
+
}
|
71
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
<?php
|
2
|
+
|
3
|
+
require_once 'ElementNode.php';
|
4
|
+
require_once 'HamlNode.php';
|
5
|
+
require_once 'DoctypeNode.php';
|
6
|
+
require_once 'TagNode.php';
|
7
|
+
require_once 'CommentNode.php';
|
8
|
+
require_once 'FilterNode.php';
|
9
|
+
|
10
|
+
class NodeFactory
|
11
|
+
{
|
12
|
+
const ELEMENT = '%';
|
13
|
+
const ID = '#';
|
14
|
+
const KLASS = '.';
|
15
|
+
|
16
|
+
const HTML_COMMENT = '/';
|
17
|
+
const HAML_COMMENT = '-#';
|
18
|
+
const DOCTYPE = '!!!';
|
19
|
+
|
20
|
+
const VARIABLE = '=';
|
21
|
+
const TAG = '-';
|
22
|
+
const FILTER = ':';
|
23
|
+
const LOUD_SCRIPT = '=';
|
24
|
+
|
25
|
+
private $_filterContainer = null;
|
26
|
+
|
27
|
+
public function setFilterContainer(FilterContainer $container)
|
28
|
+
{
|
29
|
+
$this->_filterContainer = $container;
|
30
|
+
}
|
31
|
+
|
32
|
+
protected function getNodeObject($line, Compiler $compiler) {
|
33
|
+
$strippedLine = trim($line);
|
34
|
+
|
35
|
+
if($strippedLine == '')
|
36
|
+
return null;
|
37
|
+
|
38
|
+
if (strpos($strippedLine, self::FILTER, 0) === 0) {
|
39
|
+
return new FilterNode($line, $this->_filterContainer);
|
40
|
+
}
|
41
|
+
|
42
|
+
if (strpos($strippedLine, NodeFactory::DOCTYPE, 0) !== false) {
|
43
|
+
return new DoctypeNode($line);
|
44
|
+
}
|
45
|
+
|
46
|
+
if (substr($strippedLine, 0, 1) === NodeFactory::HTML_COMMENT
|
47
|
+
|| substr($strippedLine, 0, 2) === NodeFactory::HAML_COMMENT) {
|
48
|
+
return new CommentNode($line);
|
49
|
+
}
|
50
|
+
|
51
|
+
$elements = array(
|
52
|
+
NodeFactory::ELEMENT,
|
53
|
+
NodeFactory::ID,
|
54
|
+
NodeFactory::KLASS,
|
55
|
+
);
|
56
|
+
|
57
|
+
if (in_array($strippedLine[0], $elements)) {
|
58
|
+
return new ElementNode($line, $compiler);
|
59
|
+
}
|
60
|
+
|
61
|
+
if ($strippedLine[0] === NodeFactory::TAG
|
62
|
+
||$strippedLine[0] === NodeFactory::LOUD_SCRIPT) {
|
63
|
+
return new TagNode($line);
|
64
|
+
}
|
65
|
+
|
66
|
+
return new HamlNode($line);
|
67
|
+
}
|
68
|
+
|
69
|
+
public function createNode($line, $lineNumber, Compiler $compiler)
|
70
|
+
{
|
71
|
+
$node = $this->getNodeObject($line, $compiler);
|
72
|
+
|
73
|
+
if ($node !== null) {
|
74
|
+
$node->setLineNumber($lineNumber);
|
75
|
+
$node->setCompiler($compiler);
|
76
|
+
}
|
77
|
+
|
78
|
+
return $node;
|
79
|
+
}
|
80
|
+
}
|