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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab630e2e6b7eec2139fbc4b14699985eefed370a
|
4
|
+
data.tar.gz: a132ae2fd1e1fd2d39dc8a9957f1e410dfcc821b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2624ab09740f0ee43309ffef7de6d5508e3880576ee0c461902b5762012c096ce7e829dcab577f1913fc29755956dc0cee256168e8d45bb579c3e81e9f6e0478
|
7
|
+
data.tar.gz: f859d3d06ca8bc9d1303c6afe7fa96f5a8e5a8a96d6c2d0bd67542392c2a9e4c29bb5736254786f051a6408b72db94ea41fabe415f7cdd10637ac3b26e2dea1b
|
data/Bade.gemspec
CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.summary = %q{Minimalistic template engine for Ruby.}
|
15
15
|
spec.homepage = 'https://github.com/epuber-io/bade'
|
16
16
|
spec.license = 'MIT'
|
17
|
+
spec.required_ruby_version = '>= 2.0'
|
17
18
|
|
18
19
|
spec.files = Dir['bin/**/*'] + Dir['lib/**/*'] + %w(Bade.gemspec Gemfile README.md)
|
19
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,8 @@ Minimalistic template engine written in Ruby for Ruby. Developed mainly to help
|
|
8
8
|
|
9
9
|
The language is in development state, breaking changes can be made in future. Current version supports minimal list of features to make it working in production for my purposes.
|
10
10
|
|
11
|
+
This gem acts only as library, it does not provide CLI tool, yet.
|
12
|
+
|
11
13
|
|
12
14
|
## Installation
|
13
15
|
|
@@ -19,7 +21,7 @@ gem 'bade'
|
|
19
21
|
|
20
22
|
And then execute:
|
21
23
|
|
22
|
-
$ bundle
|
24
|
+
$ bundle install
|
23
25
|
|
24
26
|
Or install it yourself as:
|
25
27
|
|
@@ -40,7 +42,6 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/epuber
|
|
40
42
|
|
41
43
|
## TODO
|
42
44
|
|
43
|
-
- [ ] move all cards from Trello to GitHub
|
44
45
|
- [ ] create documentation about syntax
|
45
46
|
- [ ] create several examples
|
46
47
|
|
data/lib/bade.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'node'
|
4
|
+
|
5
|
+
|
6
|
+
module Bade
|
7
|
+
module AST
|
8
|
+
class Document
|
9
|
+
# Root node of this document
|
10
|
+
#
|
11
|
+
# @return [Bade::Node]
|
12
|
+
#
|
13
|
+
attr_reader :root
|
14
|
+
|
15
|
+
# Path to this document, but only if it is defined from file
|
16
|
+
#
|
17
|
+
# @return [String, nil]
|
18
|
+
#
|
19
|
+
attr_reader :file_path
|
20
|
+
|
21
|
+
# @return [Array<Bade::Document>]
|
22
|
+
#
|
23
|
+
attr_reader :sub_documents
|
24
|
+
|
25
|
+
# @param root [Bade::Node]
|
26
|
+
#
|
27
|
+
def initialize(root: Node.new(:root), file_path: nil)
|
28
|
+
@root = root
|
29
|
+
|
30
|
+
@file_path = file_path.dup.freeze unless file_path.nil?
|
31
|
+
@sub_documents = []
|
32
|
+
end
|
33
|
+
|
34
|
+
def freeze
|
35
|
+
super
|
36
|
+
|
37
|
+
root.freeze
|
38
|
+
sub_documents.freeze
|
39
|
+
sub_documents.each(&:freeze)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param other [Bade::Document]
|
43
|
+
#
|
44
|
+
# @return [Bool]
|
45
|
+
#
|
46
|
+
def ==(other)
|
47
|
+
return false unless Document === other
|
48
|
+
|
49
|
+
root == other.root && sub_documents == other.sub_documents
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
module Bade
|
5
|
+
module AST
|
6
|
+
class Node
|
7
|
+
# --- MAIN INFO ---
|
8
|
+
|
9
|
+
# @return [Symbol] type of this node
|
10
|
+
#
|
11
|
+
attr_reader :type
|
12
|
+
|
13
|
+
# @return [Array<Bade::Node>]
|
14
|
+
#
|
15
|
+
attr_accessor :children
|
16
|
+
|
17
|
+
# --- METADATA ---
|
18
|
+
|
19
|
+
# @return [Int] line number
|
20
|
+
#
|
21
|
+
attr_reader :lineno
|
22
|
+
|
23
|
+
def initialize(type, lineno: nil)
|
24
|
+
@type = type
|
25
|
+
@children = []
|
26
|
+
|
27
|
+
@lineno = lineno
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
require_relative 'string_serializer'
|
32
|
+
StringSerializer.new(self).to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def inspect
|
36
|
+
to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param other [Node]
|
40
|
+
#
|
41
|
+
# @return [Bool]
|
42
|
+
#
|
43
|
+
def ==(other)
|
44
|
+
return false unless self.class == other.class
|
45
|
+
|
46
|
+
type == other.type && children == other.children
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../node'
|
4
|
+
|
5
|
+
|
6
|
+
module Bade
|
7
|
+
module AST
|
8
|
+
class DoctypeNode < ValueNode
|
9
|
+
# @return [String]
|
10
|
+
#
|
11
|
+
def xml_output
|
12
|
+
case value
|
13
|
+
when 'xml'
|
14
|
+
'<?xml version="1.0" encoding="utf-8" ?>'
|
15
|
+
|
16
|
+
when 'html'
|
17
|
+
'<!DOCTYPE html>'
|
18
|
+
|
19
|
+
else
|
20
|
+
raise Parser::ParserInternalError 'Unknown doctype type'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bade
|
4
|
+
module AST
|
5
|
+
class KeyValueNode < Node
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
# @return [Any]
|
11
|
+
#
|
12
|
+
attr_accessor :value
|
13
|
+
|
14
|
+
# @param other [KeyValueNode]
|
15
|
+
#
|
16
|
+
def ==(other)
|
17
|
+
super && name == other.name && value == other.value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bade
|
4
|
+
module AST
|
5
|
+
class MixinCommonNode < Node
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
# @return [Array<Node>]
|
11
|
+
#
|
12
|
+
def params
|
13
|
+
children.select { |n| allowed_parameter_types.include?(n.type) }
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [MixinCommonNode] other
|
17
|
+
#
|
18
|
+
def ==(other)
|
19
|
+
super && name == other.name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class MixinDeclarationNode < MixinCommonNode
|
24
|
+
def allowed_parameter_types
|
25
|
+
[:mixin_param, :mixin_key_param, :mixin_block_param]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class MixinBlockNode < MixinCommonNode
|
30
|
+
def allowed_parameter_types
|
31
|
+
[:mixin_param, :mixin_key_param]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class MixinCallNode < MixinCommonNode
|
36
|
+
def allowed_parameter_types
|
37
|
+
[:mixin_param, :mixin_key_param]
|
38
|
+
end
|
39
|
+
|
40
|
+
def blocks
|
41
|
+
children.select { |a| a.type == :mixin_block }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bade
|
4
|
+
module AST
|
5
|
+
class TagNode < Node
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
# @param [TagNode] other
|
11
|
+
#
|
12
|
+
def ==(other)
|
13
|
+
super && name == other.name
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Array<KeyValueNode>]
|
17
|
+
#
|
18
|
+
def attributes
|
19
|
+
children.select { |n| n.type == :tag_attr }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bade
|
4
|
+
module AST
|
5
|
+
class ValueNode < Node
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
attr_accessor :value
|
9
|
+
|
10
|
+
# @return [Bool]
|
11
|
+
#
|
12
|
+
attr_accessor :escaped
|
13
|
+
|
14
|
+
# @return [Bool]
|
15
|
+
#
|
16
|
+
attr_accessor :conditional
|
17
|
+
|
18
|
+
def initialize(*args)
|
19
|
+
super
|
20
|
+
|
21
|
+
@escaped = false
|
22
|
+
@conditional = false
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param [ValueNode] other
|
26
|
+
#
|
27
|
+
def ==(other)
|
28
|
+
super && value == other.value && escaped == other.escaped && conditional == other.conditional
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
module Bade
|
5
|
+
module AST
|
6
|
+
class NodeRegistrator
|
7
|
+
require_relative 'node/key_value_node'
|
8
|
+
require_relative 'node/tag_node'
|
9
|
+
require_relative 'node/value_node'
|
10
|
+
require_relative 'node/mixin_node'
|
11
|
+
require_relative 'node/doctype_node'
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# @return [Hash<Symbol, Class>]
|
15
|
+
#
|
16
|
+
def registered_types
|
17
|
+
@registered_types ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Method to map some node type to backing node class
|
21
|
+
#
|
22
|
+
# @param [Symbol] type type of the node
|
23
|
+
# @param [Class] klass registering class
|
24
|
+
#
|
25
|
+
# @return [nil]
|
26
|
+
#
|
27
|
+
def register_type(klass, type)
|
28
|
+
raise StandardError, "Class #{klass} should be subclass of #{Node}" unless klass <= Node
|
29
|
+
|
30
|
+
registered_types[type] = klass
|
31
|
+
end
|
32
|
+
|
33
|
+
# Method to create node backing instance
|
34
|
+
#
|
35
|
+
# @param [Symbol] type type of the node
|
36
|
+
# @param [Fixnum] lineno line number of the node appearance
|
37
|
+
#
|
38
|
+
# @return [Bade::AST::Node]
|
39
|
+
#
|
40
|
+
def create(type, lineno)
|
41
|
+
klass = registered_types[type]
|
42
|
+
|
43
|
+
if klass.nil?
|
44
|
+
raise ::KeyError, "Undefined node type #{type.inspect}"
|
45
|
+
end
|
46
|
+
|
47
|
+
klass.new(type, lineno: lineno)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
register_type ValueNode, :text
|
52
|
+
register_type ValueNode, :newline
|
53
|
+
register_type ValueNode, :code
|
54
|
+
register_type ValueNode, :output
|
55
|
+
|
56
|
+
register_type DoctypeNode, :doctype
|
57
|
+
|
58
|
+
register_type ValueNode, :import
|
59
|
+
|
60
|
+
# --- Comments
|
61
|
+
|
62
|
+
register_type Node, :comment
|
63
|
+
register_type Node, :html_comment
|
64
|
+
|
65
|
+
# --- Tags
|
66
|
+
|
67
|
+
register_type TagNode, :tag
|
68
|
+
register_type KeyValueNode, :tag_attr
|
69
|
+
|
70
|
+
# --- Mixins
|
71
|
+
|
72
|
+
register_type ValueNode, :mixin_param
|
73
|
+
register_type KeyValueNode, :mixin_key_param
|
74
|
+
register_type ValueNode, :mixin_block_param
|
75
|
+
|
76
|
+
register_type MixinBlockNode, :mixin_block
|
77
|
+
|
78
|
+
register_type MixinCallNode, :mixin_call
|
79
|
+
register_type MixinDeclarationNode, :mixin_decl
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
|
4
|
+
module Bade
|
5
|
+
module AST
|
6
|
+
class StringSerializer
|
7
|
+
# @return [AST::Node, AST::Document]
|
8
|
+
#
|
9
|
+
attr_reader :root
|
10
|
+
|
11
|
+
# @param [AST::Node, AST::Document] root
|
12
|
+
#
|
13
|
+
def initialize(root)
|
14
|
+
@root = root
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
case root
|
19
|
+
when Node
|
20
|
+
node_to_s(root, 0)
|
21
|
+
when Document
|
22
|
+
node_to_s(root.root, 0)
|
23
|
+
else
|
24
|
+
raise AttributeError, "Root attribute passed into initializer must be subclass of #{Node} or #{Document}, is #{root.class}!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Node] node
|
29
|
+
# @param [Fixnum] level
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
#
|
33
|
+
def node_to_s(node, level)
|
34
|
+
type_s = node.type.inspect
|
35
|
+
indent = ' ' * level
|
36
|
+
|
37
|
+
children_s = ''
|
38
|
+
if node.children.count > 0
|
39
|
+
children_s = "\n" + node.children.map { |n| node_to_s(n, level + 1) }.join("\n") + "\n#{indent}"
|
40
|
+
end
|
41
|
+
|
42
|
+
other = ''
|
43
|
+
|
44
|
+
case node
|
45
|
+
when TagNode
|
46
|
+
other = node.name
|
47
|
+
when KeyValueNode
|
48
|
+
other = "#{node.name}:#{node.value}"
|
49
|
+
when ValueNode
|
50
|
+
escaped_sign = if node.escaped
|
51
|
+
'& '
|
52
|
+
elsif node.escaped.nil?
|
53
|
+
'&(nil) '
|
54
|
+
else
|
55
|
+
''
|
56
|
+
end
|
57
|
+
other = "#{escaped_sign}#{node.value}"
|
58
|
+
when MixinCommonNode
|
59
|
+
other = node.name
|
60
|
+
when Node
|
61
|
+
# nothing
|
62
|
+
else
|
63
|
+
raise "Unknown node class #{node.class} of type #{node.type} for serializing"
|
64
|
+
end
|
65
|
+
|
66
|
+
other = ' ' + other if other && other.length > 0
|
67
|
+
|
68
|
+
"#{indent}(#{type_s}#{other}#{children_s})"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|