zarchitect 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.
- checksums.yaml +7 -0
- data/bin/zarchitect +3 -0
- data/data/_zarchitect.yaml +22 -0
- data/data/post.md.erb +16 -0
- data/lib/zarchitect.rb +179 -0
- data/lib/zarchitect/assets.rb +50 -0
- data/lib/zarchitect/audio.rb +31 -0
- data/lib/zarchitect/category.rb +62 -0
- data/lib/zarchitect/cmd_misc.rb +34 -0
- data/lib/zarchitect/cmd_new.rb +75 -0
- data/lib/zarchitect/cmd_update.rb +34 -0
- data/lib/zarchitect/config.rb +285 -0
- data/lib/zarchitect/content.rb +286 -0
- data/lib/zarchitect/file_manager.rb +64 -0
- data/lib/zarchitect/html.rb +54 -0
- data/lib/zarchitect/htmltable.rb +154 -0
- data/lib/zarchitect/image.rb +162 -0
- data/lib/zarchitect/image_set.rb +46 -0
- data/lib/zarchitect/index.rb +224 -0
- data/lib/zarchitect/misc_file.rb +19 -0
- data/lib/zarchitect/paginator.rb +73 -0
- data/lib/zarchitect/post.rb +202 -0
- data/lib/zarchitect/rouge_html.rb +34 -0
- data/lib/zarchitect/rss.rb +60 -0
- data/lib/zarchitect/scss.rb +32 -0
- data/lib/zarchitect/section.rb +126 -0
- data/lib/zarchitect/tag.rb +46 -0
- data/lib/zarchitect/util.rb +41 -0
- data/lib/zarchitect/video.rb +37 -0
- data/lib/zarchitect/zerb.rb +120 -0
- metadata +73 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'redcarpet'
|
|
2
|
+
require 'rouge'
|
|
3
|
+
require 'rouge/plugins/redcarpet'
|
|
4
|
+
|
|
5
|
+
class RougeHTML < Redcarpet::Render::HTML
|
|
6
|
+
include Rouge::Plugins::Redcarpet
|
|
7
|
+
def block_code(code, language)
|
|
8
|
+
line = code.lines.first
|
|
9
|
+
ar = line.split ':'
|
|
10
|
+
code = code.lines.to_a[1..-1].join
|
|
11
|
+
|
|
12
|
+
# add highlighting
|
|
13
|
+
str = Rouge.highlight(code, ar[1].chomp, 'html')
|
|
14
|
+
|
|
15
|
+
# add line numbers
|
|
16
|
+
code2 = ""
|
|
17
|
+
i = 1
|
|
18
|
+
str.each_line do |l|
|
|
19
|
+
j = "#{i}"
|
|
20
|
+
if j.length == 1
|
|
21
|
+
j.prepend("00")
|
|
22
|
+
elsif j.length == 2
|
|
23
|
+
j.prepend("0")
|
|
24
|
+
end
|
|
25
|
+
code2 << "<span class='codelinenumber'>#{j} </span>#{l}"
|
|
26
|
+
i += 1
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# finalize
|
|
30
|
+
code2.prepend("<pre><code class='highlight'>")
|
|
31
|
+
code2 << "</code></pre>"
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class ZRSS < Zarchitect
|
|
2
|
+
|
|
3
|
+
def initialize
|
|
4
|
+
@items = Array.new
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def try_item(page)
|
|
8
|
+
return if page.draft
|
|
9
|
+
if @items.count < Zarchitect.conf.rss_size # simply add page to rss items
|
|
10
|
+
@items.push RSSItem.new(page)
|
|
11
|
+
else # check if it's more recent than the oldest item in the feed
|
|
12
|
+
if page.date > @items.last.date
|
|
13
|
+
@items.pop
|
|
14
|
+
@items.push RSSItem.new(page)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
@items.sort_by! { |i| i.date }.reverse!
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def build
|
|
21
|
+
rss = RSS::Maker.make("atom") do |maker|
|
|
22
|
+
maker.channel.title = Zarchitect.conf.site_name
|
|
23
|
+
maker.channel.author = Zarchitect.conf.admin
|
|
24
|
+
maker.channel.updated = Time.now.to_s
|
|
25
|
+
maker.channel.about = Zarchitect.conf.site_description
|
|
26
|
+
maker.channel.link = Zarchitect.conf.url
|
|
27
|
+
|
|
28
|
+
@items.each do |item|
|
|
29
|
+
maker.items.new_item do |rss_item|
|
|
30
|
+
rss_item.title = item.title
|
|
31
|
+
rss_item.pubDate = item.dates
|
|
32
|
+
rss_item.description = item.description
|
|
33
|
+
rss_item.link = item.link
|
|
34
|
+
#rss_item.guid = item.guid
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#write rss
|
|
40
|
+
File.open("_html/feed.rss", "w") { |f| f.write(rss) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class RSSItem
|
|
48
|
+
attr_reader :date, :title, :description, :link, :guid,
|
|
49
|
+
:dates
|
|
50
|
+
|
|
51
|
+
def initialize(page)
|
|
52
|
+
@date = page.date
|
|
53
|
+
@dates = page.date.strftime("%a, %d %b %Y %T %z")
|
|
54
|
+
@title = page.name
|
|
55
|
+
@description = page.description
|
|
56
|
+
@link = page.url
|
|
57
|
+
@guid = page.url
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class SCSS < Zarchitect
|
|
2
|
+
|
|
3
|
+
def self.run
|
|
4
|
+
if Zarchitect.conf.has_option? "scss_enabled"
|
|
5
|
+
Zarchitect.conf.read("scss_enabled").each do |str|
|
|
6
|
+
path = File.join(ASSETDIR, str)
|
|
7
|
+
npath = path.clone
|
|
8
|
+
npath.gsub!(".scss", ".css")
|
|
9
|
+
update(path, npath)
|
|
10
|
+
end
|
|
11
|
+
else
|
|
12
|
+
Dir[ File.join(ASSETDIR, "**", "*") ].reverse.reject do |path|
|
|
13
|
+
unless File.directory?(path)
|
|
14
|
+
if File.extname(path) == ".scss"
|
|
15
|
+
npath = path.clone
|
|
16
|
+
npath.gsub!('.scss', '.css')
|
|
17
|
+
update(path, npath)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.update(path, npath)
|
|
25
|
+
cmd = "scss #{path} #{npath}"
|
|
26
|
+
GPI.print cmd
|
|
27
|
+
r = %x{ #{cmd} }
|
|
28
|
+
GPI.print r unless r == ""
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
class Section < Zarchitect
|
|
2
|
+
attr_reader :key, :conf, :name, :categories, :url
|
|
3
|
+
|
|
4
|
+
def initialize(conf)
|
|
5
|
+
GPI.print "Initializing Section #{conf.key}.", GPI::CLU.check_option('v')
|
|
6
|
+
@conf = conf
|
|
7
|
+
@key = conf.key
|
|
8
|
+
@name = @conf.name.clone
|
|
9
|
+
if @conf.index
|
|
10
|
+
@url = "/index.html"
|
|
11
|
+
else
|
|
12
|
+
@url = "/#{@conf.key}/index.html"
|
|
13
|
+
end
|
|
14
|
+
create_dir
|
|
15
|
+
fetch_categories
|
|
16
|
+
fetch_posts
|
|
17
|
+
sort_posts
|
|
18
|
+
if @conf.collection && @conf.categorize
|
|
19
|
+
@categories.each do |c|
|
|
20
|
+
c.setup_index
|
|
21
|
+
c.fetch_tags if @conf.tags
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
setup_index
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def posts
|
|
28
|
+
if GPI::CLU.check_option('D')
|
|
29
|
+
@posts
|
|
30
|
+
else
|
|
31
|
+
@posts.select { |p| p.draft == false }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def all_posts
|
|
36
|
+
@posts
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def build_html
|
|
40
|
+
posts.each { |p| p.build_html }
|
|
41
|
+
if @categories
|
|
42
|
+
@categories.each { |c| c.build_html }
|
|
43
|
+
end
|
|
44
|
+
@index.build_html unless @conf.has_option?("file")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def write_html
|
|
48
|
+
posts.each { |p| p.write_html }
|
|
49
|
+
if @categories
|
|
50
|
+
@categories.each { |c| c.write_html }
|
|
51
|
+
end
|
|
52
|
+
@index.write_html unless @conf.has_option?("file")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def find_category(key)
|
|
56
|
+
@categories.each do |c|
|
|
57
|
+
return c if c.key == key
|
|
58
|
+
end
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def setup_index
|
|
65
|
+
@index = Index.new(self) unless @conf.has_option?("file")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def create_dir
|
|
69
|
+
unless @conf.index
|
|
70
|
+
Util.mkdir(File.join(HTMLDIR, @conf.key))
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def fetch_categories
|
|
75
|
+
return if @conf.index
|
|
76
|
+
@categories = Array.new
|
|
77
|
+
if @conf.collection && @conf.categorize
|
|
78
|
+
@conf.categories.each do |k,v|
|
|
79
|
+
@categories.push Category.new(k, v, self)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def fetch_posts
|
|
85
|
+
if @conf.index
|
|
86
|
+
ar = @conf.uses.split(',')
|
|
87
|
+
@posts = Array.new
|
|
88
|
+
Zarchitect.sections.each do |v|
|
|
89
|
+
if ar.include? v.key
|
|
90
|
+
v.posts.each do |p|
|
|
91
|
+
@posts.push p
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
@posts = Array.new
|
|
97
|
+
if @conf.has_option?("directory")
|
|
98
|
+
Dir.filesr(@conf.directory).each do |f|
|
|
99
|
+
next unless File.extname(f) == ".md"
|
|
100
|
+
@posts.push Post.new(f, self)
|
|
101
|
+
end
|
|
102
|
+
elsif @conf.has_option?("file")
|
|
103
|
+
@posts.push Post.new(@conf.file, self)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def sort_posts
|
|
109
|
+
return if @posts.count <= 1
|
|
110
|
+
case @conf.sort_type
|
|
111
|
+
when "date"
|
|
112
|
+
if @conf.sort_order == "reverse"
|
|
113
|
+
@posts.sort_by! { |p| p.date }.reverse!
|
|
114
|
+
else
|
|
115
|
+
@posts.sort_by! { |p| p.date }
|
|
116
|
+
end
|
|
117
|
+
when "alphanum"
|
|
118
|
+
if @conf.sort_order == "reverse"
|
|
119
|
+
@posts.sort_by! { |p| p.name }.reverse!
|
|
120
|
+
else
|
|
121
|
+
@posts.sort_by! { |p| p.name }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class Tag < Zarchitect
|
|
2
|
+
attr_accessor :category, :name, :key, :url
|
|
3
|
+
|
|
4
|
+
def initialize(str, cat)
|
|
5
|
+
@category = cat
|
|
6
|
+
@name = str
|
|
7
|
+
@key = hash(str)
|
|
8
|
+
@url = "/#{@category.section.key}/#{@category.key}/#{@key}/index.html"
|
|
9
|
+
create_dir
|
|
10
|
+
setup_index
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def posts
|
|
14
|
+
@category.section.posts.select do |p|
|
|
15
|
+
((p.category == @category) && (p.tags.include?(@name)))
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def build_html
|
|
20
|
+
@index.build_html
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def write_html
|
|
24
|
+
@index.write_html
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def create_dir
|
|
30
|
+
Util.mkdir(File.join(HTMLDIR, @category.section.key, @category.key, @key))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def setup_index
|
|
34
|
+
@index = Index.new(self)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def hash(str)
|
|
38
|
+
str2 = String.new
|
|
39
|
+
str.each_char do |c|
|
|
40
|
+
str2 << c.ord.to_s
|
|
41
|
+
end
|
|
42
|
+
str2 = str2.to_i
|
|
43
|
+
str2.to_s(16).downcase
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Util
|
|
2
|
+
|
|
3
|
+
def self.mkdir(path)
|
|
4
|
+
a = path.split("/")
|
|
5
|
+
if a.count == 1
|
|
6
|
+
Util.mkdir2(path)
|
|
7
|
+
else
|
|
8
|
+
i = 0
|
|
9
|
+
p = ""
|
|
10
|
+
a.each do |s|
|
|
11
|
+
if i == 0
|
|
12
|
+
p = s
|
|
13
|
+
Util.mkdir2(p)
|
|
14
|
+
else
|
|
15
|
+
p = File.join(p, s)
|
|
16
|
+
Util.mkdir2(p)
|
|
17
|
+
end
|
|
18
|
+
i += 1
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# path to data files located in installation directory
|
|
24
|
+
def self.path_to_data
|
|
25
|
+
File.join(__dir__, "../../data")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# PRIVATE
|
|
29
|
+
|
|
30
|
+
def self.mkdir2(path)
|
|
31
|
+
npath = File.join(Dir.getwd, path)
|
|
32
|
+
GPI.print "Checking for directory #{npath}", GPI::CLU.check_option('v')
|
|
33
|
+
unless Dir.exist?(npath)
|
|
34
|
+
GPI.print "Missing directory #{npath}", GPI::CLU.check_option('v')
|
|
35
|
+
GPI.print "Creating directory #{npath}", GPI::CLU.check_option('v')
|
|
36
|
+
Dir.mkdir(npath)
|
|
37
|
+
GPI.print "Created directory #{npath}", GPI::CLU.check_option('v')
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class Video < Zarchitect
|
|
2
|
+
attr_reader :size, :type, :url
|
|
3
|
+
|
|
4
|
+
def initialize(path)
|
|
5
|
+
@path = path
|
|
6
|
+
@url = path.clone
|
|
7
|
+
@url[0] = "/"
|
|
8
|
+
@size = File.size(path)
|
|
9
|
+
@type = "video/" << File.extname(path)[1..-1]
|
|
10
|
+
|
|
11
|
+
if @size > Zarchitect.conf.video_limit.to_f.mib_to_bytes
|
|
12
|
+
GPI.print "Error: File #{path} too large "\
|
|
13
|
+
"(#{@size.bytes_to_mib.to_f.round(2)}MiB)."\
|
|
14
|
+
" Allowed size: #{Zarchitect.conf.video_limit.to_f.mb_to_mib.round(2)}"
|
|
15
|
+
GPI.quit
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.is_valid?(filename)
|
|
20
|
+
[".mp4",".avi",".webm"].include?(File.extname(filename))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.find(k, v)
|
|
24
|
+
GPI.print "Looking for video: #{v}", GPI::CLU.check_option('v')
|
|
25
|
+
ObjectSpace.each_object(Video) do |a|
|
|
26
|
+
str = a.send(k)
|
|
27
|
+
if str == v
|
|
28
|
+
GPI.print "Video found", GPI::CLU.check_option('v')
|
|
29
|
+
@@search = false
|
|
30
|
+
return a
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
@@search = false
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
class ZERB < Zarchitect
|
|
2
|
+
|
|
3
|
+
#++++++++++++++++++++++++++++++
|
|
4
|
+
# @@template_stack
|
|
5
|
+
# @@gdata
|
|
6
|
+
# @template
|
|
7
|
+
# @path
|
|
8
|
+
# @renderer
|
|
9
|
+
# @output
|
|
10
|
+
# @meta
|
|
11
|
+
# @data
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
@@template_stack = Array.new
|
|
15
|
+
|
|
16
|
+
def initialize(template)
|
|
17
|
+
@@template_stack.push(template)
|
|
18
|
+
@template = template
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def prepare
|
|
22
|
+
GPI.print "ZERB preparing #{@template}",
|
|
23
|
+
GPI::CLU.check_option('v')
|
|
24
|
+
@renderer = ERB.new(File.open(@template) { |f| f.read})
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def render
|
|
29
|
+
@out = @renderer.result(binding())
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def output
|
|
33
|
+
@@template_stack.pop
|
|
34
|
+
@out
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def handle_data(hash)
|
|
38
|
+
@data = hash
|
|
39
|
+
hash.each do |k,v|
|
|
40
|
+
if instance_variable_defined?("@#{k}")
|
|
41
|
+
GPI.print "Error: Data key invalid #{k} - already defined"
|
|
42
|
+
GPI.quit
|
|
43
|
+
end
|
|
44
|
+
instance_variable_set("@#{k}", v)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private # functions to be used in templates
|
|
49
|
+
|
|
50
|
+
def include(path, options = {})
|
|
51
|
+
path.prepend("_layouts/")
|
|
52
|
+
GPI.print "Including #{path} into " \
|
|
53
|
+
"#{@@template_stack[@@template_stack.size-1]}",
|
|
54
|
+
GPI::CLU.check_option('v')
|
|
55
|
+
if @@template_stack.include?(path)
|
|
56
|
+
GPI.print "Error: Recursive call to include"
|
|
57
|
+
GPI.quit
|
|
58
|
+
end
|
|
59
|
+
b = ZERB.new(path)
|
|
60
|
+
b.handle_data(options)
|
|
61
|
+
b.prepare
|
|
62
|
+
b.render
|
|
63
|
+
b.output
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def img(path, options = {})
|
|
67
|
+
tag = %{<img src="#{path}"}
|
|
68
|
+
options.each do |k,v|
|
|
69
|
+
tag << %{ #{k.to_s}="#{v}"}
|
|
70
|
+
end
|
|
71
|
+
tag << %{>}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def link(str, path, options = {})
|
|
75
|
+
tag = %{<a href="#{path}"}
|
|
76
|
+
options.each do |k,v|
|
|
77
|
+
tag << %{ #{k.to_s}="#{v}"}
|
|
78
|
+
end
|
|
79
|
+
tag << %{>#{str}</a>}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def fdate(date)
|
|
83
|
+
date.strftime("%F")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def include_view
|
|
87
|
+
@view
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def include_content
|
|
91
|
+
@content
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def email(f = false)
|
|
95
|
+
Zarchitect.conf.email if f
|
|
96
|
+
#TODO secure email
|
|
97
|
+
Zarchitect.conf.email
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def root_url
|
|
101
|
+
Zarchitect.conf.url
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def site_name
|
|
105
|
+
Zarchitect.conf.site_name
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def origin_year
|
|
109
|
+
Zarchitect.conf.origin_year
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def admin
|
|
113
|
+
Zarchitect.conf.admin
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def site_slogan
|
|
117
|
+
Zarchitect.conf.site_slogan
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|