nanoc3 3.2.0a3 → 3.2.0a4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. data/.gemtest +0 -0
  2. data/LICENSE +1 -1
  3. data/NEWS.md +23 -4
  4. data/README.md +7 -0
  5. data/lib/nanoc3/base/compilation/checksum_store.rb +17 -90
  6. data/lib/nanoc3/base/compilation/compiled_content_cache.rb +5 -0
  7. data/lib/nanoc3/base/compilation/compiler.rb +112 -175
  8. data/lib/nanoc3/base/compilation/compiler_dsl.rb +54 -11
  9. data/lib/nanoc3/base/compilation/dependency_tracker.rb +32 -65
  10. data/lib/nanoc3/base/compilation/filter.rb +4 -3
  11. data/lib/nanoc3/base/compilation/item_rep_proxy.rb +19 -4
  12. data/lib/nanoc3/base/compilation/item_rep_recorder_proxy.rb +90 -0
  13. data/lib/nanoc3/base/compilation/outdatedness_checker.rb +152 -15
  14. data/lib/nanoc3/base/compilation/outdatedness_reasons.rb +12 -9
  15. data/lib/nanoc3/base/compilation/rule.rb +3 -1
  16. data/lib/nanoc3/base/compilation/rule_memory_calculator.rb +42 -0
  17. data/lib/nanoc3/base/compilation/rule_memory_store.rb +53 -0
  18. data/lib/nanoc3/base/compilation/rules_collection.rb +205 -0
  19. data/lib/nanoc3/base/core_ext/array.rb +20 -0
  20. data/lib/nanoc3/base/core_ext/hash.rb +30 -0
  21. data/lib/nanoc3/base/core_ext/pathname.rb +26 -0
  22. data/lib/nanoc3/base/core_ext/string.rb +12 -0
  23. data/lib/nanoc3/base/core_ext.rb +1 -0
  24. data/lib/nanoc3/base/directed_graph.rb +11 -3
  25. data/lib/nanoc3/base/errors.rb +0 -4
  26. data/lib/nanoc3/base/memoization.rb +72 -0
  27. data/lib/nanoc3/base/result_data/item_rep.rb +64 -25
  28. data/lib/nanoc3/base/source_data/code_snippet.rb +9 -0
  29. data/lib/nanoc3/base/source_data/configuration.rb +20 -0
  30. data/lib/nanoc3/base/source_data/item.rb +29 -4
  31. data/lib/nanoc3/base/source_data/layout.rb +20 -1
  32. data/lib/nanoc3/base/source_data/site.rb +49 -26
  33. data/lib/nanoc3/base/store.rb +10 -1
  34. data/lib/nanoc3/base.rb +6 -1
  35. data/lib/nanoc3/cli/base.rb +20 -7
  36. data/lib/nanoc3/cli/commands/compile.rb +0 -2
  37. data/lib/nanoc3/cli/commands/create_site.rb +16 -7
  38. data/lib/nanoc3/cli/commands/debug.rb +3 -3
  39. data/lib/nanoc3/cli/commands/view.rb +1 -0
  40. data/lib/nanoc3/cli/commands/watch.rb +2 -1
  41. data/lib/nanoc3/data_sources/deprecated/delicious.rb +0 -2
  42. data/lib/nanoc3/data_sources/deprecated/last_fm.rb +0 -2
  43. data/lib/nanoc3/data_sources/deprecated/twitter.rb +0 -2
  44. data/lib/nanoc3/data_sources/filesystem.rb +17 -3
  45. data/lib/nanoc3/data_sources/filesystem_unified.rb +17 -17
  46. data/lib/nanoc3/extra/auto_compiler.rb +5 -1
  47. data/lib/nanoc3/extra/core_ext/time.rb +1 -1
  48. data/lib/nanoc3/extra/file_proxy.rb +11 -1
  49. data/lib/nanoc3/extra/validators/links.rb +1 -1
  50. data/lib/nanoc3/filters/asciidoc.rb +3 -3
  51. data/lib/nanoc3/filters/colorize_syntax.rb +106 -27
  52. data/lib/nanoc3/filters/erb.rb +16 -6
  53. data/lib/nanoc3/filters/erubis.rb +5 -1
  54. data/lib/nanoc3/filters/haml.rb +2 -1
  55. data/lib/nanoc3/filters/less.rb +3 -6
  56. data/lib/nanoc3/filters/mustache.rb +3 -0
  57. data/lib/nanoc3/filters/redcarpet.rb +27 -0
  58. data/lib/nanoc3/filters/sass.rb +1 -5
  59. data/lib/nanoc3/filters/slim.rb +25 -0
  60. data/lib/nanoc3/filters/typogruby.rb +23 -0
  61. data/lib/nanoc3/filters.rb +6 -0
  62. data/lib/nanoc3/helpers/blogging.rb +22 -26
  63. data/lib/nanoc3/helpers/rendering.rb +1 -1
  64. data/lib/nanoc3/helpers/xml_sitemap.rb +11 -2
  65. data/lib/nanoc3.rb +24 -3
  66. data/nanoc3.gemspec +4 -3
  67. data/tasks/clean.rake +11 -0
  68. data/tasks/doc.rake +14 -0
  69. data/tasks/test.rake +38 -0
  70. data/test/base/core_ext/array_spec.rb +55 -0
  71. data/test/base/core_ext/hash_spec.rb +82 -0
  72. data/test/base/core_ext/pathname_spec.rb +29 -0
  73. data/test/base/core_ext/string_spec.rb +39 -0
  74. data/test/base/test_checksum_store.rb +37 -0
  75. data/test/base/test_code_snippet.rb +33 -0
  76. data/test/base/test_compiler.rb +303 -0
  77. data/test/base/test_compiler_dsl.rb +156 -0
  78. data/test/base/test_context.rb +33 -0
  79. data/test/base/test_data_source.rb +48 -0
  80. data/test/base/test_dependency_tracker.rb +264 -0
  81. data/test/base/test_directed_graph.rb +285 -0
  82. data/test/base/test_filter.rb +85 -0
  83. data/test/base/test_item.rb +164 -0
  84. data/test/base/test_item_rep.rb +555 -0
  85. data/test/base/test_layout.rb +44 -0
  86. data/test/base/test_memoization.rb +53 -0
  87. data/test/base/test_notification_center.rb +36 -0
  88. data/test/base/test_outdatedness_checker.rb +365 -0
  89. data/test/base/test_plugin.rb +32 -0
  90. data/test/base/test_rule.rb +21 -0
  91. data/test/base/test_rule_context.rb +67 -0
  92. data/test/base/test_site.rb +144 -0
  93. data/test/cli/commands/test_compile.rb +12 -0
  94. data/test/cli/commands/test_create_item.rb +12 -0
  95. data/test/cli/commands/test_create_layout.rb +28 -0
  96. data/test/cli/commands/test_create_site.rb +24 -0
  97. data/test/cli/commands/test_help.rb +12 -0
  98. data/test/cli/commands/test_info.rb +12 -0
  99. data/test/cli/commands/test_update.rb +12 -0
  100. data/test/cli/test_logger.rb +12 -0
  101. data/test/data_sources/test_filesystem.rb +420 -0
  102. data/test/data_sources/test_filesystem_unified.rb +562 -0
  103. data/test/data_sources/test_filesystem_verbose.rb +359 -0
  104. data/test/extra/core_ext/test_enumerable.rb +32 -0
  105. data/test/extra/core_ext/test_time.rb +17 -0
  106. data/test/extra/deployers/test_rsync.rb +234 -0
  107. data/test/extra/test_auto_compiler.rb +417 -0
  108. data/test/extra/test_file_proxy.rb +21 -0
  109. data/test/extra/test_vcs.rb +24 -0
  110. data/test/extra/validators/test_links.rb +53 -0
  111. data/test/extra/validators/test_w3c.rb +49 -0
  112. data/test/filters/test_asciidoc.rb +22 -0
  113. data/test/filters/test_bluecloth.rb +20 -0
  114. data/test/filters/test_coderay.rb +46 -0
  115. data/test/filters/test_colorize_syntax.rb +149 -0
  116. data/test/filters/test_erb.rb +101 -0
  117. data/test/filters/test_erubis.rb +72 -0
  118. data/test/filters/test_haml.rb +98 -0
  119. data/test/filters/test_kramdown.rb +20 -0
  120. data/test/filters/test_less.rb +59 -0
  121. data/test/filters/test_markaby.rb +26 -0
  122. data/test/filters/test_maruku.rb +20 -0
  123. data/test/filters/test_mustache.rb +27 -0
  124. data/test/filters/test_rainpress.rb +31 -0
  125. data/test/filters/test_rdiscount.rb +33 -0
  126. data/test/filters/test_rdoc.rb +18 -0
  127. data/test/filters/test_redcarpet.rb +63 -0
  128. data/test/filters/test_redcloth.rb +35 -0
  129. data/test/filters/test_relativize_paths.rb +231 -0
  130. data/test/filters/test_rubypants.rb +20 -0
  131. data/test/filters/test_sass.rb +103 -0
  132. data/test/filters/test_slim.rb +37 -0
  133. data/test/filters/test_typogruby.rb +23 -0
  134. data/test/helper.rb +161 -0
  135. data/test/helpers/test_blogging.rb +756 -0
  136. data/test/helpers/test_breadcrumbs.rb +83 -0
  137. data/test/helpers/test_capturing.rb +43 -0
  138. data/test/helpers/test_filtering.rb +108 -0
  139. data/test/helpers/test_html_escape.rb +34 -0
  140. data/test/helpers/test_link_to.rb +251 -0
  141. data/test/helpers/test_rendering.rb +90 -0
  142. data/test/helpers/test_tagging.rb +89 -0
  143. data/test/helpers/test_text.rb +26 -0
  144. data/test/helpers/test_xml_sitemap.rb +105 -0
  145. data/test/tasks/test_clean.rb +69 -0
  146. metadata +96 -27
  147. data/lib/nanoc3/base/compilation/checksummer.rb +0 -68
