erbse 0.0.2 → 0.1.0

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