zwite 1.0.0

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.
@@ -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