smartgen 0.4.0 → 0.5.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 (60) hide show
  1. data/ChangeLog.md +14 -0
  2. data/Gemfile.lock +2 -2
  3. data/README.md +7 -0
  4. data/lib/smartgen/configuration.rb +1 -49
  5. data/lib/smartgen/engines.rb +1 -0
  6. data/lib/smartgen/engines/base.rb +3 -3
  7. data/lib/smartgen/engines/erb.rb +15 -0
  8. data/lib/smartgen/engines/markdown.rb +1 -1
  9. data/lib/smartgen/engines/textile.rb +1 -1
  10. data/lib/smartgen/generator.rb +29 -17
  11. data/lib/smartgen/markup_file.rb +6 -2
  12. data/lib/smartgen/object_hash.rb +15 -5
  13. data/lib/smartgen/rake_task.rb +21 -5
  14. data/lib/smartgen/renderers/erb.rb +1 -4
  15. data/lib/smartgen/resource.rb +1 -9
  16. data/lib/smartgen/version.rb +1 -1
  17. data/spec/fixtures/expectations/common/another_index.html +13 -0
  18. data/spec/fixtures/expectations/common/index.html +8 -0
  19. data/spec/fixtures/expectations/common/other_index.html +13 -0
  20. data/spec/fixtures/expectations/erb/index.html +15 -0
  21. data/spec/fixtures/expectations/erb/with_layout/index.html +19 -0
  22. data/spec/fixtures/expectations/indexer/index_with_indexer.html +16 -0
  23. data/spec/fixtures/expectations/indexer/index_with_indexer_and_numbered_index.html +16 -0
  24. data/spec/fixtures/expectations/with_layout/index.html +12 -0
  25. data/spec/fixtures/expectations/with_layout/index_with_metadata.html +43 -0
  26. data/spec/fixtures/expectations/with_layout/index_with_specific_metadata.html +44 -0
  27. data/spec/fixtures/src/assets/images/image.gif +0 -0
  28. data/spec/fixtures/src/assets/javascripts/somelib.js +2 -0
  29. data/spec/fixtures/src/assets/stylesheets/style.css +2 -0
  30. data/spec/fixtures/src/common/another_index.md +12 -0
  31. data/spec/fixtures/src/common/index.textile +10 -0
  32. data/spec/fixtures/src/common/other_index.markdown +12 -0
  33. data/spec/fixtures/src/common/somefile +10 -0
  34. data/spec/fixtures/src/erb/index.html.erb +7 -0
  35. data/spec/fixtures/src/erb/with_layout/index.html.erb +7 -0
  36. data/spec/fixtures/src/erb/with_layout/layout.html.erb +5 -0
  37. data/spec/fixtures/src/indexer/index_with_indexer.textile +26 -0
  38. data/spec/fixtures/src/indexer/index_with_indexer_and_numbered_index.textile +26 -0
  39. data/spec/fixtures/src/layout.html.erb +5 -0
  40. data/spec/fixtures/src/layout_with_metadata.html.erb +22 -0
  41. data/spec/fixtures/src/layout_with_specific_metadata.html.erb +23 -0
  42. data/spec/fixtures/src/metadata.yml +43 -0
  43. data/spec/fixtures/src/with_layout/index.textile +10 -0
  44. data/spec/fixtures/src/with_layout/index_with_specific_metadata.textile +10 -0
  45. data/spec/lib/smartgen/configuration_spec.rb +5 -0
  46. data/spec/lib/smartgen/engines/base_spec.rb +73 -0
  47. data/spec/lib/smartgen/engines/erb_spec.rb +37 -0
  48. data/spec/lib/smartgen/engines/markdown_spec.rb +23 -0
  49. data/spec/lib/smartgen/engines/textile_spec.rb +19 -0
  50. data/spec/lib/smartgen/generator_spec.rb +272 -0
  51. data/spec/lib/smartgen/indexer_spec.rb +122 -0
  52. data/spec/lib/smartgen/markup_file_spec.rb +168 -0
  53. data/spec/lib/smartgen/object_hash_spec.rb +91 -0
  54. data/spec/lib/smartgen/renderers/erb_spec.rb +32 -0
  55. data/spec/lib/smartgen/resource_spec.rb +73 -0
  56. data/spec/lib/smartgen/watcher_spec.rb +71 -0
  57. data/spec/lib/smartgen_spec.rb +18 -0
  58. data/spec/sandbox/.gitkeep +0 -0
  59. data/spec/spec_helper.rb +37 -0
  60. metadata +99 -13
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Configuration do
4
+ it { subject.should be_kind_of(Smartgen::ObjectHash) }
5
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Engine::Base do
4
+ describe "processing" do
5
+ describe "pre processing" do
6
+ before do
7
+ Smartgen::Engine::Base.pre_processors = []
8
+ end
9
+
10
+ context "without pre processors" do
11
+ it "should just return body" do
12
+ body = 'body'
13
+ subject.process(body).should == body
14
+ end
15
+ end
16
+
17
+ context "with pre processors" do
18
+ class PreProcessor
19
+ def process(body, metadata=Smartgen::ObjectHash.new) # just needs to respond_to?(:process)
20
+ "<pre_processed>#{body}#{metadata[:name]}</pre_processed>"
21
+ end
22
+ end
23
+
24
+ it "should pre process body" do
25
+ Smartgen::Engine::Base.register(PreProcessor.new)
26
+
27
+ body = 'body'
28
+ subject.process(body).should == "<pre_processed>#{body}</pre_processed>"
29
+ end
30
+
31
+ it "should pre process body with metadata" do
32
+ Smartgen::Engine::Base.register(PreProcessor.new)
33
+
34
+ body = 'body'
35
+ subject.process(body, Smartgen::ObjectHash.new({:name => " John"})).should == "<pre_processed>body John</pre_processed>"
36
+ end
37
+
38
+ it "should do run pre processors in the order they were registered" do
39
+ class AnotherPreProcessor
40
+ def process(body, metadata={})
41
+ body.gsub(/pre_processed/, 'another')
42
+ end
43
+ end
44
+
45
+ Smartgen::Engine::Base.register(PreProcessor.new)
46
+ Smartgen::Engine::Base.register(AnotherPreProcessor.new)
47
+
48
+ body = 'body'
49
+ subject.process(body).should == "<another>#{body}</another>"
50
+ end
51
+
52
+ context "of a subclass" do
53
+ class OtherPreProcessor
54
+ def process(body, metadata={})
55
+ "<another>#{body}</another>"
56
+ end
57
+ end
58
+
59
+ class MyCustomEngine < Smartgen::Engine::Base
60
+ end
61
+
62
+ it "should pre process body with different processor of ancestor" do
63
+ Smartgen::Engine::Base.register(PreProcessor.new)
64
+ MyCustomEngine.register(OtherPreProcessor.new)
65
+
66
+ body = 'body'
67
+ MyCustomEngine.new.process(body).should == "<another>#{body}</another>"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Engine::ERB do
4
+ let :body do
5
+ "2 + 2 = <%= 2 * 2 %>"
6
+ end
7
+
8
+ let :contents do
9
+ "2 + 2 = 4"
10
+ end
11
+
12
+ it "should process body using ERB" do
13
+ subject.process(body).should == contents
14
+ end
15
+
16
+ it "should support .erb extension" do
17
+ should be_supported('.erb')
18
+ end
19
+
20
+ context "with metadata" do
21
+ let :body do
22
+ "Some metadata: <%= metadata.name %>"
23
+ end
24
+
25
+ let :contents do
26
+ "Some metadata: #{metadata.name}"
27
+ end
28
+
29
+ let :metadata do
30
+ Smartgen::ObjectHash.new :name => 'Vicente'
31
+ end
32
+
33
+ it "should process body using ERB" do
34
+ subject.process(body, metadata).should == contents
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Engine::Markdown do
4
+ def body
5
+ "# Some Header\n\nSome paragraph"
6
+ end
7
+
8
+ def contents
9
+ "<h1>Some Header</h1>\n\n<p>Some paragraph</p>"
10
+ end
11
+
12
+ it "should process body using BlueCloth" do
13
+ subject.process(body).should == contents
14
+ end
15
+
16
+ it "should support .md extension" do
17
+ should be_supported('.md')
18
+ end
19
+
20
+ it "should support .markdown extension" do
21
+ should be_supported('.markdown')
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Engine::Textile do
4
+ def body
5
+ "h1. Some Header\n\nSome paragraph"
6
+ end
7
+
8
+ def contents
9
+ "<h1>Some Header</h1>\n<p>Some paragraph</p>"
10
+ end
11
+
12
+ it "should process body using RedCloth" do
13
+ subject.process(body).should == contents
14
+ end
15
+
16
+ it "should support .textile extension" do
17
+ should be_supported('.textile')
18
+ end
19
+ end
@@ -0,0 +1,272 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ describe Smartgen::Generator do
5
+ def src_files
6
+ [fixture('src/common/**/*')]
7
+ end
8
+
9
+ def output_folder
10
+ sandbox('doc')
11
+ end
12
+
13
+ def output_folder_file(path)
14
+ File.join(output_folder, path)
15
+ end
16
+
17
+ def actual_src_files
18
+ Dir[*src_files].select { |f| ['.textile', '.markdown', '.md'].include?(File.extname(f)) }
19
+ end
20
+
21
+ def actual_src_filenames
22
+ actual_src_files.map { |f| [File.basename(f, File.extname(f)), File.extname(f)] }
23
+ end
24
+
25
+ def read_output(filename)
26
+ File.read(output_folder_file(filename))
27
+ end
28
+
29
+ def read_fixture(filename)
30
+ File.read(fixture(filename))
31
+ end
32
+
33
+ def arguments
34
+ [src_files, output_folder]
35
+ end
36
+
37
+ def options
38
+ {}
39
+ end
40
+
41
+ subject { Smartgen::Generator.new arguments, options, { :verbose => false } }
42
+
43
+ before do
44
+ FileUtils.rm_rf output_folder
45
+ end
46
+
47
+ describe "generation" do
48
+ it "should create the output folder" do
49
+ capture(:stdout) { subject.invoke_all }
50
+ File.should be_directory(output_folder)
51
+ end
52
+
53
+ it "should create HTML files for each markup template in src_files" do
54
+ capture(:stdout) { subject.invoke_all }
55
+
56
+ actual_src_filenames.each do |src_filename, src_ext|
57
+ File.should be_file(output_folder_file("#{src_filename}.html"))
58
+ end
59
+ end
60
+
61
+ it "should convert markup files into HTML files when generating" do
62
+ capture(:stdout) { subject.invoke_all }
63
+ actual_src_filenames.each do |src_filename, src_ext|
64
+ read_output("#{src_filename}.html").should == read_fixture("expectations/common/#{src_filename}.html")
65
+ end
66
+ end
67
+
68
+ it "should always force generation of each file, even if it exists" do
69
+ FileUtils.mkdir_p(output_folder)
70
+ File.open(output_folder_file("index.html"), 'w') { |f| f.write('old contents') }
71
+ capture(:stdout) { subject.invoke_all }
72
+ read_output("index.html").should == read_fixture("expectations/common/index.html")
73
+ end
74
+
75
+ context "with nil layout" do
76
+ def options
77
+ { :layout => nil }
78
+ end
79
+
80
+ it "should not use layout" do
81
+ capture(:stdout) { subject.invoke_all }
82
+ actual_src_filenames.each do |src_filename, src_ext|
83
+ read_output("#{src_filename}.html").should == read_fixture("expectations/common/#{src_filename}.html")
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "inexistent file" do
89
+ def src_files
90
+ [fixture('src/common/inexistent_file.textile')]
91
+ end
92
+
93
+ it "should not generate html" do
94
+ capture(:stdout) { subject.invoke_all }
95
+ File.should_not be_file(output_folder_file("inexistent_file.html"))
96
+ end
97
+ end
98
+
99
+ describe "with ERB files" do
100
+ def src_files
101
+ [fixture('src/erb/index.html.erb')]
102
+ end
103
+
104
+ it "should generate index file" do
105
+ capture(:stdout) { subject.invoke_all }
106
+ read_output("index.html").should == read_fixture("expectations/erb/index.html")
107
+ end
108
+
109
+ describe "with layout" do
110
+ def src_files
111
+ [fixture('src/erb/with_layout/index.html.erb')]
112
+ end
113
+
114
+ def options
115
+ { :layout => fixture('src/layout.html.erb') }
116
+ end
117
+
118
+ it "should use the layout when generating" do
119
+ capture(:stdout) { subject.invoke_all }
120
+ read_output("index.html").should == read_fixture("expectations/erb/with_layout/index.html")
121
+ end
122
+
123
+ context "inside the src_files pattern" do
124
+ def src_files
125
+ [fixture('src/erb/with_layout/**/*')]
126
+ end
127
+
128
+ def options
129
+ { :layout => fixture('src/erb/with_layout/layout.html.erb') }
130
+ end
131
+
132
+ it "should use the layout when generating" do
133
+ capture(:stdout) { subject.invoke_all }
134
+ read_output("index.html").should == read_fixture("expectations/erb/with_layout/index.html")
135
+ end
136
+
137
+ it "should not attempt to render layout using ERB engine" do
138
+ capture(:stdout) { subject.invoke_all }
139
+ read_output("index.html").should == read_fixture("expectations/erb/with_layout/index.html")
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ describe "with layout" do
146
+ def src_files
147
+ [fixture('src/with_layout/index.textile')]
148
+ end
149
+
150
+ def options
151
+ { :layout => fixture('src/layout.html.erb') }
152
+ end
153
+
154
+ it "should use the layout when generating" do
155
+ capture(:stdout) { subject.invoke_all }
156
+ read_output("index.html").should == read_fixture("expectations/with_layout/index.html")
157
+ end
158
+
159
+ describe "and metadata" do
160
+ def options
161
+ { :layout => fixture('src/layout_with_metadata.html.erb'), :metadata_file => fixture('src/metadata.yml') }
162
+ end
163
+
164
+ it "should load metadata from file and expose it when rendering files" do
165
+ capture(:stdout) { subject.invoke_all }
166
+ read_output("index.html").should == read_fixture("expectations/with_layout/index_with_metadata.html")
167
+ end
168
+
169
+ describe "using conventions" do
170
+ def src_files
171
+ [fixture('src/with_layout/index_with_specific_metadata.textile')]
172
+ end
173
+
174
+ def options
175
+ { :layout => fixture('src/layout_with_specific_metadata.html.erb'), :metadata_file => fixture('src/metadata.yml') }
176
+ end
177
+
178
+ it "should expose metadata for current page data for each file in metadata.current_page" do
179
+ capture(:stdout) { subject.invoke_all }
180
+ read_output("index_with_specific_metadata.html").should == read_fixture("expectations/with_layout/index_with_specific_metadata.html")
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "assets" do
187
+ def assets
188
+ [fixture("src/assets/images"), fixture("src/assets/javascripts"), fixture("src/assets/stylesheets")]
189
+ end
190
+
191
+ def options
192
+ { :assets => assets }
193
+ end
194
+
195
+ it "should copy directories to output folder" do
196
+ capture(:stdout) { subject.invoke_all }
197
+
198
+ File.should be_directory(output_folder_file('images'))
199
+ File.should be_directory(output_folder_file('javascripts'))
200
+ end
201
+
202
+ it "should copy the contents of the given directories to output folder" do
203
+ capture(:stdout) { subject.invoke_all }
204
+
205
+ File.should be_file(output_folder_file('images/image.gif'))
206
+ File.should be_file(output_folder_file('javascripts/somelib.js'))
207
+ File.should be_file(output_folder_file('stylesheets/style.css'))
208
+ end
209
+
210
+ it "should force copy of the contents of the given directories to output folder" do
211
+ FileUtils.mkdir_p(output_folder_file('javascripts'))
212
+ File.open(output_folder_file('javascripts/somelib.js'), 'w') { |f| f.write('//some code') }
213
+
214
+ capture(:stdout) { subject.invoke_all }
215
+ read_output('javascripts/somelib.js').should == read_fixture('src/assets/javascripts/somelib.js')
216
+ end
217
+ end
218
+
219
+ describe "with indexer" do
220
+ def src_files
221
+ [fixture('src/indexer/index_with_indexer.textile')]
222
+ end
223
+
224
+ def options
225
+ { :use_indexer => true }
226
+ end
227
+
228
+ it "should add IDs to each <h> tag" do
229
+ capture(:stdout) { subject.invoke_all }
230
+
231
+ actual_src_filenames.each do |src_filename, src_ext|
232
+ read_output("#{src_filename}.html").should == read_fixture("expectations/indexer/#{src_filename}.html")
233
+ end
234
+ end
235
+
236
+ context "and numbered_index" do
237
+ def src_files
238
+ [fixture('src/indexer/index_with_indexer_and_numbered_index.textile')]
239
+ end
240
+
241
+ def options
242
+ { :use_indexer => true, :numbered_index => true }
243
+ end
244
+
245
+ it "should add numbered indexes on each <h> tag" do
246
+ capture(:stdout) { subject.invoke_all }
247
+
248
+ actual_src_filenames.each do |src_filename, src_ext|
249
+ read_output("#{src_filename}.html").should == read_fixture("expectations/indexer/#{src_filename}.html")
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
255
+
256
+ describe "renderer registration" do
257
+ it "should register ERB renderer by default" do
258
+ Smartgen::Generator.renderer.should be_an_instance_of(Smartgen::Renderer::ERB)
259
+ end
260
+
261
+ it "should allow the registration of a custom renderer" do
262
+ class MyRenderer
263
+ def render(layout, markup_file)
264
+ "do some rendering stuff"
265
+ end
266
+ end
267
+
268
+ Smartgen::Generator.renderer = MyRenderer.new
269
+ Smartgen::Generator.renderer.render('some_layout', mock(Smartgen::MarkupFile)).should == "do some rendering stuff"
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Indexer do
4
+ matcher :have_tag do |tag, attributes|
5
+ match do |actual|
6
+ tags = Nokogiri::HTML(actual).css(tag.to_s)
7
+ tags.present? && tags.any? do |tag|
8
+ attributes.all? do |attribute, value|
9
+ tag.has_attribute?(attribute.to_s) && tag[attribute.to_s] == value
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ matcher :have_tag_with_contents do |tag, content|
16
+ match do |actual|
17
+ tags = Nokogiri::HTML(actual).css(tag.to_s)
18
+ tags.present? && tags.any? do |tag|
19
+ tag.content == content
20
+ end
21
+ end
22
+ end
23
+
24
+ def html
25
+ "<h1>Some header</h1>"
26
+ end
27
+
28
+ subject { Smartgen::Indexer.new html }
29
+
30
+ describe "addition of IDs" do
31
+ def html
32
+ return <<-HTML
33
+ <html>
34
+ <body>
35
+ <h1>A h1 header</h1>
36
+ <h2>A h2 header</h2>
37
+ <h3>A h3 header</h3>
38
+ <h4>A h4 header</h4>
39
+ <h5>A h5 header</h5>
40
+ <h6>A h6 header</h6>
41
+ </body>
42
+ </html>
43
+ HTML
44
+ end
45
+
46
+ 1.upto(6).each do |header_level|
47
+ it "should add IDs for each <h#{header_level}> tag in the result" do
48
+ subject.result.should have_tag("h#{header_level}", :id => "a-h#{header_level}-header")
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "index" do
54
+ def html
55
+ return <<-HTML
56
+ <html>
57
+ <body>
58
+ <h1>A h1 header</h1>
59
+ <h2>A h2 header</h2>
60
+ <h3>A h3 header</h3>
61
+ <h3>Some other h3 header</h3>
62
+ <h2>Another h2 header</h2>
63
+ <h5>A h5 header</h5>
64
+ <h2>Yet Another h2 header</h2>
65
+ <h3>Yet Another h3 header</h3>
66
+ <h1>Other h1 header</h1>
67
+ </body>
68
+ </html>
69
+ HTML
70
+ end
71
+
72
+ it "should return an index with headers data hierarquically distributed" do
73
+ expected_index = [
74
+ { :text => 'A h1 header', :id => 'a-h1-header', :level => 1, :children => [
75
+ { :text => 'A h2 header', :id => 'a-h2-header', :level => 2, :children => [
76
+ { :text => 'A h3 header', :id => 'a-h3-header', :level => 3, :children => [] },
77
+ { :text => 'Some other h3 header', :id => 'some-other-h3-header', :level => 3, :children => [] }
78
+ ] },
79
+ { :text => 'Another h2 header', :id => 'another-h2-header', :level => 2, :children => [
80
+ { :text => 'A h5 header', :id => 'a-h5-header', :level => 5, :children => [] }
81
+ ] },
82
+ { :text => 'Yet Another h2 header', :id => 'yet-another-h2-header', :level => 2, :children => [
83
+ { :text => 'Yet Another h3 header', :id => 'yet-another-h3-header', :level => 3, :children => [] }
84
+ ] },
85
+ ]},
86
+ { :text => 'Other h1 header', :id => 'other-h1-header', :level => 1, :children => [] }
87
+ ]
88
+
89
+ subject.index.should == expected_index
90
+ end
91
+
92
+ context "when numbered_index options is given" do
93
+ subject { Smartgen::Indexer.new html, :numbered_index => true }
94
+
95
+ it "should add the numbered index to header contents" do
96
+ subject.result.should have_tag_with_contents("h1", "1 A h1 header")
97
+ subject.result.should have_tag_with_contents("h2", "1.1 A h2 header")
98
+ subject.result.should have_tag_with_contents("h3", "1.1.2 Some other h3 header")
99
+ end
100
+
101
+ it "should return an index with headers data hierarquically distributed with numbered index" do
102
+ expected_index = [
103
+ { :text => 'A h1 header', :id => 'a-h1-header', :level => 1, :numbered_index => '1', :children => [
104
+ { :text => 'A h2 header', :id => 'a-h2-header', :level => 2, :numbered_index => '1.1', :children => [
105
+ { :text => 'A h3 header', :id => 'a-h3-header', :level => 3, :numbered_index => '1.1.1', :children => [] },
106
+ { :text => 'Some other h3 header', :id => 'some-other-h3-header', :level => 3, :numbered_index => '1.1.2', :children => [] }
107
+ ] },
108
+ { :text => 'Another h2 header', :id => 'another-h2-header', :level => 2, :numbered_index => '1.2', :children => [
109
+ { :text => 'A h5 header', :id => 'a-h5-header', :level => 5, :numbered_index => '1.2.1', :children => [] }
110
+ ] },
111
+ { :text => 'Yet Another h2 header', :id => 'yet-another-h2-header', :level => 2, :numbered_index => '1.3', :children => [
112
+ { :text => 'Yet Another h3 header', :id => 'yet-another-h3-header', :level => 3, :numbered_index => '1.3.1', :children => [] }
113
+ ] },
114
+ ]},
115
+ { :text => 'Other h1 header', :id => 'other-h1-header', :level => 1, :numbered_index => '2', :children => [] }
116
+ ]
117
+
118
+ subject.index.should == expected_index
119
+ end
120
+ end
121
+ end
122
+ end