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
data/LICENCE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2012 Joshua Hawxwell
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,133 @@
1
+ # Henshin
2
+
3
+ Yes it's another static site generator. Out of the box it's set up for blogging
4
+ but henshin is so flexible and configurable it is useful in most situations
5
+ where you need to generate a static site from some data.
6
+
7
+
8
+ ## Usage
9
+
10
+ First install the gem (it requires ruby 1.9.3),
11
+
12
+ ``` bash
13
+ $ gem install henshin
14
+ ```
15
+
16
+ Next create an empty site,
17
+
18
+ ``` bash
19
+ $ henshin new my_site
20
+ ```
21
+
22
+ Now we can start a server to view the site,
23
+
24
+ ``` bash
25
+ $ cd my_site
26
+ $ henshin view
27
+ ...
28
+ ```
29
+
30
+ Henshin rebuilds the pages when requested so edit `index.slim.html` and reload
31
+ the page now.
32
+
33
+ To build the site into the `build` folder, run:
34
+
35
+ ``` bash
36
+ $ henshin build
37
+ ```
38
+
39
+ But one of the key features of henshin is that you (probably) __never__ need to
40
+ run `henshin build`. Henshin can upload your site straight to a server using
41
+ sftp. To set it up you just need to add this to the `config.yml` file,
42
+
43
+ ``` yaml
44
+ publish:
45
+ host: sftp.myserver.com
46
+ base: /path/to/public
47
+ user: username
48
+ ```
49
+
50
+ And when running `henshin publish` you will be prompted for the password.
51
+
52
+
53
+ ## Structure
54
+
55
+ Sites have a lot in common. Henshin forces some conventions but not too many.
56
+
57
+ ### ./config.yml
58
+
59
+ Contains configuration and data for your site. Anything in here is accessible in
60
+ templates and files. For instance you could add,
61
+
62
+ ``` yaml
63
+ likes:
64
+ - Italian food
65
+ - Football
66
+ - ...
67
+ ```
68
+
69
+ So that you can add a list of things you like to the homepage,
70
+
71
+ ``` slim
72
+ ul
73
+ h1 I like
74
+ - for like in site.likes
75
+ li = like
76
+ ```
77
+
78
+ ### ./init.rb
79
+
80
+ This file lets you alter Henshin in any way you imagine.
81
+
82
+ ### ./posts/
83
+
84
+ These are your published posts. They must contain yaml frontmatter with at least
85
+ title and date attributes.
86
+
87
+ ``` md
88
+ ---
89
+ title: My First Post
90
+ date: 2012-01-01
91
+ ---
92
+
93
+ So, ...
94
+ ```
95
+
96
+ ### ./drafts/
97
+
98
+ These are your unpublished posts and will not be in your built site. They are
99
+ shown when previewing your site with `henshin view` so it is easy to see what
100
+ they will look like when finished.
101
+
102
+ ### ./templates/
103
+
104
+ Most files will try to use a template, the default template used is called
105
+ "default", posts will attempt to use the "post" template if it exists. And you
106
+ can force a file to use a different template by setting `template:` in the
107
+ yaml frontmatter, for instance
108
+
109
+ ``` md
110
+ ---
111
+ ...
112
+ template: strange
113
+ ---
114
+ ...
115
+ ```
116
+
117
+ ### ./assets/scripts/
118
+
119
+ Contains scripts (these can be javascript or coffeescript). They are combined
120
+ and minimised when you build your site.
121
+
122
+ ### ./assets/styles/
123
+
124
+ Contains stylesheet files (css, sass, scss or less files). Like scripts they are
125
+ combined and minimised when you build your site.
126
+
127
+
128
+ ## Configuration
129
+
130
+
131
+ ## Extending/Hacking
132
+
133
+ ...
data/Rakefile CHANGED
@@ -1,57 +1,12 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "henshin"
8
- gem.summary = %Q{Henshin is a static site generator}
9
- gem.description = %Q{Henshin is a static site generator, with a plugin system and more}
10
- gem.email = "m@hawx.me"
11
- gem.homepage = "http://github.com/hawx/henshin"
12
- gem.authors = ["hawx"]
13
- gem.add_dependency "titlecase", ">= 0.1.0"
14
- gem.add_dependency "directory_watcher", ">= 1.3.1"
15
- gem.add_dependency "maruku", ">= 0.6.0"
16
- gem.add_dependency "liquid", ">= 2.0.0"
17
- gem.add_dependency "parsey", ">= 0.1.3"
18
- gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
19
- gem.add_development_dependency "yard", ">= 0"
20
- end
21
- Jeweler::GemcutterTasks.new
22
- rescue LoadError
23
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
24
- end
25
-
26
1
  require 'rake/testtask'
27
- Rake::TestTask.new(:test) do |test|
28
- test.libs << 'test'
29
- test.pattern = 'test/**/test_*.rb'
30
- test.verbose = true
31
- end
32
2
 