@@ -0,0 +1,164 @@
1
+ # encoding: utf-8
2
+
3
+ require 'test/helper'
4
+
5
+ class Nanoc3::ItemTest < MiniTest::Unit::TestCase
6
+
7
+ include Nanoc3::TestHelpers
8
+
9
+ def test_initialize_with_attributes_with_string_keys
10
+ item = Nanoc3::Item.new("foo", { 'abc' => 'xyz' }, '/foo/')
11
+
12
+ assert_equal nil, item.attributes['abc']
13
+ assert_equal 'xyz', item.attributes[:abc]
14
+ end
15
+
16
+ def test_initialize_with_unclean_identifier
17
+ item = Nanoc3::Item.new("foo", {}, '/foo')
18
+
19
+ assert_equal '/foo/', item.identifier
20
+ end
21
+
22
+ def test_frozen_identifier
23
+ item = Nanoc3::Item.new("foo", {}, '/foo')
24
+
25
+ error = assert_raises(RuntimeError) do
26
+ item.identifier.chop!
27
+ end
28
+ assert_equal "can't modify frozen string", error.message
29
+ end
30
+
31
+ def test_lookup
32
+ # Create item
33
+ item = Nanoc3::Item.new(
34
+ "content",
35
+ { :one => 'one in item' },
36
+ '/path/'
37
+ )
38
+
39
+ # Test finding one
40
+ assert_equal('one in item', item[:one])
41
+
42
+ # Test finding two
43
+ assert_equal(nil, item[:two])
44
+ end
45
+
46
+ def test_set_attribute
47
+ item = Nanoc3::Item.new("foo", {}, '/foo')
48
+ assert_equal nil, item[:motto]
49
+
50
+ item[:motto] = 'More human than human'
51
+ assert_equal 'More human than human', item[:motto]
52
+ end
53
+
54
+ def test_compiled_content_with_default_rep_and_default_snapshot
55
+ # Mock rep
56
+ rep = Object.new
57
+ def rep.name ; :default ; end
58
+ def rep.compiled_content(params)
59
+ "content at #{params[:snapshot].inspect}"
60
+ end
61
+
62
+ # Mock item
63
+ item = Nanoc3::Item.new("foo", {}, '/foo')
64
+ item.expects(:reps).returns([ rep ])
65
+
66
+ # Check
67
+ assert_equal 'content at nil', item.compiled_content
68
+ end
69
+
70
+ def test_compiled_content_with_custom_rep_and_default_snapshot
71
+ # Mock reps
72
+ rep = Object.new
73
+ def rep.name ; :foo ; end
74
+ def rep.compiled_content(params)
75
+ "content at #{params[:snapshot].inspect}"
76
+ end
77
+
78
+ # Mock item
79
+ item = Nanoc3::Item.new("foo", {}, '/foo')
80
+ item.expects(:reps).returns([ rep ])
81
+
82
+ # Check
83
+ assert_equal 'content at nil', item.compiled_content(:rep => :foo)
84
+ end
85
+
86
+ def test_compiled_content_with_default_rep_and_custom_snapshot
87
+ # Mock reps
88
+ rep = Object.new
89
+ def rep.name ; :default ; end
90
+ def rep.compiled_content(params)
91
+ "content at #{params[:snapshot].inspect}"
92
+ end
93
+
94
+ # Mock item
95
+ item = Nanoc3::Item.new("foo", {}, '/foo')
96
+ item.expects(:reps).returns([ rep ])
97
+
98
+ # Check
99
+ assert_equal 'content at :blah', item.compiled_content(:snapshot => :blah)
100
+ end
101
+
102
+ def test_compiled_content_with_custom_nonexistant_rep
103
+ # Mock item
104
+ item = Nanoc3::Item.new("foo", {}, '/foo')
105
+ item.expects(:reps).returns([])
106
+
107
+ # Check
108
+ assert_raises(Nanoc3::Errors::Generic) do
109
+ item.compiled_content(:rep => :lkasdhflahgwfe)
110
+ end
111
+ end
112
+
113
+ def test_path_with_default_rep
114
+ # Mock reps
115
+ rep = mock
116
+ rep.expects(:name).returns(:default)
117
+ rep.expects(:path).returns('the correct path')
118
+
119
+ # Mock item
120
+ item = Nanoc3::Item.new("foo", {}, '/foo')
121
+ item.expects(:reps).returns([ rep ])
122
+
123
+ # Check
124
+ assert_equal 'the correct path', item.path
125
+ end
126
+
127
+ def test_path_with_custom_rep
128
+ # Mock reps
129
+ rep = mock
130
+ rep.expects(:name).returns(:moo)
131
+ rep.expects(:path).returns('the correct path')
132
+
133
+ # Mock item
134
+ item = Nanoc3::Item.new("foo", {}, '/foo')
135
+ item.expects(:reps).returns([ rep ])
136
+
137
+ # Check
138
+ assert_equal 'the correct path', item.path(:rep => :moo)
139
+ end
140
+
141
+ def test_freeze_should_disallow_changes
142
+ item = Nanoc3::Item.new("foo", { :a => { :b => 123 }}, '/foo/')
143
+ item.freeze
144
+
145
+ raised = false
146
+ begin
147
+ item[:abc] = '123'
148
+ rescue => e
149
+ raised = true
150
+ assert_match /^can't modify frozen /, e.message
151
+ end
152
+ assert raised
153
+
154
+ raised = false
155
+ begin
156
+ item[:a][:b] = '456'
157
+ rescue => e
158
+ raised = true
159
+ assert_match /^can't modify frozen /, e.message
160
+ end
161
+ assert raised
162
+ end
163
+
164
+ end
@@ -0,0 +1,555 @@
1
+ # encoding: utf-8
2
+
3
+ require 'test/helper'
4
+
5
+ class Nanoc3::ItemRepTest < MiniTest::Unit::TestCase
6
+
7
+ include Nanoc3::TestHelpers
8
+
9
+ def test_created_modified_compiled
10
+ # TODO implement
11
+ end
12
+
13
+ def test_compiled_content_with_only_last_available
14
+ # Create rep
15
+ item = Nanoc3::Item.new(
16
+ 'blah blah blah', {}, '/',
17
+ :binary => false, :mtime => Time.now-500
18
+ )
19
+ rep = Nanoc3::ItemRep.new(item, nil)
20
+ rep.instance_eval { @content = { :last => 'last content' } }
21
+ rep.expects(:compiled?).returns(true)
22
+
23
+ # Check
24
+ assert_equal 'last content', rep.compiled_content
25
+ end
26
+
27
+ def test_compiled_content_with_pre_and_last_available
28
+ # Create rep
29
+ item = Nanoc3::Item.new(
30
+ 'blah blah blah', {}, '/',
31
+ :binary => false, :mtime => Time.now-500
32
+ )
33
+ rep = Nanoc3::ItemRep.new(item, nil)
34
+ rep.instance_eval { @content = { :pre => 'pre content', :last => 'last content' } }
35
+ rep.expects(:compiled?).returns(true)
36
+
37
+ # Check
38
+ assert_equal 'pre content', rep.compiled_content
39
+ end
40
+
41
+ def test_compiled_content_with_custom_snapshot
42
+ # Create rep
43
+ item = Nanoc3::Item.new(
44
+ 'blah blah blah', {}, '/',
45
+ :binary => false, :mtime => Time.now-500
46
+ )
47
+ rep = Nanoc3::ItemRep.new(item, nil)
48
+ rep.instance_eval { @content = { :pre => 'pre content', :last => 'last content' } }
49
+ rep.expects(:compiled?).returns(true)
50
+
51
+ # Check
52
+ assert_equal 'last content', rep.compiled_content(:snapshot => :last)
53
+ end
54
+
55
+ def test_compiled_content_with_invalid_snapshot
56
+ # Create rep
57
+ item = Nanoc3::Item.new(
58
+ 'blah blah blah', {}, '/',
59
+ :binary => false, :mtime => Time.now-500
60
+ )
61
+ rep = Nanoc3::ItemRep.new(item, nil)
62
+ rep.instance_eval { @content = { :pre => 'pre content', :last => 'last content' } }
63
+ rep.expects(:compiled?).returns(true)
64
+
65
+ # Check
66
+ assert_equal nil, rep.compiled_content(:snapshot => :klsjflkasdfl)
67
+ end
68
+
69
+ def test_compiled_content_with_uncompiled_content
70
+ # Create rep
71
+ item = Nanoc3::Item.new(
72
+ "blah blah", {}, '/',
73
+ :binary => false
74
+ )
75
+ rep = Nanoc3::ItemRep.new(item, nil)
76
+ rep.expects(:compiled?).returns(false)
77
+
78
+ # Check
79
+ assert_raises(Nanoc3::Errors::UnmetDependency) do
80
+ rep.compiled_content
81
+ end
82
+ end
83
+
84
+ def test_filter
85
+ # Mock site
86
+ site = MiniTest::Mock.new
87
+ site.expect(:items, [])
88
+ site.expect(:config, [])
89
+ site.expect(:layouts, [])
90
+
91
+ # Mock item
92
+ item = Nanoc3::Item.new(
93
+ %[<%= '<%= "blah" %' + '>' %>], {}, '/',
94
+ :binary => false
95
+ )
96
+
97
+ # Create item rep
98
+ item_rep = Nanoc3::ItemRep.new(item, :foo)
99
+ item_rep.instance_eval do
100
+ @content[:raw] = item.raw_content
101
+ @content[:last] = @content[:raw]
102
+ end
103
+
104
+ # Filter once
105
+ item_rep.assigns = {}
106
+ item_rep.filter(:erb)
107
+ assert_equal(%[<%= "blah" %>], item_rep.instance_eval { @content[:last] })
108
+
109
+ # Filter twice
110
+ item_rep.assigns = {}
111
+ item_rep.filter(:erb)
112
+ assert_equal(%[blah], item_rep.instance_eval { @content[:last] })
113
+ end
114
+
115
+ def test_layout
116
+ # Mock layout
117
+ layout = Nanoc3::Layout.new(%[<%= "blah" %>], {}, '/somelayout/')
118
+
119
+ # Mock item
120
+ item = Nanoc3::Item.new(
121
+ "blah blah", {}, '/',
122
+ :binary => false
123
+ )
124
+
125
+ # Create item rep
126
+ item_rep = Nanoc3::ItemRep.new(item, :foo)
127
+ item_rep.instance_eval do
128
+ @content[:raw] = item.raw_content
129
+ @content[:last] = @content[:raw]
130
+ end
131
+
132
+ # Layout
133
+ item_rep.assigns = {}
134
+ item_rep.layout(layout, :erb, {})
135
+ assert_equal(%[blah], item_rep.instance_eval { @content[:last] })
136
+ end
137
+
138
+ def test_snapshot
139
+ # Mock site
140
+ site = MiniTest::Mock.new
141
+ site.expect(:items, [])
142
+ site.expect(:config, [])
143
+ site.expect(:layouts, [])
144
+
145
+ # Mock item
146
+ item = Nanoc3::Item.new(
147
+ %[<%= '<%= "blah" %' + '>' %>], {}, '/foobar/',
148
+ :binary => false
149
+ )
150
+
151
+ # Create item rep
152
+ item_rep = Nanoc3::ItemRep.new(item, :foo)
153
+ item_rep.instance_eval do
154
+ @content[:raw] = item.raw_content
155
+ @content[:last] = @content[:raw]
156
+ end
157
+
158
+ # Filter while taking snapshots
159
+ item_rep.assigns = {}
160
+ item_rep.snapshot(:foo)
161
+ item_rep.filter(:erb)
162
+ item_rep.snapshot(:bar)
163
+ item_rep.filter(:erb)
164
+ item_rep.snapshot(:qux)
165
+
166
+ # Check snapshots
167
+ assert_equal(%[<%= '<%= "blah" %' + '>' %>], item_rep.instance_eval { @content[:foo] })
168
+ assert_equal(%[<%= "blah" %>], item_rep.instance_eval { @content[:bar] })
169
+ assert_equal(%[blah], item_rep.instance_eval { @content[:qux] })
170
+ end
171
+
172
+ def test_snapshot_should_be_written
173
+ # Mock item
174
+ item = Nanoc3::Item.new(
175
+ "blah blah", {}, '/',
176
+ :binary => false
177
+ )
178
+
179
+ # Create rep
180
+ item_rep = Nanoc3::ItemRep.new(item, :foo)
181
+ item_rep.instance_eval { @content[:last] = 'Lorem ipsum, etc.' }
182
+ item_rep.raw_paths = { :moo => 'foo-moo.txt' }
183
+
184
+ # Test non-final
185
+ refute File.file?(item_rep.raw_path(:snapshot => :moo))
186
+ item_rep.snapshot(:moo, :final => false)
187
+ refute File.file?(item_rep.raw_path(:snapshot => :moo))
188
+
189
+ # Test final 1
190
+ item_rep.snapshot(:moo, :final => true)
191
+ assert File.file?(item_rep.raw_path(:snapshot => :moo))
192
+ assert_equal 'Lorem ipsum, etc.', File.read(item_rep.raw_path(:snapshot => :moo))
193
+ FileUtils.rm_f(item_rep.raw_path(:snapshot => :moo))
194
+
195
+ # Test final 2
196
+ item_rep.snapshot(:moo)
197
+ assert File.file?(item_rep.raw_path(:snapshot => :moo))
198
+ assert_equal 'Lorem ipsum, etc.', File.read(item_rep.raw_path(:snapshot => :moo))
199
+ end
200
+
201
+ def test_write_should_not_touch_identical_textual_files
202
+ # Mock item
203
+ item = Nanoc3::Item.new(
204
+ "blah blah", {}, '/',
205
+ :binary => false
206
+ )
207
+
208
+ # Create rep
209
+ item_rep = Nanoc3::ItemRep.new(item, :foo)
210
+ def item_rep.generate_diff ; end
211
+ item_rep.instance_eval { @content[:last] = 'Lorem ipsum, etc.' }
212
+ item_rep.raw_path = 'foo/bar/baz/quux.txt'
213
+
214
+ # Write once
215
+ item_rep.write
216
+ a_long_time_ago = Time.now-1_000_000
217
+ File.utime(a_long_time_ago, a_long_time_ago, item_rep.raw_path)
218
+
219
+ # Write again
220
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
221
+ item_rep.write
222
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
223
+ end
224
+
225
+ def test_write_should_not_touch_identical_binary_files
226
+ # Create temporary source file
227
+ File.open('blahblah', 'w') { |io| io.write("Blah blah…") }
228
+ full_file_path = File.expand_path('blahblah')
229
+
230
+ # Mock item
231
+ item = Nanoc3::Item.new(
232
+ full_file_path, {}, '/',
233
+ :binary => true
234
+ )
235
+
236
+ # Create rep
237
+ item_rep = Nanoc3::ItemRep.new(item, :foo)
238
+ item_rep.raw_path = 'foo/bar/baz/quux'
239
+
240
+ # Write once
241
+ item_rep.write
242
+ a_long_time_ago = Time.now-1_000_000
243
+ File.utime(a_long_time_ago, a_long_time_ago, item_rep.raw_path)
244
+
245
+ # Write again
246
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
247
+ item_rep.write
248
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
249
+ end
250
+
251
+ def test_write
252
+ # Mock item
253
+ item = Nanoc3::Item.new(
254
+ "blah blah", {}, '/',
255
+ :binary => false
256
+ )
257
+
258
+ # Create rep
259
+ item_rep = Nanoc3::ItemRep.new(item, :foo)
260
+ item_rep.instance_eval { @content[:last] = 'Lorem ipsum, etc.' }
261
+ item_rep.raw_path = 'foo/bar/baz/quux.txt'
262
+
263
+ # Write
264
+ item_rep.write
265
+
266
+ # Check
267
+ assert(File.file?('foo/bar/baz/quux.txt'))
268
+ assert_equal('Lorem ipsum, etc.', File.read('foo/bar/baz/quux.txt'))
269
+ end
270
+
271
+ def test_filter_text_to_binary
272
+ # Mock item
273
+ item = Nanoc3::Item.new(
274
+ "blah blah", {}, '/',
275
+ :binary => false
276
+ )
277
+
278
+ # Create rep
279
+ rep = Nanoc3::ItemRep.new(item, :foo)
280
+ def rep.assigns ; {} ; end
281
+
282
+ # Create fake filter
283
+ def rep.filter_named(name)
284
+ @filter ||= Class.new(::Nanoc3::Filter) do
285
+ type :text => :binary
286
+ def run(content, params={})
287
+ File.open(output_filename, 'w') { |io| io.write(content) }
288
+ end
289
+ end
290
+ end
291
+
292
+ # Run
293
+ rep.filter(:foo)
294
+
295
+ # Check
296
+ assert rep.binary?
297
+ end
298
+
299
+ def test_filter_with_textual_rep_and_binary_filter
300
+ # Mock item
301
+ item = Nanoc3::Item.new(
302
+ "blah blah", {}, '/',
303
+ :binary => false
304
+ )
305
+
306
+ # Create rep
307
+ rep = Nanoc3::ItemRep.new(item, :foo)
308
+ def rep.assigns ; {} ; end
309
+
310
+ # Create fake filter
311
+ def rep.filter_named(name)
312
+ @filter ||= Class.new(::Nanoc3::Filter) do
313
+ type :binary
314
+ def run(content, params={})
315
+ File.open(output_filename, 'w') { |io| io.write(content) }
316
+ end
317
+ end
318
+ end
319
+
320
+ # Run
321
+ assert_raises ::Nanoc3::Errors::CannotUseBinaryFilter do
322
+ rep.filter(:foo)
323
+ end
324
+ end
325
+
326
+ def test_filter_get_compiled_content_from_binary_item
327
+ # Mock item
328
+ item = Nanoc3::Item.new(
329
+ "blah blah", {}, '/',
330
+ :binary => true
331
+ )
332
+
333
+ # Create rep
334
+ rep = Nanoc3::ItemRep.new(item, :foo)
335
+ def rep.compiled? ; true ; end
336
+
337
+ # Check
338
+ assert_nil rep.compiled_content
339
+ end
340
+
341
+ def test_using_textual_filters_on_binary_reps_raises
342
+ item = create_binary_item
343
+ site = mock_and_stub(:items => [item],
344
+ :layouts => [],
345
+ :config => []
346
+ )
347
+ item.stubs(:site).returns(site)
348
+ rep = create_rep_for(item, :foo)
349
+ create_textual_filter
350
+
351
+ assert rep.binary?
352
+ assert_raises(Nanoc3::Errors::CannotUseTextualFilter) { rep.filter(:text_filter) }
353
+ end
354
+
355
+ def test_writing_binary_reps_uses_content_in_last_filename
356
+ require 'tempfile'
357
+
358
+ in_filename = 'nanoc-in'
359
+ out_filename = 'nanoc-out'
360
+ file_content = 'Some content for this test'
361
+ File.open(in_filename, 'w') { |io| io.write(file_content) }
362
+
363
+ item = create_binary_item
364
+ rep = create_rep_for(item, :foo)
365
+ rep.temporary_filenames[:last] = in_filename
366
+ rep.raw_paths[:last] = out_filename
367
+
368
+ rep.write
369
+
370
+ assert(File.exist?(out_filename))
371
+ assert_equal(file_content, File.read(out_filename))
372
+ end
373
+
374
+ def test_converted_binary_rep_can_be_layed_out
375
+ # Mock layout
376
+ layout = Nanoc3::Layout.new(%[<%= "blah" %> <%= yield %>], {}, '/somelayout/')
377
+
378
+ # Create item and item rep
379
+ item = create_binary_item
380
+ rep = create_rep_for(item, :foo)
381
+ rep.assigns = { :content => 'meh' }
382
+
383
+ # Create filter
384
+ Class.new(::Nanoc3::Filter) do
385
+ type :binary => :text
386
+ identifier :binary_to_text
387
+ def run(content, params={})
388
+ content + ' textified'
389
+ end
390
+ end
391
+
392
+ # Run and check
393
+ rep.filter(:binary_to_text)
394
+ rep.layout(layout, :erb, {})
395
+ assert_equal('blah meh', rep.instance_eval { @content[:last] })
396
+ end
397
+
398
+ def test_converted_binary_rep_can_be_filtered_with_textual_filters
399
+ item = create_binary_item
400
+ site = mock_and_stub(:items => [item],
401
+ :layouts => [],
402
+ :config => []
403
+ )
404
+ item.stubs(:site).returns(site)
405
+ rep = create_rep_for(item, :foo)
406
+ rep.assigns = {}
407
+ create_textual_filter
408
+
409
+ assert rep.binary?
410
+
411
+ def rep.filter_named(name)
412
+ Class.new(::Nanoc3::Filter) do
413
+ type :binary => :text
414
+ def run(content, params={})
415
+ "Some textual content"
416
+ end
417
+ end
418
+ end
419
+ rep.filter(:binary_to_text)
420
+ assert !rep.binary?
421
+
422
+ def rep.filter_named(name)
423
+ Class.new(::Nanoc3::Filter) do
424
+ type :text
425
+ def run(content, params={})
426
+ "Some textual content"
427
+ end
428
+ end
429
+ end
430
+ rep.filter(:text_filter)
431
+ assert !rep.binary?
432
+ end
433
+
434
+ def test_converted_binary_rep_cannot_be_filtered_with_binary_filters
435
+ item = create_binary_item
436
+ site = mock_and_stub(
437
+ :items => [item],
438
+ :layouts => [],
439
+ :config => []
440
+ )
441
+ item.stubs(:site).returns(site)
442
+ rep = create_rep_for(item, :foo)
443
+ rep.assigns = {}
444
+ create_binary_filter
445
+
446
+ assert rep.binary?
447
+ def rep.filter_named(name)
448
+ @filter ||= Class.new(::Nanoc3::Filter) do
449
+ type :binary => :text
450
+ def run(content, params={})
451
+ "Some textual content"
452
+ end
453
+ end
454
+ end
455
+ rep.filter(:binary_to_text)
456
+ refute rep.binary?
457
+ assert_raises(Nanoc3::Errors::CannotUseBinaryFilter) { rep.filter(:binary_filter) }
458
+ end
459
+
460
+ def test_new_content_should_be_frozen
461
+ filter_class = Class.new(::Nanoc3::Filter) do
462
+ def run(content, params={})
463
+ content.gsub!('foo', 'moo')
464
+ content
465
+ end
466
+ end
467
+
468
+ item = Nanoc3::Item.new("foo bar", {}, '/foo/')
469
+ rep = Nanoc3::ItemRep.new(item, :default)
470
+ rep.instance_eval { @filter_class = filter_class }
471
+ def rep.filter_named(name) ; @filter_class ; end
472
+
473
+ raised = false
474
+ begin
475
+ rep.filter(:whatever)
476
+ rescue => e
477
+ raised = true
478
+ assert_match /^can't modify frozen /, e.message
479
+ end
480
+ assert raised
481
+ end
482
+
483
+ def test_filter_should_freeze_content
484
+ filter_class = Class.new(::Nanoc3::Filter) do
485
+ def run(content, params={})
486
+ content.gsub!('foo', 'moo')
487
+ content
488
+ end
489
+ end
490
+
491
+ item = Nanoc3::Item.new("foo bar", {}, '/foo/')
492
+ rep = Nanoc3::ItemRep.new(item, :default)
493
+ rep.instance_eval { @filter_class = filter_class }
494
+ def rep.filter_named(name) ; @filter_class ; end
495
+
496
+ raised = false
497
+ begin
498
+ rep.filter(:erb)
499
+ rep.filter(:whatever)
500
+ rescue => e
501
+ raised = true
502
+ assert_match /^can't modify frozen /, e.message
503
+ end
504
+ assert raised
505
+ end
506
+
507
+ private
508
+
509
+ def create_binary_item
510
+ Nanoc3::Item.new(
511
+ "/a/file/name.dat", {}, '/',
512
+ :binary => true
513
+ )
514
+ end
515
+
516
+ def mock_and_stub(params)
517
+ m = mock
518
+ params.each do |method, return_value|
519
+ m.stubs(method.to_sym).returns( return_value )
520
+ end
521
+ m
522
+ end
523
+
524
+ def create_rep_for(item, name)
525
+ Nanoc3::ItemRep.new(item, name)
526
+ end
527
+
528
+ def create_textual_filter
529
+ f = create_filter(:text)
530
+ f.class_eval do
531
+ def run(content, params={})
532
+ ""
533
+ end
534
+ end
535
+ f
536
+ end
537
+
538
+ def create_binary_filter
539
+ f = create_filter(:binary)
540
+ f.class_eval do
541
+ def run(content, params={})
542
+ File.open(output_filename, 'w') { |io| io.write(content) }
543
+ end
544
+ end
545
+ f
546
+ end
547
+
548
+ def create_filter(type)
549
+ filter_klass = Class.new(Nanoc3::Filter)
550
+ filter_klass.type(type)
551
+ Nanoc3::Filter.register filter_klass, "#{type}_filter".to_sym
552
+ filter_klass
553
+ end
554
+
555
+ end