zwite 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,347 @@
1
+ module Zwite
2
+
3
+ module Blog
4
+
5
+ class Archive < Object
6
+
7
+ ##
8
+ # Properties
9
+ ##
10
+
11
+ attr_accessor :blog
12
+ attr_accessor :date
13
+ attr_accessor :url
14
+
15
+ def eql?(other)
16
+ if other.class == self.class
17
+ return self.date == other.date
18
+ end
19
+ return false
20
+ end
21
+
22
+ def hash
23
+ return self.to_liquid.hash
24
+ end
25
+
26
+ def to_liquid
27
+ return {
28
+ "date" => self.date,
29
+ "url" => self.url
30
+ }
31
+ end
32
+
33
+ ##
34
+ # Initialization
35
+ ##
36
+
37
+ def initialize(blog, year, month)
38
+ self.date = DateTime.new(year, month, 1, 0, 0, 0, DateTime.now.offset)
39
+ self.blog = blog
40
+ self.url = "#{self.blog.app.url}blog/#{self.date.strftime("%Y/%m")}/"
41
+ end
42
+
43
+ ##
44
+ # Actions
45
+ ##
46
+
47
+ def <=>(other)
48
+ if other.class == self.class
49
+ return other.date <=> self.date
50
+ end
51
+ return nil
52
+ end
53
+
54
+ end
55
+
56
+ class Topic < Object
57
+
58
+ ##
59
+ # Properties
60
+ ##
61
+
62
+ attr_accessor :blog
63
+ attr_accessor :name
64
+ attr_accessor :slug
65
+ attr_accessor :url
66
+
67
+ def eql?(other)
68
+ if other.class == self.class
69
+ return self.name == other.name
70
+ end
71
+ return false
72
+ end
73
+
74
+ def hash
75
+ return self.to_liquid.hash
76
+ end
77
+
78
+ def to_liquid
79
+ return {
80
+ "name" => self.name,
81
+ "slug" => self.slug,
82
+ "url" => self.url,
83
+ }
84
+ end
85
+
86
+ ##
87
+ # Initialization
88
+ ##
89
+
90
+ def initialize(blog, name)
91
+ self.blog = blog
92
+ self.name = name
93
+ self.slug = name.slugify
94
+ self.url = "#{self.blog.app.url}blog/topics/#{self.slug}/"
95
+ end
96
+
97
+ ##
98
+ # Actions
99
+ ##
100
+
101
+ def <=>(other)
102
+ if other.class == self.class
103
+ return other.name <=> self.name
104
+ end
105
+ return nil
106
+ end
107
+
108
+ end
109
+
110
+ class Post < Object
111
+
112
+ ##
113
+ # Properties
114
+ ##
115
+
116
+ attr_accessor :blog
117
+ attr_accessor :path
118
+
119
+ attr_accessor :date
120
+ attr_accessor :archive
121
+ attr_accessor :slug
122
+ attr_accessor :url
123
+
124
+ attr_accessor :metadata
125
+ attr_accessor :content
126
+
127
+ attr_accessor :name
128
+ attr_accessor :topics
129
+
130
+ def eql?(other)
131
+ if other.class == self.class
132
+ return other.path == self.path
133
+ end
134
+ return false
135
+ end
136
+
137
+ def hash
138
+ return self.to_liquid.hash
139
+ end
140
+
141
+ def to_liquid
142
+ return {
143
+ "date" => self.date,
144
+ "archive" => self.archive,
145
+ "slug" => self.slug,
146
+ "url" => self.url,
147
+ "metadata" => self.metadata,
148
+ "content" => self.content,
149
+ "name" => self.name,
150
+ "topics" => self.topics,
151
+ }
152
+ end
153
+
154
+ ##
155
+ # Initialization
156
+ ##
157
+
158
+ def initialize(blog, path)
159
+ self.blog = blog
160
+ self.path = path
161
+
162
+ Zwite::Utils.parse_date_and_slug(self.path.basename.to_s) do |date, slug|
163
+ self.date = date
164
+ self.slug = slug
165
+ end
166
+
167
+ self.archive = Archive.new(blog, date.year, date.month)
168
+ self.url = "#{self.blog.app.url}blog/#{self.date.strftime("%Y/%m/%d")}/#{self.slug}/"
169
+
170
+ Zwite::Utils.parse_metadata_and_markdown((self.path + "post.md").read) do |metadata, markdown|
171
+ self.metadata = metadata
172
+ self.content = markdown
173
+ end
174
+
175
+ self.name = self.metadata["name"]
176
+
177
+ self.topics = []
178
+ self.metadata["topics"].each do |topic|
179
+ self.topics << Topic.new(blog, topic)
180
+ end
181
+ self.topics.sort!
182
+
183
+ end
184
+
185
+ ##
186
+ # Actions
187
+ ##
188
+
189
+ def <=>(other)
190
+ if other.class == self.class
191
+ return other.date <=> self.date
192
+ end
193
+ return nil
194
+ end
195
+
196
+ end
197
+
198
+ class Blog < Plugin
199
+ ##
200
+ # Constants
201
+ ##
202
+
203
+ POSTS_PER_PAGE = 2
204
+
205
+ ##
206
+ # Properties
207
+ ##
208
+
209
+ attr_accessor :posts
210
+ attr_accessor :topics
211
+ attr_accessor :archives
212
+
213
+ attr_accessor :posts_by_topics
214
+ attr_accessor :posts_by_archives
215
+
216
+ def name
217
+ return "blog"
218
+ end
219
+
220
+ def enabled?
221
+ return (self.app.path + "blog").exist?
222
+ end
223
+
224
+ def to_liquid
225
+ return {
226
+ "posts" => self.posts,
227
+ "topics" => self.topics,
228
+ "archives" => self.archives
229
+ }
230
+ end
231
+
232
+ ##
233
+ # Actions
234
+ ##
235
+
236
+ def preprocess
237
+ super
238
+
239
+ self.posts = []
240
+ self.archives = []
241
+ self.topics = []
242
+
243
+ self.posts_by_topics = {}
244
+ self.posts_by_archives = {}
245
+
246
+ blog_path = self.app.path + "blog"
247
+
248
+ Dir[blog_path + "posts/*"].each do |p|
249
+ post = Post.new(self, Pathname.new(p))
250
+
251
+ self.posts_by_archives[post.archive] ||= []
252
+ self.posts_by_archives[post.archive] << post
253
+
254
+ post.topics.each do |topic|
255
+ self.posts_by_topics[topic] ||= []
256
+ self.posts_by_topics[topic] << post
257
+ end
258
+
259
+ self.posts << post
260
+
261
+ end
262
+
263
+ self.posts_by_topics.each do |topic, posts|
264
+ self.topics << topic
265
+ posts.sort!
266
+ end
267
+
268
+ self.posts_by_archives.dup.each do |archive, posts|
269
+ self.archives << archive
270
+ posts.sort!
271
+ end
272
+
273
+ self.topics.sort!
274
+ self.archives.sort!.reverse!
275
+ self.posts.sort!
276
+
277
+ end
278
+
279
+ def generate
280
+ ctx = {
281
+ "topics" => self.topics,
282
+ "archives" => self.archives,
283
+ }
284
+
285
+ # generate posts
286
+ self.posts.each do |post|
287
+ post_ctx = ctx.dup
288
+ post_ctx["post"] = post
289
+
290
+ post_output_path = self.app.output_path + post.url[1..post.url.length]
291
+ post_output_path.mkpath
292
+ (post_output_path + "index.html").open("w") do |h|
293
+ h.write(self.app.render_template("blog/post.html", post_ctx))
294
+ end
295
+ end
296
+
297
+ # generate archives
298
+ self.archives.each do |archive|
299
+ archive_output_path = self.app.output_path + archive.url[1..archive.url.length]
300
+ paginator = Zwite::Pagination::Paginator.new(self.posts_by_archives[archive], POSTS_PER_PAGE)
301
+ generate_pages(paginator, archive_output_path)
302
+ end
303
+
304
+ # generate topics
305
+ self.topics.each do |topic|
306
+ topic_output_path = self.app.output_path + topic.url[1..topic.url.length]
307
+ paginator = Zwite::Pagination::Paginator.new(self.posts_by_topics[topic], POSTS_PER_PAGE)
308
+ generate_pages(paginator, topic_output_path)
309
+ end
310
+
311
+ # generate pages
312
+ paginator = Zwite::Pagination::Paginator.new(self.posts, POSTS_PER_PAGE)
313
+ generate_pages(paginator, self.app.output_path + "blog/")
314
+
315
+ end
316
+
317
+ def generate_pages(paginator, output_path)
318
+ ctx = {
319
+ "topics" => self.topics,
320
+ "archives" => self.archives,
321
+ "paginator" => paginator,
322
+ "base_path" => "/#{output_path.relative_path_from(self.app.output_path)}/",
323
+ }
324
+ paginator.pages.each do |page|
325
+ page_ctx = ctx.dup
326
+ page_ctx["page"] = page
327
+ page_ctx["posts"] = page.objects
328
+
329
+ if page.number == 1
330
+ page_output_path = output_path
331
+ else
332
+ page_output_path = output_path + "page/#{page.number}/"
333
+ end
334
+
335
+ page_output_path.mkpath
336
+ (page_output_path + "index.html").open("w") do |h|
337
+ h.write(self.app.render_template("blog/posts.html", page_ctx))
338
+ end
339
+
340
+ end
341
+ end
342
+
343
+ end
344
+
345
+ end
346
+
347
+ end
@@ -0,0 +1,58 @@
1
+ require "compass/exec"
2
+
3
+ module Zwite
4
+
5
+ class Compass < Plugin
6
+
7
+ ##
8
+ # Properties
9
+ ##
10
+
11
+ def name
12
+ return "compass"
13
+ end
14
+
15
+ ##
16
+ # Actions
17
+ ##
18
+
19
+ def generate
20
+ sass_path = (self.app.path + "compass")
21
+ cache_path = (self.app.path + ".cache/.compass-cache")
22
+ to_path = (self.app.output_path + "static/stylesheets")
23
+
24
+ args = [
25
+ "compile",
26
+ "-q",
27
+ "--output-style",
28
+ "compressed",
29
+ "-e",
30
+ "production",
31
+ "--sass-dir",
32
+ sass_path.to_s,
33
+ "--css-dir",
34
+ cache_path.to_s
35
+ ]
36
+ ::Compass::Exec::SubCommandUI.new(args).run!
37
+
38
+ to_path.mkpath
39
+
40
+ Dir[sass_path.to_s + "*/**"].each do |p|
41
+ path = Pathname.new(p).sub_ext(".css")
42
+ path_rel_path = path.relative_path_from(sass_path).to_s
43
+ path_cached_path = cache_path + path_rel_path
44
+ path_to_path = to_path + path_rel_path
45
+
46
+ unless path_cached_path.exist?
47
+ next
48
+ end
49
+
50
+ path_to_path.parent.mkpath
51
+ FileUtils.cp(path_cached_path.to_s, path_to_path.to_s)
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,53 @@
1
+ module Zwite
2
+
3
+ class StaticFiles < Plugin
4
+
5
+ ##
6
+ # Properties
7
+ ##
8
+
9
+ def name
10
+ return "staticfiles"
11
+ end
12
+
13
+ def enabled?
14
+ return (self.app.path + "source").exist?
15
+ end
16
+
17
+ ##
18
+ # Actions
19
+ ##
20
+
21
+ def generate
22
+ super
23
+ src_path = self.app.path + "source"
24
+ renderables = [".html", ".htm", ".xml"]
25
+
26
+ Dir[self.app.path + "source/**/*"].each do |p|
27
+ path = Pathname.new(p)
28
+ if path.directory?
29
+ next
30
+ end
31
+
32
+ rel_path = path.relative_path_from(src_path)
33
+ output_path = self.app.output_path + rel_path
34
+ output_dir_path = output_path.parent
35
+
36
+ output_dir_path.mkpath
37
+
38
+ if renderables.include?(path.extname)
39
+ contents = self.app.render_file(path)
40
+ output_path.open("w+") do |h|
41
+ h.write(contents)
42
+ end
43
+ else
44
+ FileUtils.copy_file(path, output_path)
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
data/lib/zwite.rb ADDED
@@ -0,0 +1,122 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ # require all
4
+ def require_all(path)
5
+ glob = File.join(File.dirname(__FILE__), path, "*.rb")
6
+ Dir[glob].each do |f|
7
+ require f
8
+ end
9
+ end
10
+
11
+ # rubygems
12
+ require "rubygems"
13
+
14
+ # stdlib
15
+ require "pathname"
16
+ require "fileutils"
17
+ require "time"
18
+ require "yaml"
19
+ require "English"
20
+ require "thread"
21
+ require "openssl"
22
+ require "date"
23
+ require "base64"
24
+
25
+ # 3rd-party
26
+ require "liquid"
27
+ require "compass"
28
+ require "rdiscount"
29
+ # require "nokogiri"
30
+
31
+ # internal
32
+ require_all("zwite/ext")
33
+ require_all("zwite/core")
34
+ require_all("zwite/liquid/ext")
35
+ require_all("zwite/liquid")
36
+ require_all("zwite/compass")
37
+ require_all("zwite/plugins")
38
+
39
+ module Zwite
40
+ VERSION = "1.0.0"
41
+
42
+ class Engine
43
+
44
+ ##
45
+ # properties
46
+ ##
47
+
48
+ attr_accessor :site
49
+
50
+ ##
51
+ # singleton
52
+ ##
53
+
54
+ @@sharedEngine = Engine.new
55
+ def self.sharedEngine
56
+ return @@sharedEngine
57
+ end
58
+
59
+ ##
60
+ # actions
61
+ ##
62
+
63
+ def run(options)
64
+ # variables
65
+ @options = options
66
+ @site = Zwite::Site.new(Pathname.new(@options["path"]))
67
+
68
+ # build
69
+ @site.build
70
+
71
+ # server
72
+ if @options["server"]
73
+ self.run_server
74
+ end
75
+
76
+ end
77
+
78
+ def run_server
79
+ require "webrick"
80
+
81
+ # mime_types
82
+ mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
83
+ mime_types.store("js", "application/javascript")
84
+
85
+ # server callback
86
+ server_callback = Proc.new do |request|
87
+ @site.build
88
+ end
89
+
90
+ # server
91
+ server = WEBrick::HTTPServer.new(
92
+ :AccessLog => [nil, nil],
93
+ :Logger => WEBrick::Log.new("/dev/null"),
94
+ :Port => @options["server_port"],
95
+ :DirectoryIndex => ["index.html","index.htm", "index.xml"],
96
+ :MimeTypes => mime_types,
97
+ )
98
+ server.mount("/", WEBrick::HTTPServlet::FileHandler, @site.output_path,
99
+ :FancyIndexing => true,
100
+ :HandlerCallback => server_callback
101
+ )
102
+
103
+ # trap
104
+ ["INT", "TERM"].each do |signal|
105
+ trap(signal) do
106
+ server.shutdown
107
+ exit(1)
108
+ end
109
+ end
110
+
111
+ server_thread = Thread.new do
112
+ puts "Running Server: localhost:#{@options["server_port"]}"
113
+ server.start
114
+ end
115
+ server_thread.join
116
+
117
+
118
+ end
119
+
120
+ end
121
+
122
+ end
data/zwite.gemspec ADDED
@@ -0,0 +1,54 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+ s.rubygems_version = '1.3.5'
5
+
6
+ s.name = "zwite"
7
+ s.version = "1.0.0"
8
+ s.date = "2012-03-01"
9
+
10
+ s.summary = "A static site generator that is very pluggable"
11
+ s.description = "Zwite is a static site generator that is very pluggable"
12
+
13
+ s.authors = ["Zwopple"]
14
+ s.email = "support@zwopple.com"
15
+ s.homepage = "http://github.com/zwopple/zwite"
16
+
17
+ s.require_paths = %w[lib]
18
+
19
+ s.executables = ["zwite"]
20
+
21
+ s.add_runtime_dependency("liquid", "~> 2.3")
22
+ s.add_runtime_dependency("rdiscount", "~> 1.6")
23
+ s.add_runtime_dependency("compass", "~> 0.11")
24
+
25
+ s.files = %w[
26
+ bin/zwite
27
+ lib/zwite/core/app.rb
28
+ lib/zwite/core/dateformat.rb
29
+ lib/zwite/core/pagination.rb
30
+ lib/zwite/core/plugin.rb
31
+ lib/zwite/core/site.rb
32
+ lib/zwite/core/utils.rb
33
+ lib/zwite/ext/class.rb
34
+ lib/zwite/ext/fixnum.rb
35
+ lib/zwite/ext/hash.rb
36
+ lib/zwite/ext/integer.rb
37
+ lib/zwite/ext/string.rb
38
+ lib/zwite/ext/time.rb
39
+ lib/zwite/liquid/block.rb
40
+ lib/zwite/liquid/ext/date.rb
41
+ lib/zwite/liquid/ext/template.rb
42
+ lib/zwite/liquid/extends.rb
43
+ lib/zwite/liquid/filesystem.rb
44
+ lib/zwite/models/Template.rb
45
+ lib/zwite/plugins/appcast.rb
46
+ lib/zwite/plugins/blog.rb
47
+ lib/zwite/plugins/compass.rb
48
+ lib/zwite/plugins/staticfiles.rb
49
+ lib/zwite.rb
50
+ README.md
51
+ zwite.gemspec
52
+ ]
53
+
54
+ end