hamlit 1.5.9 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/doc/README.md +15 -2
  4. data/doc/engine/indent.md +24 -0
  5. data/doc/engine/new_attribute.md +77 -0
  6. data/doc/engine/old_attributes.md +127 -0
  7. data/doc/engine/silent_script.md +97 -0
  8. data/doc/engine/tag.md +48 -0
  9. data/doc/engine/text.md +7 -1
  10. data/doc/faml/README.md +19 -0
  11. data/doc/faml/engine/indent.md +24 -0
  12. data/doc/faml/engine/old_attributes.md +108 -0
  13. data/doc/faml/engine/silent_script.md +97 -0
  14. data/doc/faml/engine/text.md +35 -0
  15. data/doc/faml/filters/coffee.md +125 -0
  16. data/doc/faml/filters/erb.md +24 -0
  17. data/doc/faml/filters/javascript.md +27 -0
  18. data/doc/faml/filters/less.md +57 -0
  19. data/doc/faml/filters/plain.md +25 -0
  20. data/doc/faml/filters/sass.md +62 -0
  21. data/doc/faml/filters/scss.md +68 -0
  22. data/doc/haml/README.md +15 -0
  23. data/doc/haml/engine/new_attribute.md +77 -0
  24. data/doc/haml/engine/old_attributes.md +142 -0
  25. data/doc/haml/engine/tag.md +48 -0
  26. data/doc/haml/engine/text.md +59 -0
  27. data/doc/haml/filters/erb.md +26 -0
  28. data/doc/haml/filters/javascript.md +76 -0
  29. data/doc/haml/filters/markdown.md +31 -0
  30. data/lib/hamlit/compilers/attributes.rb +1 -1
  31. data/lib/hamlit/compilers/new_attribute.rb +6 -6
  32. data/lib/hamlit/compilers/old_attribute.rb +2 -2
  33. data/lib/hamlit/compilers/text.rb +7 -10
  34. data/lib/hamlit/concerns/lexable.rb +32 -0
  35. data/lib/hamlit/parser.rb +9 -8
  36. data/lib/hamlit/parsers/attribute.rb +6 -3
  37. data/lib/hamlit/version.rb +1 -1
  38. data/spec/hamlit/engine/indent_spec.rb +1 -1
  39. data/spec/hamlit/engine/new_attribute_spec.rb +13 -2
  40. data/spec/hamlit/engine/old_attributes_spec.rb +5 -5
  41. data/spec/hamlit/engine/silent_script_spec.rb +4 -4
  42. data/spec/hamlit/engine/tag_spec.rb +23 -0
  43. data/spec/hamlit/engine/text_spec.rb +7 -3
  44. data/spec/spec_helper.rb +7 -231
  45. data/spec/spec_helper/document_generator.rb +93 -0
  46. data/spec/spec_helper/render_helper.rb +112 -0
  47. data/spec/spec_helper/test_case.rb +55 -0
  48. metadata +33 -3
  49. data/lib/hamlit/concerns/ripperable.rb +0 -20
@@ -1,3 +1,3 @@
1
1
  module Hamlit
2
- VERSION = "1.5.9"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  describe Hamlit::Engine do
2
2
  describe 'tab indent' do
3
- it 'accepts tab indentation', skipdoc: true do
3
+ it 'accepts tab indentation' do
4
4
  assert_render(<<-HAML, <<-HTML, compatible_only: :haml)
5
5
  %p
6
6
  \t%a
@@ -16,8 +16,19 @@ describe Hamlit::Engine do
16
16
  HTML
17
17
  end
18
18
 
19
+ it 'renders multi-line attributes properly' do
20
+ assert_render(<<-HAML, <<-HTML, compatible_only: :faml)
21
+ %span(a=__LINE__
22
+ b=__LINE__)
23
+ = __LINE__
24
+ HAML
25
+ <span a='1' b='2'></span>
26
+ 3
27
+ HTML
28
+ end
29
+
19
30
  describe 'html escape' do
20
- it 'escapes attribute values on static attributes', skipdoc: true do
31
+ it 'escapes attribute values on static attributes' do
21
32
  assert_render(<<-'HAML', <<-HTML, compatible_only: :faml)
22
33
  %a(title="'")
23
34
  %a(title = "'\"")
@@ -29,7 +40,7 @@ describe Hamlit::Engine do
29
40
  HTML
30
41
  end
31
42
 
