erb_parser 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []