opulent 0.0.9 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +9 -0
- data/.libold/opulent.rb +96 -0
- data/.libold/opulent/context.rb +80 -0
- data/.libold/opulent/engine.rb +88 -0
- data/.libold/opulent/filter.rb +101 -0
- data/.libold/opulent/logger.rb +67 -0
- data/.libold/opulent/nodes.rb +13 -0
- data/.libold/opulent/nodes/block.rb +29 -0
- data/.libold/opulent/nodes/comment.rb +35 -0
- data/.libold/opulent/nodes/control.rb +230 -0
- data/.libold/opulent/nodes/define.rb +42 -0
- data/.libold/opulent/nodes/eval.rb +41 -0
- data/.libold/opulent/nodes/expression.rb +28 -0
- data/.libold/opulent/nodes/filter.rb +70 -0
- data/.libold/opulent/nodes/helper.rb +69 -0
- data/.libold/opulent/nodes/node.rb +101 -0
- data/.libold/opulent/nodes/root.rb +62 -0
- data/.libold/opulent/nodes/text.rb +54 -0
- data/.libold/opulent/nodes/theme.rb +36 -0
- data/.libold/opulent/parser.rb +252 -0
- data/.libold/opulent/parser/block.rb +70 -0
- data/.libold/opulent/parser/comment.rb +32 -0
- data/.libold/opulent/parser/control.rb +83 -0
- data/.libold/opulent/parser/define.rb +39 -0
- data/.libold/opulent/parser/eval.rb +33 -0
- data/.libold/opulent/parser/expression.rb +350 -0
- data/.libold/opulent/parser/filter.rb +41 -0
- data/.libold/opulent/parser/node.rb +232 -0
- data/.libold/opulent/parser/root.rb +96 -0
- data/.libold/opulent/parser/text.rb +114 -0
- data/.libold/opulent/parser/theme.rb +36 -0
- data/.libold/opulent/preprocessor.rb +102 -0
- data/.libold/opulent/runtime.rb +144 -0
- data/.libold/opulent/template.rb +43 -0
- data/.libold/opulent/tokens.rb +276 -0
- data/.libold/opulent/version.rb +5 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.md +102 -0
- data/Rakefile +6 -0
- data/benchmark/benchmark.rb +46 -0
- data/benchmark/cases/node/node.haml +17 -0
- data/benchmark/cases/node/node.op +14 -0
- data/benchmark/cases/node/node.slim +19 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/docs/syntax.md +3 -0
- data/docs/usage.md +3 -0
- data/lib/opulent.rb +11 -64
- data/lib/opulent/compiler.rb +132 -0
- data/lib/opulent/compiler/block.rb +31 -0
- data/lib/opulent/compiler/comment.rb +22 -0
- data/lib/opulent/compiler/control.rb +152 -0
- data/lib/opulent/compiler/define.rb +88 -0
- data/lib/opulent/compiler/eval.rb +15 -0
- data/lib/opulent/compiler/filter.rb +54 -0
- data/lib/opulent/compiler/node.rb +232 -0
- data/lib/opulent/compiler/root.rb +19 -0
- data/lib/opulent/compiler/text.rb +60 -0
- data/lib/opulent/context.rb +88 -0
- data/lib/opulent/engine.rb +60 -0
- data/lib/opulent/filters.rb +222 -0
- data/lib/opulent/logger.rb +47 -0
- data/lib/opulent/parser.rb +196 -0
- data/lib/opulent/parser/block.rb +56 -0
- data/lib/opulent/parser/comment.rb +27 -0
- data/lib/opulent/parser/control.rb +112 -0
- data/lib/opulent/parser/define.rb +30 -0
- data/lib/opulent/parser/eval.rb +21 -0
- data/lib/opulent/parser/expression.rb +344 -0
- data/lib/opulent/parser/filter.rb +25 -0
- data/lib/opulent/parser/node.rb +246 -0
- data/lib/opulent/parser/root.rb +48 -0
- data/lib/opulent/parser/text.rb +127 -0
- data/lib/opulent/settings.rb +79 -0
- data/lib/opulent/template.rb +67 -0
- data/lib/opulent/tokens.rb +166 -0
- data/lib/opulent/version.rb +4 -0
- data/opulent.gemspec +36 -0
- metadata +160 -7
@@ -0,0 +1,13 @@
|
|
1
|
+
# Include Opulent nodes which know how to evaluate themselves
|
2
|
+
require_relative 'nodes/helper'
|
3
|
+
require_relative 'nodes/root'
|
4
|
+
require_relative 'nodes/node'
|
5
|
+
require_relative 'nodes/define'
|
6
|
+
require_relative 'nodes/eval'
|
7
|
+
require_relative 'nodes/expression'
|
8
|
+
require_relative 'nodes/text'
|
9
|
+
require_relative 'nodes/filter'
|
10
|
+
require_relative 'nodes/control'
|
11
|
+
require_relative 'nodes/theme'
|
12
|
+
require_relative 'nodes/block'
|
13
|
+
require_relative 'nodes/comment'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Nodes
|
4
|
+
module Nodes
|
5
|
+
# @Yield
|
6
|
+
#
|
7
|
+
class Yield < Node
|
8
|
+
# Node evaluation method which goes through all the child nodes and evaluates
|
9
|
+
# them using their own eval method
|
10
|
+
#
|
11
|
+
def evaluate(context)
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @Block
|
17
|
+
#
|
18
|
+
class Block < Node
|
19
|
+
# Node evaluation method which goes through all the child nodes and evaluates
|
20
|
+
# them using their own eval method
|
21
|
+
#
|
22
|
+
def evaluate(context)
|
23
|
+
@children.map do |child|
|
24
|
+
child.evaluate context
|
25
|
+
end.flatten.compact
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Nodes
|
4
|
+
module Nodes
|
5
|
+
# @Text
|
6
|
+
#
|
7
|
+
# The text class will output raw or escaped HTML text
|
8
|
+
#
|
9
|
+
class Comment
|
10
|
+
# Allow direct access to literal value and type
|
11
|
+
attr_accessor :value, :visible, :parent, :indent, :name
|
12
|
+
|
13
|
+
# Initialize literal instance variables
|
14
|
+
#
|
15
|
+
# @param value stores the literal's explicit value
|
16
|
+
#
|
17
|
+
def initialize(value = nil, parent = nil, indent = 0)
|
18
|
+
@value = value
|
19
|
+
@parent = parent
|
20
|
+
@indent = indent
|
21
|
+
@name = :comment
|
22
|
+
end
|
23
|
+
|
24
|
+
# Value evaluation method which returns the processed value of the
|
25
|
+
# literal
|
26
|
+
#
|
27
|
+
def evaluate(context)
|
28
|
+
comment = self.dup
|
29
|
+
comment.value = context.evaluate "\"#{@value}\""
|
30
|
+
|
31
|
+
return comment
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Nodes
|
4
|
+
module Nodes
|
5
|
+
# @CnditionalControl
|
6
|
+
#
|
7
|
+
# Control structure for if-elsif-else and unless
|
8
|
+
#
|
9
|
+
class CnditionalControl
|
10
|
+
attr_accessor :name, :value, :parent, :indent, :children
|
11
|
+
|
12
|
+
# Ruby code evaluation node
|
13
|
+
#
|
14
|
+
# @param name [String] name of the html node
|
15
|
+
# @param value [String] condition to be met
|
16
|
+
# @param parent [Node] parent of the element
|
17
|
+
# @param indent [Fixnum] node indentation for restructuring
|
18
|
+
# @param children [Array] contents to be interpreted
|
19
|
+
#
|
20
|
+
def initialize(name = '', value = '', parent = nil, indent = 0, children = [[]])
|
21
|
+
@name = name
|
22
|
+
@value = [value]
|
23
|
+
@parent = parent
|
24
|
+
@indent = indent
|
25
|
+
@children = children
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add a new node to the nodes array
|
29
|
+
#
|
30
|
+
def push(node)
|
31
|
+
@children[-1] << node
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
# Node evaluation method which goes through all the child nodes and evaluates
|
36
|
+
# them using their own eval method
|
37
|
+
#
|
38
|
+
def evaluate(context)
|
39
|
+
index = @value.index do |value|
|
40
|
+
value.empty? || context.evaluate(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
if index
|
44
|
+
@children[index].map do |child|
|
45
|
+
child.evaluate context
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @IfControl
|
52
|
+
#
|
53
|
+
# Control structure for if-elsif-else directive
|
54
|
+
#
|
55
|
+
class CaseControl
|
56
|
+
attr_accessor :name, :case, :value, :parent, :indent, :children
|
57
|
+
|
58
|
+
# Ruby code evaluation node
|
59
|
+
#
|
60
|
+
# @param name [String] name of the html node
|
61
|
+
# @param value [String] condition to be met
|
62
|
+
# @param parent [Node] parent of the element
|
63
|
+
# @param indent [Fixnum] node indentation for restructuring
|
64
|
+
# @param children [Array] contents to be interpreted
|
65
|
+
#
|
66
|
+
def initialize(name = '', switch_case = '', parent = nil, indent = 0, children = [[]])
|
67
|
+
@name = name
|
68
|
+
@case = switch_case
|
69
|
+
@value = []
|
70
|
+
@parent = parent
|
71
|
+
@indent = indent
|
72
|
+
@children = children
|
73
|
+
end
|
74
|
+
|
75
|
+
# Add a new node to the nodes array
|
76
|
+
#
|
77
|
+
def push(node)
|
78
|
+
@children[-1] << node
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
# Node evaluation method which goes through all the child nodes and evaluates
|
83
|
+
# them using their own eval method
|
84
|
+
#
|
85
|
+
def evaluate(context)
|
86
|
+
switch_case = context.evaluate @case
|
87
|
+
index = @value.index do |value|
|
88
|
+
value.empty? || switch_case == context.evaluate(value)
|
89
|
+
end
|
90
|
+
|
91
|
+
if index
|
92
|
+
@children[index].map do |child|
|
93
|
+
child.evaluate context
|
94
|
+
end.flatten.compact
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# @LoopControl
|
100
|
+
#
|
101
|
+
# Control structure for while and until directives
|
102
|
+
#
|
103
|
+
class LoopControl
|
104
|
+
attr_accessor :name, :value, :parent, :indent, :children
|
105
|
+
|
106
|
+
# Ruby code evaluation node
|
107
|
+
#
|
108
|
+
# @param name [String] name of the html node
|
109
|
+
# @param value [String] condition to be met
|
110
|
+
# @param parent [Node] parent of the element
|
111
|
+
# @param indent [Fixnum] node indentation for restructuring
|
112
|
+
# @param children [Array] contents to be interpreted
|
113
|
+
#
|
114
|
+
def initialize(name = '', value = '', parent = nil, indent = 0, children = [])
|
115
|
+
@name = name
|
116
|
+
@value = value
|
117
|
+
@parent = parent
|
118
|
+
@indent = indent
|
119
|
+
@children = children
|
120
|
+
end
|
121
|
+
|
122
|
+
# Add a new node to the nodes array
|
123
|
+
#
|
124
|
+
def push(node)
|
125
|
+
@children << node
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
# Node evaluation method which goes through all the child nodes and evaluates
|
130
|
+
# them using their own eval method
|
131
|
+
#
|
132
|
+
def evaluate(context)
|
133
|
+
result = []
|
134
|
+
|
135
|
+
evaluate_children = Proc.new do |context|
|
136
|
+
result << @children.map do |child|
|
137
|
+
child.evaluate context
|
138
|
+
end.flatten
|
139
|
+
end
|
140
|
+
|
141
|
+
case @name
|
142
|
+
when :while
|
143
|
+
while context.evaluate @value
|
144
|
+
evaluate_children[context]
|
145
|
+
end
|
146
|
+
when :until
|
147
|
+
until context.evaluate @value
|
148
|
+
evaluate_children[context]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
return result.flatten.compact
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# @EachControl
|
157
|
+
#
|
158
|
+
# Control structure for while and until directives
|
159
|
+
#
|
160
|
+
class EachControl < LoopControl
|
161
|
+
# Node evaluation method which goes through all the child nodes and evaluates
|
162
|
+
# them using their own eval method
|
163
|
+
#
|
164
|
+
def evaluate(context)
|
165
|
+
result = []
|
166
|
+
|
167
|
+
# Process named variables for each structure
|
168
|
+
variables = @value[0].clone
|
169
|
+
|
170
|
+
# The each structure accept missing arguments as well, therefore we need to
|
171
|
+
# substitute them with our defaults
|
172
|
+
#
|
173
|
+
# each in iterable
|
174
|
+
# each value in iterable
|
175
|
+
# each key, value in iterable
|
176
|
+
|
177
|
+
# Value argument name provided only
|
178
|
+
if variables.length == 1
|
179
|
+
variables.unshift Engine[:each][:default_key]
|
180
|
+
|
181
|
+
# Missing key and value arguments
|
182
|
+
elsif variables.empty?
|
183
|
+
variables[0] = Engine[:each][:default_key]
|
184
|
+
variables[1] = Engine[:each][:default_value]
|
185
|
+
end
|
186
|
+
|
187
|
+
# Evaluate in current context and add to results
|
188
|
+
evaluate_children = Proc.new do |key, value, context|
|
189
|
+
# Update the local variables in the each context with the values from the
|
190
|
+
# current loop iteration
|
191
|
+
locals = {
|
192
|
+
variables[0] => key,
|
193
|
+
variables[1] => value
|
194
|
+
}
|
195
|
+
context.extend_context locals
|
196
|
+
|
197
|
+
# Add the mapped child elements
|
198
|
+
result << @children.map do |child|
|
199
|
+
child.evaluate context
|
200
|
+
end.flatten
|
201
|
+
end
|
202
|
+
|
203
|
+
# Create a new context based on the parent context and progressively update
|
204
|
+
# variables in the new context
|
205
|
+
each_context = Context.new({}, context.binding.clone)
|
206
|
+
|
207
|
+
# Evaluate the iterable object
|
208
|
+
enumerable = each_context.evaluate(@value[1])
|
209
|
+
|
210
|
+
# Check if input can be iterated
|
211
|
+
Runtime.error :enumerable, @value[1] unless enumerable.respond_to? :each
|
212
|
+
|
213
|
+
# Selectively iterate through the input and add the result using the previously
|
214
|
+
# defined proc object
|
215
|
+
case enumerable
|
216
|
+
when Hash
|
217
|
+
enumerable.each do |key, value|
|
218
|
+
evaluate_children[key, value, context]
|
219
|
+
end
|
220
|
+
else
|
221
|
+
enumerable.each_with_index do |value, key|
|
222
|
+
evaluate_children[key, value, context]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
return result.flatten.compact
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Nodes
|
4
|
+
module Nodes
|
5
|
+
# @Define
|
6
|
+
#
|
7
|
+
# Define a custom HTML element
|
8
|
+
#
|
9
|
+
class Define < Node
|
10
|
+
# Node evaluation method which goes through all the child nodes and
|
11
|
+
# evaluates them using their own eval method
|
12
|
+
#
|
13
|
+
def evaluate(context, blocks = {})
|
14
|
+
yields = @yields.clone
|
15
|
+
|
16
|
+
@children.map do |child|
|
17
|
+
evaluated_child = child.evaluate context
|
18
|
+
|
19
|
+
# Check to see if the child element being mapped is one of the yield
|
20
|
+
# node parent pointers
|
21
|
+
if yields.include? child
|
22
|
+
yields.delete child
|
23
|
+
|
24
|
+
# We need to replace the yield nodes with the matching named block
|
25
|
+
# in order to map the yield node correctly
|
26
|
+
evaluated_child.children.map! do |subchild|
|
27
|
+
if subchild.is_a?(Yield) && blocks[subchild.name]
|
28
|
+
blocks[subchild.name]
|
29
|
+
else
|
30
|
+
subchild
|
31
|
+
end
|
32
|
+
end
|
33
|
+
evaluated_child.children.compact!
|
34
|
+
evaluated_child.children.flatten!
|
35
|
+
end
|
36
|
+
|
37
|
+
evaluated_child
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Nodes
|
4
|
+
module Nodes
|
5
|
+
# @Evaluate
|
6
|
+
#
|
7
|
+
# The eval node evaluates ruby code in the given context without printing
|
8
|
+
# any output in the page
|
9
|
+
#
|
10
|
+
class Evaluate
|
11
|
+
attr_accessor :value, :parent, :indent, :children, :name
|
12
|
+
|
13
|
+
# Ruby code evaluation node
|
14
|
+
#
|
15
|
+
# @param name [String] name of the html node
|
16
|
+
# @param parent [Node] parent of the element
|
17
|
+
# @param indent [Fixnum] node indentation for restructuring
|
18
|
+
# @param children [Array] contents to be interpreted
|
19
|
+
#
|
20
|
+
def initialize(value = '', parent = nil, indent = 0, children = [])
|
21
|
+
@name = :eval
|
22
|
+
@value = value
|
23
|
+
@parent = parent
|
24
|
+
@indent = indent
|
25
|
+
@children = children
|
26
|
+
end
|
27
|
+
|
28
|
+
# Add a new node to the nodes array
|
29
|
+
#
|
30
|
+
def push(node)
|
31
|
+
@children << node
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def evaluate(context)
|
36
|
+
context.evaluate @value
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Nodes
|
4
|
+
module Nodes
|
5
|
+
# @Expression
|
6
|
+
#
|
7
|
+
# Literals are static values that have a Ruby representation, eg.: a string, a number,
|
8
|
+
# true, false, nil, etc.
|
9
|
+
#
|
10
|
+
class Expression
|
11
|
+
attr_accessor :value, :escaped
|
12
|
+
|
13
|
+
def initialize(value = '')
|
14
|
+
@value = value
|
15
|
+
@escaped = true
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
@value
|
20
|
+
end
|
21
|
+
|
22
|
+
def evaluate(context)
|
23
|
+
evaluated = context.evaluate @value
|
24
|
+
@escaped ? Runtime.escape(evaluated) : evaluated
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Nodes
|
4
|
+
module Nodes
|
5
|
+
# @Filter
|
6
|
+
#
|
7
|
+
# Node class used to run a value interpretation
|
8
|
+
#
|
9
|
+
class Filter
|
10
|
+
# Allow direct access to node variables
|
11
|
+
attr_accessor :name, :attributes, :value, :parent, :indent
|
12
|
+
|
13
|
+
# Initialize node instance variables
|
14
|
+
#
|
15
|
+
# @param name [String] name of the html node
|
16
|
+
# @param indentation [Fixnum] node indentation for restructuring
|
17
|
+
# @param attributes [Hash] stores key="value" attributes
|
18
|
+
# @param value [String] Contents to be interpreted
|
19
|
+
#
|
20
|
+
def initialize(name = '', attributes = {}, parent = nil, indent = 0, value = '')
|
21
|
+
@name = name
|
22
|
+
@parent = parent
|
23
|
+
@indent = indent
|
24
|
+
@attributes = attributes
|
25
|
+
@value = value
|
26
|
+
end
|
27
|
+
|
28
|
+
# Update attributes with values from current evaluation context
|
29
|
+
#
|
30
|
+
def get_attributes(context)
|
31
|
+
Hash[@attributes.map{ |key, val|
|
32
|
+
unless val.nil?
|
33
|
+
value = val.evaluate(context)
|
34
|
+
value.flatten! if value.is_a?(Array)
|
35
|
+
end
|
36
|
+
[key, value]
|
37
|
+
}]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Node evaluation method which goes through all the child nodes and evaluates
|
41
|
+
# them using their own eval method
|
42
|
+
#
|
43
|
+
def evaluate(context)
|
44
|
+
# Set attributes for current context
|
45
|
+
attributes = Runtime.attributes @attributes, nil, context
|
46
|
+
|
47
|
+
# Check if filter is registered
|
48
|
+
Runtime.error :filter_registered, name unless Engine.filter? name
|
49
|
+
|
50
|
+
# Load the required filter
|
51
|
+
Engine.filters[name].load_filter
|
52
|
+
|
53
|
+
# Render output using the chosen engine
|
54
|
+
output = Engine.filters[name].render @value
|
55
|
+
|
56
|
+
# Main output node which contains filter rendered value
|
57
|
+
text_node = Text.new output, false, @parent, @indent
|
58
|
+
|
59
|
+
# If we have a provided filter tag, wrap the text node in the wrapper
|
60
|
+
# node tag and further indent
|
61
|
+
if (wrapper_tag = Engine.filters[name].options[:tag])
|
62
|
+
text_node.indent = @indent + Engine[:indent]
|
63
|
+
return Node.new wrapper_tag, Engine.filters[name].options[:attributes], @parent, @indent, [text_node]
|
64
|
+
else
|
65
|
+
return text_node
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|