hamlit 1.5.9 → 1.6.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.
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