monad 0.0.1

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 (143) hide show
  1. data/CONTRIBUTING.md +68 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE +21 -0
  4. data/README.md +88 -0
  5. data/Rakefile +136 -0
  6. data/bin/monad +102 -0
  7. data/cucumber.yml +3 -0
  8. data/features/create_sites.feature +112 -0
  9. data/features/data_sources.feature +76 -0
  10. data/features/drafts.feature +25 -0
  11. data/features/embed_filters.feature +60 -0
  12. data/features/markdown.feature +30 -0
  13. data/features/pagination.feature +54 -0
  14. data/features/permalinks.feature +65 -0
  15. data/features/post_data.feature +214 -0
  16. data/features/site_configuration.feature +206 -0
  17. data/features/site_data.feature +101 -0
  18. data/features/step_definitions/monad_steps.rb +175 -0
  19. data/features/support/env.rb +25 -0
  20. data/lib/monad.rb +90 -0
  21. data/lib/monad/command.rb +27 -0
  22. data/lib/monad/commands/build.rb +64 -0
  23. data/lib/monad/commands/doctor.rb +29 -0
  24. data/lib/monad/commands/new.rb +50 -0
  25. data/lib/monad/commands/serve.rb +33 -0
  26. data/lib/monad/configuration.rb +183 -0
  27. data/lib/monad/converter.rb +48 -0
  28. data/lib/monad/converters/identity.rb +21 -0
  29. data/lib/monad/converters/markdown.rb +43 -0
  30. data/lib/monad/converters/markdown/kramdown_parser.rb +44 -0
  31. data/lib/monad/converters/markdown/maruku_parser.rb +47 -0
  32. data/lib/monad/converters/markdown/rdiscount_parser.rb +35 -0
  33. data/lib/monad/converters/markdown/redcarpet_parser.rb +70 -0
  34. data/lib/monad/converters/textile.rb +50 -0
  35. data/lib/monad/convertible.rb +152 -0
  36. data/lib/monad/core_ext.rb +68 -0
  37. data/lib/monad/deprecator.rb +32 -0
  38. data/lib/monad/draft.rb +35 -0
  39. data/lib/monad/drivers/json_driver.rb +39 -0
  40. data/lib/monad/drivers/yaml_driver.rb +23 -0
  41. data/lib/monad/errors.rb +4 -0
  42. data/lib/monad/filters.rb +154 -0
  43. data/lib/monad/generator.rb +4 -0
  44. data/lib/monad/generators/pagination.rb +143 -0
  45. data/lib/monad/layout.rb +42 -0
  46. data/lib/monad/logger.rb +54 -0
  47. data/lib/monad/mime.types +85 -0
  48. data/lib/monad/page.rb +163 -0
  49. data/lib/monad/plugin.rb +75 -0
  50. data/lib/monad/post.rb +377 -0
  51. data/lib/monad/site.rb +455 -0
  52. data/lib/monad/static_file.rb +70 -0
  53. data/lib/monad/tags/gist.rb +30 -0
  54. data/lib/monad/tags/highlight.rb +85 -0
  55. data/lib/monad/tags/include.rb +37 -0
  56. data/lib/monad/tags/post_url.rb +61 -0
  57. data/lib/site_template/.gitignore +1 -0
  58. data/lib/site_template/_config.yml +2 -0
  59. data/lib/site_template/_layouts/default.html +46 -0
  60. data/lib/site_template/_layouts/post.html +9 -0
  61. data/lib/site_template/_posts/0000-00-00-welcome-to-monad.markdown.erb +24 -0
  62. data/lib/site_template/css/main.css +165 -0
  63. data/lib/site_template/css/syntax.css +60 -0
  64. data/lib/site_template/index.html +13 -0
  65. data/monad.gemspec +197 -0
  66. data/script/bootstrap +2 -0
  67. data/test/fixtures/broken_front_matter1.erb +5 -0
  68. data/test/fixtures/broken_front_matter2.erb +4 -0
  69. data/test/fixtures/broken_front_matter3.erb +7 -0
  70. data/test/fixtures/exploit_front_matter.erb +4 -0
  71. data/test/fixtures/front_matter.erb +4 -0
  72. data/test/fixtures/members.yaml +7 -0
  73. data/test/helper.rb +62 -0
  74. data/test/source/.htaccess +8 -0
  75. data/test/source/_includes/sig.markdown +3 -0
  76. data/test/source/_layouts/default.html +27 -0
  77. data/test/source/_layouts/simple.html +1 -0
  78. data/test/source/_plugins/dummy.rb +8 -0
  79. data/test/source/_posts/2008-02-02-not-published.textile +8 -0
  80. data/test/source/_posts/2008-02-02-published.textile +8 -0
  81. data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
  82. data/test/source/_posts/2008-11-21-complex.textile +8 -0
  83. data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
  84. data/test/source/_posts/2008-12-13-include.markdown +8 -0
  85. data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
  86. data/test/source/_posts/2009-01-27-categories.textile +7 -0
  87. data/test/source/_posts/2009-01-27-category.textile +7 -0
  88. data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
  89. data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
  90. data/test/source/_posts/2009-03-12-hash-#1.markdown +6 -0
  91. data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
  92. data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
  93. data/test/source/_posts/2009-05-18-tag.textile +6 -0
  94. data/test/source/_posts/2009-05-18-tags.textile +9 -0
  95. data/test/source/_posts/2009-06-22-empty-yaml.textile +3 -0
  96. data/test/source/_posts/2009-06-22-no-yaml.textile +1 -0
  97. data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
  98. data/test/source/_posts/2010-01-09-date-override.textile +7 -0
  99. data/test/source/_posts/2010-01-09-time-override.textile +7 -0
  100. data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
  101. data/test/source/_posts/2010-01-16-override-data.textile +4 -0
  102. data/test/source/_posts/2011-04-12-md-extension.md +7 -0
  103. data/test/source/_posts/2011-04-12-text-extension.text +0 -0
  104. data/test/source/_posts/2013-01-02-post-excerpt.markdown +14 -0
  105. data/test/source/_posts/2013-01-12-nil-layout.textile +6 -0
  106. data/test/source/_posts/2013-01-12-no-layout.textile +5 -0
  107. data/test/source/_posts/2013-03-19-not-a-post.markdown/.gitkeep +0 -0
  108. data/test/source/_posts/2013-04-11-custom-excerpt.markdown +10 -0
  109. data/test/source/_posts/2013-05-10-number-category.textile +7 -0
  110. data/test/source/_posts/es/2008-11-21-nested.textile +8 -0
  111. data/test/source/about.html +6 -0
  112. data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
  113. data/test/source/contacts.html +5 -0
  114. data/test/source/contacts/bar.html +5 -0
  115. data/test/source/contacts/index.html +5 -0
  116. data/test/source/css/screen.css +76 -0
  117. data/test/source/deal.with.dots.html +7 -0
  118. data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
  119. data/test/source/index.html +22 -0
  120. data/test/source/sitemap.xml +32 -0
  121. data/test/source/symlink-test/symlinked-file +22 -0
  122. data/test/source/win/_posts/2009-05-24-yaml-linebreak.markdown +7 -0
  123. data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
  124. data/test/suite.rb +11 -0
  125. data/test/test_command.rb +39 -0
  126. data/test/test_configuration.rb +137 -0
  127. data/test/test_convertible.rb +51 -0
  128. data/test/test_core_ext.rb +88 -0
  129. data/test/test_filters.rb +102 -0
  130. data/test/test_generated_site.rb +83 -0
  131. data/test/test_json_driver.rb +63 -0
  132. data/test/test_kramdown.rb +35 -0
  133. data/test/test_new_command.rb +104 -0
  134. data/test/test_page.rb +193 -0
  135. data/test/test_pager.rb +115 -0
  136. data/test/test_post.rb +573 -0
  137. data/test/test_rdiscount.rb +22 -0
  138. data/test/test_redcarpet.rb +61 -0
  139. data/test/test_redcloth.rb +86 -0
  140. data/test/test_site.rb +374 -0
  141. data/test/test_tags.rb +310 -0
  142. data/test/test_yaml_driver.rb +35 -0
  143. metadata +554 -0
