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,64 @@
|
|
|
1
|
+
class FileManager < Zarchitect
|
|
2
|
+
|
|
3
|
+
def initialize
|
|
4
|
+
@from = FILEDIR # where user puts files
|
|
5
|
+
@to = File.join(HTMLDIR, FILESDIR) # files in website dir tree
|
|
6
|
+
|
|
7
|
+
@img = Array.new
|
|
8
|
+
@audio = Array.new
|
|
9
|
+
@video = Array.new
|
|
10
|
+
@misc = Array.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
# iterate FROM
|
|
15
|
+
Dir[ File.join(@from, '**', '*') ].reject do |fullpath|
|
|
16
|
+
path = fullpath[(@from.length)..-1]
|
|
17
|
+
realpath = File.join(@to, path) # path of new dir/symlink
|
|
18
|
+
|
|
19
|
+
# dir handling / create copies in TO
|
|
20
|
+
Util.mkdir(realpath) if File.directory?(fullpath)
|
|
21
|
+
next if File.directory?(fullpath)
|
|
22
|
+
# file handling
|
|
23
|
+
# handle file types embedded in posts
|
|
24
|
+
if Image.is_valid?(fullpath)
|
|
25
|
+
GPI.print "processing #{fullpath} as image file",
|
|
26
|
+
GPI::CLU.check_option('v')
|
|
27
|
+
@img.push ImageSet.new(path, fullpath, realpath)
|
|
28
|
+
elsif Audio.is_valid?(fullpath)
|
|
29
|
+
GPI.print "processing #{fullpath} as audio file",
|
|
30
|
+
GPI::CLU.check_option('v')
|
|
31
|
+
@audio.push Audio.new(fullpath)
|
|
32
|
+
elsif Video.is_valid?(fullpath)
|
|
33
|
+
GPI.print "processing #{fullpath} as video file",
|
|
34
|
+
GPI::CLU.check_option('v')
|
|
35
|
+
@video.push Video.new(fullpath)
|
|
36
|
+
else
|
|
37
|
+
GPI.print "processing #{fullpath} as any file",
|
|
38
|
+
GPI::CLU.check_option('v')
|
|
39
|
+
@misc.push MiscFile.new(fullpath)
|
|
40
|
+
end
|
|
41
|
+
# create symlink in _html/files to physical files _files (if process did
|
|
42
|
+
# not abort)
|
|
43
|
+
unless File.symlink?(realpath)
|
|
44
|
+
rrealpath = File.join(Dir.getwd, fullpath)
|
|
45
|
+
symlink(rrealpath, realpath)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def symlink(from, to)
|
|
52
|
+
GPI.print "creating symlink #{to} ~> #{from}",
|
|
53
|
+
GPI::CLU.check_option('v')
|
|
54
|
+
File.symlink(from, to)
|
|
55
|
+
GPI.print "created symlink #{to} ~> #{from}",
|
|
56
|
+
GPI::CLU.check_option('v')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def clean
|
|
60
|
+
# remove all files in _html/files
|
|
61
|
+
%x{rm -r _html/files/*}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class HTML < Zarchitect
|
|
2
|
+
|
|
3
|
+
def initialize(str)
|
|
4
|
+
@data = Hash.new
|
|
5
|
+
@meta = Hash.new
|
|
6
|
+
@path = str
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def set_data(key, value)
|
|
10
|
+
@data[key] = value
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def set_meta(key, value)
|
|
14
|
+
@meta[key] = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def set_templates(layout, view)
|
|
18
|
+
@layout_path = layout
|
|
19
|
+
@view_path = view
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def compose
|
|
23
|
+
set_view
|
|
24
|
+
@data["view"] = @view.output
|
|
25
|
+
@data["meta"] = @meta
|
|
26
|
+
set_layout
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def write
|
|
30
|
+
GPI.print "Writing HTML to #{@path}.", GPI::CLU.check_option('v')
|
|
31
|
+
File.open(@path, "w") { |f| f.write(@layout.output) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def output
|
|
35
|
+
@layout.output
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def set_layout
|
|
41
|
+
@layout = ZERB.new(@layout_path)
|
|
42
|
+
@layout.handle_data(@data)
|
|
43
|
+
@layout.prepare
|
|
44
|
+
@layout.render
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def set_view
|
|
48
|
+
@view = ZERB.new(@view_path)
|
|
49
|
+
@view.handle_data(@data)
|
|
50
|
+
@view.prepare
|
|
51
|
+
@view.render
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
class HTMLTable
|
|
2
|
+
|
|
3
|
+
def initialize
|
|
4
|
+
@lines = Array.new
|
|
5
|
+
@starts_at = nil
|
|
6
|
+
@ends_at = nil
|
|
7
|
+
@coln = 0
|
|
8
|
+
@html = "<table>"
|
|
9
|
+
@rows = Array.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def process
|
|
13
|
+
@coln -= 1 # table syntax expects one more pipes than columns
|
|
14
|
+
|
|
15
|
+
@lines.each_with_index do |l,i|
|
|
16
|
+
ar = l.split('|', -1)
|
|
17
|
+
ar.shift
|
|
18
|
+
ar.pop
|
|
19
|
+
ar2 = get_colspans(ar)
|
|
20
|
+
ar.map! { |a| a.strip }
|
|
21
|
+
if ar[0].count("-") == ar[0].length && ar[0].count("-") > 0
|
|
22
|
+
# header previous row is header
|
|
23
|
+
@rows.last.set_header
|
|
24
|
+
else
|
|
25
|
+
# row
|
|
26
|
+
@rows.push HTMLTableRow.new(ar,ar2)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
@rows.each do |r|
|
|
31
|
+
r.process
|
|
32
|
+
@html << r.html
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@html << "</table>"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def add_line(l)
|
|
40
|
+
@coln = l.count('|') if l.count('|') > @coln
|
|
41
|
+
@lines.push l
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def print
|
|
45
|
+
@lines.each { |l| p l }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def starts_at(x)
|
|
49
|
+
@starts_at = x
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def ends_at(x)
|
|
53
|
+
@ends_at = x
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def replace(ar)
|
|
57
|
+
ar[@starts_at] = @html
|
|
58
|
+
if @ends_at.nil?
|
|
59
|
+
@ends_at = ar.length
|
|
60
|
+
process
|
|
61
|
+
end
|
|
62
|
+
ar.each_with_index do |x,i|
|
|
63
|
+
ar[i] = nil if i > @starts_at && i <= @ends_at
|
|
64
|
+
end
|
|
65
|
+
ar
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def get_colspans(ar)
|
|
71
|
+
cspans = Array.new
|
|
72
|
+
ar.each_with_index do |str,i|
|
|
73
|
+
if str == ""
|
|
74
|
+
cspans.push 0
|
|
75
|
+
else
|
|
76
|
+
cspans.push cspancnt(1, ar,i)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
cspans
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def cspancnt(c, ar,i)
|
|
83
|
+
if i+1 < ar.length
|
|
84
|
+
if ar[i+1] == ""
|
|
85
|
+
c += 1
|
|
86
|
+
c = cspancnt(c, ar, i+1)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
c
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class HTMLTableRow
|
|
95
|
+
|
|
96
|
+
def initialize(ar,ar2)
|
|
97
|
+
@contents = ar
|
|
98
|
+
@colspans = ar2
|
|
99
|
+
@headerf = false
|
|
100
|
+
@columns = Array.new
|
|
101
|
+
@html = "<tr>"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def set_header
|
|
105
|
+
@headerf = true
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def html
|
|
109
|
+
@html
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def process
|
|
113
|
+
@contents.each_with_index do |str,i|
|
|
114
|
+
next if @colspans[i] == 0
|
|
115
|
+
@columns.push HTMLTableCell.new(str,@colspans[i], @headerf)
|
|
116
|
+
end
|
|
117
|
+
@columns.each do |c|
|
|
118
|
+
c.process
|
|
119
|
+
@html << c.html
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
@html << "</tr>"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
class HTMLTableCell
|
|
128
|
+
|
|
129
|
+
def initialize(str,n,h)
|
|
130
|
+
@content = str
|
|
131
|
+
@colspan = n
|
|
132
|
+
@headerf = h
|
|
133
|
+
@html = String.new
|
|
134
|
+
if @headerf
|
|
135
|
+
@html << "<th colspan=\"#{@colspan}\">"
|
|
136
|
+
else
|
|
137
|
+
@html << "<td colspan=\"#{@colspan}\">"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def process
|
|
142
|
+
@html << @content
|
|
143
|
+
if @headerf
|
|
144
|
+
@html << "</th>"
|
|
145
|
+
else
|
|
146
|
+
@html << "</td>"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def html
|
|
151
|
+
@html
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
class Image < Zarchitect
|
|
2
|
+
attr_reader :dimensions, :size, :type
|
|
3
|
+
attr_writer :thumbs_f, :thumbl_f
|
|
4
|
+
|
|
5
|
+
@@search = false
|
|
6
|
+
|
|
7
|
+
#+++++++++++++++++++++++++++++
|
|
8
|
+
# @path
|
|
9
|
+
# @url
|
|
10
|
+
# @dimensions
|
|
11
|
+
# @size
|
|
12
|
+
# @thumbs_f | flags
|
|
13
|
+
# @thumbl_f
|
|
14
|
+
# @type | PNG, JPEG, BMP, GIF
|
|
15
|
+
|
|
16
|
+
def initialize(path, f)
|
|
17
|
+
@thumbf = f
|
|
18
|
+
@path = path
|
|
19
|
+
unless @thumbf
|
|
20
|
+
@url = path.clone
|
|
21
|
+
@url[0] = "/" # replace _ with /
|
|
22
|
+
else
|
|
23
|
+
# thumbnail
|
|
24
|
+
@url = path[(HTMLDIR.length)..-1]
|
|
25
|
+
end
|
|
26
|
+
@dimensions = Point.new(0,0)
|
|
27
|
+
#=============================== [0] = realpath
|
|
28
|
+
# [1] = type
|
|
29
|
+
# [2] = Dimensions
|
|
30
|
+
#=============================== [3] = Dimensions+?+?
|
|
31
|
+
#=============================== [4] = Color depth
|
|
32
|
+
#=============================== [5] = Color space
|
|
33
|
+
#=============================== [6] = Bytes // not accurate for ani-gif
|
|
34
|
+
#=============================== [7] = ?
|
|
35
|
+
#=============================== [8] = ?
|
|
36
|
+
arr = %x{identify #{@path}}.split(" ")
|
|
37
|
+
dim = arr[2].split("x")
|
|
38
|
+
@dimensions.x = dim[0].to_i
|
|
39
|
+
@dimensions.y = dim[1].to_i
|
|
40
|
+
#@size = arr[6].to_i
|
|
41
|
+
@size = File.size(path)
|
|
42
|
+
@type = arr[1].clone
|
|
43
|
+
# validate file size
|
|
44
|
+
if @size > Zarchitect.conf.image_limit.to_f.mib_to_bytes
|
|
45
|
+
GPI.print "Error: File #{path} too large "\
|
|
46
|
+
"(#{@size.bytes_to_mib.to_f.round(2)}MiB)."\
|
|
47
|
+
" Allowed size: #{Zarchitect.conf.image_limit.to_f.mb_to_mib.round(2)}"
|
|
48
|
+
GPI.quit
|
|
49
|
+
end
|
|
50
|
+
strip_exif unless @thumbf
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def thumb_small?
|
|
54
|
+
@thumbs_f
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def thumb_large?
|
|
58
|
+
@thumbl_f
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def url
|
|
62
|
+
=begin
|
|
63
|
+
if (!(Page.current_page.nil?) && Page.current_page.draft && !@@search)
|
|
64
|
+
File.join("..", DRAFTDIR, @url)
|
|
65
|
+
else
|
|
66
|
+
@url
|
|
67
|
+
end
|
|
68
|
+
=end
|
|
69
|
+
@url
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def larger_than_thumb_small?
|
|
73
|
+
@dimensions.x > Zarchitect.conf.thumbs[0].to_i ||
|
|
74
|
+
@dimensions.y > Zarchitect.conf.thumbs[1].to_i
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def larger_than_thumb_large?
|
|
78
|
+
@dimensions.x > Zarchitect.conf.thumbl[0].to_i ||
|
|
79
|
+
@dimensions.y > Zarchitect.conf.thumbl[1].to_i
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def create_thumbnail(path, thumb_x, thumb_y)
|
|
83
|
+
GPI.print "attempting to create thumbnail #{path}",
|
|
84
|
+
GPI::CLU.check_option('v')
|
|
85
|
+
return false if path.include?("/#{SHARESDIR}/") # no thumbs for pic within
|
|
86
|
+
x = @dimensions.x
|
|
87
|
+
y = @dimensions.y
|
|
88
|
+
if x <= thumb_x && y <= thumb_y # no need to create thumbnail
|
|
89
|
+
GPI.print "abort thumbnail creation. No thumbnail #{thumb_x}x"\
|
|
90
|
+
"#{thumb_y} necessary", GPI::CLU.check_option('v')
|
|
91
|
+
return false
|
|
92
|
+
end
|
|
93
|
+
if ["PNG", "GIF"].include?(@type)
|
|
94
|
+
# scale
|
|
95
|
+
while true do
|
|
96
|
+
x = x/2
|
|
97
|
+
y = y/2
|
|
98
|
+
break if x <= thumb_x && y <= thumb_y
|
|
99
|
+
end
|
|
100
|
+
if x < 1 || y < 1
|
|
101
|
+
GPI.print "failed to create #{path}: invalid downsizing",
|
|
102
|
+
GPI::CLU.check_option('v')
|
|
103
|
+
return false
|
|
104
|
+
end
|
|
105
|
+
command = "convert #{@path} -scale #{x}x#{y} #{path}"
|
|
106
|
+
GPI.print "#{command}", GPI::CLU.check_option('v')
|
|
107
|
+
o = %x{#{command}}
|
|
108
|
+
GPI.print o, GPI::CLU.check_option('v')
|
|
109
|
+
return true
|
|
110
|
+
else
|
|
111
|
+
# resize
|
|
112
|
+
command = "convert #{@path} -resize #{thumb_x}x#{thumb_y} #{path}"
|
|
113
|
+
GPI.print "#{command}", GPI::CLU.check_option('v')
|
|
114
|
+
o = %x{#{command}}
|
|
115
|
+
GPI.print o, GPI::CLU.check_option('v')
|
|
116
|
+
return true
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.is_valid?(filename)
|
|
121
|
+
[".png",".gif",".jpg",".jpeg",".bmp"].include?(File.extname(filename))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.find(k, v)
|
|
125
|
+
@@search = true
|
|
126
|
+
# o = Image.find("url", "/files/projects/tre/screen1.png") // usage
|
|
127
|
+
GPI.print "Looking for img: #{v}", GPI::CLU.check_option('v')
|
|
128
|
+
ObjectSpace.each_object(ImageSet) do |set|
|
|
129
|
+
str = set.orig.send(k)
|
|
130
|
+
#GPI.print "v: #{v}", GPI::CLU.check_option('v')
|
|
131
|
+
#GPI.print "str: #{str}", GPI::CLU.check_option('v')
|
|
132
|
+
if str == v
|
|
133
|
+
GPI.print "Image found", GPI::CLU.check_option('v')
|
|
134
|
+
@@search = false
|
|
135
|
+
return set
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
@@search = false
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
private
|
|
143
|
+
|
|
144
|
+
def strip_exif
|
|
145
|
+
return unless @type == "JPEG"
|
|
146
|
+
command = "exiv2 rm #{@path}"
|
|
147
|
+
GPI.print "#{command}", GPI::CLU.check_option('v')
|
|
148
|
+
o = %x{#{command}}
|
|
149
|
+
GPI.print o, GPI::CLU.check_option('v')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
class Point
|
|
155
|
+
attr_accessor :x, :y
|
|
156
|
+
|
|
157
|
+
def initialize(x, y)
|
|
158
|
+
@x = x
|
|
159
|
+
@y = y
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class ImageSet < Zarchitect
|
|
2
|
+
attr_reader :orig, :thumbs, :thumbl
|
|
3
|
+
#TODO abort on invalid filesize
|
|
4
|
+
|
|
5
|
+
def initialize(path, fullpath, realpath)
|
|
6
|
+
@thumbl = nil
|
|
7
|
+
@thumbs = nil
|
|
8
|
+
# path = /section/title/img.png
|
|
9
|
+
# fullpath = _files/section/title/img.png
|
|
10
|
+
# realpath = _html/files/section/title/img.png
|
|
11
|
+
filename = File.basename(path, ".*")
|
|
12
|
+
extension = File.extname(path)
|
|
13
|
+
realdir = File.dirname(realpath)
|
|
14
|
+
@orig = Image.new(fullpath, false)
|
|
15
|
+
|
|
16
|
+
# check if thumbnails exist
|
|
17
|
+
# attempt to create them if not
|
|
18
|
+
thumbs_path = "#{File.join(realdir, filename)}-thumbs#{extension}"
|
|
19
|
+
thumbl_path = "#{File.join(realdir, filename)}-thumbl#{extension}"
|
|
20
|
+
@orig.thumbs_f = File.exist?(thumbs_path)
|
|
21
|
+
@orig.thumbl_f = File.exist?(thumbl_path)
|
|
22
|
+
unless @orig.thumb_small?
|
|
23
|
+
if @orig.larger_than_thumb_small?
|
|
24
|
+
r = @orig.create_thumbnail(thumbs_path, Zarchitect.conf.thumbs[0].to_i,
|
|
25
|
+
Zarchitect.conf.thumbs[1].to_i)
|
|
26
|
+
@orig.thumbs_f = r
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
unless @orig.thumb_large?
|
|
30
|
+
if @orig.larger_than_thumb_small?
|
|
31
|
+
r = @orig.create_thumbnail(thumbl_path, Zarchitect.conf.thumbl[0].to_i,
|
|
32
|
+
Zarchitect.conf.thumbl[1].to_i)
|
|
33
|
+
@orig.thumbl_f = r
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
# set thumbnails if created
|
|
37
|
+
if @orig.thumb_small?
|
|
38
|
+
@thumbs = Image.new(thumbs_path, true)
|
|
39
|
+
end
|
|
40
|
+
if @orig.thumb_large?
|
|
41
|
+
@thumbl = Image.new(thumbl_path, true)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|