hologram 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/CHANGELOG.md +37 -0
  4. data/README.md +243 -5
  5. data/hologram.gemspec +2 -0
  6. data/lib/hologram.rb +2 -0
  7. data/lib/hologram/block_code_renderer.rb +45 -0
  8. data/lib/hologram/code_example_renderer.rb +73 -0
  9. data/lib/hologram/code_example_renderer/example.rb +27 -0
  10. data/lib/hologram/code_example_renderer/factory.rb +60 -0
  11. data/lib/hologram/code_example_renderer/renderers/haml_renderer.rb +17 -0
  12. data/lib/hologram/code_example_renderer/renderers/html_renderer.rb +6 -0
  13. data/lib/hologram/code_example_renderer/renderers/js_renderer.rb +5 -0
  14. data/lib/hologram/code_example_renderer/renderers/jsx_renderer.rb +4 -0
  15. data/lib/hologram/code_example_renderer/renderers/react_renderer.rb +21 -0
  16. data/lib/hologram/code_example_renderer/renderers/slim_renderer.rb +16 -0
  17. data/lib/hologram/code_example_renderer/template.rb +33 -0
  18. data/lib/hologram/display_message.rb +13 -0
  19. data/lib/hologram/doc_block_collection.rb +5 -1
  20. data/lib/hologram/doc_builder.rb +58 -7
  21. data/lib/hologram/doc_parser.rb +20 -4
  22. data/lib/hologram/document_block.rb +22 -4
  23. data/lib/hologram/link_helper.rb +18 -0
  24. data/lib/hologram/markdown_renderer.rb +56 -35
  25. data/lib/hologram/version.rb +1 -1
  26. data/lib/template/code_example_templates/js_example_template.html.erb +7 -0
  27. data/lib/template/code_example_templates/jsx_example_template.html.erb +7 -0
  28. data/lib/template/code_example_templates/markup_example_template.html.erb +10 -0
  29. data/lib/template/code_example_templates/markup_table_template.html.erb +23 -0
  30. data/lib/template/hologram_config.yml +23 -0
  31. data/spec/block_code_renderer_spec.rb +279 -0
  32. data/spec/code_example_renderer/example_spec.rb +26 -0
  33. data/spec/code_example_renderer/factory_spec.rb +102 -0
  34. data/spec/code_example_renderer/template_spec.rb +50 -0
  35. data/spec/display_message_spec.rb +18 -0
  36. data/spec/doc_block_collection_spec.rb +26 -1
  37. data/spec/doc_builder_spec.rb +28 -5
  38. data/spec/doc_parser_spec.rb +67 -7
  39. data/spec/document_block_spec.rb +33 -2
  40. data/spec/fixtures/source/components/button/buttons.css +8 -6
  41. data/spec/fixtures/source/components/button/skin/buttonSkins.css +17 -0
  42. data/spec/fixtures/styleguide/base_css.html +176 -52
  43. data/spec/fixtures/styleguide/index.html +6 -14
  44. data/spec/link_helper_spec.rb +57 -0
  45. data/spec/markdown_renderer_spec.rb +82 -0
  46. metadata +75 -19
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hologram::CodeExampleRenderer::Example do
4
+ let(:code) { 'goto 12' }
5
+ let(:example) { described_class.new(code) }
6
+
7
+ describe '#rendered_example' do
8
+ subject { example.rendered_example }
9
+ it { is_expected.to eq 'goto 12' }
10
+ end
11
+
12
+ describe '#code_example' do
13
+ let(:formatter) { double(:formatter) }
14
+ let(:lexer) { double(:lexer, lex: 'lexed_code') }
15
+
16
+ before do
17
+ allow(Rouge::Lexer).to receive(:find_fancy).with('guess', code) { lexer }
18
+ allow(Rouge::Formatters::HTML).to receive(:new) { formatter }
19
+ allow(formatter).to receive(:format).with('lexed_code') { 'formatted_lexed_code' }
20
+ end
21
+
22
+ subject { example.code_example }
23
+
24
+ it { is_expected.to eq 'formatted_lexed_code' }
25
+ end
26
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ Hologram::CodeExampleRenderer.load_renderers_and_templates
4
+
5
+ describe Hologram::CodeExampleRenderer::Factory do
6
+ describe '.define' do
7
+ let(:example_type) { 'foobar' }
8
+
9
+ before do
10
+ allow(Hologram::CodeExampleRenderer::Template).to receive(:new).with('custom_example_template') { double(template: 'the full custom example template') }
11
+ allow(Hologram::CodeExampleRenderer::Template).to receive(:new).with('custom_table_template') { double(template: 'the full custom table template') }
12
+ allow(Hologram::CodeExampleRenderer::Template).to receive(:new).with(nil).and_call_original
13
+ end
14
+
15
+ context "when a renderer is registered with all of the options" do
16
+ before do
17
+ custom_lexer = double(:lexer, lex: 'lexed code from supplied lexer')
18
+
19
+ Hologram::CodeExampleRenderer::Factory.define(example_type) do
20
+ example_template 'custom_example_template'
21
+ table_template 'custom_table_template'
22
+ lexer { custom_lexer }
23
+ rendered_example { |code| "special rendering for #{code}" }
24
+ end
25
+ end
26
+
27
+ after { Hologram::CodeExampleRenderer.unregister(example_type) }
28
+
29
+ describe "the registered example class" do
30
+ let(:example_class) { Hologram::CodeExampleRenderer.example_class_for(example_type) }
31
+ let(:example) { example_class.new('some code') }
32
+
33
+ it "renders the example using the block supplied to the factory" do
34
+ expect(example.rendered_example).to eq "special rendering for some code"
35
+ end
36
+
37
+ it "formats the code uses the supplied lexer" do
38
+ formatter = double(:formatter)
39
+ allow(Rouge::Formatters::HTML).to receive(:new) { formatter }
40
+
41
+ expect(formatter).to receive(:format).with('lexed code from supplied lexer') { 'formatted code' }
42
+ example.code_example
43
+ end
44
+ end
45
+
46
+ describe "the registered templates" do
47
+ let(:example_template) { Hologram::CodeExampleRenderer.example_template_for(example_type) }
48
+ let(:table_template) { Hologram::CodeExampleRenderer.table_template_for(example_type) }
49
+
50
+ it "uses the supplied example template" do
51
+ expect(example_template).to eq 'the full custom example template'
52
+ end
53
+
54
+ it "uses the supplied table template" do
55
+ expect(table_template).to eq 'the full custom table template'
56
+ end
57
+ end
58
+ end
59
+
60
+ context "when a renderer is registered with only some of the options" do
61
+ before do
62
+
63
+ Hologram::CodeExampleRenderer::Factory.define(example_type) do
64
+ example_template 'custom_example_template'
65
+ end
66
+ end
67
+
68
+ after { Hologram::CodeExampleRenderer.unregister(example_type) }
69
+
70
+ describe "the registered example class" do
71
+ let(:example_class) { Hologram::CodeExampleRenderer.example_class_for(example_type) }
72
+ let(:example) { example_class.new('some code') }
73
+
74
+ it "renders the example as is" do
75
+ expect(example.rendered_example).to eq "some code"
76
+ end
77
+
78
+ it "formats the code uses the default lexer" do
79
+ formatter = double(:formatter)
80
+ allow(Rouge::Lexer).to receive(:find_fancy).with('guess', 'some code') { double(lex: 'default lexed code') }
81
+ allow(Rouge::Formatters::HTML).to receive(:new) { formatter }
82
+
83
+ expect(formatter).to receive(:format).with('default lexed code') { 'formatted code' }
84
+ example.code_example
85
+ end
86
+ end
87
+
88
+ describe "the registered templates" do
89
+ let(:example_template) { Hologram::CodeExampleRenderer.example_template_for(example_type) }
90
+ let(:table_template) { Hologram::CodeExampleRenderer.table_template_for(example_type) }
91
+
92
+ it "uses the supplied example template" do
93
+ expect(example_template).to eq 'the full custom example template'
94
+ end
95
+
96
+ it "does not have a table template" do
97
+ expect(table_template).to be_nil
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hologram::CodeExampleRenderer::Template do
4
+ describe '#template' do
5
+ subject { described_class.new(template_name).template }
6
+
7
+ context 'when template_name is nil' do
8
+ let(:template_name) { nil }
9
+ it { is_expected.to be_nil }
10
+ end
11
+
12
+ context 'when template_name is not nil' do
13
+ let(:template_name) { 'bar' }
14
+
15
+ let(:custom_template_filename) { 'custom/bar.html.erb' }
16
+ let(:default_template_filename) { 'cwd/../../template/code_example_templates/bar.html.erb' }
17
+
18
+ before do
19
+ allow(File).to receive(:dirname) { 'cwd/' }
20
+ allow(File).to receive(:read).with(custom_template_filename) { 'custom template' }
21
+ allow(File).to receive(:read).with(default_template_filename) { 'default template' }
22
+ end
23
+
24
+ context 'when path_to_custom_example_templates is defined' do
25
+ before do
26
+ described_class.path_to_custom_example_templates = 'custom/'
27
+ allow(File).to receive(:file?).with(custom_template_filename) { has_custom_template? }
28
+ end
29
+
30
+ after do
31
+ described_class.path_to_custom_example_templates = nil
32
+ end
33
+
34
+ context 'when a custom template exists' do
35
+ let(:has_custom_template?) { true }
36
+ it { is_expected.to eq 'custom template' }
37
+ end
38
+
39
+ context 'when a custom template does not exist' do
40
+ let(:has_custom_template?) { false }
41
+ it { is_expected.to eq 'default template' }
42
+ end
43
+ end
44
+
45
+ context 'when a path_to_custom_example_templates is not defined' do
46
+ it { is_expected.to eq 'default template' }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -60,10 +60,28 @@ describe Hologram::DisplayMessage do
60
60
  end
