bade 0.1.4 → 0.2.0
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/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
|