smartgen 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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,168 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::MarkupFile do
4
+ def path
5
+ fixture('src/common/index.textile')
6
+ end
7
+
8
+ subject { Smartgen::MarkupFile.new path }
9
+
10
+ describe "engine registration" do
11
+ before do
12
+ Smartgen::MarkupFile.engines.clear
13
+ end
14
+
15
+ after do
16
+ Smartgen::MarkupFile.engines.clear
17
+ end
18
+
19
+ it "should register textile engine by default" do
20
+ Smartgen::MarkupFile.engines.one? { |engine| engine.instance_of?(Smartgen::Engine::Textile) }.should be_true, "Textile was not registered as engine"
21
+ end
22
+
23
+ it "should register markdown engine by default" do
24
+ Smartgen::MarkupFile.engines.one? { |engine| engine.instance_of?(Smartgen::Engine::Markdown) }.should be_true, "Markdown was not registered as engine"
25
+ end
26
+
27
+ class MyEngine < Smartgen::Engine::Base
28
+ protected
29
+ def parse(body)
30
+ "some processing"
31
+ end
32
+
33
+ def extensions
34
+ ['.something', '.otherext']
35
+ end
36
+ end
37
+
38
+ it "should register an engine" do
39
+ Smartgen::MarkupFile.register(MyEngine)
40
+ Smartgen::MarkupFile.engines.one? { |engine| engine.instance_of?(MyEngine) }.should be_true, "MyEngine was not registered as engine"
41
+ end
42
+
43
+ it "should register the engine with high priority" do
44
+ Smartgen::MarkupFile.register(MyEngine)
45
+ Smartgen::MarkupFile.engines.first.should be_an_instance_of(MyEngine)
46
+ end
47
+ end
48
+
49
+ describe "attributes" do
50
+ it "should have a file path" do
51
+ subject.path.should == path
52
+ end
53
+
54
+ it "should have a filename" do
55
+ subject.filename.should == File.basename(path, File.extname(path))
56
+ end
57
+
58
+ context "when filename ends with .html" do
59
+ def path
60
+ fixture('src/erb/index.html.erb')
61
+ end
62
+
63
+ it "should not have .html in filename" do
64
+ subject.filename.should == File.basename(path, ".html#{File.extname(path)}")
65
+ end
66
+ end
67
+
68
+ it "should have an extension" do
69
+ subject.extension.should == File.extname(path)
70
+ end
71
+ end
72
+
73
+ describe "contents" do
74
+ it "should returns its raw contents" do
75
+ subject.raw_contents.should == File.read(path)
76
+ end
77
+
78
+ it "should return its contents" do
79
+ subject.contents.should == File.read(fixture('expectations/common/index.html'))
80
+ end
81
+ end
82
+
83
+ context "engines usage" do
84
+ context "using default engine" do
85
+ it "should use textile as markup engine when using defaults for files without extension" do
86
+ def path
87
+ fixture('src/common/somefile')
88
+ end
89
+
90
+ subject.engine.should be_an_instance_of(Smartgen::Engine::Textile)
91
+ end
92
+
93
+ it "should use the engine with the highest priority for files without extension" do
94
+ class MyEngine
95
+ def process(body, metadata={})
96
+ "some processing"
97
+ end
98
+
99
+ def supported?(extension)
100
+ ['.something'].include?(extension)
101
+ end
102
+ end
103
+
104
+ def path
105
+ fixture('src/common/somefile')
106
+ end
107
+
108
+ Smartgen::MarkupFile.register(MyEngine)
109
+ subject.engine.should be_an_instance_of(MyEngine)
110
+ Smartgen::MarkupFile.engines.clear
111
+ end
112
+ end
113
+
114
+ context "using textile engine" do
115
+ it "should use textile as markup engine" do
116
+ subject.engine.should be_an_instance_of(Smartgen::Engine::Textile)
117
+ end
118
+ end
119
+
120
+ context "using markdown engine" do
121
+ it "should use markdown as markup engine for files with .markdown" do
122
+ def path
123
+ fixture('src/common/other_index.markdown')
124
+ end
125
+
126
+ subject.engine.should be_an_instance_of(Smartgen::Engine::Markdown)
127
+ end
128
+
129
+ it "should use markdown as markup engine for files with .md" do
130
+ def path
131
+ fixture('src/common/another_index.md')
132
+ end
133
+
134
+ subject.engine.should be_an_instance_of(Smartgen::Engine::Markdown)
135
+ end
136
+ end
137
+
138
+ context "using erb engine" do
139
+ it "should use markdown as markup engine for files with .md" do
140
+ def path
141
+ fixture('src/erb/index.html.erb')
142
+ end
143
+
144
+ subject.engine.should be_an_instance_of(Smartgen::Engine::ERB)
145
+ end
146
+ end
147
+ end
148
+
149
+ describe "indexer" do
150
+ subject { Smartgen::MarkupFile.new path, :indexer => true }
151
+
152
+ it "should be accessible when using indexer" do
153
+ subject.indexer.should be_an_instance_of(Smartgen::Indexer)
154
+ end
155
+
156
+ it "should use indexer" do
157
+ mock_indexer = mock(Smartgen::Indexer, :result => 'result')
158
+ Smartgen::Indexer.should_receive(:new).and_return(mock_indexer)
159
+ subject
160
+ end
161
+
162
+ it "should return indexer result as contents" do
163
+ mock_indexer = mock(Smartgen::Indexer, :result => 'result')
164
+ Smartgen::Indexer.should_receive(:new).and_return(mock_indexer)
165
+ subject.contents.should == 'result'
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::ObjectHash do
4
+ it { should be_a_kind_of(HashWithIndifferentAccess) }
5
+
6
+ it "should be duped as an Smartgen::ObjectHash" do
7
+ subject.dup.should be_an_instance_of(Smartgen::ObjectHash)
8
+ end
9
+
10
+ it "should differentiate itself when its inspected" do
11
+ subject.inspect.should == "ObjectHash({})"
12
+ end
13
+
14
+ it "should respond to all of its keys" do
15
+ subject.merge!({:foo => 'foo', 'bar' => 'bar'})
16
+
17
+ subject.keys.each do |key|
18
+ should respond_to(key)
19
+ end
20
+ end
21
+
22
+ it "should respond to all of its keys with setter methods" do
23
+ subject.merge!({:foo => 'foo', 'bar' => 'bar'})
24
+
25
+ subject.keys.map { |k| "#{k}=" }.each do |key|
26
+ should respond_to(key)
27
+ end
28
+ end
29
+
30
+ describe "inexistent key" do
31
+ it "should not respond to" do
32
+ capture(:stderr) { subject.should_not respond_to("invalid_key") }
33
+ end
34
+
35
+ it "should return an empty ObjectHash" do
36
+ capture(:stderr) { subject.invalid_key.should be_an_instance_of(Smartgen::ObjectHash) }
37
+ end
38
+
39
+ it "should print a warn" do
40
+ capture(:stderr) { subject.invalid_key }.should == "warning: key invalid_key not found on #{subject.inspect}\n"
41
+ end
42
+ end
43
+
44
+ it "should respond to ancestor methods" do
45
+ ancestor = Smartgen::ObjectHash.ancestors.first
46
+ ancestor.instance_methods.each do |method|
47
+ should respond_to(method)
48
+ end
49
+ end
50
+
51
+ it "should fetch key when calling method with the same name directly" do
52
+ subject.merge!({:foo => 'foo'})
53
+ subject.foo.should == 'foo'
54
+ end
55
+
56
+ it "should set a new key when any setter method is called" do
57
+ subject.foo = 'foo'
58
+ subject.foo.should == 'foo'
59
+ end
60
+
61
+ it "should update an existing key when setter method is called" do
62
+ subject.merge!({:foo => 'foo'})
63
+ subject.foo = 'bar'
64
+ subject.foo.should == 'bar'
65
+ end
66
+
67
+ describe "nested hashes" do
68
+ subject { Smartgen::ObjectHash.new({:nested_hash => {:some_key => 'value'}})}
69
+
70
+ it "should accept calling nested methods" do
71
+ subject.nested_hash.some_key.should == 'value'
72
+ end
73
+ end
74
+
75
+ describe "nested array with hashes" do
76
+ subject { Smartgen::ObjectHash.new({:array => [{:some_key => 'value'}]})}
77
+
78
+ it "should accept calling nested methods" do
79
+ subject.array.first.some_key.should == 'value'
80
+ end
81
+ end
82
+
83
+ describe Hash do
84
+ subject { Hash.new }
85
+
86
+ it "should return an object hash" do
87
+ subject.with_object_hash.should be_an_instance_of(Smartgen::ObjectHash)
88
+ end
89
+ end
90
+ end
91
+
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Renderer::ERB do
4
+ def contents
5
+ "<p>Some HTML content</p>"
6
+ end
7
+
8
+ def markup_file
9
+ @markup_file ||= mock(Smartgen::MarkupFile, :contents => contents)
10
+ end
11
+
12
+ it "should render the given layout with markup_file variable" do
13
+ layout = "<html><body><%= markup_file.contents %></body></html>"
14
+
15
+ subject.render(layout, markup_file).should == "<html><body>#{contents}</body></html>"
16
+ end
17
+
18
+ it "should render the given layout with metadata variable" do
19
+ layout = "<html><body><%= markup_file.contents %><div><%= metadata[:some_key] %></div></body></html>"
20
+ subject.render(layout, markup_file, Smartgen::ObjectHash.new(:some_key => 'some_value')).should == "<html><body>#{contents}<div>some_value</div></body></html>"
21
+ end
22
+
23
+ it "should render the given layout with metadata variable, using methods instead of accessing keys" do
24
+ layout = "<html><body><%= markup_file.contents %><div><%= metadata.some_key %></div></body></html>"
25
+ subject.render(layout, markup_file, Smartgen::ObjectHash.new(:some_key => 'some_value')).should == "<html><body>#{contents}<div>some_value</div></body></html>"
26
+ end
27
+
28
+ it "should render the given layout with metadata variable, using nested methods instead of accessing keys" do
29
+ layout = "<html><body><%= markup_file.contents %><div><%= metadata.nested_hash.some_key %></div></body></html>"
30
+ subject.render(layout, markup_file, Smartgen::ObjectHash.new(:nested_hash => {:some_key => 'some_value'})).should == "<html><body>#{contents}<div>some_value</div></body></html>"
31
+ end
32
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Resource do
4
+ describe "configuration" do
5
+ it "should yield a configuration when configuring" do
6
+ subject.configure do |config|
7
+ config.should be_an_instance_of(Smartgen::Configuration)
8
+ end
9
+ end
10
+
11
+ it "should use the same configuration on later accesses" do
12
+ configuration = nil
13
+ subject.configure { |config| configuration = config }
14
+
15
+ subject.configure do |config|
16
+ config.should be_equal(configuration)
17
+ end
18
+ end
19
+ end
20
+
21
+ describe "generating" do
22
+ shared_examples_for "generation with configuration" do
23
+ let :expected_arguments do
24
+ [subject.config.src_files, subject.config.output_folder]
25
+ end
26
+
27
+ it "should generate files using the configuration" do
28
+ mock_generator = mock(Smartgen::Generator)
29
+ Smartgen::Generator.
30
+ should_receive(:new).
31
+ with(expected_arguments, expected_options).
32
+ and_return(mock_generator)
33
+
34
+ mock_generator.should_receive(:invoke_all)
35
+ subject.generate!
36
+ end
37
+ end
38
+
39
+ context "with default options" do
40
+ let :expected_options do
41
+ Smartgen::ObjectHash.new
42
+ end
43
+
44
+ it_should_behave_like "generation with configuration"
45
+ end
46
+
47
+ context "with customized options" do
48
+ before do
49
+ subject.configure do |c|
50
+ c.src_files = ['help/**/*', 'ChangeLog', 'doc_src/**/*']
51
+ c.output_folder = 'public/docs'
52
+ c.layout = 'doc_src/layout.html.erb'
53
+ c.assets = ['doc_src/javascript/*.js', 'doc_src/stylesheets/*.css', 'doc_src/images/*.*']
54
+ c.metadata_file = 'doc_src/metadata.yml'
55
+ c.some_other_option = true
56
+ c.and_another_one = 'some-value'
57
+ end
58
+ end
59
+
60
+ let :expected_options do
61
+ Smartgen::ObjectHash.new({
62
+ :layout => subject.config.layout,
63
+ :assets => subject.config.assets,
64
+ :metadata_file => subject.config.metadata_file,
65
+ :some_other_option => subject.config.some_other_option,
66
+ :and_another_one => subject.config.and_another_one
67
+ })
68
+ end
69
+
70
+ it_should_behave_like "generation with configuration"
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Smartgen::Watcher do
4
+ it "should create a resource and yield its configuration" do
5
+ expected_config = nil
6
+ Smartgen::Watcher.new(:my_resource) { |config| expected_config = config }
7
+ expected_config.should == Smartgen[:my_resource].config
8
+ end
9
+
10
+ context "when it will start watching" do
11
+ def src_files
12
+ ['doc/**/*']
13
+ end
14
+
15
+ def directory_watcher
16
+ return @directory_watcher if @directory_watcher
17
+
18
+ @directory_watcher = mock(DirectoryWatcher, :add_observer => 'observer', :interval= => '2')
19
+ @directory_watcher.stub!(:start).and_return(@directory_watcher)
20
+ @directory_watcher.stub!(:join).and_return(@directory_watcher)
21
+ @directory_watcher
22
+ end
23
+
24
+ before do
25
+ DirectoryWatcher.stub!(:new).and_return(directory_watcher)
26
+ end
27
+
28
+ subject do
29
+ Smartgen::Watcher.new(:my_resource) do |config|
30
+ config.src_files = src_files
31
+ config.output_folder = 'public/docs'
32
+ end
33
+ end
34
+
35
+ it "should create a directory watcher, pre loading src_files" do
36
+ DirectoryWatcher.should_receive(:new).with('.', :glob => src_files).and_return(directory_watcher)
37
+ capture(:stdout) { subject.start }
38
+ end
39
+
40
+ it "should add itself as an observer, with :generate method as the callback" do
41
+ directory_watcher.should_receive(:add_observer).with(subject, :generate)
42
+ capture(:stdout) { subject.start }
43
+ end
44
+
45
+ it "should start watching" do
46
+ directory_watcher.should_receive(:start)
47
+ directory_watcher.should_receive(:join)
48
+ capture(:stdout) { subject.start }
49
+ end
50
+
51
+ it "should set interval to 2 seconds" do
52
+ directory_watcher.should_receive(:interval=).with(2)
53
+ capture(:stdout) { subject.start }
54
+ end
55
+
56
+ context "when generating" do
57
+ it "should generate files" do
58
+ Smartgen[:my_resource].should_receive(:generate!)
59
+ capture(:stdout) { subject.generate }
60
+ end
61
+ end
62
+
63
+ context "when user hits ctrl+c" do
64
+ it "should exit gracefully" do
65
+ directory_watcher.should_receive(:stop)
66
+ Kernel.should_receive(:trap).with('INT').and_yield
67
+ capture(:stdout) { subject.start }
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe Smartgen do
5
+ describe "resources" do
6
+ it "should create a resource the first time it is accessed" do
7
+ Smartgen[:foo].should be_an_instance_of(Smartgen::Resource)
8
+ end
9
+
10
+ it "should use the same resource when it is accessed in the future" do
11
+ Smartgen[:foo].should be_equal(Smartgen[:foo])
12
+ end
13
+
14
+ it "should create different resource for each given name" do
15
+ Smartgen[:foo].should_not be_equal(Smartgen[:bar])
16
+ end
17
+ end
18
+ end