henshin 0.4.2 → 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/LICENCE +18 -0
  2. data/README.md +133 -0
  3. data/Rakefile +6 -51
  4. data/bin/henshin +127 -134
  5. data/lib/henshin.rb +163 -38
  6. data/lib/henshin/compressor.rb +31 -0
  7. data/lib/henshin/compressors/css.rb +20 -0
  8. data/lib/henshin/compressors/js.rb +20 -0
  9. data/lib/henshin/core_ext.rb +69 -0
  10. data/lib/henshin/error.rb +28 -0
  11. data/lib/henshin/file.rb +67 -0
  12. data/lib/henshin/files/abstract.rb +102 -0
  13. data/lib/henshin/files/attributes.rb +31 -0
  14. data/lib/henshin/files/empty_template.rb +24 -0
  15. data/lib/henshin/files/physical.rb +117 -0
  16. data/lib/henshin/files/post.rb +64 -0
  17. data/lib/henshin/files/templatable.rb +29 -0
  18. data/lib/henshin/files/template.rb +45 -0
  19. data/lib/henshin/files/tilt.rb +50 -0
  20. data/lib/henshin/files/tilt_template.rb +45 -0
  21. data/lib/henshin/package.rb +27 -0
  22. data/lib/henshin/packages/script.rb +23 -0
  23. data/lib/henshin/packages/style.rb +20 -0
  24. data/lib/henshin/path.rb +143 -0
  25. data/lib/henshin/publisher.rb +42 -0
  26. data/lib/henshin/publishers/sftp.rb +79 -0
  27. data/lib/henshin/reader.rb +68 -0
  28. data/lib/henshin/safety.rb +74 -0
  29. data/lib/henshin/scope.rb +55 -0
  30. data/lib/henshin/site.rb +291 -228
  31. data/lib/henshin/ui.rb +35 -0
  32. data/lib/henshin/version.rb +3 -0
  33. data/lib/henshin/writer.rb +43 -0
  34. data/lib/rack/henshin.rb +113 -0
  35. data/site/assets/scripts/config.js +11 -0
  36. data/site/assets/styles/_mixins.sass +16 -0
  37. data/site/assets/styles/screen.sass +198 -0
  38. data/site/config.yml +13 -0
  39. data/site/drafts/a-work-in-progress.md +5 -0
  40. data/site/feed.xml.slim +19 -0
  41. data/site/index.html.slim +28 -0
  42. data/site/init.rb +33 -0
  43. data/site/posts/1-hello-world.md +46 -0
  44. data/site/posts/2-code-testing.md +36 -0
  45. data/site/posts/3-style-test.md +80 -0
  46. data/site/templates/default.slim +11 -0
  47. data/site/templates/post.slim +30 -0
  48. data/site/test.html.md +7 -0
  49. data/spec/helper.rb +70 -0
  50. data/spec/henshin/compressor_spec.rb +25 -0
  51. data/spec/henshin/compressors/css_spec.rb +22 -0
  52. data/spec/henshin/compressors/js_spec.rb +22 -0
  53. data/spec/henshin/core_ext_spec.rb +59 -0
  54. data/spec/henshin/error_spec.rb +22 -0
  55. data/spec/henshin/file_spec.rb +28 -0
  56. data/spec/henshin/files/abstract_spec.rb +98 -0
  57. data/spec/henshin/files/attributes_spec.rb +25 -0
  58. data/spec/henshin/files/empty_template_spec.rb +11 -0
  59. data/spec/henshin/files/physical_spec.rb +55 -0
  60. data/spec/henshin/files/post_spec.rb +66 -0
  61. data/spec/henshin/files/template_spec.rb +53 -0
  62. data/spec/henshin/files/tilt_spec.rb +59 -0
  63. data/spec/henshin/package_spec.rb +24 -0
  64. data/spec/henshin/packages/script_spec.rb +17 -0
  65. data/spec/henshin/packages/style_spec.rb +17 -0
  66. data/spec/henshin/path_spec.rb +56 -0
  67. data/spec/henshin/publisher_spec.rb +44 -0
  68. data/spec/henshin/publishers/sftp_spec.rb +21 -0
  69. data/spec/henshin/reader_spec.rb +55 -0
  70. data/spec/henshin/safety_spec.rb +66 -0
  71. data/spec/henshin/scope_spec.rb +33 -0
  72. data/spec/henshin/site_spec.rb +142 -0
  73. data/spec/henshin/ui_spec.rb +26 -0
  74. data/spec/henshin/writer_spec.rb +26 -0
  75. metadata +352 -197
  76. data/.gitignore +0 -27
  77. data/LICENSE +0 -20
  78. data/README.markdown +0 -35
  79. data/VERSION +0 -1
  80. data/henshin.gemspec +0 -121
  81. data/lib/henshin/archive.rb +0 -133
  82. data/lib/henshin/exec/files.rb +0 -46
  83. data/lib/henshin/ext.rb +0 -55
  84. data/lib/henshin/gen.rb +0 -154
  85. data/lib/henshin/labels.rb +0 -144
  86. data/lib/henshin/plugin.rb +0 -100
  87. data/lib/henshin/plugins/highlight.rb +0 -24
  88. data/lib/henshin/plugins/liquid.rb +0 -61
  89. data/lib/henshin/plugins/maruku.rb +0 -18
  90. data/lib/henshin/plugins/sass.rb +0 -24
  91. data/lib/henshin/plugins/textile.rb +0 -18
  92. data/lib/henshin/post.rb +0 -156
  93. data/lib/henshin/static.rb +0 -33
  94. data/test/helper.rb +0 -44
  95. data/test/site/css/_reset.sass +0 -34
  96. data/test/site/css/print.css +0 -12
  97. data/test/site/css/screen.sass +0 -70
  98. data/test/site/includes/head.html +0 -1
  99. data/test/site/index.html +0 -23
  100. data/test/site/layouts/archive_date.html +0 -20
  101. data/test/site/layouts/archive_month.html +0 -24
  102. data/test/site/layouts/archive_year.html +0 -26
  103. data/test/site/layouts/category_index.html +0 -27
  104. data/test/site/layouts/category_page.html +0 -20
  105. data/test/site/layouts/main.html +0 -13
  106. data/test/site/layouts/post.html +0 -36
  107. data/test/site/layouts/tag_index.html +0 -27
  108. data/test/site/layouts/tag_page.html +0 -20
  109. data/test/site/options.yaml +0 -17
  110. data/test/site/plugins/test.rb +0 -3
  111. data/test/site/posts/Testing-Stuff.markdown +0 -14
  112. data/test/site/posts/Textile-Test.textile +0 -7
  113. data/test/site/posts/cat/test.markdown +0 -6
  114. data/test/site/posts/lorem-ipsum.markdown +0 -7
  115. data/test/site/posts/same-date.markdown +0 -7
  116. data/test/site/static.html +0 -19
  117. data/test/suite.rb +0 -4
  118. data/test/test_gen.rb +0 -98
  119. data/test/test_options.rb +0 -73
  120. data/test/test_post.rb +0 -67
  121. data/test/test_site.rb +0 -197
  122. data/test/test_static.rb +0 -13