61
61
 
62
62
  context '.warning' do
63
+ around do |example|
64
+ display.quiet!
65
+ example.run
66
+ display.show!
67
+ end
68
+
63
69
  it 'displays a warning message in yellow' do
64
70
  expect(display).to receive(:puts).with("\e[33mWarning: foo\e[0m")
65
71
  display.warning('foo')
66
72
  end
73
+
74
+ context 'when .exit_on_warnings! has been called' do
75
+ around do |example|
76
+ display.exit_on_warnings!
77
+ example.run
78
+ display.continue_on_warnings!
79
+ end
80
+
81
+ it 'exits' do
82
+ expect{ display.warning('foo') }.to raise_error SystemExit
83
+ end
84
+ end
67
85
  end
68
86
 
69
87
  context '.colorize' do
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Hologram::DocBlockCollection do
4
4
  let(:comment) do
5
- comment = <<comment
5
+ <<-comment
6
6
  /*doc
7
7
  ---
8
8
  title: Buttons
@@ -49,6 +49,31 @@ comment
49
49
  expect(collection.doc_blocks.size).to eql 0
50
50
  end
51
51
  end
52
+
53
+ context 'when the block has the same name as another block in the collection' do
54
+ let(:duplicate_comment) do
55
+ <<-comment
56
+ /*doc
57
+ ---
58
+ title: Imposter Buttons
59
+ name: button
60
+ category: Base CSS
61
+ ---
62
+
63
+ Same old stuff
64
+ */
65
+ comment
66
+ end
67
+
68
+ before do
69
+ collection.add_doc_block(comment, 'fake_file.sass')
70
+ end
71
+
72
+ it 'displays a warning' do
73
+ expect(Hologram::DisplayMessage).to receive(:warning)
74
+ collection.add_doc_block(duplicate_comment, 'fake_file.sass')
75
+ end
76
+ end
52
77
  end
