nanoc3 3.1.7 → 3.1.8

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 (91) hide show
  1. data/.gemtest +0 -0
  2. data/LICENSE +1 -1
  3. data/NEWS.md +9 -0
  4. data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
  5. data/lib/nanoc3/base/item.rb +1 -1
  6. data/lib/nanoc3/base/item_rep.rb +1 -0
  7. data/lib/nanoc3/base/layout.rb +1 -1
  8. data/lib/nanoc3/cli/base.rb +4 -2
  9. data/lib/nanoc3/cli/commands/view.rb +1 -0
  10. data/lib/nanoc3/data_sources/filesystem.rb +25 -6
  11. data/lib/nanoc3/data_sources/filesystem_unified.rb +5 -5
  12. data/lib/nanoc3/extra/validators/links.rb +1 -1
  13. data/lib/nanoc3/filters/rdiscount.rb +2 -1
  14. data/lib/nanoc3/filters/sass.rb +20 -8
  15. data/lib/nanoc3/filters/sass.rb.orig +75 -0
  16. data/lib/nanoc3.rb +1 -1
  17. data/nanoc3.gemspec +41 -0
  18. data/tasks/clean.rake +11 -0
  19. data/tasks/doc.rake +14 -0
  20. data/tasks/gem.rake +13 -0
  21. data/tasks/test.rake +38 -0
  22. data/test/base/core_ext/array_spec.rb +23 -0
  23. data/test/base/core_ext/hash_spec.rb +41 -0
  24. data/test/base/core_ext/string_spec.rb +27 -0
  25. data/test/base/test_code_snippet.rb +33 -0
  26. data/test/base/test_compiler.rb +410 -0
  27. data/test/base/test_compiler_dsl.rb +121 -0
  28. data/test/base/test_context.rb +33 -0
  29. data/test/base/test_data_source.rb +48 -0
  30. data/test/base/test_dependency_tracker.rb +510 -0
  31. data/test/base/test_directed_graph.rb +91 -0
  32. data/test/base/test_filter.rb +85 -0
  33. data/test/base/test_item.rb +141 -0
  34. data/test/base/test_item_rep.rb +953 -0
  35. data/test/base/test_layout.rb +44 -0
  36. data/test/base/test_notification_center.rb +36 -0
  37. data/test/base/test_plugin.rb +32 -0
  38. data/test/base/test_rule.rb +21 -0
  39. data/test/base/test_rule_context.rb +63 -0
  40. data/test/base/test_site.rb +366 -0
  41. data/test/cli/commands/test_compile.rb +12 -0
  42. data/test/cli/commands/test_create_item.rb +12 -0
  43. data/test/cli/commands/test_create_layout.rb +28 -0
  44. data/test/cli/commands/test_create_site.rb +24 -0
  45. data/test/cli/commands/test_help.rb +12 -0
  46. data/test/cli/commands/test_info.rb +12 -0
  47. data/test/cli/commands/test_update.rb +12 -0
  48. data/test/cli/test_logger.rb +12 -0
  49. data/test/data_sources/test_filesystem.rb +420 -0
  50. data/test/data_sources/test_filesystem_unified.rb +538 -0
  51. data/test/data_sources/test_filesystem_verbose.rb +359 -0
  52. data/test/extra/core_ext/test_enumerable.rb +32 -0
  53. data/test/extra/core_ext/test_time.rb +17 -0
  54. data/test/extra/deployers/test_rsync.rb +234 -0
  55. data/test/extra/test_auto_compiler.rb +482 -0
  56. data/test/extra/test_file_proxy.rb +21 -0
  57. data/test/extra/test_vcs.rb +24 -0
  58. data/test/extra/validators/test_links.rb +53 -0
  59. data/test/extra/validators/test_w3c.rb +49 -0
  60. data/test/filters/test_bluecloth.rb +20 -0
  61. data/test/filters/test_coderay.rb +46 -0
  62. data/test/filters/test_colorize_syntax.rb +56 -0
  63. data/test/filters/test_erb.rb +72 -0
  64. data/test/filters/test_erubis.rb +72 -0
  65. data/test/filters/test_haml.rb +98 -0
  66. data/test/filters/test_kramdown.rb +20 -0
  67. data/test/filters/test_less.rb +59 -0
  68. data/test/filters/test_markaby.rb +26 -0
  69. data/test/filters/test_maruku.rb +20 -0
  70. data/test/filters/test_rainpress.rb +31 -0
  71. data/test/filters/test_rdiscount.rb +33 -0
  72. data/test/filters/test_rdoc.rb +18 -0
  73. data/test/filters/test_redcloth.rb +20 -0
  74. data/test/filters/test_relativize_paths.rb +231 -0
  75. data/test/filters/test_rubypants.rb +20 -0
  76. data/test/filters/test_sass.rb +170 -0
  77. data/test/filters/test_sass.rb.orig +103 -0
  78. data/test/gem_loader.rb +11 -0
  79. data/test/helper.rb +99 -0
  80. data/test/helpers/test_blogging.rb +808 -0
  81. data/test/helpers/test_breadcrumbs.rb +83 -0
  82. data/test/helpers/test_capturing.rb +42 -0
  83. data/test/helpers/test_filtering.rb +108 -0
  84. data/test/helpers/test_html_escape.rb +18 -0
  85. data/test/helpers/test_link_to.rb +251 -0
  86. data/test/helpers/test_rendering.rb +109 -0
  87. data/test/helpers/test_tagging.rb +89 -0
  88. data/test/helpers/test_text.rb +26 -0
  89. data/test/helpers/test_xml_sitemap.rb +69 -0
  90. data/test/tasks/test_clean.rb +71 -0
  91. metadata +83 -8
