fast_haml 0.1.7 → 0.1.8

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: 435825826b3948fd94accaf5eaafc29e1d7ea4f1
4
- data.tar.gz: 3b0ad21919d9a8ec7bccee42f39740431acd2b8d
3
+ metadata.gz: ec965b362a4b85f320d2144ebc3117d16476505a
4
+ data.tar.gz: 4cdd71b4c7664e6fe6e9bf74f225be290b02456e
5
5
  SHA512:
6
- metadata.gz: 3c03f60242ffe2650685d696c1e1cc36d3561d28b31aaa86feee6412154551c938d76f3406948527a5b959122d846bc5cd827a85f11558e79dab8e02e453f1f2
7
- data.tar.gz: d5a8252b40bfd94d5f2748870add6eda2cda54579b50aee5dc91de16f46e61c3bf22e6dd4e77ed3f90c2ce20ff2b08c25fabd15b5fe588d67e63b9e9c0e175f5
6
+ metadata.gz: 4e8e90941f16081fba0ffc531cdcbc84fba4cf65ff629ebfcee51b50ad65660c78b4b92fbe965afa7798e3407567cdddc2064317fd996cec82c140a015831f71
7
+ data.tar.gz: f461f513f3e2d5249156e5dcc399216c777057431ebb5027bedcc372bd25e15d1374b961267d0d62af159250747a175ab66f27d3c4ccdc380bdae797ec44007b
@@ -1,3 +1,7 @@
1
+ ## 0.1.8 (2015-03-17)
2
+ - Fix whitespace removal (`<` and `>`) behavior
3
+ - Internally, new instructions `mknl` and `rmnl` are added.
4
+
1
5
  ## 0.1.7 (2015-03-16)
2
6
  - Fix attribute rendering with falsey values
3
7
  - https://github.com/eagletmt/fast_haml/pull/11
data/README.md CHANGED
@@ -88,6 +88,24 @@ I introduced incompatibility to expand the chance: all attribute values are conv
88
88
  This will enable us to avoid runtime expensive hash merging and rendering.
89
89
  The runtime hash merging is implemented by C extension in fast_haml.
90
90
 
91
+ Internally, attributes are categolized into three types.
92
+
93
+ 1. Static attributes
94
+ - Both the key and the value are literal.
95
+ - Compiled into string literals.
96
+ - Fastest.
97
+ - e.g. `%input{checked: false}`
98
+ 2. Dynamic attributes
99
+ - The key is literal but the value isn't.
100
+ - The key is compiled into string literal. The value is interpolated at run-time.
101
+ - Relatively fast.
102
+ - e.g. `%input{checked: helper_method(@record)}`
103
+ 3. Ruby attributes
104
+ - Both the key and the value are non-literal expression.
105
+ - The attributes are stringified at run-time.
106
+ - Slow.
107
+ - e.g. `%input{helper_method(@record)}`
108
+
91
109
  ## Contributing
92
110
 