53
78
 
54
79
  context '#create_nested_structure' do
@@ -131,6 +131,32 @@ describe Hologram::DocBuilder do
131
131
  end
132
132
  end
133
133
 
134
+ context '#initialize' do
135
+ subject { Hologram::DocBuilder.new(config) }
136
+
137
+ context 'when the "exit_on_warnings" option is passed in as true' do
138
+ let(:config) do
139
+ { 'exit_on_warnings' => true }
140
+ end
141
+
142
+ it 'calls DisplayMessage.exit_on_warnings!' do
143
+ expect(Hologram::DisplayMessage).to receive(:exit_on_warnings!)
144
+ subject
145
+ end
146
+ end
147
+
148
+ context 'when the "exit_on_warnings" option is not passed in' do
149
+ let(:config) do
150
+ { }
151
+ end
152
+
153
+ it 'does not call DisplayMessage.exit_on_warnings!' do
154
+ expect(Hologram::DisplayMessage).not_to receive(:exit_on_warnings!)
155
+ subject
156
+ end
157
+ end
158
+ end
159
+
134
160
  context '#is_valid?' do
135
161
 
136
162
  let(:config) do
@@ -204,8 +230,6 @@ describe Hologram::DocBuilder do
204
230
  end
205
231
 
206
232
  context '#build' do
