opulent 0.0.9 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.libold/opulent.rb +96 -0
  4. data/.libold/opulent/context.rb +80 -0
  5. data/.libold/opulent/engine.rb +88 -0
  6. data/.libold/opulent/filter.rb +101 -0
  7. data/.libold/opulent/logger.rb +67 -0
  8. data/.libold/opulent/nodes.rb +13 -0
  9. data/.libold/opulent/nodes/block.rb +29 -0
  10. data/.libold/opulent/nodes/comment.rb +35 -0
  11. data/.libold/opulent/nodes/control.rb +230 -0
  12. data/.libold/opulent/nodes/define.rb +42 -0
  13. data/.libold/opulent/nodes/eval.rb +41 -0
  14. data/.libold/opulent/nodes/expression.rb +28 -0
  15. data/.libold/opulent/nodes/filter.rb +70 -0
  16. data/.libold/opulent/nodes/helper.rb +69 -0
  17. data/.libold/opulent/nodes/node.rb +101 -0
  18. data/.libold/opulent/nodes/root.rb +62 -0
  19. data/.libold/opulent/nodes/text.rb +54 -0
  20. data/.libold/opulent/nodes/theme.rb +36 -0
  21. data/.libold/opulent/parser.rb +252 -0
  22. data/.libold/opulent/parser/block.rb +70 -0
  23. data/.libold/opulent/parser/comment.rb +32 -0
  24. data/.libold/opulent/parser/control.rb +83 -0
  25. data/.libold/opulent/parser/define.rb +39 -0
  26. data/.libold/opulent/parser/eval.rb +33 -0
  27. data/.libold/opulent/parser/expression.rb +350 -0
  28. data/.libold/opulent/parser/filter.rb +41 -0
  29. data/.libold/opulent/parser/node.rb +232 -0
  30. data/.libold/opulent/parser/root.rb +96 -0
  31. data/.libold/opulent/parser/text.rb +114 -0
  32. data/.libold/opulent/parser/theme.rb +36 -0
  33. data/.libold/opulent/preprocessor.rb +102 -0
  34. data/.libold/opulent/runtime.rb +144 -0
  35. data/.libold/opulent/template.rb +43 -0
  36. data/.libold/opulent/tokens.rb +276 -0
  37. data/.libold/opulent/version.rb +5 -0
  38. data/.rspec +2 -0
  39. data/.travis.yml +4 -0
  40. data/Gemfile +2 -0
  41. data/LICENSE +21 -0
  42. data/README.md +102 -0
  43. data/Rakefile +6 -0
  44. data/benchmark/benchmark.rb +46 -0
  45. data/benchmark/cases/node/node.haml +17 -0
  46. data/benchmark/cases/node/node.op +14 -0
  47. data/benchmark/cases/node/node.slim +19 -0
  48. data/bin/console +14 -0
  49. data/bin/setup +7 -0
  50. data/docs/syntax.md +3 -0
  51. data/docs/usage.md +3 -0
  52. data/lib/opulent.rb +11 -64
  53. data/lib/opulent/compiler.rb +132 -0
  54. data/lib/opulent/compiler/block.rb +31 -0
  55. data/lib/opulent/compiler/comment.rb +22 -0
  56. data/lib/opulent/compiler/control.rb +152 -0
  57. data/lib/opulent/compiler/define.rb +88 -0
  58. data/lib/opulent/compiler/eval.rb +15 -0
  59. data/lib/opulent/compiler/filter.rb +54 -0
  60. data/lib/opulent/compiler/node.rb +232 -0
  61. data/lib/opulent/compiler/root.rb +19 -0
  62. data/lib/opulent/compiler/text.rb +60 -0
  63. data/lib/opulent/context.rb +88 -0
  64. data/lib/opulent/engine.rb +60 -0
  65. data/lib/opulent/filters.rb +222 -0
  66. data/lib/opulent/logger.rb +47 -0
  67. data/lib/opulent/parser.rb +196 -0
  68. data/lib/opulent/parser/block.rb +56 -0
  69. data/lib/opulent/parser/comment.rb +27 -0
  70. data/lib/opulent/parser/control.rb +112 -0
  71. data/lib/opulent/parser/define.rb +30 -0
  72. data/lib/opulent/parser/eval.rb +21 -0
  73. data/lib/opulent/parser/expression.rb +344 -0
  74. data/lib/opulent/parser/filter.rb +25 -0
  75. data/lib/opulent/parser/node.rb +246 -0
  76. data/lib/opulent/parser/root.rb +48 -0
  77. data/lib/opulent/parser/text.rb +127 -0
  78. data/lib/opulent/settings.rb +79 -0
  79. data/lib/opulent/template.rb +67 -0
  80. data/lib/opulent/tokens.rb +166 -0
  81. data/lib/opulent/version.rb +4 -0
  82. data/opulent.gemspec +36 -0
  83. metadata +160 -7
@@ -0,0 +1,5 @@
1
+ module Opulent
2
+ # Opulent version string
3
+ # @api public
4
+ VERSION = '0.0.1'
5
+ end
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ before_install: gem install bundler -v 1.10.5
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
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.
@@ -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).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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 &copy; Hello world!
@@ -0,0 +1,14 @@
1
+ html
2
+ head
3
+ title
4
+ meta
5
+ body
6
+ nav
7
+ ul
8
+ li
9
+ li
10
+ li
11
+ content
12
+ container
13
+ row
14
+ col-md-12
@@ -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 &copy; Hello world!
@@ -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
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ #Opulent Syntax
2
+
3
+ @TODO
@@ -0,0 +1,3 @@
1
+ # Opulent Usage
2
+
3
+ @TODO
@@ -1,64 +1,11 @@
1
- require 'pp'
2
- require 'json'
3
- require_relative 'opulent/engine'
4
- require_relative 'opulent/logger'
5
- require_relative 'opulent/preprocessor'
6
- require_relative 'opulent/tokens'
7
- require_relative 'opulent/nodes'
8
- require_relative 'opulent/parser'
9
- require_relative 'opulent/runtime'
10
-
11
- module Opulent
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