32
- it 'escapes attribute values on dynamic attributes', skipdoc: true do
43
+ it 'escapes attribute values on dynamic attributes' do
33
44
  assert_render(<<-'HAML', <<-HTML, compatible_only: :faml)
34
45
  - title = "'\""
35
46
  - href = '/search?foo=bar&hoge=<fuga>'
@@ -121,7 +121,7 @@ describe Hamlit::Engine do
121
121
  HTML
122
122
  end
123
123
 
124
- it 'joins attribute class and element class', skipdoc: true do
124
+ it 'joins attribute class and element class' do
125
125
  assert_render(<<-HAML, <<-HTML, compatible_only: :haml)
126
126
  .foo{ class: ['bar'] }
127
127
  .foo{ class: ['bar', nil] }
@@ -223,7 +223,7 @@ describe Hamlit::Engine do
223
223
  end
224
224
 
225
225
  describe 'html escape' do
226
- it 'escapes attribute values on static attributes', skipdoc: true do
226
+ it 'escapes attribute values on static attributes' do
227
227
  assert_render(<<-'HAML', <<-HTML, compatible_only: :faml)
228
228
  %a{title: "'"}
229
229
  %a{title: "'\""}
@@ -235,7 +235,7 @@ describe Hamlit::Engine do
235
235
  HTML
236
236
  end
237
237
 
238
- it 'escapes attribute values on dynamic attributes', skipdoc: true do
238
+ it 'escapes attribute values on dynamic attributes' do
239
239
  assert_render(<<-'HAML', <<-HTML, compatible_only: :faml)
240
240
  - title = "'\""
241
241
  - href = '/search?foo=bar&hoge=<fuga>'
@@ -247,7 +247,7 @@ describe Hamlit::Engine do
247
247
  HTML
248
248
  end
249
249
 
250
- it 'escapes attribute values on hash attributes', skipdoc: true do
250
+ it 'escapes attribute values on hash attributes' do
251
251
  assert_render(<<-'HAML', <<-HTML, compatible_only: :faml)
252
252
  - title = { title: "'\"" }
253
253
  - href = { href: '/search?foo=bar&hoge=<fuga>' }
@@ -270,7 +270,7 @@ describe Hamlit::Engine do
270
270
  HTML
271
271
  end
272
272
 
273
- it 'renders true attributes', skipdoc: true do
273
+ it 'renders true attributes' do
274
274
  assert_render(<<-'HAML', <<-HTML, compatible_only: :haml)
275
275
  %span{ data: { disable: true } } bar
276
276
  HAML
@@ -76,7 +76,7 @@ describe Hamlit::Engine do
76
76
  HTML
77
77
  end
78
78
 
79
- it 'renders empty elsif statement', skipdoc: true do
79
+ it 'renders empty elsif statement' do
80
80
  assert_render(<<-'HAML', <<-HTML, compatible_only: :haml, error_with: :faml)
81
81
  %span
82
82
  - if false
@@ -87,7 +87,7 @@ describe Hamlit::Engine do
87
87
  HTML
88
88
  end
89
89
 
90
- it 'renders empty else statement', skipdoc: true do
90
+ it 'renders empty else statement' do
91
91
  assert_render(<<-'HAML', <<-HTML, compatible_only: :haml, error_with: :faml)
92
92
  %span
93
93
  - if false
@@ -99,7 +99,7 @@ describe Hamlit::Engine do
99
99
  HTML
100
100
  end
101
101
 
102
- it 'renders empty when statement', skipdoc: true do
102
+ it 'renders empty when statement' do
103
103
  assert_render(<<-'HAML', <<-HTML, compatible_only: :haml, error_with: :faml)
104
104
  %span
105
105
  - case
@@ -187,7 +187,7 @@ describe Hamlit::Engine do
187
187
  HTML
188
188
  end
189
189
 
190
- it 'joins a next line if a current line ends with ","', skipdoc: true do
190
+ it 'joins a next line if a current line ends with ","' do
191
191
  assert_render("- foo = [', \n ']\n= foo", <<-HTML, compatible_only: :haml)
192
192
  [&quot;, &quot;]
193
193
  HTML
@@ -267,6 +267,29 @@ describe Hamlit::Engine do
267
267
  <div class='foo'>bar1bar1bar1bar12</div>
268
268
  HTML
269
269
  end
