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,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