93
111
  1. Fork it ( https://github.com/eagletmt/fast_haml/fork )
@@ -13,12 +13,6 @@ module FastHaml
13
13
 
14
14
  class Root < Struct.new(:children)
15
15
  include HasChildren
16
- attr_reader :leading_empty_lines
17
-
18
- def initialize(*)
19
- super
20
- @leading_empty_lines = 0
21
- end
22
16
  end
23
17
 
24
18
  class Doctype < Struct.new(:doctype)
@@ -1,3 +1,4 @@
1
+ require 'parser/current'
1
2
  require 'temple'
2
3
  require 'fast_haml/ast'
3
4
  require 'fast_haml/filter_compilers'
@@ -6,6 +7,9 @@ require 'fast_haml/text_compiler'
6
7
 
7
8
  module FastHaml
8
9
  class Compiler < Temple::Parser
10
+ class UnparsableRubyCode < StandardError
11
+ end
12
+
9
13
  DEFAULT_AUTO_CLOSE_TAGS = %w[
10
14
  area base basefont br col command embed frame hr img input isindex keygen
11
15
  link menuitem meta param source track wbr
@@ -72,34 +76,15 @@ module FastHaml
72
76
 
73
77
  def compile_root(ast)
74
78
  [:multi].tap do |temple|
75
- temple.concat([[:newline]] * ast.leading_empty_lines)
76
79
  compile_children(ast, temple)
77
80
  end
78
81
  end
79
82
 
80
83
  def compile_children(ast, temple)
81
- was_newline = false
82
84
  ast.children.each do |c|
83
- if c.is_a?(Ast::Element) && c.nuke_outer_whitespace && was_newline
84
- # pop newline
85
- x = temple.pop
86
- if x == [:newline]
87
- x = temple.pop
88
- if x != [:static, "\n"]
89
- raise "InternalError: Unexpected pop (expected [:static, \\n]): #{x}"
90
- end
91
- elsif x == [:static, "\n"]
92
- # nothing
93
- else
94
- raise "InternalError: Unexpected pop (expected [:newline] or [:static, \\n]): #{x}"
95
- end
96
- unless suppress_code_newline?(c.oneline_child)
97
- temple << [:newline]
98
- end
99
- end
100
85
  temple << compile(c)
101
- if was_newline = need_newline?(ast, c)
102
- temple << [:static, "\n"]
86
+ if need_newline?(c)
87
+ temple << [:mknl]
103
88
  end
104
89
  unless suppress_code_newline?(c)
105
90
  temple << [:newline]
@@ -107,10 +92,7 @@ module FastHaml
107
92
  end
108
93
  end
109
94
 
110
- def need_newline?(parent, child)
111
- if parent.is_a?(Ast::Element) && nuke_inner_whitespace?(parent) && parent.children.last.equal?(child)
112
- return false
113
- end
95
+ def need_newline?(child)
114
96
  case child
115
97
  when Ast::Script
116
98
  child.children.empty?
@@ -127,7 +109,8 @@ module FastHaml
127
109
  ast.is_a?(Ast::Script) ||
128
110
  ast.is_a?(Ast::SilentScript) ||
129
111
  (ast.is_a?(Ast::Element) && suppress_code_newline?(ast.oneline_child)) ||
130
- (ast.is_a?(Ast::Element) && !ast.children.empty?)
112
+ (ast.is_a?(Ast::Element) && !ast.children.empty?) ||
113
+ (ast.is_a?(Ast::HtmlComment) && !ast.conditional.empty?)
131
114
  end
132
115
 
133
116
  def compile_text(ast)
@@ -160,9 +143,9 @@ module FastHaml
160
143
  else
161
144
  temple = [:multi]
162
145
  if ast.conditional.empty?
163
- temple << [:static, "\n"]
146
+ temple << [:mknl]
164
147
  else
165
- temple << [:static, "[#{ast.conditional}]>\n"]
148
+ temple << [:static, "[#{ast.conditional}]>"] << [:mknl] << [:newline]
166
149
  end
167
150
  compile_children(ast, temple)
168
151
  unless ast.conditional.empty?
@@ -189,14 +172,21 @@ module FastHaml
189
172
  elsif !ast.children.empty?
190
173
  children = [:multi]
191
174
  unless nuke_inner_whitespace?(ast)
192
- children << [:static, "\n"]
175
+ children << [:mknl]
193
176
  end
194
177
  children << [:newline]
195
178
  compile_children(ast, children)
179
+ if nuke_inner_whitespace?(ast)
180
+ children << [:rmnl]
181
+ end
196
182
  temple << children
197
183
  end
198
184
 
199
- temple
185
+ if ast.nuke_outer_whitespace
186
+ [:multi, [:rmnl], temple]
187
+ else
188
+ temple
189
+ end
200
190
  end
201
191
 
202
192
  def self_closing?(ast)
@@ -249,6 +239,7 @@ module FastHaml
249
239
  def try_optimize_attributes(text, static_id, static_class)
250
240
  parser = StaticHashParser.new
251
241
  unless parser.parse("{#{text}}")
242
+ assert_valid_ruby_code!(text)
252
243
  return nil
253
244
  end
254
245
 
@@ -271,6 +262,17 @@ module FastHaml
271
262
  end
272
263
  end
273
264
 
265
+ def assert_valid_ruby_code!(text)
266
+ parser = ::Parser::CurrentRuby.new
267
+ parser.diagnostics.consumer = nil
268
+ buffer = ::Parser::Source::Buffer.new('(fast_haml)')
269
+ buffer.source = "call(#{text})"
270
+ parser.parse(buffer)
271
+ true
272
+ rescue ::Parser::SyntaxError
273
+ raise UnparsableRubyCode.new("Unparsable Ruby code is given to attributes: #{text}")
274
+ end
275
+
274
276
  def build_optimized_attributes(parser, static_id, static_class)
275
277
  static_attributes = {}
276
278
  parser.static_attributes.each do |k, v|
@@ -1,6 +1,7 @@
1
1
  require 'temple'
2
2
  require 'fast_haml/compiler'
3
3
  require 'fast_haml/html'
4
+ require 'fast_haml/newline'
4
5
  require 'fast_haml/parser'
5
6
 
6
7
  module FastHaml
@@ -24,6 +25,7 @@ module FastHaml
24
25
  filter :Escapable
25
26
  filter :ControlFlow
26
27
  filter :MultiFlattener
28
+ use Newline
27
29
  filter :StaticMerger
28
30
  use :Generator do
29
31
  options[:generator].new(options.to_hash.reject {|k,v| !options[:generator].options.valid_key?(k) })
@@ -0,0 +1,30 @@
1
+ require 'temple'
2
+
3
+ module FastHaml
4
+ class Newline < Temple::Filter
5
+ def on_multi(*exprs)
6
+ i = exprs.size-1
7
+ marker = false
8
+ while i >= 0
9
+ case exprs[i]
10
+ when [:rmnl]
11
+ if marker
12
+ raise "InternalError: double rmnl error"
13
+ else
14
+ marker = true
15
+ exprs.delete_at(i)
16
+ end
17
+ when [:mknl]
18
+ if marker
19
+ marker = false
20
+ exprs.delete_at(i)
21
+ else
22
+ exprs[i] = [:static, "\n"]
23
+ end
24
+ end
25
+ i -= 1
26
+ end
27
+ [:multi, *exprs]
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module FastHaml
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.8"
3
3
  end
@@ -75,4 +75,23 @@ HAML
75
75
  %span= raise LineVerifier
76
76
  HAML
77
77
  end
78
+
79
+ context 'with conditional comment' do
80
+ it do
81
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(3))
82
+ %div
83
+ / [if IE]
84
+ %span= raise LineVerifier
85
+ HAML
86
+ end
87
+
88
+ it do
89
+ expect { render_string(<<HAML) }.to raise_error(LineVerifier, raised_at(4))
90
+ %div
91
+ / [if IE]
92
+ %span hello
93
+ %span= raise LineVerifier
94
+ HAML
95
+ end
96
+ end
78
97
  end
@@ -63,6 +63,10 @@ HAML
63
63
  expect(render_string(%q|%span{foo: true, bar: 1} hello|)).to eq(%Q{<span bar='1' foo>hello</span>\n})
64
64
  end
65
65
 
66
+ it 'raises error when unparsable Ruby code is given' do
67
+ expect { render_string('%span{x ==== 2}') }.to raise_error(FastHaml::Compiler::UnparsableRubyCode)
68
+ end
69
+
66
70
  context 'with xhtml format' do
67
71
  it 'renders name="name" if value is true' do
68
72
  expect(render_string(%q|%span{foo: true, bar: 1} hello|, format: :xhtml)).to eq(%Q{<span bar='1' foo='foo'>hello</span>\n})
@@ -119,45 +119,6 @@ HAML
119
119
  expect(render_string('%meta{"http-equiv" => "Content-Type", :content => "text/html"}')).to eq("<meta content='text/html' http-equiv='Content-Type'>\n")
120
120
  end
121
121
 
122
- it 'parses nuke-inner-whitespace (<)' do
123
- expect(render_string(<<HAML)).to eq("<blockquote><div>\nFoo!\n</div></blockquote>\n")
124
- %blockquote<
125
- %div
126
- Foo!
127
- HAML
128
- end
129
-
130
- it 'renders pre tag as nuke-inner-whitespace by default' do
131
- expect(render_string(<<HAML)).to eq("<pre>hello\nworld</pre>\n")
132
- %pre
133
- hello
134
- world
135
- HAML
136
- end
137
-
138
- it 'parses nuke-outer-whitespace (>)' do
139
- expect(render_string(<<HAML)).to eq("<img><span>hello</span><img>\n")
140
- %img
141
- %span> hello
142
- %img
143
- HAML
144
- expect(render_string(<<HAML)).to eq("<div>\n<span>1</span><span>hoge</span></div>\n")
145
- %div
146
- %span= 1
147
- %span> hoge
148
- HAML
149
- end
150
-
151
- it 'parses nuke-whitespaces' do
152
- expect(render_string(<<HAML)).to eq("<img><pre>foo\nbar</pre><img>\n")
153
- %img
154
- %pre><
155
- foo
156
- bar
157
- %img
158
- HAML
159
- end
160
-
161
122
  it 'parses == syntax' do
162
123
  expect(render_string('%p== =#{1+2}hello')).to eq("<p>=3hello</p>\n")
163
124
  end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Newline with > and <', type: :render do
4
+ describe '>' do
5
+ it 'parses nuke-outer-whitespace (>)' do
6
+ expect(render_string(<<HAML)).to eq("<img><span>hello</span><img>\n")
7
+ %img
8
+ %span> hello
9
+ %img
10
+ HAML
11
+
12
+ expect(render_string(<<HAML)).to eq("<div>\n<span>1</span><span>hoge</span></div>\n")
13
+ %div
14
+ %span= 1
15
+ %span> hoge
16
+ HAML
17
+ end
18
+
19
+ it 'handles silent script' do
20
+ expect(render_string(<<HAML)).to eq("<div><span>0</span><span>1</span></div>\n")
21
+ %div
22
+ - 2.times do |i|
23
+ %span>= i
24
+ HAML
25
+ end
26
+
27
+ it 'handles comment' do
28
+ expect(render_string(<<HAML)).to eq("<div>\n<!--<span>0</span><span>1</span>-->\n</div>\n")
29
+ %div
30
+ /
31
+ - 2.times do |i|
32
+ %span>= i
33
+ HAML
34
+ end
35
+
36
+ it 'handles conditional comment' do
37
+ expect(render_string(<<HAML)).to eq("<div>\n<!--[if IE]><span>0</span><span>1</span><![endif]-->\n</div>\n")
38
+ %div
39
+ / [if IE]
40
+ - 2.times do |i|
41
+ %span>= i
42
+ HAML
43
+ end
44
+ end
45
+
46
+ describe '>' do
47
+ it 'parses nuke-inner-whitespace (<)' do
48
+ expect(render_string(<<HAML)).to eq("<blockquote><div>\nFoo!\n</div></blockquote>\n")
49
+ %blockquote<
50
+ %div
51
+ Foo!
52
+ HAML
53
+ end
54
+
55
+ it 'renders pre tag as nuke-inner-whitespace by default' do
56
+ expect(render_string(<<HAML)).to eq("<pre>hello\nworld</pre>\n")
57
+ %pre
58
+ hello
59
+ world
60
+ HAML
61
+ end
62
+
63
+ it 'handles silent script' do
64
+ expect(render_string(<<HAML)).to eq("<div>012</div>\n")
65
+ %div<
66
+ - 3.times do |i|
67
+ = i
68
+ HAML
69
+ end
70
+ end
71
+
72
+ describe '><' do
73
+ it 'parses nuke-whitespaces' do
74
+ expect(render_string(<<HAML)).to eq("<img><pre>foo\nbar</pre><img>\n")
75
+ %img
76
+ %pre><
77
+ foo
78
+ bar
79
+ %img
80
+ HAML
81
+ end
82
+ end
83
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_haml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kohei Suzuki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-16 00:00:00.000000000 Z
11
+ date: 2015-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: escape_utils
@@ -241,6 +241,7 @@ files:
241
241
  - lib/fast_haml/html.rb
242
242
  - lib/fast_haml/indent_tracker.rb
243
243
  - lib/fast_haml/line_parser.rb
244
+ - lib/fast_haml/newline.rb
244
245
  - lib/fast_haml/parser.rb
245
246
  - lib/fast_haml/parser_utils.rb
246
247
  - lib/fast_haml/rails_handler.rb
@@ -319,6 +320,7 @@ files:
319
320
  - spec/render/filters_spec.rb
320
321
  - spec/render/haml_comment_spec.rb
321
322
  - spec/render/multiline_spec.rb
323
+ - spec/render/newline_spec.rb
322
324
  - spec/render/plain_spec.rb
323
325
  - spec/render/preserve_spec.rb
324
326
  - spec/render/sanitize_spec.rb
@@ -420,6 +422,7 @@ test_files:
420
422
  - spec/render/filters_spec.rb
421
423
  - spec/render/haml_comment_spec.rb
422
424
  - spec/render/multiline_spec.rb
425
+ - spec/render/newline_spec.rb
423
426
  - spec/render/plain_spec.rb
424
427
  - spec/render/preserve_spec.rb
425
428
  - spec/render/sanitize_spec.rb