270
+
271
+ it 'does not remove whitespace after string interpolation' do
272
+ assert_render(<<-'HAML', <<-HTML, compatible_only: :faml)
273
+ %div<
274
+ #{'hello'}
275
+ world
276
+ HAML
277
+ <div>hello
278
+ world</div>
279
+ HTML
280
+ end
281
+
282
+ it 'removes whitespace inside script inside silent script' do
283
+ assert_render(<<-HAML, <<-HTML, compatible_only: :faml)
284
+ .bar<
285
+ - 1.times do
286
+ = '1'
287
+ = '2'
288
+ HAML
289
+ <div class='bar'>1
290
+ 2</div>
291
+ HTML
292
+ end
270
293
  end
271
294
  end
272
295
  end
@@ -16,13 +16,17 @@ describe Hamlit::Engine do
16
16
  assert_render(<<-HAML, <<-HTML, compatible_only: [], error_with: :haml)
17
17
  .
18
18
  .*
19
+ ..
19
20
  #
20
21
  #+
22
+ ##
21
23
  HAML
22
24
  .
23
25
  .*
26
+ ..
24
27
  #
25
28
  #+
29
+ ##
26
30
  HTML
27
31
  end
28
32
 
@@ -112,15 +116,15 @@ describe Hamlit::Engine do
112
116
  end
113
117
 
114
118
  it 'renders !, & operator right before a non-space character' do
115
- assert_render(<<-'HAML', <<-'HTML', compatible_only: :faml)
119
+ assert_render(<<-'HAML', <<-'HTML', compatible_only: :haml)
116
120
  &nbsp;
117
121
  \&nbsp;
118
122
  !hello
119
123
  \!hello
120
124
  HAML
121
- nbsp;
122
125
  &nbsp;
123
- hello
126
+ &nbsp;
127
+ !hello
124
128
  !hello
125
129
  HTML
126
130
  end
@@ -1,236 +1,10 @@
1
- require 'haml'
2
- require 'faml'
3
- require 'hamlit'
4
1
  require 'unindent'
