hologram 1.0.1 → 1.1.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.
@@ -1,35 +1,57 @@
1
1
  module Hologram
2
2
  class DocumentBlock
3
- attr_accessor :name, :parent, :children, :title, :category, :markdown, :config, :heading
3
+ COMMENT_REGEX = /^\s*---\s(.*?)\s---$/m
4
+
5
+ attr_accessor :name, :parent, :children, :title, :categories, :markdown, :config, :heading, :errors
4
6
 
5
7
  def initialize(config = nil, markdown = nil)
6
8
  @children = {}
9
+ @errors = []
7
10
  set_members(config, markdown) if config and markdown
8
11
  end
9
12
 
13
+ def self.from_comment(comment)
14
+ comment_match = COMMENT_REGEX.match(comment)
15
+ return if !comment_match
16
+
17
+ markdown = comment.sub(comment_match[0], '')
18
+ config = YAML::load(comment_match[1])
19
+
20
+ self.new(config, markdown)
21
+ rescue ArgumentError, Psych::SyntaxError
22
+ raise CommentLoadError, "Could not parse comment:\n#{comment}"
23
+ end
24
+
10
25
  def set_members(config, markdown)
11
26
  @name = config['name']
12
- @category = config['category']
27
+ @categories = Array(config['category'] || config['categories'])
13
28
  @title = config['title']
14
29
  @parent = config['parent']
15
30
  @markdown = markdown
31
+
32
+ if @name.nil?
33
+ @name = @title.gsub(' ', '_')
34
+ end
16
35
  end
17
36
 
18
37
  def get_hash
19
38
  {:name => @name,
20
39
  :parent => @parent,
21
- :category => @category,
40
+ :categories => @categories,
22
41
  :title => @title
23
42
  }
24
43
  end
25
44
 
26
45
  def is_valid?
27
- !!(@name && @markdown)
46
+ errors << 'Missing required category and/or parent config value' if !categories and !parent
47
+ errors << 'Missing name or title config value' if !name and !title
48
+ errors << 'Missing required markdown' if !markdown
49
+ errors.empty?
28
50
  end
29
51
 
30
52
  # sets the header tag based on how deep your nesting is
31
53
  def markdown_with_heading(heading = 1)
32
- @markdown = "\n\n<h#{heading.to_s} id=\"#{@name}\">#{@title}</h#{heading.to_s}>" + @markdown
54
+ "\n\n<h#{heading.to_s} id=\"#{@name}\">#{@title}</h#{heading.to_s}>" + @markdown
33
55
  end
34
56
  end
35
57
  end
@@ -0,0 +1,12 @@
1
+ module Hologram
2
+ class CommentLoadError < StandardError
3
+ end
4
+ end
5
+
6
+ module Hologram
7
+ class NoCategoryError < StandardError
8
+ def message
9
+ "Hologram comments found with no defined category. Are there other warnings/errors that need to be resolved?"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,49 @@
1
+ module Hologram
2
+ class MarkdownRenderer < Redcarpet::Render::HTML
3
+ def block_code(code, language)
4
+ if language and language.include?('example')
5
+ if language.include?('js')
6
+ # first actually insert the code in the docs so that it will run and make our example work.
7
+ '<script>' + code + '</script>
8
+ <div class="codeBlock jsExample">' + Pygments.highlight(code) + '</div>'
9
+ else
10
+ '<div class="codeExample">' + '<div class="exampleOutput">' + render_html(code, language) + '</div>' + '<div class="codeBlock">' + Pygments.highlight(code, :lexer => get_lexer(language)) + '</div>' + '</div>'
11
+ end
12
+ else
13
+ '<div class="codeBlock">' + Pygments.highlight(code) + '</div>'
14
+ end
15
+ end
16
+
17
+ private
18
+ def render_html(code, language)
19
+ case language
20
+ when 'haml_example'
21
+ safe_require('haml', language)
22
+ return Haml::Engine.new(code.strip).render(template_rendering_scope, {})
23
+ else
24
+ code
25
+ end
26
+ end
27
+
28
+ def template_rendering_scope
29
+ Object.new
30
+ end
31
+
32
+ def get_lexer(language)
33
+ case language
34
+ when 'haml_example'
35
+ 'haml'
36
+ else
37
+ 'html'
38
+ end
39
+ end
40
+
41
+ def safe_require(templating_library, language)
42
+ begin
43
+ require templating_library
44
+ rescue LoadError
45
+ raise "#{templating_library} must be present for you to use #{language}"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -2,7 +2,7 @@ module Hologram
2
2
 
