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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d6fdf705335f29c2162e3b2868398f4015ba29c
|
4
|
+
data.tar.gz: be920ffc6c6349e76d76ef802425146e5ed734e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ff789a689f140eccd4f853322bef8bec37747e52187a62d8c87a59d799944732451d419cd534fd7fc06ab216a55ac48db0a027db98200b86ce912d85c89ad3f
|
7
|
+
data.tar.gz: bfcb9e0566c3081bb99f2fe9f30ec697b7f78d35af9924e0fe0fd2835e04176007a62e90a072da4dc0361b23c902213d679d33cc24d486f085155176db67c21a
|
data/.gitignore
ADDED
data/.libold/opulent.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'htmlentities'
|
2
|
+
require 'tilt'
|
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/context'
|
10
|
+
require_relative 'opulent/runtime'
|
11
|
+
require_relative 'opulent/template'
|
12
|
+
require_relative 'opulent/filter'
|
13
|
+
require 'pp'
|
14
|
+
|
15
|
+
# @Opulent
|
16
|
+
module Opulent
|
17
|
+
# Wrapper method for creating a new Opulent instance
|
18
|
+
#
|
19
|
+
def Opulent.new
|
20
|
+
return Opulent.new
|
21
|
+
end
|
22
|
+
|
23
|
+
# @Opulent
|
24
|
+
class Opulent
|
25
|
+
# Analyze the input code and check for matching tokens. In case no match was
|
26
|
+
# found, throw an exception. In special cases, modify the token hash.
|
27
|
+
#
|
28
|
+
# @param file [String] The file that needs to be analyzed
|
29
|
+
# @param locals [Hash] Render call local variables
|
30
|
+
# @param block [Proc] Processing environment data
|
31
|
+
#
|
32
|
+
def render_file(file, locals = {}, &block)
|
33
|
+
# Temporarily set file render mode for using it in the Preprocessor
|
34
|
+
@mode = :file
|
35
|
+
|
36
|
+
# Render the file
|
37
|
+
render file, locals, &block
|
38
|
+
end
|
39
|
+
|
40
|
+
# Analyze the input code and check for matching tokens. In case no match was
|
41
|
+
# found, throw an exception. In special cases, modify the token hash.
|
42
|
+
#
|
43
|
+
# @param file [String] The file that needs to be analyzed
|
44
|
+
# @param locals [Hash] Render call local variables
|
45
|
+
# @param block [Proc] Processing environment data
|
46
|
+
#
|
47
|
+
def render(code, locals = {}, &block)
|
48
|
+
# Get the code from the input file
|
49
|
+
@code = PreProcessor.process code, @mode, &block
|
50
|
+
|
51
|
+
# Reset rendering mode to code. The mode variable is used to specify
|
52
|
+
# whether we're using render file or render code. When using render code,
|
53
|
+
# the preprocessor can be used only when a block is also passed
|
54
|
+
@mode = :code
|
55
|
+
|
56
|
+
# Instantiate required language components
|
57
|
+
@syntax = Parser.parse @code
|
58
|
+
|
59
|
+
# Create a new context based on our rendering environment
|
60
|
+
#bind = block.binding if block
|
61
|
+
#@context = Context.new locals, bind
|
62
|
+
|
63
|
+
# Instantiate required language components
|
64
|
+
#@model = Runtime.remodel @syntax, @context
|
65
|
+
|
66
|
+
#puts "\n\nModel\n---"
|
67
|
+
#Logger.pretty_print @model
|
68
|
+
end
|
69
|
+
|
70
|
+
# Update the engine options with the required option changes
|
71
|
+
#
|
72
|
+
def update_options(opts)
|
73
|
+
Engine.update_options(opts)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Give an explicit error report where an unexpected sequence of tokens
|
79
|
+
# appears and give indications on how to solve it
|
80
|
+
#
|
81
|
+
# @param context [Symbol] Context name in which the error happens
|
82
|
+
# @param data [Array] Additional error information
|
83
|
+
#
|
84
|
+
def error(context, *data)
|
85
|
+
message = case context
|
86
|
+
when :options_key
|
87
|
+
"The input \"#{data[0]}\" is not a valid option name."
|
88
|
+
end
|
89
|
+
|
90
|
+
# Reconstruct lines to display where errors occur
|
91
|
+
fail "\n\nOpulent " + Logger.red("[Engine Error]") + "\n---\n" +
|
92
|
+
"An error has been encountered when updating the engine options.\n" +
|
93
|
+
"#{message}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Context
|
4
|
+
#
|
5
|
+
# The context class is used to differentiate local, instance and class variables
|
6
|
+
# and to define the current working environment. Each class, method and instance
|
7
|
+
# has its own context
|
8
|
+
#
|
9
|
+
class Context
|
10
|
+
attr_accessor :locals, :binding, :parent, :name
|
11
|
+
|
12
|
+
# Create a context from the environment binding, extended with the locals
|
13
|
+
# given as arguments
|
14
|
+
#
|
15
|
+
# @param locals [Hash] Binding extension
|
16
|
+
# @param bind [Binding] Call environment binding
|
17
|
+
#
|
18
|
+
def initialize(locals = {}, bind = nil)
|
19
|
+
@binding = if bind
|
20
|
+
bind.clone
|
21
|
+
else
|
22
|
+
Binding.new
|
23
|
+
end
|
24
|
+
|
25
|
+
extend_locals locals
|
26
|
+
end
|
27
|
+
|
28
|
+
# Evaluate ruby code in current context
|
29
|
+
#
|
30
|
+
# @param code [String] Code to be evaluated
|
31
|
+
#
|
32
|
+
def evaluate(code)
|
33
|
+
begin
|
34
|
+
eval code, @binding
|
35
|
+
rescue NameError => variable
|
36
|
+
Runtime.error :binding, variable, code
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Extend the call context with a Hash, String or other Object
|
41
|
+
#
|
42
|
+
# @param context [Object] Extension object
|
43
|
+
#
|
44
|
+
def extend_locals(locals)
|
45
|
+
# Create new local variables from the input hash
|
46
|
+
locals.each do |key, value|
|
47
|
+
begin
|
48
|
+
@binding.local_variable_set(key.to_sym, value)
|
49
|
+
rescue NameError => variable
|
50
|
+
Runtime.error :variable_name, variable, key
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Extend instance, class and global variables for use in definitions
|
56
|
+
#
|
57
|
+
# @param bind [Binding] Binding to extend current context binding
|
58
|
+
#
|
59
|
+
def extend_nonlocals(bind)
|
60
|
+
bind.eval('instance_variables').each do |var|
|
61
|
+
@binding.eval('self').instance_variable_set var, bind.eval(var.to_s)
|
62
|
+
end
|
63
|
+
|
64
|
+
bind.eval('self.class.class_variables').each do |var|
|
65
|
+
@binding.eval('self').class_variable_set var, bind.eval(var.to_s)
|
66
|
+
end
|
67
|
+
|
68
|
+
bind.eval('self.class.constants').each do |var|
|
69
|
+
@binding.eval('self').const_set var, bind.eval(var.to_s)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @Binding
|
75
|
+
class Binding
|
76
|
+
def self.new
|
77
|
+
binding
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# @SugarCube
|
2
|
+
module Opulent
|
3
|
+
# @Engine
|
4
|
+
module Engine
|
5
|
+
# Default (root) theme name which can be accesed using the root definitions
|
6
|
+
DEFAULT_THEME = :default
|
7
|
+
|
8
|
+
# Default yield target which is used for child block replacements
|
9
|
+
DEFAULT_YIELD = :children
|
10
|
+
|
11
|
+
# List of self enclosing node elements
|
12
|
+
SELF_ENCLOSING = %w(img link input meta br hr area base col command embed keygen param source track wbr)
|
13
|
+
|
14
|
+
# @Singleton
|
15
|
+
class << self
|
16
|
+
attr_accessor :filters, :options
|
17
|
+
|
18
|
+
# Opulent runtime options
|
19
|
+
@@defaults = {
|
20
|
+
pretty: true,
|
21
|
+
indent: 2,
|
22
|
+
dependency_manager: true,
|
23
|
+
shorthand: {
|
24
|
+
class: /\./,
|
25
|
+
id: /\#/,
|
26
|
+
name: /\&/
|
27
|
+
},
|
28
|
+
each: {
|
29
|
+
:default_key => :key,
|
30
|
+
:default_value => :value
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
# Set defaults as initial options
|
35
|
+
@@options = @@defaults.clone
|
36
|
+
|
37
|
+
# Get an option at runtime
|
38
|
+
#
|
39
|
+
# @param name [Symbol] Identifier for the option
|
40
|
+
#
|
41
|
+
def [](name)
|
42
|
+
@@options[name]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set a new option at runtime
|
46
|
+
#
|
47
|
+
# @param name [Symbol] Identifier for the option
|
48
|
+
# @param value Option value to be set
|
49
|
+
#
|
50
|
+
def []=(name, value)
|
51
|
+
@@options[name] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add a new Opulent filter to the filters knowledgebase
|
55
|
+
#
|
56
|
+
# @param class [Class] Class to be used for filter instance
|
57
|
+
# @param name [Symbol] Identifier in the filters hash
|
58
|
+
# @param options [Hash] Filter engine instance options
|
59
|
+
#
|
60
|
+
def register(klass, name, options)
|
61
|
+
@filters ||= {}
|
62
|
+
@filters[name] = klass.new name, options
|
63
|
+
end
|
64
|
+
|
65
|
+
# Check if the chosen filter name is registed within our knowledgebase
|
66
|
+
#
|
67
|
+
def filter?(name)
|
68
|
+
@filters.has_key? name
|
69
|
+
end
|
70
|
+
|
71
|
+
# Update the engine options with the required option changes
|
72
|
+
#
|
73
|
+
# @param opts [Hash] Option extension
|
74
|
+
#
|
75
|
+
def update_options(opts)
|
76
|
+
@@options = @@defaults.clone
|
77
|
+
|
78
|
+
opts.each do |key, value|
|
79
|
+
if @@options[key]
|
80
|
+
@@options[key] = value
|
81
|
+
else
|
82
|
+
error :options_key, key
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Filter
|
4
|
+
module Filter
|
5
|
+
# @Filter
|
6
|
+
class Filter
|
7
|
+
attr_accessor :name, :options, :loaded
|
8
|
+
|
9
|
+
# Set tag and attribute options for filter
|
10
|
+
#
|
11
|
+
def initialize(name, options)
|
12
|
+
@name = name
|
13
|
+
@options = options
|
14
|
+
@loaded = false
|
15
|
+
end
|
16
|
+
|
17
|
+
# Error output in case the filter does not exist
|
18
|
+
#
|
19
|
+
def load_filter
|
20
|
+
unless @loaded
|
21
|
+
# Try to load the library associated to the chosen filter
|
22
|
+
begin
|
23
|
+
require gem_name
|
24
|
+
@loaded = true
|
25
|
+
rescue LoadError => error
|
26
|
+
# Error output with filter name and installation instructions
|
27
|
+
Runtime.error :filter_load, @name, install_error
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Error message to be shown in order to provide installation instructions
|
33
|
+
# for the developer
|
34
|
+
#
|
35
|
+
def install_error
|
36
|
+
"gem install #{gem_name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Process input code using this filter and return the output to the
|
40
|
+
# evaluation method from the Filter Node
|
41
|
+
#
|
42
|
+
def render(code, options = {})
|
43
|
+
raise NoMethodError
|
44
|
+
end
|
45
|
+
|
46
|
+
# RubyGems name for explicit library require
|
47
|
+
#
|
48
|
+
def gem_name
|
49
|
+
raise NoMethodError
|
50
|
+
# "gem_name"
|
51
|
+
end
|
52
|
+
|
53
|
+
# After defining how to render the code,
|
54
|
+
#
|
55
|
+
# Engine.register self, :filter, tag: :tag, attributes: { type: 'text/css' }
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Add the default registered rendering filters for Opulent
|
60
|
+
|
61
|
+
# @CoffeeScript
|
62
|
+
class CoffeeScript < Filter
|
63
|
+
def render(code, options = {})
|
64
|
+
::CoffeeScript.compile code, options
|
65
|
+
end
|
66
|
+
|
67
|
+
def gem_name
|
68
|
+
"coffee-script"
|
69
|
+
end
|
70
|
+
|
71
|
+
Engine.register self, :coffeescript, tag: :script, attributes: { type: 'javascript' }
|
72
|
+
end
|
73
|
+
|
74
|
+
# @Scss
|
75
|
+
class Scss < Filter
|
76
|
+
def render(code, options = {})
|
77
|
+
::Sass.compile code, options
|
78
|
+
end
|
79
|
+
|
80
|
+
def gem_name
|
81
|
+
"sass"
|
82
|
+
end
|
83
|
+
|
84
|
+
Engine.register self, :scss, tag: :style, attributes: { type: 'text/css' }
|
85
|
+
end
|
86
|
+
|
87
|
+
# @Sass
|
88
|
+
class Sass < Filter
|
89
|
+
def render(code, options = {})
|
90
|
+
options[:syntax] = :sass
|
91
|
+
::Sass.compile code, options
|
92
|
+
end
|
93
|
+
|
94
|
+
def gem_name
|
95
|
+
"sass"
|
96
|
+
end
|
97
|
+
|
98
|
+
Engine.register self, :sass, tag: :style, attributes: { type: 'text/css' }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Logger
|
4
|
+
module Logger
|
5
|
+
# @Singleton
|
6
|
+
class << self
|
7
|
+
# Color the input text with the chosen color
|
8
|
+
#
|
9
|
+
# @param text [String] the string that will be colored
|
10
|
+
# @param color_code [String] preset code for certain colors
|
11
|
+
#
|
12
|
+
def colorize(text, color_code)
|
13
|
+
require_windows_libs
|
14
|
+
"#{color_code}#{text}\e[0m"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Colors available in the terminal
|
18
|
+
#
|
19
|
+
def black(text); colorize(text, "\e[30m"); end
|
20
|
+
def red(text); colorize(text, "\e[31m"); end
|
21
|
+
def green(text); colorize(text, "\e[32m"); end
|
22
|
+
def yellow(text); colorize(text, "\e[33m"); end
|
23
|
+
def blue(text); colorize(text, "\e[34m"); end
|
24
|
+
def magenta(text); colorize(text, "\e[35m"); end
|
25
|
+
def cyan(text); colorize(text, "\e[36m"); end
|
26
|
+
def white(text); colorize(text, "\e[37m"); end
|
27
|
+
def default(text); colorize(text, "\e[38m"); end
|
28
|
+
|
29
|
+
# Require windows libraries for ANSI Console output
|
30
|
+
#
|
31
|
+
def require_windows_libs
|
32
|
+
begin
|
33
|
+
require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/
|
34
|
+
rescue LoadError
|
35
|
+
raise 'You must run "gem install win32console" to use Opulent\'s
|
36
|
+
error reporting on Windows.'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Pretty print Nodes with their important details
|
41
|
+
#
|
42
|
+
def pretty_print(model, indent = 0)
|
43
|
+
model.each do |node|
|
44
|
+
case node
|
45
|
+
when Nodes::Node
|
46
|
+
puts " " * indent +
|
47
|
+
node.name.to_s +
|
48
|
+
"::" + node.class.to_s.split('::').last +
|
49
|
+
" #{node.attributes unless node.attributes.empty?}"
|
50
|
+
pretty_print node.children, indent + 2
|
51
|
+
when Nodes::Text, Nodes::Print
|
52
|
+
puts " " * indent +
|
53
|
+
"text" +
|
54
|
+
"::" + node.class.to_s.split('::').last +
|
55
|
+
" {:value => \"#{node.value}\"}"
|
56
|
+
when NilClass
|
57
|
+
else
|
58
|
+
puts " " * indent +
|
59
|
+
node.name.to_s +
|
60
|
+
"::" + node.class.to_s.split('::').last +
|
61
|
+
" {:value => \"#{node.value}\"}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|