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.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e616139da8f4b17f4fc7f52bb66b3e18d4d42be
4
- data.tar.gz: eb8dfdcaae0b2fb04c83430a742c7ae31ad34364
3
+ metadata.gz: 3d6fdf705335f29c2162e3b2868398f4015ba29c
4
+ data.tar.gz: be920ffc6c6349e76d76ef802425146e5ed734e8
5
5
  SHA512:
6
- metadata.gz: aca80c297f91ccc02b465534f6da7c755749092a10c14ca9b733e64df2f1aa90c551aeaa0383fa49ffd15ea3ecf81e6035df4b48e4bc6163e80aa41a4e0af048
7
- data.tar.gz: 7363ff73b1572727aa7aecaa42b86b04c6e101b82e399b763d25a3538a9c2aee1e1974254b34be5073cc08d1aa8e0dc0269746de8215af2d5a41670fb20751ea
6
+ metadata.gz: 5ff789a689f140eccd4f853322bef8bec37747e52187a62d8c87a59d799944732451d419cd534fd7fc06ab216a55ac48db0a027db98200b86ce912d85c89ad3f
7
+ data.tar.gz: bfcb9e0566c3081bb99f2fe9f30ec697b7f78d35af9924e0fe0fd2835e04176007a62e90a072da4dc0361b23c902213d679d33cc24d486f085155176db67c21a
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -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