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