33
- begin
34
- require 'rcov/rcovtask'
35
- Rcov::RcovTask.new do |test|
36
- test.libs << 'test'
37
- test.pattern = 'test/**/test_*.rb'
38
- test.verbose = true
39
- end
40
- rescue LoadError
41
- task :rcov do
42
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
43
- end
3
+ Rake::TestTask.new :test do |t|
4
+ t.libs << 'lib' << 'spec'
5
+ t.pattern = 'spec/**/*_spec.rb'
44
6
  end
45
7
 
46
- task :test => :check_dependencies
8
+ task :lint do
9
+ system "RBENV_VERSION='rbx-2.0.0-dev' sh -c 'rbx -S pelusa'"
10
+ end
47
11
 
48
12
  task :default => :test
49
-
50
- begin
51
- require 'yard'
52
- YARD::Rake::YardocTask.new
53
- rescue LoadError
54
- task :yardoc do
55
- abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
56
- end
57
- end
@@ -1,149 +1,142 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'henshin'
4
- require 'henshin/exec/files'
5
-
6
- require 'optparse'
7
- require 'fileutils'
8
-
9
- banner = <<EOS
10
- Usage: henshin
11
- henshin [source]
12
- henshin [source]:[destination]
13
-
14
- henshin create
15
- henshin create [path for site]
16
-
17
- EOS
18
-
19
-
20
- if ARGV[0] == "create"
21
- if ARGV[1]
22
- # create the directory
23
- FileUtils.mkdir_p ARGV[1]
24
- # and cd to it
25
- Dir.chdir ARGV[1]
26
- end
27
-
28
- # create directories
29
- dirs = ['layouts', 'posts']
30
- dirs.each {|d| FileUtils.mkdir_p d}
31
-
32
- # write files
33
- files = {'options.yaml' => opt_content,
34
- 'index.html' => index_content,
35
- 'layouts/main.html' => layout_content,
36
- 'posts/hello-world.markdown' => post_content}
37
- files.each do |f, c|
38
- file = File.new( f, "w" )
39
- file.puts c
40
- end
3
+ require 'clive'
4
+
5
+ require_relative '../lib/henshin'
6
+
7
+ module Henshin
41
8
 
42
- else
9
+ class CLI < Clive
43
10
 
44
- override = {}
45
- build = {:server => false, :auto => false, :port => 9991, :address => '0.0.0.0'}
46
- opts = OptionParser.new do |opts|
47
- opts.banner = banner
48
-
49
- opts.on("--server", "-s", "Start server") do
50
- build[:server] = true
11
+ config name: 'henshin'
12
+
13
+ desc 'Builds the site'
14
+ command :build, arg: '[<root>]', as: Pathname, default: '.' do
15
+ action do
16
+ Henshin.eval_init root
17
+ Henshin.build root
18
+ end
51
19
  end
52
-
53
- opts.on("--auto", "-a", "Auto regenerate files") do
54
- build[:auto] = true
20
+
21
+ desc 'Creates a new site'
22
+ command :new, arg: '[<root>]', as: Pathname, default: '.' do
23
+ action do
24
+ Henshin.copy_site root
25
+ end
55
26
  end
56
-
57
- opts.on("--version", "Display current version of Henshin") do
58
- puts "Henshin #{Henshin.version}"
59
- exit 0
27
+
28
+ desc 'Serves the site to view in a web browser'
29
+ command :view, arg: '[<root>]', as: Pathname, default: '.' do
30
+
31
+ desc 'Specify port number'
32
+ opt :p, :port, arg: '<num>', as: Integer
33
+
34
+ desc 'Hostname to run on'
35
+ opt :host, arg: '<addr>'
36
+
37
+ desc 'Handler to use'
38
+ opt :H, :handler, arg: '<name>'
39
+
40
+ desc 'Daemonise process'
41
+ opt :D, :daemonise
42
+
43
+ action do
44
+ require_relative '../lib/rack/henshin'
45
+ Henshin.eval_init root
46
+
47
+ site = ::Henshin::SETTINGS[:klass].new(root)
48
+ site.extend ::Henshin::Site::Servable
49
+ ::Henshin::File::Abstract.send :include, ::Henshin::File::Servable
50
+
51
+ Henshin.serve site, @state.to_h
52
+ end
60
53
  end
61
-
62
- end
63
- opts.parse!
64
-
65
- if ARGV[0]
66
- override['root'] = ARGV[0].split(':')[0]
67
- if ARGV[0].split(':')[1]
68
- override['target'] = ARGV[0].split(':')[1]
69
- else
70
- override['target'] = File.join(override['root'], Henshin::Defaults['target'])
54
+
55
+ desc 'Publishes the site'
56
+ command :publish, arg: '[<root>]', as: Pathname, default: '.' do
57
+ action do
58
+ Henshin.eval_init root
59
+ Henshin.publish root
60
+ end
71
61
  end
