erb_parser 0.0.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.
- data/lib/erb_parser.rb +33 -0
- data/lib/erb_parser/erb_grammar.treetop +47 -0
- data/lib/erb_parser/erb_tag.rb +23 -0
- data/lib/erb_parser/nodes.rb +27 -0
- data/lib/erb_parser/parsed_erb.rb +29 -0
- data/lib/erb_parser/treetop_runner.rb +18 -0
- data/lib/erb_parser/xml_transformer.rb +52 -0
- metadata +100 -0
data/lib/erb_parser.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'treetop'
|
2
|
+
require 'erb_parser/nodes'
|
3
|
+
require 'erb_parser/treetop_runner'
|
4
|
+
require 'erb_parser/parsed_erb'
|
5
|
+
require 'erb_parser/erb_tag'
|
6
|
+
require 'erb_parser/xml_transformer'
|
7
|
+
|
8
|
+
module ErbParser
|
9
|
+
def self.parse(str)
|
10
|
+
ParsedErb.new TreetopRunner.run(str)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Takes a string representing an XML document or fragment. Finds every ERB tag in the
|
14
|
+
# XML and replaces it with the tag <erb>. The contents of the replacement tag will be
|
15
|
+
# the inner Ruby code, escaped for XML. You can override the tag like so:
|
16
|
+
#
|
17
|
+
# ErbParser.transform_xml str, :tag => 'tag-name'
|
18
|
+
#
|
19
|
+
# If the ERB tag is of the form +<%=+, the attribute +interpolated="true"+ will be
|
20
|
+
# added. Else if the ERB tag is of the form +<#+, the attribute +comment="true"+ will be
|
21
|
+
# added. You can override this behavior like so:
|
22
|
+
#
|
23
|
+
# ErbParser.transform_xml str, :interp_attr => {'attr-name' => 'attr-value'}
|
24
|
+
# ErbParser.transform_xml str, :interp_attr => false
|
25
|
+
#
|
26
|
+
# ErbParser.transform_xml str, :comment_attr => {'attr-name' => 'attr-value'}
|
27
|
+
# ErbParser.transform_xml str, :comment_attr => false
|
28
|
+
#
|
29
|
+
# The returned value is a string representing the transformed XML document or fragment.
|
30
|
+
def self.transform_xml(str, options = {})
|
31
|
+
XmlTransformer.transform(parse(str), options)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ErbParser
|
2
|
+
grammar ErbGrammar
|
3
|
+
rule document
|
4
|
+
(erb_tag / text)*
|
5
|
+
end
|
6
|
+
|
7
|
+
rule text
|
8
|
+
(!'<%' .)+
|
9
|
+
<Text>
|
10
|
+
end
|
11
|
+
|
12
|
+
rule erb_tag
|
13
|
+
'<%'
|
14
|
+
number_sign:'#'? equal_sign:'='?
|
15
|
+
_ruby_code:ruby_code
|
16
|
+
'%>'
|
17
|
+
<ErbTag>
|
18
|
+
end
|
19
|
+
|
20
|
+
rule ruby_code
|
21
|
+
(string_literal / (!'%>' .))*
|
22
|
+
end
|
23
|
+
|
24
|
+
# Matches the following quote styles:
|
25
|
+
# "string"
|
26
|
+
# 'string'
|
27
|
+
# %q(string (string) string)
|
28
|
+
# %Q(string (string) string)
|
29
|
+
# %(string (string) string)
|
30
|
+
# %q{string {string} string}
|
31
|
+
# %Q{string {string} string}
|
32
|
+
# %{string {string} string}
|
33
|
+
rule string_literal
|
34
|
+
('"' ('\"' / !'"' .)* '"') /
|
35
|
+
('\'' ('\\\'' / !'\'' .)* '\'') /
|
36
|
+
('%' ('q' / 'Q')? (curly_brackets / parens))
|
37
|
+
end
|
38
|
+
|
39
|
+
rule curly_brackets
|
40
|
+
'{' (curly_brackets / '\}' / !'}' .)* '}'
|
41
|
+
end
|
42
|
+
|
43
|
+
rule parens
|
44
|
+
'(' (parens / '\)' / !')' .)* ')'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ErbParser
|
2
|
+
class ErbTag
|
3
|
+
def comment?
|
4
|
+
@treetop_node.comment?
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(treetop_node)
|
8
|
+
@treetop_node = treetop_node
|
9
|
+
end
|
10
|
+
|
11
|
+
def interpolated?
|
12
|
+
@treetop_node.interpolated?
|
13
|
+
end
|
14
|
+
|
15
|
+
def ruby_code
|
16
|
+
@treetop_node.ruby_code
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@treetop_node.text_value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ErbParser
|
2
|
+
module ErbGrammar
|
3
|
+
module Text
|
4
|
+
def type
|
5
|
+
:text
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ErbTag
|
10
|
+
def comment?
|
11
|
+
!number_sign.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def interpolated?
|
15
|
+
!equal_sign.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def ruby_code
|
19
|
+
_ruby_code.text_value
|
20
|
+
end
|
21
|
+
|
22
|
+
def type
|
23
|
+
:erb_tag
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ErbParser
|
2
|
+
class ParsedErb
|
3
|
+
# Accesses the parsed tokens as an array. Each element of the array is either a
|
4
|
+
# String, representing plain text, or an ErbTag.
|
5
|
+
def [](index)
|
6
|
+
@tokens[index]
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(treetop_ast)
|
10
|
+
@treetop_ast = treetop_ast
|
11
|
+
@tokens = treetop_ast.elements.map do |elem|
|
12
|
+
case elem.type
|
13
|
+
when :text
|
14
|
+
elem.text_value
|
15
|
+
when :erb_tag
|
16
|
+
ErbTag.new elem
|
17
|
+
else
|
18
|
+
raise "Unexpected type: #{elem.type}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the array of parsed tokens.
|
24
|
+
attr_reader :tokens
|
25
|
+
|
26
|
+
# Returns the raw Treetop AST.
|
27
|
+
attr_reader :treetop_ast
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Treetop.load File.join(File.dirname(__FILE__), 'erb_grammar')
|
2
|
+
|
3
|
+
module ErbParser
|
4
|
+
# This module doesn't do much. It just provides some boilerplate code to invoke Treetop.
|
5
|
+
# The result is whatever Treetop returns.
|
6
|
+
module TreetopRunner
|
7
|
+
def self.run(str, options = {})
|
8
|
+
treetop = ErbGrammarParser.new
|
9
|
+
if result = treetop.parse(str, options)
|
10
|
+
result
|
11
|
+
else
|
12
|
+
raise ParseError, treetop.failure_reason
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ParseError < RuntimeError; end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module ErbParser
|
4
|
+
module XmlTransformer
|
5
|
+
def self.transform(parsed_erb, options)
|
6
|
+
options = {
|
7
|
+
:tag => 'erb',
|
8
|
+
:interp_attr => {'interpolated' => 'true'},
|
9
|
+
:comment_attr => {'comment' => 'true'}
|
10
|
+
}.merge(options)
|
11
|
+
|
12
|
+
parsed_erb.tokens.map do |elem|
|
13
|
+
case elem
|
14
|
+
when String
|
15
|
+
elem
|
16
|
+
when ErbTag
|
17
|
+
if elem.interpolated?
|
18
|
+
if options[:interp_attr].is_a?(Hash)
|
19
|
+
attrs = options[:interp_attr]
|
20
|
+
else
|
21
|
+
attrs = {}
|
22
|
+
end
|
23
|
+
elsif elem.comment?
|
24
|
+
if options[:comment_attr].is_a?(Hash)
|
25
|
+
attrs = options[:comment_attr]
|
26
|
+
else
|
27
|
+
attrs = {}
|
28
|
+
end
|
29
|
+
else
|
30
|
+
attrs = {}
|
31
|
+
end
|
32
|
+
content_tag options[:tag], CGI.escape_html(elem.ruby_code), attrs
|
33
|
+
else
|
34
|
+
raise "Unexpected element: #{elem.class.name}"
|
35
|
+
end
|
36
|
+
end.join
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.content_tag(name, contents, attrs = {})
|
40
|
+
if attrs.empty?
|
41
|
+
attrs_str = ''
|
42
|
+
else
|
43
|
+
attrs_str = ' ' + attrs.map do |key, val|
|
44
|
+
key = CGI.escape_html(key.to_s)
|
45
|
+
val = CGI.escape_html(val.to_s)
|
46
|
+
%Q(#{key}="#{val}")
|
47
|
+
end.join(' ')
|
48
|
+
end
|
49
|
+
'<' + name.to_s + attrs_str + '>' + contents.to_s + '</' + name.to_s + '>'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: erb_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jarrett Colby
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-02-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: treetop
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: minitest
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: turn
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: ! 'Parses ERB templates into two types of tokens: Plain text and ERB
|
63
|
+
tags. Special support for HTML/XML.'
|
64
|
+
email: jarrett@madebyhq.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- lib/erb_parser/erb_grammar.treetop
|
70
|
+
- lib/erb_parser/erb_tag.rb
|
71
|
+
- lib/erb_parser/nodes.rb
|
72
|
+
- lib/erb_parser/parsed_erb.rb
|
73
|
+
- lib/erb_parser/treetop_runner.rb
|
74
|
+
- lib/erb_parser/xml_transformer.rb
|
75
|
+
- lib/erb_parser.rb
|
76
|
+
homepage: http://madebyhq.com/
|
77
|
+
licenses: []
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.8.25
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: Parser for ERB templates
|
100
|
+
test_files: []
|