3
3
  #Helper class for binding things for ERB
4
4
  class TemplateVariables
5
- attr_accessor :title, :file_name, :blocks, :categories
5
+ attr_accessor :title, :file_name, :blocks, :output_files_by_category, :config, :pages
6
6
 
7
7
  def initialize(args)
8
8
  set_args(args)
@@ -0,0 +1,16 @@
1
+ module Hologram
2
+ module Utils
3
+ def self.get_markdown_renderer(custom_markdown = nil)
4
+ return MarkdownRenderer if custom_markdown.nil?
5
+
6
+ load custom_markdown
7
+ renderer_class = File.basename(custom_markdown, '.rb').split(/_/).map(&:capitalize).join
8
+ DisplayMessage.info("Custom markdown renderer #{renderer_class} loaded.")
9
+ Module.const_get(renderer_class)
10
+ rescue LoadError => e
11
+ DisplayMessage.error("Could not load #{custom_markdown}.")
12
+ rescue NameError => e
13
+ DisplayMessage.error("Class #{renderer_class} not found in #{custom_markdown}.")
14
+ end
15
+ end
16
+ end
@@ -25,5 +25,5 @@
25
25
  # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
26
 
27
27
  module Hologram
28
- VERSION = "1.0.1"
28
+ VERSION = "1.1.0"
29
29
  end
@@ -19,6 +19,6 @@ dependencies:
19
19
  - ./build
20
20
 
21
21
  # Mark which category should be the index page
22
- # Alternatively, you may have an index.md in the documenatation assets
23
- # folder instead of specifying this configu.
22
+ # Alternatively, you may have an index.md in the documentation assets
23
+ # folder instead of specifying this config.
24
24
  index: basics
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'hologram/cli'
3
+
4
+ describe Hologram::CLI do
5
+ let(:argv) { [] }
6
+ subject(:cli) { Hologram::CLI.new(argv) }
7
+
8
+ context '#run' do
9
+ context 'when arg is "init"' do
10
+ let(:argv) { ['init'] }
11
+
12
+ it 'setups the dir' do
13
+ expect(Hologram::DocBuilder).to receive(:setup_dir)
14
+ cli.run
15
+ end
16
+ end
17
+
18
+ context 'when arg is empty' do
19
+ subject(:builder) { double(Hologram::DocBuilder, is_valid?: true, build: true) }
20
+
21
+ it 'builds the documentation' do
22
+ expect(Hologram::DocBuilder).to receive(:from_yaml).and_return(builder)
23
+ cli.run
24
+ end
25
+ end
26
+
27
+ context 'when a config file is passed' do
28
+ let(:argv) { ['test.yml'] }
29
+ subject(:builder) { double(Hologram::DocBuilder, is_valid?: true, build: true) }
30
+
31
+ it 'builds the documentation' do
32
+ expect(Hologram::DocBuilder).to receive(:from_yaml).with('test.yml').and_return(builder)
33
+ cli.run
34
+ end
35
+ end
36
+ end
37
+ end
@@ -4,23 +4,6 @@ require 'tempfile'
4
4
  describe Hologram::DisplayMessage do
5
5
  subject(:display) { Hologram::DisplayMessage }
6
6
 
7
- #Rails kernerl helper
8
- def capture(stream)
9
- stream = stream.to_s
10
- captured_stream = Tempfile.new(stream)
11
- stream_io = eval("$#{stream}")
12
- origin_stream = stream_io.dup
13
- stream_io.reopen(captured_stream)
14
-
15
- yield
16
-
17
- stream_io.rewind
18
- return captured_stream.read
19
- ensure
20
- captured_stream.unlink
21
- stream_io.reopen(origin_stream)
22
- end
23
-
24
7
  context '.quiet!' do
25
8
  around do |example|
26
9
  display.quiet!
@@ -32,7 +32,7 @@ comment
32
32
  context '#add_doc_block' do
33
33
  context 'when the comment is valid' do
34
34
  before do
35
- collection.add_doc_block(comment)
35
+ collection.add_doc_block(comment, 'fake_file.sass')
36
36
  end
37
37
 
