erbse 0.0.2 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 37f385edabdf30c0807542d7c5560537b5db5f82
4
- data.tar.gz: 0bd510e68988198ff9e4ef3f3e796900fde9a41a
3
+ metadata.gz: df7ee95b6879b5591ad8cd4ee86fd374ac12e66d
4
+ data.tar.gz: a4c1100201726eebaada8b091c763d1b1925892c
5
5
  SHA512:
6
- metadata.gz: 69a822ab5ad04ec4495f484353b9cdce8780a9b78cb25018b57193ec670224a18e10470e0c88b84c01639cfb817456d322a77057e912e04852627209f2ae7bfb
7
- data.tar.gz: 80e5540f89a2ac0922730960d1c291e7bdd117a3db70b4b9c74f03245dc1945a279d7f59a008b806d5153d53da17b0dcfe7915b6c6814a9c692dddcdf7487c59
6
+ metadata.gz: 999650c0c6f0e0ac13d597874b10f62010ae573f04a51964f50a43543808c58b6b1a53456d4f931a6d0cfe41f6272cb22c8cd225e21913edb961a795585663d7
7
+ data.tar.gz: 42fb43d4d2de42d32c97e9e752175c1170395a9361be975c6ca59c65f5c6298055aea1430f421b755d850effd776b4c85c809b6c4d7b81af46d63f1f981114be
data/CHANGES.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 0.1.0
2
+
3
+ * Internally, we're parsing the ERB template into a SEXP structure and let [Temple](https://github.com/judofyr/temple) compile it to Ruby. Many thanks to the Temple team! 😘
4
+ * Yielding ERB blocks will simply return the content, no output buffering with instance variables will happen.
5
+ This allows to pass ERB blocks around and yield them in other objects without having it output twice as in 0.0.2.
6
+ * No instance variables are used anymore, output buffering always happens via locals the way [Slim](https://github.com/slim-template/slim) does it. This might result in a minimal speed decrease but cleans up the code and architecture immensely.
7
+ * Removed `Erbse::Template`, it was completely unnecessary code.
8
+
1
9
  # 0.0.2
2
10
 
3
- * First release. No escaping is happening and I'm not sure how capture works, yet. But: it's great!
11
+ * First release. No escaping is happening and I'm not sure how capture works, yet. But: it's great!
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gemspec
3
+ gemspec
4
+
5
+ gem "minitest-line"
data/README.md CHANGED
@@ -2,32 +2,54 @@
2
2
 
3
3
  _An updated version of Erubis._
4
4
 
5
- Erbse compiles an ERB string to a string of Ruby. It is completely decoupled from any framework and does only one thing. Pretty boring, I know.
5
+ Erbse compiles an ERB string to a string of Ruby.
6
6
 
7
- ## Added features
7
+ ## API
8
8
 
9
- * Block support a la Rails.
9
+ The API is one public method.
10
10
 
11
- ```erb
12
- <%= form_tag .. do |f| %>
13
- <%= f.fields_for do %>
14
- ...
15
- <% end %>
16
- <% end %>
17
- ```
11
+ ```ruby
12
+ Erbse::Engine.new.call("<% ... %>") #=> string of compiled ruby.
13
+ ```
18
14
 
19
- ## API
15
+ The returned string can then be `eval`uated in a certain context.
16
+
17
+ ## Block Yielding
20
18
 
21
- The API is extremely simple.
19
+ Erbse supports blocks à la Rails.
20
+
21
+ You may pass any mix of text/ERB via blocks to Ruby methods.
22
+
23
+ ```erb
24
+ <%= form do %>
25
+ <em>Please fill out all fields!</em>
26
+ <%= input :email %>
27
+ <button type="submit">
28
+ <% end %>
29
+ ```
30
+
31
+ Here, the `form` method receives a block of compiled Ruby.
32
+
33
+ When `yield`ed, the block simply returns its evaluated content as a string. It's your job to assign it to an output buffer, **no instance variables are used**.
22
34
 
23
35
  ```ruby
24
- Erbse::Template.new("<% ... %>").call #=> string of compiled ruby.
36
+ def form(&block)
37
+ content = yield
38
+ "<form>#{content}</form>"
39
+ end
25
40
  ```
41
+ Usually, returning the content from the helper will be sufficient.
42
+
43
+ However, you can totally pass that block to a completely different object and yield it there. Since there's no global state as in ERB, this will work.
26
44
 
27
- Template only accepts a content string which is the ERB template. The only public `#call` method returns a string of the compiled template that can then be evaluated in a context.
45
+ ## Removed Features
28
46
 
29
- The user layer, like Tilt, has to take care of caching the `Erbse::Template` instances.
47
+ Erbse does *not* support any tags other than `<% %>` and `<%= %>`. Tags such as `<%% %>`, `<%== %>`, `<%- %>` or `<% -%>` will be reduced to the supported tags.
30
48
 
49
+ ## TODO
50
+
51
+ * Block comments
52
+ * Add newlines in compiled Ruby.
31
53
 
32
54
  ## Planned
33
55
 
@@ -45,20 +67,17 @@ This fragment could then be overridden.
45
67
 
46
68
  Feel free to contribute!!!
47
69
 
70
+ ## Users
48
71
 
49
- ## Used where?
50
-
51
- Erbse is the ERB engine in [Cells 4](https://github.com/apotonick/cells).
52
-
53
- It also hopefully gets used in Rails 5/6, so we can remove those horrible hacks from AV.
54
-
72
+ Erbse is the ERB engine in [Cells](https://github.com/apotonick/cells).
55
73
 
56
- # License
74
+ ## License
57
75
 
58
76
  MIT License
59
77
 
60
- # Contributors
78
+ ## Contributors
61
79
 
80
+ * Special thanks to [Aman Gupta](https://github.com/tmm1) for [performance tweaks](https://github.com/rails/rails/pull/9555) that are merged in Erbse.
62
81
  * @iazel
63
82
  * @seuros
64
83
 
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.add_dependency "temple"
23
+
22
24
  spec.add_development_dependency "rake"
23
25
  spec.add_development_dependency "minitest"
24
26
  end
@@ -1,49 +1,35 @@
1
- ##
2
- ## an implementation of eRuby
3
- ##
4
- ## ex.
5
- ## input = <<'END'
6
- ## <ul>
7
- ## <% for item in @list %>
8
- ## <li><%= item %>
9
- ## <%== item %></li>
10
- ## <% end %>
11
- ## </ul>
12
- ## END
13
- ## list = ['<aaa>', 'b&b', '"ccc"']
14
- ## eruby = Erubis::Eruby.new(input)
15
- ## puts "--- code ---"
16
- ## puts eruby.src
17
- ## puts "--- result ---"
18
- ## context = Erubis::Context.new() # or new(:list=>list)
19
- ## context[:list] = list
20
- ## puts eruby.evaluate(context)
21
- ##
22
- ## result:
23
- ## --- source ---
24
- ## _buf = ''; _buf << '<ul>
25
- ## '; for item in @list
26
- ## _buf << ' <li>'; _buf << ( item ).to_s; _buf << '
27
- ## '; _buf << ' '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
28
- ## '; end
29
- ## _buf << '</ul>
30
- ## ';
31
- ## _buf.to_s
32
- ## --- result ---
33
- ## <ul>
34
- ## <li><aaa>
35
- ## &lt;aaa&gt;</li>
36
- ## <li>b&b
37
- ## b&amp;b</li>
38
- ## <li>"ccc"
39
- ## &quot;ccc&quot;</li>
40
- ## </ul>
41
- ##
42
-
1
+ require "temple"
2
+ require "erbse/parser"
43
3
 
44
4
  module Erbse
5
+ class BlockFilter < Temple::Filter
6
+ # Highly inspired by https://github.com/slim-template/slim/blob/master/lib/slim/controls.rb#on_slim_output
7
+ def on_erb_block(code, content_ast)
8
+ # this is for <%= do %>
9
+ outter_i = unique_name
10
+ inner_i = unique_name
11
+
12
+ # this still needs the Temple::Filters::ControlFlow run-through.
13
+ [:multi,
14
+ [:block, "#{outter_i} = #{code}",
15
+ [:capture, inner_i, compile(content_ast)] # compile() is recursion on nested block content.
16
+ ],
17
+ [:dynamic, outter_i] # return the outter buffer. # DISCUSS: why do we need that, again?
18
+ ]
19
+ end
20
+ end
21
+
22
+ class Engine < Temple::Engine
23
+ use Parser
24
+ use BlockFilter
25
+
26
+ # filter :MultiFlattener
27
+ # filter :StaticMerger
28
+ # filter :DynamicInliner
29
+ filter :ControlFlow
30
+
31
+ generator :ArrayBuffer
32
+ end
33
+ # DISCUSS: can we add more optimizers?
45
34
  end
46
35
 
47
- require "erbse/converter"
48
- require "erbse/template"
49
- require "erbse/eruby"
@@ -0,0 +1,62 @@
1
+ module Erbse
2
+ class Parser
3
+ # ERB_EXPR = /<%(=|\#)?(.*?)%>(\n)*/m # this is the desired pattern.
4
+ ERB_EXPR = /<%(=+|-|\#|%)?(.*?)[-=]?%>(\n)*/m # this is for backward-compatibility.
5
+ # BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
6
+ BLOCK_EXPR = /\b(if|unless)\b|\bdo\b/
7
+
8
+ def initialize(*)
9
+ end
10
+
11
+ def call(str)
12
+ pos = 0
13
+ buffers = []
14
+ result = [:multi]
15
+ buffers << result
16
+ match = nil
17
+
18
+ str.scan(ERB_EXPR) do |indicator, code, newlines|
19
+ match = Regexp.last_match
20
+ len = match.begin(0) - pos
21
+
22
+ text = str[pos, len]
23
+ pos = match.end(0)
24
+ ch = indicator ? indicator[0] : nil
25
+
26
+ if text and !text.strip.empty? # text
27
+ buffers.last << [:static, text]
28
+ end
29
+
30
+ if ch == ?= # <%= %>
31
+ if code =~ BLOCK_EXPR
32
+ buffers.last << [:erb, :block, code, block = [:multi]] # picked up by our own BlockFilter.
33
+ buffers << block
34
+ else
35
+ buffers.last << [:dynamic, code]
36
+ end
37
+ elsif code =~ /\bend\b/ # <% end %>
38
+ buffers.pop
39
+ elsif ch =~ /#/ # DISCUSS: doesn't catch <% # this %>
40
+ newlines = code.count("\n")
41
+ buffers.last.concat [[:newline]] * newlines if newlines > 0
42
+ else # <% %>
43
+ if code =~ BLOCK_EXPR
44
+ buffers.last << [:block, code, block = [:multi]] # picked up by Temple's ControlFlow filter.
45
+ buffers << block
46
+ else
47
+ buffers.last << [:code, code]
48
+ end
49
+ end
50
+
51
+ # FIXME: only adds one newline.
52
+ # TODO: does that influence speed?
53
+ buffers.last << [:newline] if newlines
54
+ end
55
+
56
+ # add text after last/none ERB tag.
57
+ buffers.last << [:static, str[pos..str.length]] if pos < str.length
58
+
59
+ buffers.last
60
+ end
61
+ end
62
+ end
@@ -1,3 +1,3 @@
1
1
  module Erbse
2
- VERSION = "0.0.2"
3
- end
2
+ VERSION = "0.1.0"
3
+ end
@@ -1,14 +1,116 @@
1
1
  require "test_helper"
2
2
 
3
- # most tests are via cells-erb.
3
+ #ob_0 = '';;ob_0<< ( true ).to_s;ob_0 << ' '.freeze;;ob_1 = form_for do ; ob_2='';;ob_2<< ( 1 ).to_s;;ob_2<< ( 2 ).to_s;;ob_3 = nested do ; ob_4='';;ob_4<< ( 3 ).to_s;;ob_4<< ( 4 ).to_s;ob_4; end ;ob_2 << ob_3;ob_3; end ;ob_1 << ob_2;ob_0.to_s
4
4
 
5
- class ErbseTest < MiniTest::Spec
6
- it do
7
- Erbse::Template.new(%{<%- text = "Hello" %> <%= text %>}).call.must_equal "@output_buffer = output_buffer; text = \"Hello\" ;@output_buffer.safe_append=' '.freeze;@output_buffer.append=( text );@output_buffer.to_s"
5
+ class ErbseTest < Minitest::Spec
6
+ let (:str) { %{
7
+ <%= true %>
8
+ Text
9
+ <%= form_for do %><%= 1 %><% 2 %>
10
+ <%= nested do %>
11
+ <%= this %>
12
+ <a/>
13
+ <% end %>
14
+ <% end %>}
15
+ }
16
+
17
+ it "what" do
18
+ Erbse::Parser.new.(str).must_equal [:multi,
19
+ [:dynamic, " true "], [:newline],
20
+ [:static, "Text\n"],
21
+ [:erb, :block, " form_for do ", [:multi,
22
+ [:dynamic, " 1 "],
23
+ [:code, " 2 "], [:newline],
24
+ [:erb, :block, " nested do ", [:multi, [:newline],
25
+ [:dynamic, " this "], [:newline],
26
+ [:static, " <a/>\n "],
27
+ ]], [:newline]]]]
28
+ end
29
+
30
+ it "generates ruby" do
31
+ code = %{_buf = []; _buf << ( true ); @; _buf << ("Text@@".freeze); _erbse_blockfilter1 = form_for do ; _erbse_blockfilter2 = ''; _erbse_blockfilter2 << (( 1 ).to_s); 2 ; @; _erbse_blockfilter3 = nested do ; _erbse_blockfilter4 = ''; @; _erbse_blockfilter4 << (( this ).to_s); @; _erbse_blockfilter4 << (" <a/>@@ ".freeze); _erbse_blockfilter4; end; _erbse_blockfilter2 << ((_erbse_blockfilter3).to_s); @; _erbse_blockfilter2; end; _buf << (_erbse_blockfilter1); _buf = _buf.join("".freeze)}
32
+ ruby = Erbse::Engine.new.(str).gsub("\n", "@").gsub('\n', "@@")
33
+ # puts ruby
34
+ ruby.must_equal code
35
+ end
36
+
37
+ describe "<% %>" do
38
+ let (:str) { %{
39
+ <% self %>
40
+ <% 2.times do |i| %>
41
+ <%= i+1 %>
42
+ <% puts %>
43
+ <% end %>
44
+
45
+ <% if 1 %>
46
+ Hello
47
+ <% end %>
48
+ }
49
+ }
50
+ it "what" do
51
+ Erbse::Parser.new.(str).must_equal [:multi,
52
+ [:code, " self "], [:newline],
53
+ [:block, " 2.times do |i| ", [:multi, [:newline],
54
+ [:dynamic, " i+1 "], [:newline],
55
+ [:code, " puts "], [:newline]]], [:newline],
56
+ [:block, " if 1 ", [:multi, [:newline],
57
+ [:static, " Hello
58
+ "]]], [:newline]]
59
+ end
60
+
61
+ it do
62
+ ruby = Erbse::Engine.new.(str)
63
+ ruby = ruby.gsub("\n", "@")
64
+
65
+ # ruby.must_equal %{_buf = []; self ; 2.times do |i| ; _buf << ( i+1 ); puts ; end; _buf = _buf.join(\"\".freeze)}
66
+ ruby.must_equal '_buf = []; self ; @; 2.times do |i| ; @; _buf << ( i+1 ); @; puts ; @; end; @; if 1 ; @; _buf << (" Hello\n".freeze); end; @; _buf = _buf.join("".freeze)'
67
+ end
68
+
69
+ it do
70
+ ruby = Erbse::Engine.new.(str)
71
+ eval(ruby).must_equal "12 Hello\n"
72
+ end
73
+ end
74
+
75
+ describe "pure text" do
76
+ let (:str) { %{Holla
77
+ Hi}
78
+ }
79
+ it { Erbse::Parser.new.(str).must_equal [:multi, [:static, "Holla\nHi"]] }
80
+ end
81
+
82
+ # comments
83
+ describe "<%# this %>" do
84
+ let (:str) { %{Hello
85
+ <%# Ignore this %>
86
+ Hola
87
+ <%# Ignore
88
+ this %>
89
+ Hi
90
+ <% # this %>
91
+ } }
92
+
93
+ it do
94
+ Erbse::Parser.new.(str).must_equal [:multi, [:static, "Hello\n"], [:newline], [:static, "Hola\n"], [:newline], [:newline], [:static, "Hi\n"], [:code, " # this "], [:newline]]
95
+ end
96
+
97
+ it do
98
+ ruby = Erbse::Engine.new.(str).gsub("\n", "@").gsub('\n', "@@")
99
+ code = %{_buf = []; _buf << ("Hello@@".freeze); @; _buf << ("Hola@@".freeze); @; @; _buf << ("Hi@@".freeze); # this ; @; _buf = _buf.join("".freeze)}
100
+ ruby.must_equal code
101
+ end
102
+ end
103
+
104
+ describe "content after last ERB tag" do
105
+ let (:str) { %{<b><%= 1 %>bla
106
+ blubb</b>} }
107
+
108
+ it { Erbse::Parser.new.(str).must_equal [:multi, [:static, "<b>"], [:dynamic, " 1 "], [:static, "bla\nblubb</b>"]] }
8
109
  end
9
110
 
10
- # nested <%= block do %> syntax.
11
- it do
12
- Erbse::Template.new(%{<%= form_for do %><%= content_tag :div do %>DIV<% end %><% end %>}).call.must_equal "@output_buffer = output_buffer;@output_buffer.append= form_for do @output_buffer.append= content_tag :div do @output_buffer.safe_append='DIV'.freeze; end ; end ;@output_buffer.to_s"
111
+ describe "<%* %>" do
112
+ it { Erbse::Parser.new.(%{<%- 1 %>}).must_equal [:multi, [:code, " 1 "]] }
113
+ it { Erbse::Parser.new.(%{<%% 1 %>}).must_equal [:multi, [:code, " 1 "]] }
114
+ it { Erbse::Parser.new.(%{<%% 1 -%>}).must_equal [:multi, [:code, " 1 "]] }
13
115
  end
14
- end
116
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erbse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-25 00:00:00.000000000 Z
11
+ date: 2016-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: temple
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rake
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -60,9 +74,7 @@ files:
60
74
  - benchmark/templates/bench_eruby.rhtml
61
75
  - erbse.gemspec
62
76
  - lib/erbse.rb
63
- - lib/erbse/converter.rb
64
- - lib/erbse/eruby.rb
65
- - lib/erbse/template.rb
77
+ - lib/erbse/parser.rb
66
78
  - lib/erbse/version.rb
67
79
  - test/erbse_test.rb
68
80
  - test/test_helper.rb
@@ -86,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
98
  version: '0'
87
99
  requirements: []
88
100
  rubyforge_project:
89
- rubygems_version: 2.2.2
101
+ rubygems_version: 2.5.1
90
102
  signing_key:
91
103
  specification_version: 4
92
104
  summary: Updated Erubis.
@@ -1,157 +0,0 @@
1
- module Erbse
2
- # convert input string into target language
3
- class Converter
4
- def initialize(properties={}, generator)
5
- init_converter!(properties)
6
- @generator = generator
7
- end
8
-
9
- def convert(input) # TODO: rename to #call.
10
- codebuf = "" # or []
11
- @preamble.nil? ? generator.add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
12
- convert_input(codebuf, input)
13
- @postamble.nil? ? generator.add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
14
- @_proc = nil # clear cached proc object
15
- return codebuf # or codebuf.join()
16
- end
17
-
18
- private
19
- attr_accessor :preamble, :postamble, :escape
20
-
21
- attr_reader :generator
22
-
23
- def init_converter!(properties)
24
- @preamble = properties[:preamble]
25
- @postamble = properties[:postamble]
26
- @escape = properties[:escape]
27
- end
28
-
29
- ##
30
- ## detect spaces at beginning of line
31
- ##
32
- def detect_spaces_at_bol(text, is_bol)
33
- lspace = nil
34
- if text.empty?
35
- lspace = "" if is_bol
36
- elsif text[-1] == ?\n
37
- lspace = ""
38
- else
39
- rindex = text.rindex(?\n)
40
- if rindex
41
- s = text[rindex+1..-1]
42
- if s =~ /\A[ \t]*\z/
43
- lspace = s
44
- #text = text[0..rindex]
45
- text[rindex+1..-1] = ''
46
- end
47
- else
48
- if is_bol && text =~ /\A[ \t]*\z/
49
- #lspace = text
50
- #text = nil
51
- lspace = text.dup
52
- text[0..-1] = ''
53
- end
54
- end
55
- end
56
- return lspace
57
- end
58
- end
59
-
60
-
61
- module Basic
62
- end
63
-
64
-
65
- ##
66
- ## basic converter which supports '<% ... %>' notation.
67
- ##
68
- class Basic::Converter < Converter
69
- def self.supported_properties # :nodoc:
70
- return [
71
- [:pattern, '<% %>', "embed pattern"],
72
- [:trim, true, "trim spaces around <% ... %>"],
73
- ]
74
- end
75
-
76
-
77
- private
78
-
79
- attr_accessor :pattern, :trim
80
-
81
- def init_converter!(properties={})
82
- super(properties)
83
- @pattern = properties[:pattern]
84
- @trim = properties[:trim] != false
85
- end
86
-
87
-
88
-
89
- ## return regexp of pattern to parse eRuby script
90
- def self.pattern_regexp(pattern)
91
- @prefix, @postfix = pattern.split() # '<% %>' => '<%', '%>'
92
- return /#{@prefix}(=+|-|\#|%)?(.*?)([-=])?#{@postfix}([ \t]*\r?\n)?/m
93
- end
94
-
95
- DEFAULT_REGEXP = pattern_regexp('<% %>')
96
-
97
- def convert_input(src, input)
98
- pat = @pattern
99
- regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
100
- pos = 0
101
- is_bol = true # is beginning of line
102
- input.scan(regexp) do |indicator, code, tailch, rspace|
103
- match = Regexp.last_match()
104
- len = match.begin(0) - pos
105
- text = input[pos, len]
106
- pos = match.end(0)
107
- ch = indicator ? indicator[0] : nil
108
- lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
109
- is_bol = rspace ? true : false
110
- generator.add_text(src, text) if text && !text.empty?
111
- ## * when '<%= %>', do nothing
112
- ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
113
- if ch == ?= # <%= %>
114
- rspace = nil if tailch && !tailch.empty?
115
- generator.add_text(src, lspace) if lspace
116
- add_expr(src, code, indicator)
117
- generator.add_text(src, rspace) if rspace
118
- elsif ch == ?\# # <%# %>
119
- n = code.count("\n") + (rspace ? 1 : 0)
120
- if @trim && lspace && rspace
121
- generator.add_stmt(src, "\n" * n)
122
- else
123
- generator.add_text(src, lspace) if lspace
124
- generator.add_stmt(src, "\n" * n)
125
- generator.add_text(src, rspace) if rspace
126
- end
127
- elsif ch == ?% # <%% %>
128
- s = "#{lspace}#{@prefix||='<%'}#{code}#{tailch}#{@postfix||='%>'}#{rspace}"
129
- generator.add_text(src, s)
130
- else # <% %>
131
- if @trim && lspace && rspace
132
- generator.add_stmt(src, "#{lspace}#{code}#{rspace}")
133
- else
134
- generator.add_text(src, lspace) if lspace
135
- generator.add_stmt(src, code)
136
- generator.add_text(src, rspace) if rspace
137
- end
138
- end
139
- end
140
- #rest = $' || input # ruby1.8
141
- rest = pos == 0 ? input : input[pos..-1] # ruby1.9
142
- generator.add_text(src, rest)
143
- end
144
-
145
- ## add expression code to src
146
- def add_expr(src, code, indicator)
147
- case indicator
148
- when '='
149
- @escape ? generator.add_expr_escaped(src, code) : generator.add_expr_literal(src, code)
150
- when '=='
151
- @escape ? generator.add_expr_literal(src, code) : generator.add_expr_escaped(src, code)
152
- when '==='
153
- generator.add_expr_debug(src, code)
154
- end
155
- end
156
- end
157
- end
@@ -1,114 +0,0 @@
1
- module Erbse
2
- class RubyGenerator
3
- def init_generator(properties={})
4
- @escapefunc ||= "Erubis::XmlHelper.escape_xml"
5
- end
6
-
7
- def escape_text(text)
8
- text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
9
- end
10
-
11
- def escaped_expr(code)
12
- return "#{@escapefunc}(#{code})"
13
- end
14
-
15
- #--
16
- #def add_preamble(src)
17
- # src << "#{@bufvar} = [];"
18
- #end
19
- #++
20
- def add_preamble(src)
21
- @newline_pending = 0
22
- src << "@output_buffer = output_buffer;" # DISCUSS: i removed the output_buffer || ActionView::OB.new rubbish here.
23
- end
24
-
25
- # def add_text(src, text)
26
- # src << " #{@bufvar} << '" << escape_text(text) << "';" unless text.empty?
27
- # end
28
- def add_text(src, text)
29
- return if text.empty?
30
-
31
- if text == "\n"
32
- @newline_pending += 1
33
- else
34
- src << "@output_buffer.safe_append='"
35
- src << "\n" * @newline_pending if @newline_pending > 0
36
- src << escape_text(text)
37
- src << "'.freeze;"
38
-
39
- @newline_pending = 0
40
- end
41
- end
42
-
43
- # Erubis toggles <%= and <%== behavior when escaping is enabled.
44
- # We override to always treat <%== as escaped.
45
- # def add_expr(src, code, indicator)
46
- # case indicator
47
- # when '=='
48
- # add_expr_escaped(src, code)
49
- # else
50
- # super
51
- # end
52
- # end
53
-
54
- def ____add_stmt(src, code)
55
- src << code
56
- src << ';' unless code[-1] == ?\n
57
- end
58
-
59
- def add_stmt(src, code)
60
- flush_newline_if_pending(src)
61
- ____add_stmt(src, code)
62
- end
63
-
64
- # def add_expr_literal(src, code)
65
- # src << " #{@bufvar} << (" << code << ').to_s;'
66
- # end
67
- BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
68
-
69
- def add_expr_literal(src, code)
70
- flush_newline_if_pending(src)
71
- if code =~ BLOCK_EXPR
72
- src << '@output_buffer.append= ' << code
73
- else
74
- src << '@output_buffer.append=(' << code << ');'
75
- end
76
- end
77
-
78
- def add_expr_escaped(src, code)
79
- flush_newline_if_pending(src)
80
- if code =~ BLOCK_EXPR
81
- src << "@output_buffer.safe_expr_append= " << code
82
- else
83
- src << "@output_buffer.safe_expr_append=(" << code << ");"
84
- end
85
- end
86
-
87
- # def add_expr_escaped(src, code)
88
- # src << " #{@bufvar} << " << escaped_expr(code) << ';'
89
- # end
90
-
91
- def add_expr_debug(src, code)
92
- code.strip!
93
- s = (code.dump =~ /\A"(.*)"\z/) && $1
94
- src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
95
- end
96
-
97
- #--
98
- #def add_postamble(src)
99
- # src << "\n#{@bufvar}.join\n"
100
- #end
101
- #++
102
- def add_postamble(src)
103
- flush_newline_if_pending(src)
104
- src << '@output_buffer.to_s'
105
- end
106
-
107
- def flush_newline_if_pending(src)
108
- if @newline_pending > 0
109
- src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
110
- @newline_pending = 0
111
- end
112
- end
113
- end
114
- end
@@ -1,14 +0,0 @@
1
- module Erbse
2
- # Compiles the runtime method for an ERB input string.
3
- class Template
4
- def initialize(input, properties={})
5
- generator = RubyGenerator.new
6
- converter = Basic::Converter.new(properties, generator)
7
- @src = converter.convert(input)
8
- end
9
-
10
- def call
11
- @src
12
- end
13
- end
14
- end