72
- else
73
- override['root'] = Henshin::Defaults['root']
74
- override['target'] = Henshin::Defaults['target']
75
- end
76
-
77
-
78
- site = Henshin::Site.new(override)
79
- unless build[:auto]
80
- start = Time.now
81
- # build normally
82
- puts "Building site..."
83
- site.build
84
- puts "Site created in #{site.config['target']} (#{Time.now - start}s)"
85
- end
86
-
87
- threads = []
88
- # start a server
89
- if build[:server]
90
- begin
91
- require 'mongrel'
92
-
93
- threads << Thread.new {
94
- @h = Mongrel::HttpServer.new(build[:address], build[:port])
95
- @h.register("/", Mongrel::DirHandler.new(override['target']))
96
- puts "Server launched at http://#{build[:address]}:#{build[:port]}"
97
- trap("INT") {
98
- @h.stop
99
- puts "\n"
100
- }
101
- @h.run.join
102
- }
103
- rescue LoadError
104
-
105
- require 'webrick'
106
- threads << Thread.new {
107
- server = WEBrick::HTTPServer.new(
108
- :Port => build[:port],
109
- :DocumentRoot => override['target'],
110
- :MimeTypes => WEBrick::HTTPUtils::DefaultMimeTypes
111
- )
112
- trap("INT") { server.shutdown }
113
- server.start
114
- }
115
-
62
+
63
+ desc 'Only display errors'
64
+ opt :quiet do
65
+ Henshin.set :quiet
116
66
  end
117
- end
118
-
119
- # regenerate files when changed
120
- if build[:auto]
121
- require 'directory_watcher'
122
-
123
- puts "", "Auto-build initiated..."
124
-
125
- # build the glob pattern
126
- gl = Dir[ File.join(override['root'], '*')].select { |x| File.directory?(x) }
127
- ['/_site', '/plugins'].each do |r|
128
- gl = gl.select {|i| !i.include?( File.join(override['root'], r) )}
67
+
68
+ desc 'Shows what a command will do, without writing any files'
69
+ opt :dry_run do
70
+ puts "Starting dry run..."
71
+ Henshin.set :dry_run
72
+ end
73
+
74
+ desc 'Use local links between files'
75
+ opt :local do
76
+ Henshin.set :local
77
+ end
78
+
79
+ desc 'Print time taken to generate site'
80
+ opt :profile do
81
+ Henshin.set :profile
82
+ end
83
+
84
+ desc 'Do not use colours in output'
85
+ opt :no_colour do
86
+ Henshin.unset :colour
87
+ end
88
+
89
+ desc 'Kills any running henshin daemon'
90
+ opt :kill do
91
+ if ::File.exist?('henshin.pid')
92
+ pid = ::File.read('henshin.pid').to_i
93
+ Process.kill('INT', pid)
94
+ end
95
+ end
96
+
97
+ desc 'Display the current version'
98
+ opt :version, tail: true do
99
+ puts Henshin::VERSION
100
+ exit 0
129
101
  end
130
- gl.collect! {|x| "#{x}/**/*"[override['root'].size+1..-1]}
131
- gl += ['*']
132
-
133
- dw = DirectoryWatcher.new(override['root'], :glob => gl)
134
- dw.interval = 1
135
- dw.add_observer do |*args|
136
- if args.size > 1
137
- puts "rebuilding -> #{args.size} files"
102
+
103
+ end
104
+
105
+ def self.copy_site(to)
106
+ from = Pathname.new(__FILE__) + '..' + '..' + 'site'
107
+ FileUtils.cp_r(from, to) unless Henshin.dry_run?
108
+
109
+ Pathname.glob(from + '**' + '*').each do |path|
110
+ if path.directory?
111
+ UI.made(to + path.relative_path_from(from))
138
112
  else
139
- puts "rebuilding -> #{args[0].path}"
113
+ UI.wrote(to + path.relative_path_from(from))
140
114
  end
141
- site.build
142
115
  end
143
-
144
- threads << Thread.new { dw.start }
145
- loop { sleep 1000 } unless build[:server]
146
- end
116
+ end
117
+
118
+ def self.serve(site, opts={})
119
+ if opts[:daemonise]
120
+ cwd = FileUtils.pwd
121
+ Process.daemon
122
+ FileUtils.cd cwd
123
+ ::File.open('henshin.pid', 'w') {|f| f.write "#{Process.pid}" }
124
+ at_exit { ::File.delete('henshin.pid') if ::File.exist?('henshin.pid') }
125
+ end
126
+
127
+ config = site.config.server || Hashie::Mash.new
128
+ handler = Rack::Handler.get(opts[:handler] || config.handler)
129
+ handler = Rack::Handler.default unless handler
130
+
131
+ app = Rack::Builder.new do
132
+ use Rack::ShowExceptions
133
+ run Rack::Henshin.new(nil, site: site)
134
+ end
147
135
 
148
- threads.each {|t| t.join}
136
+ handler.run app,
137
+ Host: (opts[:host] || config.host),
138
+ Port: (opts[:port] || config.port)
139
+ end
149
140
  end
141
+
142
+ Henshin::CLI.run