5
-
6
- module HamlitSpecHelper
7
- DEFAULT_OPTIONS = { ugly: true, escape_html: true }.freeze
8
-
9
- def parse_string(str)
10
- Hamlit::Parser.new.call(str)
11
- end
12
-
13
- def render_string(str, options = {})
14
- eval Hamlit::Engine.new(options).call(str)
15
- end
16
-
17
- def assert_render(haml, html, options = {})
18
- errs = array_wrap(options.delete(:error_with) || [])
19
- impls = array_wrap(options.delete(:compatible_only) || [:haml, :faml] - errs)
20
- fails = [:haml, :faml] - impls - errs
21
-
22
- test = TestCase.new
23
- test.src_haml = haml.unindent
24
- test.hamlit_html = html.unindent
25
-
26
- expect(render_string(test.src_haml, options)).to eq(test.hamlit_html)
27
- impls.each { |i| expect_compatibility(i, test, options) }
28
- errs.each { |i| expect_compatibility(i, test, options, type: :error) }
29
- fails.each { |i| expect_compatibility(i, test, options, type: :failure) }
30
-
31
- if TestCase.generate_docs? && (errs.any? || fails.any?)
32
- write_caller!(test)
33
- TestCase.register_test!(test)
34
- end
35
- end
36
-
37
- def assert_parse(haml, &block)
38
- haml = haml.unindent
39
- ast = block.call
40
-
41
- expect(parse_string(haml)).to eq(ast)
42
- end
43
-
44
- def assert_compile(before, after)
45
- result = described_class.new.call(before)
46
- expect(result).to eq(after)
47
- end
48
-
49
- private
50
-
51
- def write_caller!(test)
52
- line = caller.find{ |l| l =~ %r{spec/hamlit} }
53
- path, lineno = line.match(/^([^:]+):([0-9]+)/).to_a.last(2)
54
- test.lineno = lineno.to_i - 1
55
- test.dir, test.file = path.gsub(%r{^.+spec/hamlit/}, '').split('/')
56
- end
57
-
58
- def expect_compatibility(impl, test, options, type: :success)
59
- case impl
60
- when :haml
61
- expect_haml(impl, test, options, type)
62
- when :faml
63
- expect_faml(impl, test, options, type)
64
- end
65
- end
66
-
67
- def expect_haml(impl, test, options, type)
68
- expect_implementation(impl, test, options, type) do |test, options|
69
- options = DEFAULT_OPTIONS.merge(options)
70
- Haml::Engine.new(test.src_haml, options).render(Object.new, {})
71
- end
72
- end
73
-
74
- def expect_faml(impl, test, options, type)
75
- expect_implementation(impl, test, options, type) do |test, options|
76
- options = options.dup
77
- options.delete(:escape_html)
78
- eval Faml::Engine.new(options).call(test.src_haml)
79
- end
80
- end
81
-
82
- def expect_implementation(impl, test, options, type, &block)
83
- if type == :error
84
- expect { block.call(test, options) }.to raise_error
85
- begin
86
- block.call(test, options)
87
- rescue Exception => e
88
- err = "#{e.class}: #{e.message}"
89
- test.send(:"#{impl}_html=", err)
90
- end
91
- return
92
- end
93
-
94
- result = block.call(test, options)
95
- test.send(:"#{impl}_html=", result)
96
-
97
- case type
98
- when :success
99
- expect(test.hamlit_html).to eq(result)
100
- when :failure
101
- expect(test.hamlit_html).to_not eq(result)
102
- end
103
- end
104
-
105
- def array_wrap(arr)
106
- return arr if arr.is_a?(Array)
107
- [arr]
108
- end
109
-
110
- def tests
111
- @tests ||= []
112
- end
113
- end
114
-
115
- # This is used to generate a document automatically.
116
- class TestCase < Struct.new(:file, :dir, :lineno, :src_haml, :haml_html, :faml_html, :hamlit_html)
117
- class << self
118
- def incompatibilities
119
- @incompatibilities ||= []
120
- end
121
-
122
- def generate_docs!
123
- prepare_dirs!
124
- generate_toc!
125
-
126
- incompatibilities.group_by(&:doc_path).each do |path, tests|
127
- doc = tests.sort_by(&:lineno).map(&:document).join("\n")
128
- full_path = File.join(doc_dir, path)
129
- File.write(full_path, doc)
130
- end
131
- end
132
-
133
- def generate_docs?
134
- ENV['AUTODOC']
135
- end
136
-
137
- def register_test!(test)
138
- incompatibilities << test unless @skipdoc
139
- end
140
-
141
- def skipdoc(&block)
142
- @skipdoc = true
143
- block.call
144
- ensure
145
- @skipdoc = false
146
- end
147
-
148
- private
149
-
150
- def generate_toc!
151
- table_of_contents = <<-TOC.unindent
152
- # Hamlit incompatibilities
153
-
154
- This is a document generated from RSpec test cases.
155
- Showing incompatibilities against [Haml](https://github.com/haml/haml) and [Faml](https://github.com/eagletmt/faml).
156
- TOC
157
-
158
- incompatibilities.group_by(&:dir).each do |dir, tests|
159
- # TODO: Split incompatibility documents into haml and faml
160
- # There are too many noisy documents now.
161
- next if dir == 'filters'
162
-
163
- table_of_contents << "\n## #{dir}\n"
164
-
165
- tests.group_by(&:doc_path).each do |path, tests|
166
- test = tests.first
167
- file_path = File.join(test.dir, test.file)
168
- table_of_contents << "\n- [#{escape_markdown(file_path)}](#{path})"
169
- end
170
- table_of_contents << "\n"
171
- end
172
-
173
- path = File.join(doc_dir, 'README.md')
174
- File.write(path, table_of_contents)
175
- end
176
-
177
- def prepare_dirs!
178
- system("rm -rf #{doc_dir}")
179
- incompatibilities.map(&:dir).uniq.each do |dir|
180
- system("mkdir -p #{doc_dir}/#{dir}")
181
- end
182
- end
183
-
184
- def doc_dir
185
- @doc_dir ||= File.expand_path('./doc')
186
- end
187
-
188
- def escape_markdown(text)
189
- text.gsub(/_/, '\\_')
190
- end
191
- end
192
-
193
- def document
194
- base_path = '/spec/hamlit'
195
- path = File.join(base_path, dir, file)
196
- doc = <<-DOC
197
- # [#{escape_markdown("#{file}:#{lineno}")}](#{path}#L#{lineno})
198
- ## Input
199
- ```haml
200
- #{src_haml}
201
- ```
202
-
203
- ## Output
204
- DOC
205
-
206
- html_by_name = {
207
- 'Haml' => haml_html,
208
- 'Faml' => faml_html,
209
- 'Hamlit' => hamlit_html,
210
- }
211
- html_by_name.group_by(&:last).each do |html, pairs|
212
- doc << "### #{pairs.map(&:first).join(', ')}\n"
213
- doc << "```html\n"
214
- doc << "#{html}\n"
215
- doc << "```\n\n"
216
- end
217
-
218
- doc
219
- end
220
-
221
- def doc_path
222
- File.join(dir, file.gsub(/_spec\.rb$/, '.md'))
223
- end
224
-
225
- private
226
-
227
- def escape_markdown(text)
228
- self.class.send(:escape_markdown, text)
229
- end
230
- end
2
+ require_relative 'spec_helper/document_generator'
3
+ require_relative 'spec_helper/render_helper'
4
+ require_relative 'spec_helper/test_case'
231
5
 
232
6
  RSpec.configure do |config|
233
- config.include HamlitSpecHelper
7
+ config.include RenderHelper
234
8
 
235
9
  config.expect_with :rspec do |expectations|
236
10
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
@@ -247,6 +21,8 @@ RSpec.configure do |config|
247
21
  end
248
22
 
249
23
  config.after(:suite) do
250
- TestCase.generate_docs! if TestCase.generate_docs?
24
+ if DocumentGenerator.generate_docs?
25
+ DocumentGenerator.generate_docs!
26
+ end
251
27
  end
252
28
  end
@@ -0,0 +1,93 @@
1
+ require 'singleton'
2
+
3
+ class DocumentGenerator
4
+ class << self
5
+ def incompatibilities
6
+ @incompatibilities ||= []
7
+ end
8
+
9
+ def generate_docs!
10
+ prepare_dirs!
11
+
12
+ [nil, 'haml', 'faml'].each do |impl|
13
+ generate_toc!(impl)
14
+ generate_doc!(impl)
15
+ end
16
+ end
17
+
18
+ def generate_docs?
19
+ ENV['AUTODOC']
20
+ end
21
+
22
+ def register_test!(test)
23
+ incompatibilities << test unless @skipdoc
24
+ end
25
+
26
+ def skipdoc(&block)
27
+ @skipdoc = true
28
+ block.call
29
+ ensure
30
+ @skipdoc = false
31
+ end
32
+
33
+ private
34
+
35
+ def generate_doc!(impl)
36
+ incompatibilities_for(impl).group_by(&:doc_path).each do |path, tests|
37
+ doc = tests.sort_by(&:lineno).map { |t| t.document(impl) }.join("\n")
38
+ full_path = File.join(*[doc_dir, impl, path].compact)
39
+ File.write(full_path, doc)
40
+ end
41
+ end
42
+
43
+ def generate_toc!(impl = nil)
44
+ path = File.join(*[doc_dir, impl, 'README.md'].compact)
45
+ File.write(path, table_of_contents_for(impl))
46
+ end
47
+
48
+ def table_of_contents_for(impl = nil)
49
+ toc = "# Hamlit incompatibilities\nThis is a document generated from RSpec test cases. "
50
+ toc << "\n#{target_description(impl)}"
51
+
52
+ incompatibilities_for(impl).group_by(&:dir).each do |dir, tests|
53
+ toc << "\n\n## #{dir}\n"
54
+ tests.map { |t| [t.spec_path, t.doc_path] }.uniq.each do |spec_path, doc_path|
55
+ toc << "- [#{spec_path}](#{doc_path})\n"
56
+ end
57
+ end
58
+ toc
59
+ end
60
+
61
+ def incompatibilities_for(impl)
62
+ return incompatibilities unless impl
63
+ incompatibilities.select { |t| t.send(:"#{impl}_html") != t.hamlit_html }
64
+ end
65
+
66
+ def target_description(impl)
67
+ case impl
68
+ when 'haml'
69
+ 'Showing incompatibilities against [Haml](https://github.com/haml/haml).'
70
+ when 'faml'
71
+ 'Showing incompatibilities against [Faml](https://github.com/eagletmt/faml).'
72
+ else
73
+ 'Showing incompatibilities against [Haml](https://github.com/haml/haml) and [Faml](https://github.com/eagletmt/faml).'
74
+ end
75
+ end
76
+
77
+ def prepare_dirs!
78
+ system("rm -rf #{doc_dir}")
79
+ incompatibilities.map(&:dir).uniq.each do |dir|
80
+ system("mkdir -p #{File.join(doc_dir, dir)}")
81
+ end
82
+ %w[haml faml].each do |impl|
83
+ incompatibilities.map(&:dir).uniq.each do |dir|
84
+ system("mkdir -p #{File.join(doc_dir, impl, dir)}")
85
+ end
86
+ end
87
+ end
88
+
89
+ def doc_dir
90
+ @doc_dir ||= File.expand_path('./doc')
91
+ end
92
+ end
93
+ end