@@ -0,0 +1,59 @@
1
+ require_relative '../helper'
2
+
3
+ describe Hash do
4
+
5
+ describe '#symbolise' do
6
+ it 'changes string keys to symbols' do
7
+ {'a' => 1}.symbolise.must_equal :a => 1
8
+ end
9
+
10
+ it 'works recursively' do
11
+ {'a' => {'b' => 2}}.symbolise.must_equal :a => {:b => 2}
12
+ end
13
+ end
14
+
15
+ describe '#deep_merge' do
16
+ it 'merges a hash into another hash' do
17
+ a = {a: {b: 1, d: 4}}
18
+ b = {a: {b: 2, c: 3}}
19
+ c = {a: {b: 2, c: 3, d: 4}}
20
+
21
+ a.deep_merge(b).must_equal c
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ describe Pathname do
28
+
29
+ describe '#same_type?' do
30
+ it 'returns true if both absolute' do
31
+ a, b = Pathname.new('/a'), Pathname.new('/b')
32
+ a.must_be :same_type?, b
33
+ end
34
+
35
+ it 'returns true if both relative' do
36
+ a, b = Pathname.new('a'), Pathname.new('b')
37
+ a.must_be :same_type?, b
38
+ end
39
+
40
+ it 'returns false otherwise' do
41
+ a, b = Pathname.new('a'), Pathname.new('/b')
42
+ a.wont_be :same_type?, b
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ describe String do
49
+
50
+ describe '#slugify' do
51
+ it 'turns a string into a nice slug' do
52
+ s = "Oh god, wait? I've got wierd bits in-this=string... "
53
+ r = "oh-god-wait-ive-got-wierd-bits-in-this-string"
54
+
55
+ s.slugify.must_equal r
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,22 @@
1
+ require_relative '../helper'
2
+
3
+ describe Henshin::Error do
4
+
5
+ subject { Henshin::Error }
6
+
7
+ describe '.prettify' do
8
+ it 'shows a nice reduced error' do
9
+ err = nil
10
+ begin
11
+ raise StandardError
12
+ rescue => induced
13
+ err = induced
14
+ end
15
+
16
+ subject.stubs(:exit)
17
+
18
+ # ...
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,28 @@
1
+ require_relative '../helper'
2
+
3
+ describe Henshin::File do
4
+
5
+ let(:site) { test_site }
6
+ subject { Henshin::File }
7
+
8
+ describe 'registering new file type' do
9
+ it 'is picked up by .create' do
10
+ klass = Class.new(subject::Physical)
11
+ subject.register /\.test/, klass
12
+
13
+ file = subject.create(site, Pathname.new('something.test'))
14
+ file.class.must_equal klass
15
+ end
16
+ end
17
+
18
+ describe 'registering new module to apply' do
19
+ it 'is picked up by .create' do
20
+ mod = Module.new
21
+ subject.apply /\.apply/, mod
22
+
23
+ file = subject.create(site, Pathname.new('something.apply'))
24
+ file.singleton_class.ancestors.must_include mod
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,98 @@
1
+ require_relative '../../helper'
2
+
3
+ describe Henshin::File::Abstract do
4
+
5
+ let(:subclass) {
6
+ Class.new(Henshin::File::Abstract) {
7
+ def path
8
+ @path ||= Object.new
9
+ end
10
+ }
11
+ }
12
+
13
+ let(:site) { test_site }
14
+
15
+ subject { subclass.new(site) }
16
+
17
+
18
+ describe '#site' do
19
+ it 'can not be written' do
20
+ subject.site.write(Object.new).must_equal nil
21
+ end
22
+ end
23
+
24
+ it 'returns a String for #text' do
25
+ subject.text.must_be_kind_of String
26
+ end
27
+
28
+ it 'has a #permalink' do
29
+ subject.path.expects(:permalink).returns('here')
30
+ subject.permalink.must_equal 'here'
31
+ end
32
+
33
+ it 'has a #url' do
34
+ subject.path.expects(:url).returns('here')
35
+ subject.url.must_equal 'here'
36
+ end
37
+
38
+ it 'has an #extension' do
39
+ subject.path.expects(:extension).returns('.txt')
40
+ subject.extension.must_equal '.txt'
41
+ end
42
+
43
+ describe '#write' do
44
+ it 'writes the file' do
45
+ writer = mock { expects(:write).with(Pathname.new('here'), 'text') }
46
+
47
+ subject.stubs(:text).returns('text')
48
+ subject.stubs(:permalink).returns('/here')
49
+ Henshin::UI.expects(:wrote).with('/here')
50
+
51
+ subject.write writer
52
+ end
53
+
54
+ it 'passes time taken to UI if in profile mode' do
55
+ with_profiling! do
56
+ writer = mock { expects(:write).with(Pathname.new('here'), 'text') }
57
+
58
+ Time.stubs(:now).returns(5, 6)
59
+
60
+ subject.stubs(:text).returns('text')
61
+ subject.stubs(:permalink).returns('/here')
62
+ Henshin::UI.expects(:wrote).with('/here', 1)
63
+
64
+ subject.write writer
65
+ end
66
+ end
67
+
68
+ # it 'raises a pretty error if problem occurs' do
69
+ # writer = mock()
70
+ # def writer.write(where, what)
71
+ # raise IOError,'Problems, what did you expect?'
72
+ # end
73
+
74
+ # proc {
75
+ # subject.stubs(:permalink).returns(:here)
76
+ # subject.write(writer)
77
+ # }.must_output
78
+ # end
79
+
80
+ it 'does nothing if not #writeable?' do
81
+ subject.stubs(:writeable?).returns(false)
82
+ writer = mock { expects(:write).never }
83
+
84
+ subject.write writer
85
+ end
86
+ end
87
+
88
+ describe '#<=>' do
89
+ it 'compares permalinks' do
90
+ a = subject.dup
91
+ a.stubs(:permalink).returns('a')
92
+ b = subject.dup
93
+ b.stubs(:permalink).returns('b')
94
+ a.must_be :<=>, b, -1
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,25 @@
1
+ require_relative '../../helper'
2
+
3
+ describe Henshin::File::Attributes do
4
+
5
+ subject {
6
+ obj = Object.new
7
+ obj.extend Henshin::File::Attributes
8
+ obj
9
+ }
10
+
11
+ describe '#requires' do
12
+ it 'adds a required key to the list' do
13
+ subject.requires :apples
14
+ subject.required.must_include :apples
15
+ end
16
+ end
17
+
18
+ describe '#required' do
19
+ it 'returns the required keys' do
20
+ subject.requires :apples, :oranges
21
+ subject.required.to_a.must_equal [:apples, :oranges]
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,11 @@
1
+ require_relative '../../helper'
2
+
3
+ describe Henshin::File::EmptyTemplate do
4
+
5
+ subject { Henshin::File::EmptyTemplate.new }
6
+
7
+ it 'has #name of "none"' do
8
+ subject.name.must_equal 'none'
9
+ end
10
+
11
+ end
@@ -0,0 +1,55 @@
1
+ require_relative '../../helper'
2
+
3
+ describe Henshin::File::Physical do
4
+
5
+ let(:text) {
6
+ <<EOS
7
+ ---
8
+ title: Test
9
+ date: 2012-01-03
10
+ ---
11
+
12
+ So, here we are. A test.
13
+ EOS
14
+ }
15
+
16
+ subject { Henshin::File::Physical }
17
+
18
+ let(:site) { DummySite.new(test_path) }
19
+ let(:file) { Henshin::File::Physical.new(site, test_path + 'test.txt') }
20
+
21
+ before {
22
+ file.instance_variable_get(:@path).stubs(:read).returns(text)
23
+ }
24
+
25
+ describe '#method_missing' do
26
+ it 'accesses yaml attributes' do
27
+ file.title.must_equal 'Test'
28
+ file.date.must_equal Date.new(2012, 1, 3)
29
+ end
30
+ end
31
+
32
+ describe '#text' do
33
+ it 'returns the text' do
34
+ file.text.must_equal "\nSo, here we are. A test.\n"
35
+ end
36
+ end
37
+
38
+ describe '#permalink' do
39
+ it 'returns the permalink' do
40
+ file.permalink.must_equal '/test.txt'
41
+ end
42
+
43
+ it 'returns yaml permalink if set' do
44
+ file.stubs(:yaml).returns(permalink: '/cool.permalink')
45
+ file.permalink.must_equal '/cool.permalink'
46
+ end
47
+
48
+ it 'removes input file extension if it exists' do
49
+ file = subject.new(site, test_path + 'index.html.slim')
50
+ file.instance_variable_get(:@path).stubs(:read).returns(text)
51
+ file.permalink.must_equal '/index.html'
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,66 @@
1
+ require_relative '../../helper'
2
+
3
+ describe Henshin::File::Post do
4
+
5
+ let(:text) {
6
+ <<EOS
7
+ ---
8
+ title: Hello World
9
+ date: 2012-01-03
10
+ tag: Test
11
+ ---
12
+
13
+ So, a post. Finally?
14
+ EOS
15
+ }
16
+
17
+ let(:site) { test_site }
18
+
19
+ subject { Henshin::File::Post }
20
+ let(:post) {
21
+ file = Henshin::File::Physical.new(site, Pathname.new('posts/1-hello-world.md'))
22
+ file.extend subject
23
+ file
24
+ }
25
+
26
+ before {
27
+ post.instance_variable_get(:@path).stubs(:read).returns(text)
28
+ }
29
+
30
+ describe '#text' do
31
+ it 'returns the text, rendered, templated' do
32
+ post.text.must_equal "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\" /><link href=\"&#47;style.css\" rel=\"stylesheet\" /><title>Hello World</title></head><body onload=\"window.scrollBy(0,54);\"><nav><a class=\"home\" href=\"&#47;\">Home</a></nav><header><h1>Hello World</h1></header>
33
+ So, a post. Finally?
34
+ <div class=\"meta\"><span class=\"date\">&mdash; </span></div><script src=\"http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js\"></script><script src=\"http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js\"></script><script src=\"&#47;script.js\"></script></body></html>"
35
+ end
36
+ end
37
+
38
+ it 'returns date suitable for rss with #rss_date' do
39
+ post.rss_date.must_equal "Tue, 3 Jan 2012 00:00:00 +0000"
40
+ end
41
+
42
+ describe 'next post' do
43
+ let(:n) { Object.new }
44
+
45
+ it 'can set and get next post' do
46
+ post.next = n
47
+ post.next_post.must_equal n
48
+ end
49
+ end
50
+
51
+ describe 'prev post' do
52
+ let(:p) { Object.new }
53
+
54
+ it 'can set and get previous post' do
55
+ post.prev = p
56
+ post.prev_post.must_equal p
57
+ end
58
+ end
59
+
60
+ describe '#path' do
61
+ it 'returns the path' do
62
+ post.path.must_be :===, '/hello-world/index.html'
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,53 @@
1
+ require_relative '../../helper'
2
+
3
+ describe Henshin::File::Template do
4
+
5
+ subject { Henshin::File::Template }
6
+ let(:site) { test_site }
7
+ let(:path) { Pathname.new('templates/default.slim') }
8
+ let(:template) {
9
+ f = Henshin::File::TiltTemplate.new(site, path)
10
+ f.extend subject
11
+ f
12
+ }
13
+
14
+ describe '#name' do
15
+ it 'returns the name' do
16
+ template.name.must_equal 'default'
17
+ end
18
+ end
19
+
20
+ describe '#template' do
21
+ it 'renders the template with the given data' do
22
+ path.stubs(:read).returns <<EOS
23
+ h1 = title
24
+ == yield
25
+ EOS
26
+
27
+ other = Henshin::File::Physical.new(site, 'sometest.md')
28
+ other.stubs(:title).returns('Cool post')
29
+ other.stubs(:text).returns('<p>Hey so here is the text.</p>')
30
+ other.instance_variable_get(:@path).stubs(:read).returns <<EOS
31
+ ---
32
+ title: Cool post
33
+ ---
34
+
35
+ Hey so here is the text.
36
+ EOS
37
+
38
+ template.template(other).must_equal "<h1>Cool post</h1><p>Hey so here is the text.</p>"
39
+ end
40
+
41
+ it 'disallows writing' do
42
+ path.stubs(:read).returns <<EOS
43
+ p = write(Object.new)
44
+ EOS
45
+
46
+ other = Henshin::File::Physical.new(site, Pathname.new('sometest.md'))
47
+ other.instance_variable_get(:@path).stubs(:read).returns("")
48
+
49
+ template.template(other).must_equal "<p></p>"
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,59 @@
1
+ require_relative '../../helper'
2
+
3
+ describe Henshin::File::Tilt do
4
+
5
+ subject { Henshin::File::Tilt }
6
+ let(:site) { test_site }
7
+
8
+ describe '#text' do
9
+ it 'uses tilt to render the contents of the file' do
10
+ path = Pathname.new('some-file.md')
11
+ path.stubs(:read).returns <<EOS
12
+ ---
13
+ title: Some File
14
+ ---
15
+
16
+ A _lot_ of markdown is __good__ for `testing`.
17
+ EOS
18
+
19
+ file = subject.new(site, path)
20
+
21
+ file.text.must_equal "<p>A <em>lot</em> of markdown is <strong>good</strong> for <code>testing</code>.</p>\n"
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ describe Henshin::File::TiltTemplate do
28
+
29
+ subject { Henshin::File::TiltTemplate }
30
+ let(:site) { test_site }
31
+
32
+ describe '#text' do
33
+ it 'uses tilt to render the template' do
34
+ path = Pathname.new('some-file.md')
35
+ path.stubs(:read).returns <<EOS
36
+ ---
37
+ title: Some File
38
+ ---
39
+
40
+ A _lot_ of markdown is __good__ for `testing`.
41
+ EOS
42
+
43
+ file = Henshin::File::Tilt.new(site, path)
44
+
45
+ path = Pathname.new('template/page.slim')
46
+ path.stubs(:read).returns <<EOS
47
+ h1 = title
48
+ == yield
49
+ EOS
50
+
51
+ tmpl = subject.new(site, path)
52
+
53
+ tmpl.stubs(:data).returns(file)
54
+ tmpl.text.must_equal "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\" /><link href=\"&#47;style.css\" rel=\"stylesheet\" /><title>Some File</title></head><body><p>A <em>lot</em> of markdown is <strong>good</strong> for <code>testing</code>.</p>
55
+ <script src=\"&#47;script.js\"></script></body></html>"
56
+ end
57
+ end
58
+
59
+ end