bade 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Bade.gemspec +1 -0
- data/Gemfile +3 -0
- data/README.md +3 -2
- data/lib/bade.rb +1 -0
- data/lib/bade/ast/document.rb +53 -0
- data/lib/bade/ast/node.rb +50 -0
- data/lib/bade/ast/node/doctype_node.rb +25 -0
- data/lib/bade/ast/node/key_value_node.rb +21 -0
- data/lib/bade/ast/node/mixin_node.rb +45 -0
- data/lib/bade/ast/node/tag_node.rb +23 -0
- data/lib/bade/ast/node/value_node.rb +32 -0
- data/lib/bade/ast/node_registrator.rb +82 -0
- data/lib/bade/ast/string_serializer.rb +72 -0
- data/lib/bade/generator.rb +353 -6
- data/lib/bade/parser.rb +199 -129
- data/lib/bade/precompiled.rb +61 -0
- data/lib/bade/renderer.rb +151 -31
- data/lib/bade/ruby_extensions/array.rb +45 -0
- data/lib/bade/ruby_extensions/string.rb +50 -20
- data/lib/bade/runtime.rb +2 -0
- data/lib/bade/runtime/block.rb +56 -10
- data/lib/bade/runtime/mixin.rb +43 -0
- data/lib/bade/runtime/render_binding.rb +53 -9
- data/lib/bade/version.rb +2 -1
- metadata +16 -14
- data/lib/bade/document.rb +0 -33
- data/lib/bade/generator/html_generator.rb +0 -80
- data/lib/bade/generator/ruby_generator.rb +0 -336
- data/lib/bade/node.rb +0 -116
- data/lib/bade/node/doctype_node.rb +0 -21
- data/lib/bade/node/key_value_node.rb +0 -10
- data/lib/bade/node/mixin_node.rb +0 -69
- data/lib/bade/node/tag_node.rb +0 -29
- data/lib/bade/ruby_extensions/object.rb +0 -11
data/lib/bade/runtime.rb
CHANGED
data/lib/bade/runtime/block.rb
CHANGED
@@ -1,9 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Bade
|
3
4
|
module Runtime
|
4
5
|
class RuntimeError < ::StandardError; end
|
5
6
|
|
6
7
|
class Block
|
8
|
+
class MissingBlockDefinitionError < RuntimeError
|
9
|
+
# @return [String]
|
10
|
+
#
|
11
|
+
attr_accessor :name
|
12
|
+
|
13
|
+
# @return [Symbol] context of missing block, allowed values are :render and :call
|
14
|
+
#
|
15
|
+
attr_accessor :context
|
16
|
+
|
17
|
+
def initialize(name, context, msg = nil)
|
18
|
+
super()
|
19
|
+
|
20
|
+
self.name = name
|
21
|
+
self.context = context
|
22
|
+
|
23
|
+
@message = msg
|
24
|
+
end
|
25
|
+
|
26
|
+
def message
|
27
|
+
@message || "Block `#{name}` must have block definition to #{context}."
|
28
|
+
end
|
29
|
+
end
|
7
30
|
|
8
31
|
# @return [Proc]
|
9
32
|
#
|
@@ -13,28 +36,51 @@ module Bade
|
|
13
36
|
#
|
14
37
|
attr_reader :name
|
15
38
|
|
16
|
-
# @
|
39
|
+
# @return [RenderBinding]
|
40
|
+
#
|
41
|
+
attr_reader :render_binding
|
42
|
+
|
43
|
+
# @param [String] name name of the block
|
44
|
+
# @param [RenderBinding] render_binding reference to current binding instance
|
45
|
+
# @param [Proc] block reference to lambda
|
17
46
|
#
|
18
|
-
def initialize(name, &block)
|
47
|
+
def initialize(name, render_binding, &block)
|
19
48
|
@name = name
|
20
|
-
@
|
49
|
+
@render_binding = render_binding
|
50
|
+
@block = block
|
21
51
|
end
|
22
52
|
|
53
|
+
# --- Calling methods
|
54
|
+
|
23
55
|
def call(*args)
|
24
|
-
|
56
|
+
call!(*args) unless @block.nil?
|
25
57
|
end
|
26
58
|
|
27
59
|
def call!(*args)
|
28
60
|
if @block.nil?
|
29
|
-
raise
|
61
|
+
raise MissingBlockDefinitionError.new(name, :call)
|
30
62
|
else
|
31
|
-
@block.call(*args)
|
63
|
+
render_binding.__buff.concat(@block.call(*args))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# --- Rendering methods
|
68
|
+
|
69
|
+
def render(*args)
|
70
|
+
if @block.nil?
|
71
|
+
''
|
72
|
+
else
|
73
|
+
render!(*args)
|
32
74
|
end
|
33
75
|
end
|
34
|
-
end
|
35
|
-
end
|
36
76
|
|
37
|
-
|
38
|
-
|
77
|
+
def render!(*args)
|
78
|
+
if @block.nil?
|
79
|
+
raise MissingBlockDefinitionError.new(name, :render)
|
80
|
+
else
|
81
|
+
@block.call(*args).join
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
39
85
|
end
|
40
86
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bade
|
4
|
+
module Runtime
|
5
|
+
require_relative 'block'
|
6
|
+
|
7
|
+
class Mixin < Block
|
8
|
+
def call!(blocks, *args)
|
9
|
+
block.call(blocks, *args)
|
10
|
+
rescue ArgumentError => e
|
11
|
+
case e.message
|
12
|
+
when /\Awrong number of arguments \(given ([0-9]+), expected ([0-9]+)\)\Z/, /\Awrong number of arguments \(([0-9]+) for ([0-9]+)\)\Z/
|
13
|
+
# handle incorrect parameters count
|
14
|
+
|
15
|
+
# minus one, because first argument is always hash of blocks
|
16
|
+
given = $1.to_i - 1
|
17
|
+
expected = $2.to_i - 1
|
18
|
+
raise ArgumentError, "wrong number of arguments (given #{given}, expected #{expected}) for mixin `#{name}`"
|
19
|
+
|
20
|
+
when /\Aunknown keyword: (.*)\Z/
|
21
|
+
# handle unknown key-value parameter
|
22
|
+
key_name = $1
|
23
|
+
raise ArgumentError, "unknown key-value argument `#{key_name}` for mixin `#{name}`"
|
24
|
+
|
25
|
+
else
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
|
29
|
+
rescue Block::MissingBlockDefinitionError => e
|
30
|
+
msg = case e.context
|
31
|
+
when :call
|
32
|
+
"Mixin `#{name}` requires block to get called of block `#{e.name}`"
|
33
|
+
when :render
|
34
|
+
"Mixin `#{name}` requires block to get rendered content of block `#{e.name}`"
|
35
|
+
else
|
36
|
+
raise ::ArgumentError, "Unknown context #{e.context} of error #{e}!"
|
37
|
+
end
|
38
|
+
|
39
|
+
raise Block::MissingBlockDefinitionError.new(e.name, e.context, msg)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
require_relative 'block'
|
3
4
|
|
@@ -6,27 +7,70 @@ module Bade
|
|
6
7
|
class RenderBinding
|
7
8
|
class KeyError < ::StandardError; end
|
8
9
|
|
10
|
+
# @return [Array<Array<String>>]
|
11
|
+
#
|
12
|
+
attr_accessor :__buffs_stack
|
13
|
+
|
14
|
+
# @return [Hash<String, Mixin>]
|
15
|
+
#
|
16
|
+
attr_accessor :__mixins
|
17
|
+
|
18
|
+
# Holds
|
19
|
+
# @return [String]
|
20
|
+
#
|
21
|
+
attr_accessor :__new_line, :__base_indent
|
22
|
+
|
9
23
|
# @param vars [Hash]
|
10
24
|
#
|
11
25
|
def initialize(vars = {})
|
12
|
-
|
26
|
+
__reset
|
27
|
+
|
28
|
+
vars.each do |key, value|
|
29
|
+
raise KeyError, "Already defined variable #{key.inspect} in this binding" if respond_to?(key.to_sym)
|
30
|
+
|
31
|
+
define_singleton_method(key) do
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
13
35
|
end
|
14
36
|
|
15
|
-
|
16
|
-
|
17
|
-
|
37
|
+
# Resets this binding to default state, this method should be envoked after running the template lambda
|
38
|
+
#
|
39
|
+
# @return [nil]
|
40
|
+
#
|
41
|
+
def __reset
|
42
|
+
@__buffs_stack = [[]]
|
43
|
+
@__mixins = Hash.new { |_hash, key| raise "Undefined mixin '#{key}'" }
|
18
44
|
end
|
19
45
|
|
20
46
|
# @return [Binding]
|
21
47
|
#
|
22
|
-
def
|
48
|
+
def __get_binding
|
23
49
|
binding
|
24
50
|
end
|
25
51
|
|
26
52
|
# Shortcut for creating blocks
|
27
53
|
#
|
28
|
-
def __create_block(
|
29
|
-
Bade::Runtime::Block.new(
|
54
|
+
def __create_block(name, &block)
|
55
|
+
Bade::Runtime::Block.new(name, self, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def __create_mixin(name, &block)
|
59
|
+
Bade::Runtime::Mixin.new(name, self, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
# --- Methods for dealing with pushing and poping buffers in stack
|
63
|
+
|
64
|
+
def __buff
|
65
|
+
__buffs_stack.last
|
66
|
+
end
|
67
|
+
|
68
|
+
def __buffs_push
|
69
|
+
__buffs_stack.push([])
|
70
|
+
end
|
71
|
+
|
72
|
+
def __buffs_pop
|
73
|
+
__buffs_stack.pop
|
30
74
|
end
|
31
75
|
|
32
76
|
# Escape input text with html escapes
|
@@ -35,14 +79,14 @@ module Bade
|
|
35
79
|
#
|
36
80
|
# @return [String]
|
37
81
|
#
|
38
|
-
def
|
82
|
+
def __html_escaped(text)
|
39
83
|
text.sub('&', '&')
|
40
84
|
.sub('<', '<')
|
41
85
|
.sub('>', '>')
|
42
86
|
.sub('"', '"')
|
43
87
|
end
|
44
88
|
|
45
|
-
def
|
89
|
+
def __tag_render_attribute(name, *values)
|
46
90
|
values = values.compact
|
47
91
|
return if values.empty?
|
48
92
|
|
data/lib/bade/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bade
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Kříž
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -63,21 +63,24 @@ files:
|
|
63
63
|
- Gemfile
|
64
64
|
- README.md
|
65
65
|
- lib/bade.rb
|
66
|
-
- lib/bade/document.rb
|
66
|
+
- lib/bade/ast/document.rb
|
67
|
+
- lib/bade/ast/node.rb
|
68
|
+
- lib/bade/ast/node/doctype_node.rb
|
69
|
+
- lib/bade/ast/node/key_value_node.rb
|
70
|
+
- lib/bade/ast/node/mixin_node.rb
|
71
|
+
- lib/bade/ast/node/tag_node.rb
|
72
|
+
- lib/bade/ast/node/value_node.rb
|
73
|
+
- lib/bade/ast/node_registrator.rb
|
74
|
+
- lib/bade/ast/string_serializer.rb
|
67
75
|
- lib/bade/generator.rb
|
68
|
-
- lib/bade/generator/html_generator.rb
|
69
|
-
- lib/bade/generator/ruby_generator.rb
|
70
|
-
- lib/bade/node.rb
|
71
|
-
- lib/bade/node/doctype_node.rb
|
72
|
-
- lib/bade/node/key_value_node.rb
|
73
|
-
- lib/bade/node/mixin_node.rb
|
74
|
-
- lib/bade/node/tag_node.rb
|
75
76
|
- lib/bade/parser.rb
|
77
|
+
- lib/bade/precompiled.rb
|
76
78
|
- lib/bade/renderer.rb
|
77
|
-
- lib/bade/ruby_extensions/
|
79
|
+
- lib/bade/ruby_extensions/array.rb
|
78
80
|
- lib/bade/ruby_extensions/string.rb
|
79
81
|
- lib/bade/runtime.rb
|
80
82
|
- lib/bade/runtime/block.rb
|
83
|
+
- lib/bade/runtime/mixin.rb
|
81
84
|
- lib/bade/runtime/render_binding.rb
|
82
85
|
- lib/bade/version.rb
|
83
86
|
homepage: https://github.com/epuber-io/bade
|
@@ -92,7 +95,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
95
|
requirements:
|
93
96
|
- - ">="
|
94
97
|
- !ruby/object:Gem::Version
|
95
|
-
version: '0'
|
98
|
+
version: '2.0'
|
96
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
100
|
requirements:
|
98
101
|
- - ">="
|
@@ -100,9 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
103
|
version: '0'
|
101
104
|
requirements: []
|
102
105
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.
|
106
|
+
rubygems_version: 2.5.1
|
104
107
|
signing_key:
|
105
108
|
specification_version: 4
|
106
109
|
summary: Minimalistic template engine for Ruby.
|
107
110
|
test_files: []
|
108
|
-
has_rdoc:
|
data/lib/bade/document.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
|
2
|
-
require_relative 'node'
|
3
|
-
|
4
|
-
|
5
|
-
module Bade
|
6
|
-
class Document
|
7
|
-
# Root node of this document
|
8
|
-
#
|
9
|
-
# @return [Bade::Node]
|
10
|
-
#
|
11
|
-
attr_accessor :root
|
12
|
-
|
13
|
-
# Path to this document, but only if it is defined from file
|
14
|
-
#
|
15
|
-
# @return [String, nil]
|
16
|
-
#
|
17
|
-
attr_reader :file_path
|
18
|
-
|
19
|
-
# @return [Array<Bade::Document>]
|
20
|
-
#
|
21
|
-
attr_reader :sub_documents
|
22
|
-
|
23
|
-
# @param root [Bade::Node]
|
24
|
-
#
|
25
|
-
def initialize(root: nil, file_path: nil)
|
26
|
-
@root = root || Node.new(:root)
|
27
|
-
@root.parent = self
|
28
|
-
|
29
|
-
@file_path = file_path
|
30
|
-
@sub_documents = []
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
require_relative '../generator'
|
2
|
-
|
3
|
-
module Bade
|
4
|
-
class HTMLGenerator < Generator
|
5
|
-
|
6
|
-
# @param [Node] root node
|
7
|
-
# @return [String]
|
8
|
-
#
|
9
|
-
def self.node_to_lambda(root, new_line: "\n", indent: "\t")
|
10
|
-
str = node_to_html_array(root, new_line: new_line, indent: indent).join
|
11
|
-
|
12
|
-
lambda {
|
13
|
-
str
|
14
|
-
}
|
15
|
-
end
|
16
|
-
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
# @param [Node] root node
|
21
|
-
# @return [Array<String>]
|
22
|
-
#
|
23
|
-
def self.node_to_html_array(root, new_line: "\n", indent: "\t", indent_level: 0)
|
24
|
-
unless root.kind_of? Node
|
25
|
-
return [ root.inspect ]
|
26
|
-
end
|
27
|
-
|
28
|
-
buff = []
|
29
|
-
|
30
|
-
if indent_level > 0 and not indent.empty?
|
31
|
-
buff << indent * indent_level
|
32
|
-
end
|
33
|
-
|
34
|
-
append_childrens = lambda { |indent_plus|
|
35
|
-
root.childrens.each { |node|
|
36
|
-
buff += node_to_html_array(node, new_line: new_line, indent: indent, indent_level: indent_level+indent_plus)
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
|
-
|
41
|
-
case root.type
|
42
|
-
when :root
|
43
|
-
append_childrens.call(0)
|
44
|
-
|
45
|
-
when :text
|
46
|
-
buff << root.data
|
47
|
-
|
48
|
-
when :tag
|
49
|
-
attributes = formatted_attributes root
|
50
|
-
|
51
|
-
if attributes.length > 0
|
52
|
-
buff << "<#{root.data} #{attributes}>" + new_line
|
53
|
-
else
|
54
|
-
buff << "<#{root.data}>" + new_line
|
55
|
-
end
|
56
|
-
|
57
|
-
append_childrens.call(1)
|
58
|
-
|
59
|
-
buff << "</#{root.data}>" + new_line
|
60
|
-
end
|
61
|
-
|
62
|
-
buff
|
63
|
-
end
|
64
|
-
|
65
|
-
# @param [Node] tag_node
|
66
|
-
#
|
67
|
-
# @return [String] formatted attributes
|
68
|
-
#
|
69
|
-
def self.formatted_attributes(tag_node)
|
70
|
-
|
71
|
-
attributes = tag_node.childrens.select { |child|
|
72
|
-
child.type == :tag_attribute
|
73
|
-
}.map { |attr|
|
74
|
-
"#{attr.data}=\"#{attr.childrens.first.data}\""
|
75
|
-
}
|
76
|
-
|
77
|
-
attributes.join ' '
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,336 +0,0 @@
|
|
1
|
-
require_relative '../generator'
|
2
|
-
require_relative '../runtime'
|
3
|
-
require_relative '../document'
|
4
|
-
|
5
|
-
module Bade
|
6
|
-
class RubyGenerator < Generator
|
7
|
-
|
8
|
-
BUFF_NAME = '__buff'
|
9
|
-
MIXINS_NAME = '__mixins'
|
10
|
-
START_STRING = "
|
11
|
-
lambda {
|
12
|
-
#{BUFF_NAME} = []
|
13
|
-
#{MIXINS_NAME} = Hash.new { |hash, key| raise \"Undefined mixin '\#{key}'\" }
|
14
|
-
"
|
15
|
-
|
16
|
-
END_STRING = "
|
17
|
-
#{BUFF_NAME}.join
|
18
|
-
}"
|
19
|
-
|
20
|
-
# @param [Document] document
|
21
|
-
#
|
22
|
-
# @return [Proc]
|
23
|
-
#
|
24
|
-
def self.document_to_lambda(document, new_line: "\n", indent: "\t", filename: '')
|
25
|
-
generator = self.new(new_line, indent)
|
26
|
-
generator.generate_lambda(document, filename)
|
27
|
-
end
|
28
|
-
|
29
|
-
# @param [Document] document
|
30
|
-
#
|
31
|
-
# @return [String]
|
32
|
-
#
|
33
|
-
def self.document_to_lambda_string(document, new_line: "\n", indent: "\t", filename: '')
|
34
|
-
generator = self.new(new_line, indent)
|
35
|
-
generator.generate_lambda_string(document)
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# @param [String] new_line_string
|
41
|
-
# @param [String] indent_string
|
42
|
-
#
|
43
|
-
def initialize(new_line_string, indent_string)
|
44
|
-
@new_line_string = new_line_string
|
45
|
-
@indent_string = indent_string
|
46
|
-
end
|
47
|
-
|
48
|
-
# @param [Document] document
|
49
|
-
# @param [String] filename
|
50
|
-
#
|
51
|
-
def generate_lambda(document, filename)
|
52
|
-
eval(generate_lambda_string(document), nil, filename)
|
53
|
-
end
|
54
|
-
|
55
|
-
# @param [Document] document
|
56
|
-
#
|
57
|
-
# @return [String] string to parse with Ruby
|
58
|
-
#
|
59
|
-
def generate_lambda_string(document)
|
60
|
-
@buff = []
|
61
|
-
@indent = 0
|
62
|
-
@code_indent = 1
|
63
|
-
|
64
|
-
@buff << START_STRING
|
65
|
-
|
66
|
-
visit_document(document)
|
67
|
-
|
68
|
-
@buff << END_STRING
|
69
|
-
|
70
|
-
@buff.join("\n")
|
71
|
-
end
|
72
|
-
|
73
|
-
# @param [String] text
|
74
|
-
#
|
75
|
-
def buff_print_text(text, indent: false, new_line: false)
|
76
|
-
indent_text = if indent
|
77
|
-
@indent_string * @indent
|
78
|
-
else
|
79
|
-
''
|
80
|
-
end
|
81
|
-
|
82
|
-
prepended_text = indent_text + text
|
83
|
-
|
84
|
-
if prepended_text.length > 0
|
85
|
-
buff_code %Q{#{BUFF_NAME} << %Q{#{prepended_text}}}
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def buff_code(text)
|
90
|
-
@buff << "\t" * @code_indent + text
|
91
|
-
end
|
92
|
-
|
93
|
-
|
94
|
-
# @param document [Bade::Document]
|
95
|
-
#
|
96
|
-
def visit_document(document)
|
97
|
-
document.sub_documents.each do |sub_document|
|
98
|
-
visit_document(sub_document)
|
99
|
-
end
|
100
|
-
|
101
|
-
buff_code("# ----- start file #{document.file_path}") unless document.file_path.nil?
|
102
|
-
visit_node(document.root)
|
103
|
-
buff_code("# ----- end file #{document.file_path}") unless document.file_path.nil?
|
104
|
-
end
|
105
|
-
|
106
|
-
# @param current_node [Node]
|
107
|
-
#
|
108
|
-
def visit_node_childrens(current_node)
|
109
|
-
visit_nodes(current_node.childrens)
|
110
|
-
end
|
111
|
-
|
112
|
-
# @param nodes [Array<Node>]
|
113
|
-
#
|
114
|
-
def visit_nodes(nodes)
|
115
|
-
nodes.each { |node|
|
116
|
-
visit_node(node)
|
117
|
-
}
|
118
|
-
end
|
119
|
-
|
120
|
-
# @param current_node [Node]
|
121
|
-
#
|
122
|
-
def visit_node(current_node)
|
123
|
-
case current_node.type
|
124
|
-
when :root
|
125
|
-
visit_node_childrens(current_node)
|
126
|
-
|
127
|
-
when :text
|
128
|
-
buff_print_text current_node.data
|
129
|
-
|
130
|
-
when :tag
|
131
|
-
visit_tag(current_node)
|
132
|
-
|
133
|
-
when :ruby_code
|
134
|
-
buff_code current_node.data
|
135
|
-
|
136
|
-
when :html_comment
|
137
|
-
buff_print_text '<!-- '
|
138
|
-
visit_node_childrens(current_node)
|
139
|
-
buff_print_text ' -->'
|
140
|
-
|
141
|
-
when :comment
|
142
|
-
comment_text = current_node.childrens.select { |node|
|
143
|
-
!node.data.nil?
|
144
|
-
}.map { |node|
|
145
|
-
node.data
|
146
|
-
}.join(@new_line_string + '#')
|
147
|
-
|
148
|
-
buff_code '#' + comment_text
|
149
|
-
|
150
|
-
when :doctype
|
151
|
-
buff_print_text current_node.xml_output
|
152
|
-
|
153
|
-
when :mixin_declaration
|
154
|
-
params = formatted_mixin_params(current_node)
|
155
|
-
buff_code "#{MIXINS_NAME}['#{current_node.data}'] = lambda { |#{params}|"
|
156
|
-
|
157
|
-
indent {
|
158
|
-
blocks_name_declaration(current_node)
|
159
|
-
visit_node_childrens(current_node)
|
160
|
-
}
|
161
|
-
|
162
|
-
buff_code '}'
|
163
|
-
|
164
|
-
when :mixin_call
|
165
|
-
params = formatted_mixin_params(current_node)
|
166
|
-
buff_code "#{MIXINS_NAME}['#{current_node.data}'].call(#{params})"
|
167
|
-
|
168
|
-
when :output
|
169
|
-
data = current_node.data
|
170
|
-
output_code = if current_node.escaped
|
171
|
-
"\#{html_escaped(#{data})}"
|
172
|
-
else
|
173
|
-
"\#{#{data}}"
|
174
|
-
end
|
175
|
-
buff_print_text output_code
|
176
|
-
|
177
|
-
when :newline
|
178
|
-
buff_print_text @new_line_string if @new_line_string.length > 0
|
179
|
-
|
180
|
-
when :import
|
181
|
-
# nothing
|
182
|
-
|
183
|
-
else
|
184
|
-
raise "Unknown type #{current_node.type}"
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
# @param [TagNode] current_node
|
189
|
-
#
|
190
|
-
def visit_tag(current_node)
|
191
|
-
attributes = formatted_attributes current_node
|
192
|
-
|
193
|
-
text = "<#{current_node.name}"
|
194
|
-
|
195
|
-
if attributes.length > 0
|
196
|
-
text += "#{attributes}"
|
197
|
-
end
|
198
|
-
|
199
|
-
other_than_new_lines = current_node.childrens.any? { |node|
|
200
|
-
node.type != :newline
|
201
|
-
}
|
202
|
-
|
203
|
-
if other_than_new_lines
|
204
|
-
text += '>'
|
205
|
-
else
|
206
|
-
text += '/>'
|
207
|
-
end
|
208
|
-
|
209
|
-
buff_print_text text, new_line: true, indent: true
|
210
|
-
|
211
|
-
if other_than_new_lines
|
212
|
-
last_node = current_node.childrens.last
|
213
|
-
is_last_newline = !last_node.nil? && last_node.type == :newline
|
214
|
-
nodes = if is_last_newline
|
215
|
-
current_node.childrens[0...-1]
|
216
|
-
else
|
217
|
-
current_node.childrens
|
218
|
-
end
|
219
|
-
|
220
|
-
indent do
|
221
|
-
visit_nodes(nodes)
|
222
|
-
end
|
223
|
-
|
224
|
-
buff_print_text "</#{current_node.name}>", new_line: true, indent: true
|
225
|
-
|
226
|
-
# print new line after the tag
|
227
|
-
visit_node(last_node) if is_last_newline
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
# @param [TagNode] tag_node
|
232
|
-
#
|
233
|
-
# @return [String] formatted attributes
|
234
|
-
#
|
235
|
-
def formatted_attributes(tag_node)
|
236
|
-
all_attributes = Hash.new { |hash, key| hash[key] = [] }
|
237
|
-
xml_attributes = []
|
238
|
-
|
239
|
-
tag_node.attributes.each do |attr|
|
240
|
-
unless all_attributes.include?(attr.name)
|
241
|
-
xml_attributes << attr.name
|
242
|
-
end
|
243
|
-
|
244
|
-
all_attributes[attr.name] << attr.value
|
245
|
-
end
|
246
|
-
|
247
|
-
xml_attributes.map do |attr_name|
|
248
|
-
joined = all_attributes[attr_name].join('), (')
|
249
|
-
%Q{\#{tag_render_attribute('#{attr_name}', (#{joined}))}}
|
250
|
-
end.join
|
251
|
-
end
|
252
|
-
|
253
|
-
def indent(plus = 1)
|
254
|
-
@code_indent += plus
|
255
|
-
yield
|
256
|
-
@code_indent -= plus
|
257
|
-
end
|
258
|
-
|
259
|
-
# @param [MixinCommonNode] mixin_node
|
260
|
-
#
|
261
|
-
# @return [String] formatted params
|
262
|
-
#
|
263
|
-
def formatted_mixin_params(mixin_node)
|
264
|
-
params = mixin_node.params
|
265
|
-
result = []
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
if mixin_node.type == :mixin_call
|
270
|
-
if mixin_node.blocks.length > 0
|
271
|
-
buff_code '__blocks = {}'
|
272
|
-
|
273
|
-
mixin_node.blocks.each { |block|
|
274
|
-
block_name = block.data ? block.data : 'default_block'
|
275
|
-
buff_code "__blocks['#{block_name}'] = __create_block('#{block_name}') do"
|
276
|
-
indent {
|
277
|
-
visit_node_childrens(block)
|
278
|
-
}
|
279
|
-
buff_code 'end'
|
280
|
-
}
|
281
|
-
|
282
|
-
result << '__blocks.dup'
|
283
|
-
else
|
284
|
-
result << '{}'
|
285
|
-
end
|
286
|
-
elsif mixin_node.type == :mixin_declaration
|
287
|
-
result << '__blocks'
|
288
|
-
end
|
289
|
-
|
290
|
-
|
291
|
-
# normal params
|
292
|
-
result += params.select { |param|
|
293
|
-
param.type == :mixin_param
|
294
|
-
}.map { |param|
|
295
|
-
param.data
|
296
|
-
}
|
297
|
-
|
298
|
-
result += params.select { |param|
|
299
|
-
param.type == :mixin_key_param
|
300
|
-
}.map { |param|
|
301
|
-
"#{param.name}: #{param.value}"
|
302
|
-
}
|
303
|
-
|
304
|
-
result.join(', ')
|
305
|
-
end
|
306
|
-
|
307
|
-
|
308
|
-
# @param [String] block_name
|
309
|
-
#
|
310
|
-
def block_name_declaration(block_name)
|
311
|
-
buff_code "#{block_name} = __blocks.delete('#{block_name}') { __create_block('#{block_name}') }"
|
312
|
-
end
|
313
|
-
|
314
|
-
# @param [MixinDeclarationNode] mixin_node
|
315
|
-
#
|
316
|
-
def blocks_name_declaration(mixin_node)
|
317
|
-
mixin_node.params.select { |param|
|
318
|
-
param.type == :mixin_block_param
|
319
|
-
}.each { |param|
|
320
|
-
block_name_declaration(param.data)
|
321
|
-
}
|
322
|
-
|
323
|
-
block_name_declaration('default_block')
|
324
|
-
end
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
# @param [String] str
|
329
|
-
#
|
330
|
-
# @return [Void]
|
331
|
-
#
|
332
|
-
def escape_double_quotes!(str)
|
333
|
-
str.gsub!(/"/, '\"')
|
334
|
-
end
|
335
|
-
end
|
336
|
-
end
|