207
- let(:style_files) { Dir[File.expand_path('../fixtures/styleguide/**/*.*', __FILE__)] }
208
- let(:processed_files) { Dir[File.join(builder.destination, '.', '**/*.*')] }
209
233
  let(:config_path) { File.join(Dir.pwd, 'spec/fixtures/source/config.yml') }
210
234
  let(:config_copy_path) { File.join(Dir.pwd, 'spec/fixtures/source/config.yml.copy') }
211
235
  let(:builder) { Hologram::DocBuilder.from_yaml(config_copy_path) }
@@ -226,9 +250,8 @@ describe Hologram::DocBuilder do
226
250
 
227
251
  it 'builds a styleguide' do
228
252
  builder.build
229
- style_files.each_with_index do |file, index|
230
- expect(FileUtils.cmp(file, processed_files[index])).to be_truthy
231
- end
253
+ expect(File.read(File.expand_path('../fixtures/styleguide/base_css.html', __FILE__))).to eq File.read(File.join(builder.destination, '.', 'base_css.html'))
254
+ expect(File.read(File.expand_path('../fixtures/styleguide/index.html', __FILE__))).to eq File.read(File.join(builder.destination, '.', 'index.html'))
232
255
  end
233
256
  end
234
257
  end
@@ -15,6 +15,19 @@ Markdown stuff
15
15
  eos
16
16
  end
17
17
 
18
+ let(:docs_child) do
19
+ <<-eos
20
+ /*doc
21
+ ---
22
+ parent: otherStyle
23
+ title: Other Style Child
24
+ name: otherStyleChild
25
+ ---
26
+ Markdown stuff
27
+ */
28
+ eos
29
+ end
30
+
18
31
  let(:child_doc) do
19
32
  <<-eos
20
33
  /*doc
@@ -28,6 +41,19 @@ Markdown stuff
28
41
  eos
29
42
  end
30
43
 
44
+ let(:grandchild_doc) do
45
+ <<-eos
46
+ /*doc
47
+ ---
48
+ parent: otherStyle
49
+ name: grandbaby
50
+ title: Grandbaby
51
+ ---
52
+ Markdown stuff
53
+ */
54
+ eos
55
+ end
56
+
31
57
  let(:multi_category_child_doc) do
32
58
  <<-eos