38
38
  it 'adds a doc block to the collection' do
@@ -42,7 +42,7 @@ comment
42
42
 
43
43
  context 'when no yaml is provided' do
44
44
  before do
45
- collection.add_doc_block('')
45
+ collection.add_doc_block('', 'fake_file.sass')
46
46
  end
47
47
 
48
48
  it 'does not add a new block' do
@@ -54,7 +54,7 @@ comment
54
54
  context '#create_nested_structure' do
55
55
  context 'when the collection has blocks with parents' do
56
56
  before do
57
- collection.add_doc_block(comment)
57
+ collection.add_doc_block(comment, 'fake_file.sass')
58
58
  collection.add_doc_block(%q{
59
59
  /*doc
60
60
  ---
@@ -63,7 +63,7 @@ comment
63
63
  parent: button
64
64
  ---
65
65
  some other button style
66
- */})
66
+ */}, 'fake_file.sass')
67
67
 
68
68
  collection.create_nested_structure
69
69
  end
@@ -1,31 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Hologram::DocBuilder do
4
- subject(:builder) { Hologram::DocBuilder.new }
4
+ subject(:builder) { Hologram::DocBuilder }
5
5
 
6
- context '#init' do
7
- around do |example|
8
- Hologram::DisplayMessage.quiet!
9
- example.run
10
- Hologram::DisplayMessage.show!
11
- end
12
-
13
- context 'when passed an invalid config' do
14
- before do
15
- File.open('bad_config.yml', 'w'){ |io| io << '%' }
16
- end
17
-
18
- after do
19
- FileUtils.rm('bad_config.yml')
20
- end
6
+ around do |example|
7
+ Hologram::DisplayMessage.quiet!
8
+ example.run
9
+ Hologram::DisplayMessage.show!
10
+ end
21
11
 
22
- it 'exits the process' do
23
- expect { builder.init(['bad_config.yml']) }.to raise_error SystemExit
24
- end
25
- end
12
+ context '.from_yaml' do
13
+ subject(:builder) { Hologram::DocBuilder }
26
14
 
27
- context 'when passed a config file' do
28
- let(:style_files) { Dir[File.expand_path('../fixtures/styleguide/**/*.*', __FILE__)] }
15
+ context 'when passed a valid config file' do
29
16
  let(:config_path) { File.join(Dir.pwd, 'spec/fixtures/source/config.yml') }
30
17
  let(:config_copy_path) { File.join(Dir.pwd, 'spec/fixtures/source/config.yml.copy') }
31
18
 
@@ -43,50 +30,146 @@ describe Hologram::DocBuilder do
43
30
  end
44
31
  end
45
32
 
33
+ it 'returns a DocBuilder instance' do
34
+ expect(subject.from_yaml(config_copy_path)).to be_a Hologram::DocBuilder
35
+ end
36
+ end
37
+
38
+ context 'when passed an invalid config' do
46
39
  before do
47
- builder.init([config_copy_path])
40
+ File.open('bad_config.yml', 'w'){ |io| io << '%' }
41
+ end
42
+
43
+ after do
44
+ FileUtils.rm('bad_config.yml')
45
+ end
46
+
47
+ it 'exits the process' do
48
+ expect { subject.from_yaml('bad_config.yml') }.to raise_error SyntaxError
48
49
  end
50
+ end
51
+ end
52
+
53
+ context '.setup_dir' do
54
+ subject(:builder) { Hologram::DocBuilder }
49
55
 
50
- it 'builds a styleguide' do
51
- processed_files = Dir[File.join('.', '**/*.*')]
52
- processed_files.each_with_index do |file, index|
53
- expect(FileUtils.cmp(file, style_files[index])).to be_true
56
+ around do |example|
57
+ Dir.mktmpdir do |dir|
58
+ Dir.chdir(dir) do
59
+ example.run
54
60
  end
55
61
  end
56
62
  end
57
63
 
58
- context 'when passed "init" as arg' do
59
- around do |example|
60
- Dir.mktmpdir do |dir|
61
- Dir.chdir(dir) do
62
- example.run
63
- end
64
+ before do
65
+ builder.setup_dir
66
+ end
67
+
68
+ it 'creates a config file' do
69
+ expect(File.exists?('hologram_config.yml')).to be_true
70
+ end
71
+
72
+ it 'creates default assets' do
73
+ Dir.chdir('doc_assets') do
74
+ ['_header.html', '_footer.html'].each do |asset|
75
+ expect(File.exists?(asset)).to be_true
64
76
  end
