opulent 0.0.9 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Pixevil
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Opulent
|
2
|
+
|
3
|
+
Opulent is an __Intelligent Web Templating Engine__ created for extremly fast, efficient and DRY Web Development. Based on the idea of creating lightweight __Web Component__ definitions, Opulent greatly speeds up the development process of any project.
|
4
|
+
|
5
|
+
## Syntax
|
6
|
+
|
7
|
+
Opulent is as beautiful as it gets: no tags, indentation based, optional brackets, inline text, inline children and in page definitions.
|
8
|
+
|
9
|
+
__Page Markup__
|
10
|
+
```
|
11
|
+
html
|
12
|
+
head
|
13
|
+
title Opulent is Awesome
|
14
|
+
body
|
15
|
+
#content
|
16
|
+
ul.list-inline
|
17
|
+
li > a href="http://opulent.io" Opulent
|
18
|
+
li > a href="http://github.com" GitHub
|
19
|
+
|
20
|
+
footer |
|
21
|
+
With Opulent, you can do anything.
|
22
|
+
```
|
23
|
+
|
24
|
+
__Web Component__
|
25
|
+
```
|
26
|
+
def hello(place)
|
27
|
+
p Hello #{place}
|
28
|
+
|
29
|
+
hello place="World"
|
30
|
+
```
|
31
|
+
|
32
|
+
__Control Structures__
|
33
|
+
```
|
34
|
+
ul.navbar
|
35
|
+
if @user.logged_in?
|
36
|
+
li Hello #{@user.name}
|
37
|
+
else
|
38
|
+
li > a href=link_to_register Sign Up
|
39
|
+
```
|
40
|
+
|
41
|
+
__Starting to feel it?__ There's so much more you can do with Opulent.
|
42
|
+
|
43
|
+
[Read the Documentation](docs/syntax.md)
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
## Installation
|
48
|
+
|
49
|
+
Install it yourself using the ruby gem:
|
50
|
+
|
51
|
+
$ gem install opulent
|
52
|
+
|
53
|
+
---
|
54
|
+
|
55
|
+
Or add this line to your application's Gemfile:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
gem 'opulent'
|
59
|
+
```
|
60
|
+
|
61
|
+
And then execute:
|
62
|
+
|
63
|
+
$ bundle
|
64
|
+
|
65
|
+
|
66
|
+
## Usage
|
67
|
+
|
68
|
+
Using Opulent to render a file is as easy as including it in your application and using the render method.
|
69
|
+
|
70
|
+
[Read the Documentation](docs/usage.md)
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
require 'opulent'
|
74
|
+
|
75
|
+
Opulent.new.render_file 'file.op'
|
76
|
+
```
|
77
|
+
|
78
|
+
<!--
|
79
|
+
## Development
|
80
|
+
|
81
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
82
|
+
|
83
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
84
|
+
-->
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/opulent/opulent. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
89
|
+
|
90
|
+
#### Under Development
|
91
|
+
Opulent is currently in the Beta Phase. It has serious potential to becoming the next generation of Templating Engines for Ruby, therefore any contribution is more than welcome.
|
92
|
+
|
93
|
+
It still has development going on the following subjects:
|
94
|
+
|
95
|
+
* Template amble (preamble, cache, postamble) generation
|
96
|
+
* More block yielding tests
|
97
|
+
* Multiple page layouts
|
98
|
+
* More to come
|
99
|
+
|
100
|
+
## License
|
101
|
+
|
102
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require_relative '../lib/opulent'
|
3
|
+
require 'slim'
|
4
|
+
require 'haml'
|
5
|
+
|
6
|
+
# Choose the benchmark you want to run
|
7
|
+
BENCHMARK = :node
|
8
|
+
|
9
|
+
# How many times each command should be run
|
10
|
+
N = 1000
|
11
|
+
|
12
|
+
# Templating engine initialization
|
13
|
+
puts "BENCHMARK"
|
14
|
+
case BENCHMARK
|
15
|
+
when :node
|
16
|
+
case_folder = 'cases/node/'
|
17
|
+
opulent = Tilt.new("#{case_folder}node.op")
|
18
|
+
slim = Tilt.new("#{case_folder}node.slim")
|
19
|
+
haml = Tilt.new("#{case_folder}node.haml")
|
20
|
+
|
21
|
+
locals = {
|
22
|
+
a: 3,
|
23
|
+
b: 4,
|
24
|
+
c: 5
|
25
|
+
}
|
26
|
+
|
27
|
+
scope = Object.new
|
28
|
+
|
29
|
+
Benchmark.bm do |x|
|
30
|
+
x.report("haml") do
|
31
|
+
N.times do
|
32
|
+
haml.render(scope, locals) do end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
x.report("opulent") do
|
36
|
+
N.times do
|
37
|
+
opulent.render(scope, locals) do end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
x.report("slim") do
|
41
|
+
N.times do
|
42
|
+
slim.render(scope, locals) do end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
%html
|
2
|
+
%head
|
3
|
+
%title Hello world
|
4
|
+
%meta(name="description" content="Node benchmark")
|
5
|
+
%body
|
6
|
+
%nav.navbar
|
7
|
+
%ul.nav.left
|
8
|
+
%li Home
|
9
|
+
%li About
|
10
|
+
%li Contact
|
11
|
+
#content
|
12
|
+
.container
|
13
|
+
.row
|
14
|
+
.col-md-12
|
15
|
+
| Hello world, this is a dummy text used for the speed benchmark in Opulent
|
16
|
+
%footer
|
17
|
+
| Copyright © Hello world!
|
@@ -0,0 +1,19 @@
|
|
1
|
+
html
|
2
|
+
head
|
3
|
+
- a = 3
|
4
|
+
title =a
|
5
|
+
meta name="description" content="Node benchmark"
|
6
|
+
body
|
7
|
+
nav.navbar
|
8
|
+
ul.nav.left
|
9
|
+
li Home
|
10
|
+
li About
|
11
|
+
li Contact
|
12
|
+
#content
|
13
|
+
.container
|
14
|
+
.row
|
15
|
+
.col-md-12
|
16
|
+
| Hello world, this is a dummy text used for
|
17
|
+
the speed benchmark in Opulent
|
18
|
+
footer
|
19
|
+
| Copyright © Hello world!
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "opulent"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/docs/syntax.md
ADDED
data/docs/usage.md
ADDED
data/lib/opulent.rb
CHANGED
@@ -1,64 +1,11 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require_relative 'opulent/
|
4
|
-
require_relative 'opulent/
|
5
|
-
require_relative 'opulent/
|
6
|
-
require_relative 'opulent/
|
7
|
-
require_relative 'opulent/
|
8
|
-
require_relative 'opulent/parser'
|
9
|
-
require_relative 'opulent/
|
10
|
-
|
11
|
-
|
12
|
-
class << self
|
13
|
-
# Analyze the input code and check for matching tokens. In case no match was
|
14
|
-
# found, throw an exception. In special cases, modify the token hash.
|
15
|
-
#
|
16
|
-
# @param file [String] The file that needs to be analyzed
|
17
|
-
# @param context [Hash | String] Processing environment data
|
18
|
-
#
|
19
|
-
def render(file, context = nil)
|
20
|
-
# Get the code from the input file
|
21
|
-
@code = PreProcessor.process(file)
|
22
|
-
|
23
|
-
# Accept both ruby hashes and JSON files as database environments
|
24
|
-
@context = Runtime.apply context
|
25
|
-
|
26
|
-
# Instantiate required language components
|
27
|
-
@syntax = Parser.parse code
|
28
|
-
|
29
|
-
pretty = Proc.new do |elements, indent|
|
30
|
-
if elements.is_a? Nodes::Text
|
31
|
-
puts " " * indent + "text: " + elements.value
|
32
|
-
else
|
33
|
-
elements.each do |element|
|
34
|
-
text = " " * indent + element.name.to_s
|
35
|
-
if element.respond_to? :attributes
|
36
|
-
text += " " + element.attributes.to_s
|
37
|
-
elsif element.respond_to? :value
|
38
|
-
text += " -> " + element.value.to_s
|
39
|
-
end
|
40
|
-
puts text
|
41
|
-
|
42
|
-
if element.is_a?(Nodes::Text) || element.is_a?(Nodes::Print) || element.is_a?(Nodes::Comment) || element.children.empty?
|
43
|
-
elsif [Nodes::CnditionalControl, Nodes::CaseControl].any? do |node| element.is_a? node end
|
44
|
-
element.children.each do |c| pretty[c, indent+2] end
|
45
|
-
else
|
46
|
-
pretty[element.children, indent + 2]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
puts "Definitions\n---"
|
53
|
-
@syntax.themes.each do |theme, theme_value|
|
54
|
-
puts theme.to_s
|
55
|
-
theme_value.each do |key, value|
|
56
|
-
puts " " + key.to_s + " " + value.attributes.to_s
|
57
|
-
pretty[value.children, 4]
|
58
|
-
end
|
59
|
-
end
|
60
|
-
puts "\n\nNodes\n---"
|
61
|
-
pretty[@syntax.children, 0]
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
1
|
+
require 'tilt'
|
2
|
+
require 'htmlentities'
|
3
|
+
require_relative 'opulent/compiler.rb'
|
4
|
+
require_relative 'opulent/context.rb'
|
5
|
+
require_relative 'opulent/engine.rb'
|
6
|
+
require_relative 'opulent/filters.rb'
|
7
|
+
require_relative 'opulent/logger.rb'
|
8
|
+
require_relative 'opulent/parser.rb'
|
9
|
+
require_relative 'opulent/settings.rb'
|
10
|
+
require_relative 'opulent/template.rb'
|
11
|
+
require_relative 'opulent/tokens.rb'
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative 'compiler/block.rb'
|
2
|
+
require_relative 'compiler/comment.rb'
|
3
|
+
require_relative 'compiler/control.rb'
|
4
|
+
require_relative 'compiler/define.rb'
|
5
|
+
require_relative 'compiler/eval.rb'
|
6
|
+
require_relative 'compiler/filter.rb'
|
7
|
+
require_relative 'compiler/node.rb'
|
8
|
+
require_relative 'compiler/root.rb'
|
9
|
+
require_relative 'compiler/text.rb'
|
10
|
+
|
11
|
+
# @Opulent
|
12
|
+
module Opulent
|
13
|
+
# @Compiler
|
14
|
+
class Compiler
|
15
|
+
Buffer = :_buffer
|
16
|
+
|
17
|
+
# All node Objects (Array) must follow the next convention in order
|
18
|
+
# to make parsing faster
|
19
|
+
#
|
20
|
+
# [:node_type, :value, :attributes, :children, :indent]
|
21
|
+
#
|
22
|
+
def initialize
|
23
|
+
# Setup convention accessors
|
24
|
+
@type = 0
|
25
|
+
@value = 1
|
26
|
+
@options = 2
|
27
|
+
@children = 3
|
28
|
+
@indent = 4
|
29
|
+
|
30
|
+
# Create the HTML Entities encoder/decoder
|
31
|
+
@entities = HTMLEntities.new
|
32
|
+
|
33
|
+
# Get special node types from the settings
|
34
|
+
@multi_node = Settings::MultiNode
|
35
|
+
@inline_node = Settings::InlineNode
|
36
|
+
|
37
|
+
# Quick accessor for default yield constant
|
38
|
+
@default_yield = Settings::DefaultYield
|
39
|
+
|
40
|
+
# The node stack is needed to keep track of all the visited nodes
|
41
|
+
# from the current branch level
|
42
|
+
@node_stack = []
|
43
|
+
|
44
|
+
# The sibling stack keeps track of the sibling count from the current
|
45
|
+
# branch level being generated
|
46
|
+
@sibling_stack = []
|
47
|
+
|
48
|
+
# Whenever we enter a definition compilation, add the provided blocks to
|
49
|
+
# the current block stack. When exiting a definition, remove blocks.
|
50
|
+
@block_stack = []
|
51
|
+
end
|
52
|
+
|
53
|
+
# Compile input nodes, replace them with their definitions and
|
54
|
+
#
|
55
|
+
# @param root [Array] Root node containing all document nodes
|
56
|
+
# @param context [Context] Context holding environment variables
|
57
|
+
#
|
58
|
+
def compile(root_node, context)
|
59
|
+
# Compiler generated code
|
60
|
+
@code = ""
|
61
|
+
@generator = ""
|
62
|
+
|
63
|
+
# Set initial parent, from which we start generating code
|
64
|
+
@sibling_stack << root_node[@children].size
|
65
|
+
|
66
|
+
# Start building up the code from the root node
|
67
|
+
root_node[@children].each do |child|
|
68
|
+
root child, 0, context
|
69
|
+
end
|
70
|
+
|
71
|
+
return @code
|
72
|
+
end
|
73
|
+
|
74
|
+
# Escape a given input value using htmlentities
|
75
|
+
#
|
76
|
+
# @param value [String] String to be escaped
|
77
|
+
#
|
78
|
+
def escape(value)
|
79
|
+
@entities.encode value
|
80
|
+
end
|
81
|
+
|
82
|
+
# Remove the last newline from the current code buffer
|
83
|
+
#
|
84
|
+
def remove_trailing_newline
|
85
|
+
@code.chop! if @code[-1] == "\n"
|
86
|
+
end
|
87
|
+
|
88
|
+
# Indent all lines of the input text using give indentation
|
89
|
+
#
|
90
|
+
# @param text [String] Input text to be indented
|
91
|
+
# @param indent [String] Indentation string to be appended
|
92
|
+
#
|
93
|
+
def indent_lines text, indent
|
94
|
+
text ||= ""
|
95
|
+
text.lines.inject("") do |result, line|
|
96
|
+
result += indent + line
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Give an explicit error report where an unexpected sequence of tokens
|
101
|
+
# appears and give indications on how to solve it
|
102
|
+
#
|
103
|
+
# @param context [Symbol] Context name in which the error happens
|
104
|
+
# @param data [Array] Additional error information
|
105
|
+
#
|
106
|
+
def error(context, *data)
|
107
|
+
message = case context
|
108
|
+
when :enumerable
|
109
|
+
"The provided each structure iteration input \"#{data[0]}\" is not Enumerable."
|
110
|
+
when :binding
|
111
|
+
data[0] = data[0].to_s.match(/\`(.*)\'/)
|
112
|
+
data[0] = data[0][1] if data[0]
|
113
|
+
"Found an undefined local variable or method \"#{data[0]}\" at \"#{data[1]}\"."
|
114
|
+
when :variable_name
|
115
|
+
data[0] = data[0].to_s.match(/\`(.*)\'/)[1]
|
116
|
+
"Found an undefined local variable or method \"#{data[0]}\" in locals."
|
117
|
+
when :extension
|
118
|
+
"The extension sequence \"#{data[0]}\" is not a valid attributes extension. " +
|
119
|
+
"Please use a Hash to extend attributes."
|
120
|
+
when :filter_registered
|
121
|
+
"The \"#{data[0]}\" filter could not be recognized by Opulent."
|
122
|
+
when :filter_load
|
123
|
+
"The gem required for the \"#{data[0]}\" filter is not installed. You can install it by running:\n\n#{data[1]}"
|
124
|
+
end
|
125
|
+
|
126
|
+
# Reconstruct lines to display where errors occur
|
127
|
+
fail "\n\nOpulent " + Logger.red("[Runtime Error]") + "\n---\n" +
|
128
|
+
"A runtime error has been encountered when building the compiled node tree.\n" +
|
129
|
+
"#{message}\n\n\n"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|