33
59
  /*doc
@@ -77,10 +103,10 @@ multi-parent
77
103
  expect(output_files_by_category).to be_a Hash
78
104
  end
79
105
 
80
- context "when the source has multiple paths" do
106
+ context 'when the source has multiple paths' do
81
107
  subject(:parser) { Hologram::DocParser.new(['spec/fixtures/source/colors', 'spec/fixtures/source/components'], nil, plugins) }
82
108
 
83
- it "parses all sources" do
109
+ it 'parses all sources' do
84
110
  expect(pages['base_css.html'][:md]).to include 'Base colors'
85
111
  expect(pages['base_css.html'][:md]).to include 'Background Colors'
86
112
  end
@@ -123,6 +149,30 @@ multi-parent
123
149
  it 'takes the category in a collection and treats them as the page names' do
124
150
  expect(pages.keys).to include 'foo.html'
125
151
  end
152
+
153
+ context 'when nav_level is set to section' do
154
+ before do
155
+ File.open(temp_doc, 'a+'){ |io| io << docs_child }
156
+ parser.nav_level = 'section'
157
+ end
158
+
159
+ it 'generates navigation to children from their parent' do
160
+ parser.parse
161
+ expect(pages['foo.html'][:md]).to include '<li><a href="#otherStyleChild">Other Style Child</a></li>'
162
+ end
163
+ end
164
+
165
+ context 'when nav_level is not set' do
166
+ before do
167
+ File.open(temp_doc, 'a+'){ |io| io << docs_child }
168
+ parser.nav_level = nil
169
+ end
170
+
171
+ it 'should not generate sub navigation' do
172
+ parser.parse
173
+ expect(pages['foo.html'][:md]).not_to include '<li><a href="#otherStyleChild">Other Style Child</a></li>'
174
+ end
175
+ end
126
176
  end
127
177
 
128
178
  context 'when a source doc is a child' do
@@ -132,16 +182,26 @@ multi-parent
132
182
  FileUtils.rm(temp_doc)
133
183
  end
134
184
 
135
- before do
136
- parser.parse
137
- end
138
-
139
185
  it 'appends the child doc to the category page' do
186
+ parser.parse
140
187
  expect(pages['base_css.html'][:md]).to include 'Some other style'
141
188
  end
142
189
 
143
190
  it 'assigns the child doc a deeper header' do
144
- expect(pages['base_css.html'][:md]).to include '<h2 id="otherStyle">Some other style</h2>'
191
+ parser.parse
192
+ expect(pages['base_css.html'][:md]).to include '<h2 id="otherStyle" class="styleguide">Some other style</h2>'
193
+ end
194
+
195
+ context 'when nav_level is set to all' do
196
+ before do
197
+ File.open(temp_doc, 'a+'){ |io| io << grandchild_doc }
198
+ parser.nav_level = 'all'
199
+ end
200
+
201
+ it 'generates navigation to grandchildren from their parent' do
202
+ parser.parse
203
+ expect(pages['base_css.html'][:md]).to include '<li><a href="#grandbaby">Grandbaby</a></li>'
204
+ end
145
205
  end
146
206
  end
147
207
 
@@ -116,8 +116,39 @@ eos
116
116
  end
117
117
 
118
118
  context '#markdown_with_heading' do
119
- it 'returns markdown with a specified header' do
120
- expect(doc_block.markdown_with_heading(2)).to eql "\n\n<h2 id=\"foo\">baz</h2>blah"
119
+ context 'when include_sub_nav is false' do
120
+ it 'returns markdown with a specified header' do
121
+ expect(doc_block.markdown_with_heading(2)).to eql "\n\n<h2 id=\"foo\" class=\"styleguide\">baz</h2>blah"
122
+ end
123
+ end
124
+
125
+ context 'when include_sub_nav is true' do
126
+ context 'when the component has no children' do
127
+ it 'returns markdown with no nav' do
128
+ expect(doc_block.markdown_with_heading(2, include_sub_nav: true)).to eql "\n\n<h2 id=\"foo\" class=\"styleguide\">baz</h2>blah"
129
+ end
130
+ end
131
+
132
+ context 'when the component has children' do
133
+ before do
134
+ doc_block.children['child-one'] = double( name: 'child-one', title: 'Child 1' )
135
+ doc_block.children['child-two'] = double( name: 'child-two', title: 'Child 2' )
136
+ end
137
+
138
+ it 'returns markdown with no nav' do
139
+ expected_output = <<-eos
140
+
141
+
142
+ <h2 id="foo" class="styleguide">baz</h2>
143
+ <ul class="section-nav">
144
+ <li><a href="#child-one">Child 1</a></li>
145
+ <li><a href="#child-two">Child 2</a></li>
146
+ </ul>
147
+ blah
148
+ eos
149
+ expect(doc_block.markdown_with_heading(2, include_sub_nav: true)).to eql expected_output.rstrip
150
+ end
151
+ end
121
152
  end
122
153
  end
123
154
  end