65
77
  end
78
+ end
66
79
 
67
- before do
68
- builder.init(['init'])
80
+ context 'when a hologram_config.yml already exists' do
81
+ it 'does nothing' do
82
+ open('hologram_config.yml', 'w') {|io|io << 'foo'}
83
+ builder.setup_dir
84
+ expect(IO.read('hologram_config.yml')).to eql('foo')
85
+ end
86
+ end
87
+ end
88
+
89
+ context '#is_valid?' do
90
+
91
+ let(:config) do
92
+ {
93
+ 'source' => 'spec/fixtures/source/components',
94
+ 'documentation_assets' => 'spec/fixtures/source/templates',
95
+ 'base_path' => 'spec/fixtures/source/'
96
+ }
97
+ end
98
+
99
+ let(:builder) { Hologram::DocBuilder.new(config) }
100
+
101
+ around do |example|
102
+ Dir.mktmpdir do |tmpdir|
103
+ config['destination'] = tmpdir
104
+ example.run
69
105
  end
106
+ end
70
107
 
71
- it 'creates a config file' do
72
- expect(File.exists?('hologram_config.yml')).to be_true
108
+ context 'when config vars are present and directories exists' do
109
+ it 'returns true' do
110
+ expect(builder.is_valid?).to be_true
73
111
  end
112
+ end
74
113
 
75
- it 'creates default assets' do
76
- Dir.chdir('doc_assets') do
77
- ['_header.html', '_footer.html'].each do |asset|
78
- expect(File.exists?(asset)).to be_true
79
- end
114
+ ['source', 'destination', 'documentation_assets'].each do |config_var|
115
+ context "when the required #{config_var} parameter is missing" do
116
+ before do
117
+ config.delete(config_var)
118
+ end
119
+
120
+ it 'returns false' do
121
+ expect(builder.is_valid?).to be_false
80
122
  end
81
- end
82
123
 
83
- context 'when a hologram_config.yml already exists' do
84
- it 'does nothing' do
85
- open('hologram_config.yml', 'w') {|io|io << 'foo'}
86
- builder.init(['init'])
87
- expect(IO.read('hologram_config.yml')).to eql('foo')
124
+ it 'populates errors' do
125
+ builder.is_valid?
126
+ expect(builder.errors.size).to eql 1
88
127
  end
89
128
  end
90
129
  end
130
+
131
+ context "when the source directory does not exist" do
132
+ before do
133
+ config['source'] = './foo'
134
+ end
135
+
136
+ it 'returns false' do
137
+ expect(builder.is_valid?).to be_false
138
+ end
139
+
140
+ it 'populates errors' do
141
+ builder.is_valid?
142
+ expect(builder.errors.size).to eql 1
143
+ end
144
+ end
145
+ end
146
+
147
+ context '#build' do
148
+ let(:style_files) { Dir[File.expand_path('../fixtures/styleguide/**/*.*', __FILE__)] }
149
+ let(:processed_files) { Dir[File.join(builder.destination, '.', '**/*.*')] }
150
+ let(:config_path) { File.join(Dir.pwd, 'spec/fixtures/source/config.yml') }
151
+ let(:config_copy_path) { File.join(Dir.pwd, 'spec/fixtures/source/config.yml.copy') }
152
+ let(:builder) { Hologram::DocBuilder.from_yaml(config_copy_path) }
153
+
154
+ around do |example|
155
+ Dir.mktmpdir do |tmpdir|
156
+ FileUtils.cp(config_path, config_copy_path)
157
+ File.open(config_copy_path, 'a'){ |io| io << "destination: #{tmpdir}" }
158
+ current_dir = Dir.pwd
159
+ Dir.chdir('spec/fixtures/source')
160
+
161
+ example.run
162
+
163
+ Dir.chdir(current_dir)
164
+ FileUtils.rm(config_copy_path)
165
+ end
166
+ end
167
+
168
+ it 'builds a styleguide' do
169
+ builder.build
170
+ style_files.each_with_index do |file, index|
171
+ expect(FileUtils.cmp(file, processed_files[index])).to be_true
172
+ end
173
+ end
91
174
  end
92
175
  end