@@ -0,0 +1,953 @@
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_not_outdated
14
+ # Mock item
15
+ item = Nanoc3::Item.new(
16
+ 'blah blah blah', {}, '/',
17
+ :mtime => Time.now-500
18
+ )
19
+
20
+ # Mock layouts
21
+ layouts = [ mock ]
22
+ layouts[0].stubs(:mtime).returns(Time.now-800)
23
+
24
+ # Mock code snippets
25
+ code_snippets = [ mock ]
26
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
27
+
28
+ # Mock site
29
+ site = mock
30
+ site.stubs(:layouts).returns(layouts)
31
+ site.stubs(:code_snippets).returns(code_snippets)
32
+ site.stubs(:config_mtime).returns(Time.now-1100)
33
+ site.stubs(:rules_mtime).returns(Time.now-1200)
34
+ item.stubs(:site).returns(site)
35
+
36
+ # Create output file
37
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
38
+ File.utime(Time.now-100, Time.now-200, 'output.html')
39
+
40
+ # Create rep
41
+ rep = Nanoc3::ItemRep.new(item, 'blah')
42
+ rep.instance_eval { @raw_path = 'output.html' }
43
+
44
+ # Test
45
+ refute(rep.outdated?)
46
+ ensure
47
+ FileUtils.rm_f('output.html')
48
+ end
49
+
50
+ def test_outdated_if_mtime_nil
51
+ # Mock item
52
+ item = Nanoc3::Item.new(
53
+ 'blah blah blah', {}, '/'
54
+ )
55
+
56
+ # Mock layouts
57
+ layouts = [ mock ]
58
+ layouts[0].stubs(:mtime).returns(Time.now-800)
59
+
60
+ # Mock code snippets
61
+ code_snippets = [ mock ]
62
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
63
+
64
+ # Mock site
65
+ site = mock
66
+ site.stubs(:layouts).returns(layouts)
67
+ site.stubs(:code_snippets).returns(code_snippets)
68
+ item.stubs(:site).returns(site)
69
+
70
+ # Create output file
71
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
72
+ File.utime(Time.now-100, Time.now-200, 'output.html')
73
+
74
+ # Create rep
75
+ rep = Nanoc3::ItemRep.new(item, 'blah')
76
+ rep.instance_eval { @raw_path = 'output.html' }
77
+
78
+ # Test
79
+ assert(rep.outdated?)
80
+ ensure
81
+ FileUtils.rm_f('output.html')
82
+ end
83
+
84
+ def test_outdated_if_force_outdated
85
+ # Mock item
86
+ item = Nanoc3::Item.new(
87
+ 'blah blah blah', {}, '/',
88
+ :mtime => Time.now-500, :binary => false
89
+ )
90
+
91
+ # Mock layouts
92
+ layouts = [ mock ]
93
+ layouts[0].stubs(:mtime).returns(Time.now-800)
94
+
95
+ # Mock code snippets
96
+ code_snippets = [ mock ]
97
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
98
+
99
+ # Mock site
100
+ site = mock
101
+ site.stubs(:layouts).returns(layouts)
102
+ site.stubs(:code_snippets).returns(code_snippets)
103
+ item.stubs(:site).returns(site)
104
+
105
+ # Create output file
106
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
107
+ File.utime(Time.now-100, Time.now-200, 'output.html')
108
+
109
+ # Create rep
110
+ rep = Nanoc3::ItemRep.new(item, 'blah')
111
+ rep.instance_eval { @raw_path = 'output.html' }
112
+ rep.instance_eval { @force_outdated = true }
113
+
114
+ # Test
115
+ assert(rep.outdated?)
116
+ ensure
117
+ FileUtils.rm_f('output.html')
118
+ end
119
+
120
+ def test_outdated_if_compiled_file_doesnt_exist
121
+ # Mock item
122
+ item = Nanoc3::Item.new(
123
+ 'blah blah blah', {}, '/',
124
+ :binary => false, :mtime => Time.now-500
125
+ )
126
+
127
+ # Mock layouts
128
+ layouts = [ mock ]
129
+ layouts[0].stubs(:mtime).returns(Time.now-800)
130
+
131
+ # Mock code snippets
132
+ code_snippets = [ mock ]
133
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
134
+
135
+ # Mock site
136
+ site = mock
137
+ site.stubs(:layouts).returns(layouts)
138
+ site.stubs(:code_snippets).returns(code_snippets)
139
+ item.stubs(:site).returns(site)
140
+
141
+ # Create rep
142
+ rep = Nanoc3::ItemRep.new(item, 'blah')
143
+ rep.instance_eval { @raw_path = 'output.html' }
144
+
145
+ # Test
146
+ assert(rep.outdated?)
147
+ ensure
148
+ FileUtils.rm_f('output.html')
149
+ end
150
+
151
+ def test_outdated_if_source_file_too_old
152
+ # Mock item
153
+ item = Nanoc3::Item.new(
154
+ 'blah blah blah', {}, '/',
155
+ :binary => false, :mtime => Time.now-100
156
+ )
157
+
158
+ # Mock layouts
159
+ layouts = [ mock ]
160
+ layouts[0].stubs(:mtime).returns(Time.now-800)
161
+
162
+ # Mock code snippets
163
+ code_snippets = [ mock ]
164
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
165
+
166
+ # Mock site
167
+ site = mock
168
+ site.stubs(:layouts).returns(layouts)
169
+ site.stubs(:code_snippets).returns(code_snippets)
170
+ item.stubs(:site).returns(site)
171
+
172
+ # Create output file
173
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
174
+ File.utime(Time.now-500, Time.now-600, 'output.html')
175
+
176
+ # Create rep
177
+ rep = Nanoc3::ItemRep.new(item, 'blah')
178
+ rep.instance_eval { @raw_path = 'output.html' }
179
+
180
+ # Test
181
+ assert(rep.outdated?)
182
+ ensure
183
+ FileUtils.rm_f('output.html')
184
+ end
185
+
186
+ def test_outdated_if_layouts_outdated
187
+ # Mock item
188
+ item = Nanoc3::Item.new(
189
+ 'blah blah blah', {}, '/',
190
+ :binary => false, :mtime => Time.now-500
191
+ )
192
+
193
+ # Mock layouts
194
+ layouts = [ mock ]
195
+ layouts[0].stubs(:mtime).returns(Time.now-100)
196
+
197
+ # Mock code snippets
198
+ code_snippets = [ mock ]
199
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
200
+
201
+ # Mock site
202
+ site = mock
203
+ site.stubs(:layouts).returns(layouts)
204
+ site.stubs(:code_snippets).returns(code_snippets)
205
+ item.stubs(:site).returns(site)
206
+
207
+ # Create output file
208
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
209
+ File.utime(Time.now-200, Time.now-300, 'output.html')
210
+
211
+ # Create rep
212
+ rep = Nanoc3::ItemRep.new(item, 'blah')
213
+ rep.instance_eval { @raw_path = 'output.html' }
214
+
215
+ # Test
216
+ assert(rep.outdated?)
217
+ ensure
218
+ FileUtils.rm_f('output.html')
219
+ end
220
+
221
+ def test_outdated_if_code_snippets_outdated
222
+ # Mock item
223
+ item = Nanoc3::Item.new(
224
+ 'blah blah blah', {}, '/',
225
+ :binary => false, :mtime => Time.now-500
226
+ )
227
+
228
+ # Mock layouts
229
+ layouts = [ mock ]
230
+ layouts[0].stubs(:mtime).returns(Time.now-800)
231
+
232
+ # Mock code snippets
233
+ code_snippets = [ mock ]
234
+ code_snippets[0].stubs(:mtime).returns(Time.now-100)
235
+
236
+ # Mock site
237
+ site = mock
238
+ site.stubs(:layouts).returns(layouts)
239
+ site.stubs(:code_snippets).returns(code_snippets)
240
+ item.stubs(:site).returns(site)
241
+
242
+ # Create output file
243
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
244
+ File.utime(Time.now-200, Time.now-300, 'output.html')
245
+
246
+ # Create rep
247
+ rep = Nanoc3::ItemRep.new(item, 'blah')
248
+ rep.instance_eval { @raw_path = 'output.html' }
249
+
250
+ # Test
251
+ assert(rep.outdated?)
252
+ ensure
253
+ FileUtils.rm_f('output.html')
254
+ end
255
+
256
+ def test_outdated_if_config_outdated
257
+ # Mock item
258
+ item = Nanoc3::Item.new(
259
+ 'blah blah blah', {}, '/',
260
+ :binary => false, :mtime => Time.now-500
261
+ )
262
+
263
+ # Mock layouts
264
+ layouts = [ mock ]
265
+ layouts[0].stubs(:mtime).returns(Time.now-800)
266
+
267
+ # Mock code snippets
268
+ code_snippets = [ mock ]
269
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
270
+
271
+ # Mock site
272
+ site = mock
273
+ site.stubs(:layouts).returns(layouts)
274
+ site.stubs(:code_snippets).returns(code_snippets)
275
+ site.stubs(:config_mtime).returns(Time.now-100)
276
+ item.stubs(:site).returns(site)
277
+
278
+ # Create output file
279
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
280
+ File.utime(Time.now-200, Time.now-300, 'output.html')
281
+
282
+ # Create rep
283
+ rep = Nanoc3::ItemRep.new(item, 'blah')
284
+ rep.instance_eval { @raw_path = 'output.html' }
285
+
286
+ # Test
287
+ assert(rep.outdated?)
288
+ ensure
289
+ FileUtils.rm_f('output.html')
290
+ end
291
+
292
+ def test_outdated_if_config_mtime_missing
293
+ # Mock item
294
+ item = Nanoc3::Item.new(
295
+ 'blah blah blah', {}, '/',
296
+ :binary => false, :mtime => Time.now-500
297
+ )
298
+
299
+ # Mock layouts
300
+ layouts = [ mock ]
301
+ layouts[0].stubs(:mtime).returns(Time.now-800)
302
+
303
+ # Mock code snippets
304
+ code_snippets = [ mock ]
305
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
306
+
307
+ # Mock site
308
+ site = mock
309
+ site.stubs(:layouts).returns(layouts)
310
+ site.stubs(:code_snippets).returns(code_snippets)
311
+ site.stubs(:config_mtime).returns(nil)
312
+ item.stubs(:site).returns(site)
313
+
314
+ # Create output file
315
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
316
+ File.utime(Time.now-200, Time.now-300, 'output.html')
317
+
318
+ # Create rep
319
+ rep = Nanoc3::ItemRep.new(item, 'blah')
320
+ rep.instance_eval { @raw_path = 'output.html' }
321
+
322
+ # Test
323
+ assert(rep.outdated?)
324
+ ensure
325
+ FileUtils.rm_f('output.html')
326
+ end
327
+
328
+ def test_outdated_if_rules_outdated
329
+ # Mock item
330
+ item = Nanoc3::Item.new(
331
+ 'blah blah blah', {}, '/',
332
+ :binary => false, :mtime => Time.now-500
333
+ )
334
+
335
+ # Mock layouts
336
+ layouts = [ mock ]
337
+ layouts[0].stubs(:mtime).returns(Time.now-800)
338
+
339
+ # Mock code snippets
340
+ code_snippets = [ mock ]
341
+ code_snippets[0].stubs(:mtime).returns(Time.now-900)
342
+
343
+ # Mock site
344
+ site = mock
345
+ site.stubs(:layouts).returns(layouts)
346
+ site.stubs(:code_snippets).returns(code_snippets)
347
+ site.stubs(:config_mtime).returns(Time.now-1100)
348
+ site.stubs(:rules_mtime).returns(Time.now-100)
349
+ item.stubs(:site).returns(site)
350
+
351
+ # Create output file
352
+ File.open('output.html', 'w') { |io| io.write('Testing testing 123...') }
353
+ File.utime(Time.now-200, Time.now-300, 'output.html')
354
+
355
+ # Create rep
356
+ rep = Nanoc3::ItemRep.new(item, 'blah')
357
+ rep.instance_eval { @raw_path = 'output.html' }
358
+
359
+ # Test
360
+ assert(rep.outdated?)
361
+ ensure
362
+ FileUtils.rm_f('output.html')
363
+ end
364
+
365
+ def test_compiled_content_with_only_last_available
366
+ # Create rep
367
+ item = Nanoc3::Item.new(
368
+ 'blah blah blah', {}, '/',
369
+ :binary => false, :mtime => Time.now-500
370
+ )
371
+ rep = Nanoc3::ItemRep.new(item, nil)
372
+ rep.instance_eval { @content = { :last => 'last content' } }
373
+ rep.expects(:compiled?).returns(true)
374
+
375
+ # Check
376
+ assert_equal 'last content', rep.compiled_content
377
+ end
378
+
379
+ def test_compiled_content_with_pre_and_last_available
380
+ # Create rep
381
+ item = Nanoc3::Item.new(
382
+ 'blah blah blah', {}, '/',
383
+ :binary => false, :mtime => Time.now-500
384
+ )
385
+ rep = Nanoc3::ItemRep.new(item, nil)
386
+ rep.instance_eval { @content = { :pre => 'pre content', :last => 'last content' } }
387
+ rep.expects(:compiled?).returns(true)
388
+
389
+ # Check
390
+ assert_equal 'pre content', rep.compiled_content
391
+ end
392
+
393
+ def test_compiled_content_with_custom_snapshot
394
+ # Create rep
395
+ item = Nanoc3::Item.new(
396
+ 'blah blah blah', {}, '/',
397
+ :binary => false, :mtime => Time.now-500
398
+ )
399
+ rep = Nanoc3::ItemRep.new(item, nil)
400
+ rep.instance_eval { @content = { :pre => 'pre content', :last => 'last content' } }
401
+ rep.expects(:compiled?).returns(true)
402
+
403
+ # Check
404
+ assert_equal 'last content', rep.compiled_content(:snapshot => :last)
405
+ end
406
+
407
+ def test_compiled_content_with_invalid_snapshot
408
+ # Create rep
409
+ item = Nanoc3::Item.new(
410
+ 'blah blah blah', {}, '/',
411
+ :binary => false, :mtime => Time.now-500
412
+ )
413
+ rep = Nanoc3::ItemRep.new(item, nil)
414
+ rep.instance_eval { @content = { :pre => 'pre content', :last => 'last content' } }
415
+ rep.expects(:compiled?).returns(true)
416
+
417
+ # Check
418
+ assert_equal nil, rep.compiled_content(:snapshot => :klsjflkasdfl)
419
+ end
420
+
421
+ def test_compiled_content_with_uncompiled_content
422
+ # Create rep
423
+ item = Nanoc3::Item.new(
424
+ "blah blah", {}, '/',
425
+ :binary => false
426
+ )
427
+ rep = Nanoc3::ItemRep.new(item, nil)
428
+ rep.expects(:compiled?).returns(false)
429
+
430
+ # Check
431
+ assert_raises(Nanoc3::Errors::UnmetDependency) do
432
+ rep.compiled_content
433
+ end
434
+ end
435
+
436
+ def test_filter
437
+ # Mock site
438
+ site = MiniTest::Mock.new
439
+ site.expect(:items, [])
440
+ site.expect(:config, [])
441
+ site.expect(:layouts, [])
442
+
443
+ # Mock item
444
+ item = Nanoc3::Item.new(
445
+ %[<%= '<%= "blah" %' + '>' %>], {}, '/',
446
+ :binary => false
447
+ )
448
+ item.site = site
449
+
450
+ # Create item rep
451
+ item_rep = Nanoc3::ItemRep.new(item, '/foo/')
452
+ item_rep.instance_eval do
453
+ @content[:raw] = item.raw_content
454
+ @content[:last] = @content[:raw]
455
+ end
456
+
457
+ # Filter once
458
+ item_rep.filter(:erb)
459
+ assert_equal(%[<%= "blah" %>], item_rep.instance_eval { @content[:last] })
460
+
461
+ # Filter twice
462
+ item_rep.filter(:erb)
463
+ assert_equal(%[blah], item_rep.instance_eval { @content[:last] })
464
+ end
465
+
466
+ def test_layout
467
+ # Mock layout
468
+ layout = mock
469
+ layout.stubs(:identifier).returns('/somelayout/')
470
+ layout.stubs(:raw_content).returns(%[<%= "blah" %>])
471
+
472
+ # Mock compiler
473
+ stack = mock
474
+ stack.expects(:push).with(layout)
475
+ stack.expects(:pop)
476
+ compiler = mock
477
+ compiler.stubs(:stack).returns(stack)
478
+ compiler.expects(:filter_for_layout).with(layout).returns([ :erb, {} ])
479
+
480
+ # Mock site
481
+ site = mock
482
+ site.stubs(:items).returns([])
483
+ site.stubs(:config).returns([])
484
+ site.stubs(:layouts).returns([ layout ])
485
+ site.stubs(:compiler).returns(compiler)
486
+
487
+ # Mock item
488
+ item = Nanoc3::Item.new(
489
+ "blah blah", {}, '/',
490
+ :binary => false
491
+ )
492
+ item.site = site
493
+
494
+ # Create item rep
495
+ item_rep = Nanoc3::ItemRep.new(item, '/foo/')
496
+ item_rep.instance_eval do
497
+ @content[:raw] = item.raw_content
498
+ @content[:last] = @content[:raw]
499
+ end
500
+
501
+ # Layout
502
+ item_rep.layout('/somelayout/')
503
+ assert_equal(%[blah], item_rep.instance_eval { @content[:last] })
504
+ end
505
+
506
+ def test_layout_multiple
507
+ # Mock layout 1
508
+ layouts = [ mock, mock ]
509
+ layouts[0].stubs(:identifier).returns('/one/')
510
+ layouts[0].stubs(:raw_content).returns('{one}<%= yield %>{/one}')
511
+ layouts[1].stubs(:identifier).returns('/two/')
512
+ layouts[1].stubs(:raw_content).returns('{two}<%= yield %>{/two}')
513
+
514
+ # Mock compiler
515
+ stack = mock
516
+ stack.stubs(:push)
517
+ stack.stubs(:pop)
518
+ compiler = mock
519
+ compiler.stubs(:stack).returns(stack)
520
+ compiler.stubs(:filter_for_layout).returns([ :erb, {} ])
521
+
522
+ # Mock site
523
+ site = mock
524
+ site.stubs(:items).returns([])
525
+ site.stubs(:config).returns([])
526
+ site.stubs(:layouts).returns(layouts)
527
+ site.stubs(:compiler).returns(compiler)
528
+
529
+ # Mock item
530
+ item = Nanoc3::Item.new('blah', {}, '/', :binary => false)
531
+ item.site = site
532
+
533
+ # Create item rep
534
+ item_rep = Nanoc3::ItemRep.new(item, '/foo/')
535
+ item_rep.instance_eval do
536
+ @content[:raw] = item.raw_content
537
+ @content[:last] = @content[:raw]
538
+ end
539
+
540
+ # Layout
541
+ item_rep.layout('/one/')
542
+ item_rep.layout('/two/')
543
+ assert_equal('blah', item_rep.instance_eval { @content[:pre] })
544
+ assert_equal('{two}{one}blah{/one}{/two}', item_rep.instance_eval { @content[:post] })
545
+ assert_equal('{two}{one}blah{/one}{/two}', item_rep.instance_eval { @content[:last] })
546
+ end
547
+
548
+ def test_snapshot
549
+ # Mock site
550
+ site = MiniTest::Mock.new
551
+ site.expect(:items, [])
552
+ site.expect(:config, [])
553
+ site.expect(:layouts, [])
554
+
555
+ # Mock item
556
+ item = Nanoc3::Item.new(
557
+ %[<%= '<%= "blah" %' + '>' %>], {}, '/foobar/',
558
+ :binary => false
559
+ )
560
+ item.site = site
561
+
562
+ # Create item rep
563
+ item_rep = Nanoc3::ItemRep.new(item, '/foo/')
564
+ item_rep.instance_eval do
565
+ @content[:raw] = item.raw_content
566
+ @content[:last] = @content[:raw]
567
+ end
568
+
569
+ # Filter while taking snapshots
570
+ item_rep.snapshot(:foo)
571
+ item_rep.filter(:erb)
572
+ item_rep.snapshot(:bar)
573
+ item_rep.filter(:erb)
574
+ item_rep.snapshot(:qux)
575
+
576
+ # Check snapshots
577
+ assert_equal(%[<%= '<%= "blah" %' + '>' %>], item_rep.instance_eval { @content[:foo] })
578
+ assert_equal(%[<%= "blah" %>], item_rep.instance_eval { @content[:bar] })
579
+ assert_equal(%[blah], item_rep.instance_eval { @content[:qux] })
580
+ end
581
+
582
+ def test_write
583
+ # Mock item
584
+ item = Nanoc3::Item.new(
585
+ "blah blah", {}, '/',
586
+ :binary => false
587
+ )
588
+
589
+ # Create rep
590
+ item_rep = Nanoc3::ItemRep.new(item, '/foo/')
591
+ item_rep.instance_eval { @content[:last] = 'Lorem ipsum, etc.' }
592
+ item_rep.raw_path = 'foo/bar/baz/quux.txt'
593
+
594
+ # Write
595
+ item_rep.write
596
+
597
+ # Check
598
+ assert(File.file?('foo/bar/baz/quux.txt'))
599
+ assert_equal('Lorem ipsum, etc.', File.read('foo/bar/baz/quux.txt'))
600
+ end
601
+
602
+ def test_write_should_not_touch_identical_textual_files
603
+ # Mock item
604
+ item = Nanoc3::Item.new(
605
+ "blah blah", {}, '/',
606
+ :binary => false
607
+ )
608
+
609
+ # Create rep
610
+ item_rep = Nanoc3::ItemRep.new(item, '/foo/')
611
+ def item_rep.generate_diff ; end
612
+ item_rep.instance_eval { @content[:last] = 'Lorem ipsum, etc.' }
613
+ item_rep.raw_path = 'foo/bar/baz/quux.txt'
614
+
615
+ # Write once
616
+ item_rep.write
617
+ a_long_time_ago = Time.now-1_000_000
618
+ File.utime(a_long_time_ago, a_long_time_ago, item_rep.raw_path)
619
+
620
+ # Write again
621
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
622
+ item_rep.write
623
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
624
+ end
625
+
626
+ def test_write_should_not_touch_identical_binary_files
627
+ # Create temporary source file
628
+ File.open('blahblah', 'w') { |io| io.write("Blah blah…") }
629
+ full_file_path = File.expand_path('blahblah')
630
+
631
+ # Mock item
632
+ item = Nanoc3::Item.new(
633
+ full_file_path, {}, '/',
634
+ :binary => true
635
+ )
636
+
637
+ # Create rep
638
+ item_rep = Nanoc3::ItemRep.new(item, '/foo/')
639
+ item_rep.raw_path = 'foo/bar/baz/quux'
640
+
641
+ # Write once
642
+ item_rep.write
643
+ a_long_time_ago = Time.now-1_000_000
644
+ File.utime(a_long_time_ago, a_long_time_ago, item_rep.raw_path)
645
+
646
+ # Write again
647
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
648
+ item_rep.write
649
+ assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
650
+ end
651
+
652
+ def test_filter_for_layout_with_unmapped_layout
653
+ # Mock site
654
+ site = mock
655
+
656
+ # Mock item
657
+ item = Nanoc3::Item.new(
658
+ "blah blah", {}, '/',
659
+ :binary => false
660
+ )
661
+ item.site = site
662
+
663
+ # Create rep
664
+ rep = Nanoc3::ItemRep.new(item, '/foo/')
665
+
666
+ # Create compiler
667
+ compiler = Nanoc3::Compiler.new(site)
668
+ site.expects(:compiler).returns(compiler)
669
+ compiler.layout_filter_mapping.replace({})
670
+
671
+ # Mock layout
672
+ layout = MiniTest::Mock.new
673
+ layout.expect(:identifier, '/some_layout/')
674
+
675
+ # Check
676
+ assert_raises(Nanoc3::Errors::CannotDetermineFilter) do
677
+ rep.send :filter_for_layout, layout
678
+ end
679
+ end
680
+
681
+ def test_hash
682
+ # Mock item
683
+ item = Nanoc3::Item.new(
684
+ "blah blah", {}, '/',
685
+ :binary => false
686
+ )
687
+
688
+ # Create rep
689
+ rep = Nanoc3::ItemRep.new(item, '/foo/')
690
+
691
+ # Create files
692
+ File.open('one', 'w') { |io| io.write('abc') }
693
+ File.open('two', 'w') { |io| io.write('abcdefghijklmnopqrstuvwxyz') }
694
+
695
+ # Test
696
+ assert_equal 'a9993e364706816aba3e25717850c26c9cd0d89d',
697
+ rep.send(:hash_for_file, 'one')
698
+ assert_equal '32d10c7b8cf96570ca04ce37f2a19d84240d3a89',
699
+ rep.send(:hash_for_file, 'two')
700
+ end
701
+
702
+ def test_filter_text_to_binary
703
+ # Mock item
704
+ item = Nanoc3::Item.new(
705
+ "blah blah", {}, '/',
706
+ :binary => false
707
+ )
708
+
709
+ # Create rep
710
+ rep = Nanoc3::ItemRep.new(item, '/foo/')
711
+ def rep.assigns ; {} ; end
712
+
713
+ # Create fake filter
714
+ def rep.filter_named(name)
715
+ @filter ||= Class.new(::Nanoc3::Filter) do
716
+ type :text => :binary
717
+ def run(content, params={})
718
+ File.open(output_filename, 'w') { |io| io.write(content) }
719
+ end
720
+ end
721
+ end
722
+
723
+ # Run
724
+ rep.filter(:foo)
725
+
726
+ # Check
727
+ assert rep.binary?
728
+ end
729
+
730
+ def test_filter_with_textual_rep_and_binary_filter
731
+ # Mock item
732
+ item = Nanoc3::Item.new(
733
+ "blah blah", {}, '/',
734
+ :binary => false
735
+ )
736
+
737
+ # Create rep
738
+ rep = Nanoc3::ItemRep.new(item, '/foo/')
739
+ def rep.assigns ; {} ; end
740
+
741
+ # Create fake filter
742
+ def rep.filter_named(name)
743
+ @filter ||= Class.new(::Nanoc3::Filter) do
744
+ type :binary
745
+ def run(content, params={})
746
+ File.open(output_filename, 'w') { |io| io.write(content) }
747
+ end
748
+ end
749
+ end
750
+
751
+ # Run
752
+ assert_raises ::Nanoc3::Errors::CannotUseBinaryFilter do
753
+ rep.filter(:foo)
754
+ end
755
+ end
756
+
757
+ def test_filter_get_compiled_content_from_binary_item
758
+ # Mock item
759
+ item = Nanoc3::Item.new(
760
+ "blah blah", {}, '/',
761
+ :binary => true
762
+ )
763
+
764
+ # Create rep
765
+ rep = Nanoc3::ItemRep.new(item, '/foo/')
766
+ def rep.compiled? ; true ; end
767
+
768
+ # Check
769
+ assert_nil rep.compiled_content
770
+ end
771
+
772
+ def test_using_textual_filters_on_binary_reps_raises
773
+ item = create_binary_item
774
+ site = mock_and_stub(:items => [item],
775
+ :layouts => [],
776
+ :config => []
777
+ )
778
+ item.stubs(:site).returns(site)
779
+ rep = create_rep_for(item, '/foo/')
780
+ create_textual_filter
781
+
782
+ assert rep.binary?
783
+ assert_raises(Nanoc3::Errors::CannotUseTextualFilter) { rep.filter(:text_filter) }
784
+ end
785
+
786
+ def test_writing_binary_reps_uses_content_in_last_filename
787
+ require 'tempfile'
788
+
789
+ in_filename = 'nanoc-in'
790
+ out_filename = 'nanoc-out'
791
+ file_content = 'Some content for this test'
792
+ File.open(in_filename, 'w') { |io| io.write(file_content) }
793
+
794
+ item = create_binary_item
795
+ rep = create_rep_for(item, /foo/)
796
+ rep.instance_eval { @filenames[:last] = in_filename }
797
+ rep.raw_path = out_filename
798
+
799
+ rep.write
800
+
801
+ assert(File.exist?(out_filename))
802
+ assert_equal(file_content, File.read(out_filename))
803
+ end
804
+
805
+ def test_converted_binary_rep_can_be_layed_out
806
+ layout = mock_and_stub(
807
+ :identifier => '/somelayout/',
808
+ :raw_content => %[<%= "blah" %> <%= yield %>]
809
+ )
810
+
811
+ # Mock compiler
812
+ stack = mock_and_stub(:pop => layout)
813
+ stack.stubs(:push).returns(stack)
814
+ compiler = mock_and_stub(
815
+ :stack => stack,
816
+ :filter_for_layout => [ :erb, {} ]
817
+ )
818
+
819
+ # Mock site
820
+ site = mock_and_stub(
821
+ :items => [],
822
+ :config => [],
823
+ :layouts => [ layout ],
824
+ :compiler => compiler
825
+ )
826
+
827
+ item = create_binary_item
828
+ item.site = site
829
+
830
+ rep = create_rep_for(item, '/foo/')
831
+ def rep.filter_named(name)
832
+ @filter ||= Class.new(::Nanoc3::Filter) do
833
+ type :binary => :text
834
+ def run(content, params={})
835
+ "Some textual content"
836
+ end
837
+ end
838
+ end
839
+
840
+ rep.filter(:binary_to_text)
841
+ rep.layout('/somelayout/')
842
+ assert_equal('blah Some textual content', rep.instance_eval { @content[:last] })
843
+ end
844
+
845
+ def test_converted_binary_rep_can_be_filterd_with_textual_filters
846
+ item = create_binary_item
847
+ site = mock_and_stub(:items => [item],
848
+ :layouts => [],
849
+ :config => []
850
+ )
851
+ item.stubs(:site).returns(site)
852
+ rep = create_rep_for(item, /foo/)
853
+ create_textual_filter
854
+
855
+ assert rep.binary?
856
+
857
+ def rep.filter_named(name)
858
+ Class.new(::Nanoc3::Filter) do
859
+ type :binary => :text
860
+ def run(content, params={})
861
+ "Some textual content"
862
+ end
863
+ end
864
+ end
865
+ rep.filter(:binary_to_text)
866
+ assert !rep.binary?
867
+
868
+ def rep.filter_named(name)
869
+ Class.new(::Nanoc3::Filter) do
870
+ type :text
871
+ def run(content, params={})
872
+ "Some textual content"
873
+ end
874
+ end
875
+ end
876
+ rep.filter(:text_filter)
877
+ assert !rep.binary?
878
+ end
879
+
880
+ def test_converted_binary_rep_cannot_be_filterd_with_binary_filters
881
+ item = create_binary_item
882
+ site = mock_and_stub(
883
+ :items => [item],
884
+ :layouts => [],
885
+ :config => []
886
+ )
887
+ item.stubs(:site).returns(site)
888
+ rep = create_rep_for(item, '/foo/')
889
+ create_binary_filter
890
+
891
+ assert rep.binary?
892
+ def rep.filter_named(name)
893
+ @filter ||= Class.new(::Nanoc3::Filter) do
894
+ type :binary => :text
895
+ def run(content, params={})
896
+ "Some textual content"
897
+ end
898
+ end
899
+ end
900
+ rep.filter(:binary_to_text)
901
+ assert ! rep.binary?
902
+ assert_raises(Nanoc3::Errors::CannotUseBinaryFilter) { rep.filter(:binary_filter) }
903
+ end
904
+
905
+ private
906
+
907
+ def create_binary_item
908
+ Nanoc3::Item.new(
909
+ "/a/file/name.dat", {}, '/',
910
+ :binary => true
911
+ )
912
+ end
913
+
914
+ def mock_and_stub(params)
915
+ m = mock
916
+ params.each do |method, return_value|
917
+ m.stubs(method.to_sym).returns( return_value )
918
+ end
919
+ m
920
+ end
921
+
922
+ def create_rep_for(item, name)
923
+ Nanoc3::ItemRep.new(item, name)
924
+ end
925
+
926
+ def create_textual_filter
927
+ f = create_filter(:text)
928
+ f.class_eval do
929
+ def run(content, params={})
930
+ ""
931
+ end
932
+ end
933
+ f
934
+ end
935
+
936
+ def create_binary_filter
937
+ f = create_filter(:binary)
938
+ f.class_eval do
939
+ def run(content, params={})
940
+ File.open(output_filename, 'w') { |io| io.write(content) }
941
+ end
942
+ end
943
+ f
944
+ end
945
+
946
+ def create_filter(type)
947
+ filter_klass = Class.new(Nanoc3::Filter)
948
+ filter_klass.type(type)
949
+ Nanoc3::Filter.register filter_klass, "#{type}_filter".to_sym
950
+ filter_klass
951
+ end
952
+
953
+ end