@@ -0,0 +1,83 @@
1
+ require 'helper'
2
+
3
+ class TestGeneratedSite < Test::Unit::TestCase
4
+ context "generated sites" do
5
+ setup do
6
+ clear_dest
7
+ stub(Monad).configuration do
8
+ Monad::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
9
+ end
10
+
11
+ @site = Site.new(Monad.configuration)
12
+ @site.process
13
+ @index = File.read(dest_dir('index.html'))
14
+ end
15
+
16
+ should "ensure post count is as expected" do
17
+ assert_equal 34, @site.posts.size
18
+ end
19
+
20
+ should "insert site.posts into the index" do
21
+ assert @index.include?("#{@site.posts.size} Posts")
22
+ end
23
+
24
+ should "render latest post's content" do
25
+ assert @index.include?(@site.posts.last.content)
26
+ end
27
+
28
+ should "hide unpublished posts" do
29
+ published = Dir[dest_dir('publish_test/2008/02/02/*.html')].map {|f| File.basename(f)}
30
+
31
+ assert_equal 1, published.size
32
+ assert_equal "published.html", published.first
33
+ end
34
+
35
+ should "not copy _posts directory" do
36
+ assert !File.exist?(dest_dir('_posts'))
37
+ end
38
+
39
+ should "process other static files and generate correct permalinks" do
40
+ assert File.exists?(dest_dir('/about/index.html'))
41
+ assert File.exists?(dest_dir('/contacts.html'))
42
+ end
43
+ end
44
+
45
+ context "generating limited posts" do
46
+ setup do
47
+ clear_dest
48
+ stub(Monad).configuration do
49
+ Monad::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => 5})
50
+ end
51
+
52
+ @site = Site.new(Monad.configuration)
53
+ @site.process
54
+ @index = File.read(dest_dir('index.html'))
55
+ end
56
+
57
+ should "generate only the specified number of posts" do
58
+ assert_equal 5, @site.posts.size
59
+ end
60
+
61
+ should "ensure limit posts is 0 or more" do
62
+ assert_raise ArgumentError do
63
+ clear_dest
64
+ stub(Monad).configuration do
65
+ Monad::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => -1})
66
+ end
67
+
68
+ @site = Site.new(Monad.configuration)
69
+ end
70
+ end
71
+
72
+ should "acceptable limit post is 0" do
73
+ assert_nothing_raised ArgumentError do
74
+ clear_dest
75
+ stub(Monad).configuration do
76
+ Monad::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => 0})
77
+ end
78
+
79
+ @site = Site.new(Monad.configuration)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,63 @@
1
+ require 'helper'
2
+
3
+ class TestJsonDriver < Test::Unit::TestCase
4
+ context 'json driver' do
5
+ context 'incorrect input' do
6
+ should 'throw exception if url option is not parsed in' do
7
+ assert_raise FatalException do
8
+ Monad::Drivers::JsonDriver.new({})
9
+ end
10
+ end
11
+
12
+ should 'throw exception if url option is nil' do
13
+ assert_raise Monad::FatalException do
14
+ Monad::Drivers::JsonDriver.new('url' => nil)
15
+ end
16
+ end
17
+
18
+ should 'throw exception if parsed in url is invalid' do
19
+ assert_raise FatalException do
20
+ json_driver = Monad::Drivers::JsonDriver.new('url' => 'abc.com')
21
+ end
22
+ end
23
+
24
+ should 'throw exception if parsed in url is not http' do
25
+ assert_raise FatalException do
26
+ json_driver = Monad::Drivers::JsonDriver.new('url' => 'ftp://abc.com')
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'incorrect environment' do
32
+ should 'throw exception if server does not respond' do
33
+ assert_raise Errno::ECONNREFUSED do
34
+ Monad::Drivers::JsonDriver.new('url' => 'http://127.0.0.1:1').load
35
+ end
36
+ end
37
+
38
+ should 'throw exception if server returns non-json content' do
39
+ assert_raise JSON::ParserError do
40
+ Monad::Drivers::JsonDriver.new('url' => 'http://www.wikipedia.org/').load
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'correct input and correct environment' do
46
+ should 'handle http request correctly' do
47
+ assert_nothing_raised do
48
+ data = Monad::Drivers::JsonDriver.new('url' => 'http://jsonip.com/').load
49
+ assert_not_nil data['ip']
50
+ assert_not_nil data['about']
51
+ end
52
+ end
53
+
54
+ should 'handle https request correctly' do
55
+ assert_nothing_raised do
56
+ data = Monad::Drivers::JsonDriver.new('url' => 'https://maps.googleapis.com/maps/api/geocode/json').load
57
+ assert_not_nil data['results']
58
+ assert_not_nil data['status']
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'helper'
4
+
5
+ class TestKramdown < Test::Unit::TestCase
6
+ context "kramdown" do
7
+ setup do
8
+ @config = {
9
+ 'markdown' => 'kramdown',
10
+ 'kramdown' => {
11
+ 'auto_ids' => false,
12
+ 'footnote_nr' => 1,
13
+ 'entity_output' => 'as_char',
14
+ 'toc_levels' => '1..6',
15
+ 'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo'
16
+ }
17
+ }
18
+ end
19
+
20
+ # http://kramdown.rubyforge.org/converter/html.html#options
21
+ should "pass kramdown options" do
22
+ markdown = Converters::Markdown.new(@config)
23
+ assert_equal "<h1>Some Header</h1>", markdown.convert('# Some Header #').strip
24
+ end
25
+
26
+ should "convert quotes to smart quotes" do
27
+ markdown = Converters::Markdown.new(@config)
28
+ assert_match /<p>(&#8220;|“)Pit(&#8217;|’)hy(&#8221;|”)<\/p>/, markdown.convert(%{"Pit'hy"}).strip
29
+
30
+ override = { 'kramdown' => { 'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo' } }
31
+ markdown = Converters::Markdown.new(@config.deep_merge(override))
32
+ assert_match /<p>(&#171;|«)Pit(&#8250;|›)hy(&#187;|»)<\/p>/, markdown.convert(%{"Pit'hy"}).strip
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,104 @@
1
+ require 'helper'
2
+ require 'monad/commands/new'
3
+
4
+ class TestNewCommand < Test::Unit::TestCase
5
+ def dir_contents(path)
6
+ Dir["#{path}/**/*"].each do |file|
7
+ file.gsub! path, ''
8
+ end
9
+ end
10
+
11
+ def site_template
12
+ File.expand_path("../lib/site_template", File.dirname(__FILE__))
13
+ end
14
+
15
+ context 'when args contains a path' do
16
+ setup do
17
+ @path = 'new-site'
18
+ @args = [@path]
19
+ @full_path = File.expand_path(@path, Dir.pwd)
20
+ end
21
+
22
+ teardown do
23
+ FileUtils.rm_r @full_path
24
+ end
25
+
26
+ should 'create a new directory' do
27
+ assert !File.exists?(@full_path)
28
+ capture_stdout { Monad::Commands::New.process(@args) }
29
+ assert File.exists?(@full_path)
30
+ end
31
+
32
+ should 'display a success message' do
33
+ output = capture_stdout { Monad::Commands::New.process(@args) }
34
+ success_message = "New monad site installed in #{@full_path}.\n"
35
+ assert_equal success_message, output
36
+ end
37
+
38
+ should 'copy the static files in site template to the new directory' do
39
+ static_template_files = dir_contents(site_template).reject do |f|
40
+ File.extname(f) == '.erb'
41
+ end
42
+
43
+ capture_stdout { Monad::Commands::New.process(@args) }
44
+
45
+ new_site_files = dir_contents(@full_path).reject do |f|
46
+ File.extname(f) == '.markdown'
47
+ end
48
+
49
+ assert_same_elements static_template_files, new_site_files
50
+ end
51
+
52
+ should 'process any ERB files' do
53
+ erb_template_files = dir_contents(site_template).select do |f|
54
+ File.extname(f) == '.erb'
55
+ end
56
+
57
+ stubbed_date = '2013-01-01'
58
+ stub.instance_of(Time).strftime { stubbed_date }
59
+
60
+ erb_template_files.each do |f|
61
+ f.chomp! '.erb'
62
+ f.gsub! '0000-00-00', stubbed_date
63
+ end
64
+
65
+ capture_stdout { Monad::Commands::New.process(@args) }
66
+
67
+ new_site_files = dir_contents(@full_path).select do |f|
68
+ erb_template_files.include? f
69
+ end
70
+
71
+ assert_same_elements erb_template_files, new_site_files
72
+ end
73
+ end
74
+
75
+ context 'when multiple args are given' do
76
+ setup do
77
+ @site_name_with_spaces = 'new site name'
78
+ @multiple_args = @site_name_with_spaces.split
79
+ end
80
+
81
+ teardown do
82
+ FileUtils.rm_r File.expand_path(@site_name_with_spaces, Dir.pwd)
83
+ end
84
+
85
+ should 'create a new directory' do
86
+ assert !File.exists?(@site_name_with_spaces)
87
+ capture_stdout { Monad::Commands::New.process(@multiple_args) }
88
+ assert File.exists?(@site_name_with_spaces)
89
+ end
90
+ end
91
+
92
+ context 'when no args are given' do
93
+ setup do
94
+ @empty_args = []
95
+ end
96
+
97
+ should 'raise an ArgumentError' do
98
+ exception = assert_raise ArgumentError do
99
+ Monad::Commands::New.process(@empty_args)
100
+ end
101
+ assert_equal 'You must specify a path.', exception.message
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,193 @@
1
+ require 'helper'
2
+
3
+ class TestPage < Test::Unit::TestCase
4
+ def setup_page(*args)
5
+ dir, file = args
6
+ dir, file = ['', dir] if file.nil?
7
+ @page = Page.new(@site, source_dir, dir, file)
8
+ end
9
+
10
+ def do_render(page)
11
+ layouts = { "default" => Layout.new(@site, source_dir('_layouts'), "simple.html")}
12
+ page.render(layouts, {"site" => {"posts" => []}})
13
+ end
14
+
15
+ context "A Page" do
16
+ setup do
17
+ clear_dest
18
+ stub(Monad).configuration { Monad::Configuration::DEFAULTS }
19
+ @site = Site.new(Monad.configuration)
20
+ end
21
+
22
+ context "processing pages" do
23
+ should "create url based on filename" do
24
+ @page = setup_page('contacts.html')
25
+ assert_equal "/contacts.html", @page.url
26
+ end
27
+
28
+ context "in a directory hierarchy" do
29
+ should "create url based on filename" do
30
+ @page = setup_page('/contacts', 'bar.html')
31
+ assert_equal "/contacts/bar.html", @page.url
32
+ end
33
+
34
+ should "create index url based on filename" do
35
+ @page = setup_page('/contacts', 'index.html')
36
+ assert_equal "/contacts/index.html", @page.url
37
+ end
38
+ end
39
+
40
+ should "deal properly with extensions" do
41
+ @page = setup_page('deal.with.dots.html')
42
+ assert_equal ".html", @page.ext
43
+ end
44
+
45
+ should "deal properly with dots" do
46
+ @page = setup_page('deal.with.dots.html')
47
+ assert_equal "deal.with.dots", @page.basename
48
+ end
49
+
50
+ context "with pretty url style" do
51
+ setup do
52
+ @site.permalink_style = :pretty
53
+ end
54
+
55
+ should "return dir correctly" do
56
+ @page = setup_page('contacts.html')
57
+ assert_equal '/contacts/', @page.dir
58
+ end
59
+
60
+ should "return dir correctly for index page" do
61
+ @page = setup_page('index.html')
62
+ assert_equal '/', @page.dir
63
+ end
64
+
65
+ context "in a directory hierarchy" do
66
+ should "create url based on filename" do
67
+ @page = setup_page('/contacts', 'bar.html')
68
+ assert_equal "/contacts/bar/", @page.url
69
+ end
70
+
71
+ should "create index url based on filename" do
72
+ @page = setup_page('/contacts', 'index.html')
73
+ assert_equal "/contacts/", @page.url
74
+ end
75
+
76
+ should "return dir correctly" do
77
+ @page = setup_page('/contacts', 'bar.html')
78
+ assert_equal '/contacts/bar/', @page.dir
79
+ end
80
+
81
+ should "return dir correctly for index page" do
82
+ @page = setup_page('/contacts', 'index.html')
83
+ assert_equal '/contacts/', @page.dir
84
+ end
85
+ end
86
+ end
87
+
88
+ context "with any other url style" do
89
+ should "return dir correctly" do
90
+ @site.permalink_style = nil
91
+ @page = setup_page('contacts.html')
92
+ assert_equal '/', @page.dir
93
+ end
94
+ end
95
+
96
+ should "respect permalink in yaml front matter" do
97
+ file = "about.html"
98
+ @page = setup_page(file)
99
+
100
+ assert_equal "/about/", @page.permalink
101
+ assert_equal @page.permalink, @page.url
102
+ assert_equal "/about/", @page.dir
103
+ end
104
+ end
105
+
106
+ context "with specified layout of nil" do
107
+ setup do
108
+ @page = setup_page('sitemap.xml')
109
+ end
110
+
111
+ should "layout of nil is respected" do
112
+ assert_equal "nil", @page.data["layout"]
113
+ end
114
+ end
115
+
116
+ context "rendering" do
117
+ setup do
118
+ clear_dest
119
+ end
120
+
121
+ should "write properly" do
122
+ page = setup_page('contacts.html')
123
+ do_render(page)
124
+ page.write(dest_dir)
125
+
126
+ assert File.directory?(dest_dir)
127
+ assert File.exists?(File.join(dest_dir, 'contacts.html'))
128
+ end
129
+
130
+ should "write properly without html extension" do
131
+ page = setup_page('contacts.html')
132
+ page.site.permalink_style = :pretty
133
+ do_render(page)
134
+ page.write(dest_dir)
135
+
136
+ assert File.directory?(dest_dir)
137
+ assert File.exists?(File.join(dest_dir, 'contacts', 'index.html'))
138
+ end
139
+
140
+ should "write properly with extension different from html" do
141
+ page = setup_page("sitemap.xml")
142
+ page.site.permalink_style = :pretty
143
+ do_render(page)
144
+ page.write(dest_dir)
145
+
146
+ assert_equal("/sitemap.xml", page.url)
147
+ assert_nil(page.url[/\.html$/])
148
+ assert File.directory?(dest_dir)
149
+ assert File.exists?(File.join(dest_dir,'sitemap.xml'))
150
+ end
151
+
152
+ should "write dotfiles properly" do
153
+ page = setup_page('.htaccess')
154
+ do_render(page)
155
+ page.write(dest_dir)
156
+
157
+ assert File.directory?(dest_dir)
158
+ assert File.exists?(File.join(dest_dir, '.htaccess'))
159
+ end
160
+
161
+ context "in a directory hierarchy" do
162
+ should "write properly the index" do
163
+ page = setup_page('/contacts', 'index.html')
164
+ do_render(page)
165
+ page.write(dest_dir)
166
+
167
+ assert File.directory?(dest_dir)
168
+ assert File.exists?(File.join(dest_dir, 'contacts', 'index.html'))
169
+ end
170
+
171
+ should "write properly" do
172
+ page = setup_page('/contacts', 'bar.html')
173
+ do_render(page)
174
+ page.write(dest_dir)
175
+
176
+ assert File.directory?(dest_dir)
177
+ assert File.exists?(File.join(dest_dir, 'contacts', 'bar.html'))
178
+ end
179
+
180
+ should "write properly without html extension" do
181
+ page = setup_page('/contacts', 'bar.html')
182
+ page.site.permalink_style = :pretty
183
+ do_render(page)
184
+ page.write(dest_dir)
185
+
186
+ assert File.directory?(dest_dir)
187
+ assert File.exists?(File.join(dest_dir, 'contacts', 'bar', 'index.html'))
188
+ end
189
+ end
190
+ end
191
+
192
+ end
193
+ end