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
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
|