monad 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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