runeblog 0.1.76 → 0.1.78
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/data/standard.tgz +0 -0
- data/lib/default.rb +3 -5
- data/lib/helpers-blog.rb +28 -8
- data/lib/liveblog.rb +455 -37
- data/lib/post.rb +55 -71
- data/lib/publish.rb +1 -1
- data/lib/repl.rb +24 -3
- data/lib/runeblog.rb +127 -52
- data/lib/runeblog_version.rb +5 -1
- data/lib/view.rb +3 -2
- data/runeblog.gemspec +1 -1
- data/test/make_blog.rb +37 -35
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e483b3ec658dfbb130d8b2b090107155af6c5371066949ae9d78bf8b4851525
|
4
|
+
data.tar.gz: 91ae3aebfefc68e69ddea4aa9cb700a28a572a422f41b9c010b570271069c22e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd0a51b5eef53f86f738e51dca6428bf2eefa6373912e023c61819aadef977b30f4e7735d0a3a183944f4071c136d797ba6f32f06e327e663bd75ba84db4efe2
|
7
|
+
data.tar.gz: a531739bb62e383d4e660a7f9e630a786934d739badfd179359d63392f23f5486c62b6f53922169b0ee12c319da71edad2fb7ec7839497fa2c3121be4d2bcf6c
|
data/data/standard.tgz
CHANGED
Binary file
|
data/lib/default.rb
CHANGED
@@ -3,7 +3,7 @@ class RuneBlog::Default
|
|
3
3
|
# This will all become much more generic later.
|
4
4
|
|
5
5
|
|
6
|
-
def RuneBlog.post_template(title: "No title", date: nil, view: "test_view",
|
6
|
+
def RuneBlog.post_template(num: 0, title: "No title", date: nil, view: "test_view",
|
7
7
|
teaser: "No teaser", body: "No body", tags: ["untagged"],
|
8
8
|
views: [], back: "javascript:history.go(-1)", home: "no url")
|
9
9
|
viewlist = (views + [view.to_s]).join(" ")
|
@@ -11,6 +11,8 @@ def RuneBlog.post_template(title: "No title", date: nil, view: "test_view",
|
|
11
11
|
<<-TEXT
|
12
12
|
.mixin liveblog
|
13
13
|
. ^ get rid of this later
|
14
|
+
|
15
|
+
.post #{num}
|
14
16
|
|
15
17
|
.title #{title}
|
16
18
|
.pubdate #{date}
|
@@ -21,10 +23,6 @@ def RuneBlog.post_template(title: "No title", date: nil, view: "test_view",
|
|
21
23
|
#{teaser}
|
22
24
|
.end
|
23
25
|
#{body}
|
24
|
-
<hr>
|
25
|
-
<a href='#{back}' style='text-decoration: none'>Back</a>
|
26
|
-
<br>
|
27
|
-
<a href='#{home}' style='text-decoration: none'>Home</a>
|
28
26
|
TEXT
|
29
27
|
|
30
28
|
end
|
data/lib/helpers-blog.rb
CHANGED
@@ -1,15 +1,31 @@
|
|
1
1
|
require 'runeblog_version'
|
2
2
|
|
3
|
+
# Home = Dir.pwd # unless Home
|
4
|
+
|
3
5
|
module RuneBlog::Helpers
|
4
6
|
|
7
|
+
def get_root
|
8
|
+
if $_blog
|
9
|
+
if $_blog.root
|
10
|
+
puts "0. Returned: #{$_blog.root}/"
|
11
|
+
return $_blog.root + "/"
|
12
|
+
else
|
13
|
+
puts "1. Returned: ./"
|
14
|
+
return "./"
|
15
|
+
end
|
16
|
+
else
|
17
|
+
puts "2. Returned: ./"
|
18
|
+
return "./"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
5
22
|
def read_config(file, *syms)
|
6
|
-
#
|
23
|
+
# puts "dir = #{Dir.pwd}"
|
7
24
|
lines = File.readlines(file).map(&:chomp)
|
8
25
|
obj = ::OpenStruct.new
|
9
26
|
lines.each do |line|
|
10
27
|
next if line == "\n" || line[0] == "#"
|
11
28
|
key, val = line.split(/: +/, 2)
|
12
|
-
# STDERR.puts [key, val].inspect
|
13
29
|
obj.send(key+"=", val)
|
14
30
|
end
|
15
31
|
return obj if syms.empty?
|
@@ -37,6 +53,8 @@ module RuneBlog::Helpers
|
|
37
53
|
|
38
54
|
def write_config(obj, file)
|
39
55
|
hash = obj.to_h
|
56
|
+
# Dir.chdir(::Home)
|
57
|
+
# puts "--- wc: pwd = #{Dir.pwd}"
|
40
58
|
File.open(file, "w") do |f|
|
41
59
|
hash.each_pair do |key, val|
|
42
60
|
f.puts "#{key}: #{val}"
|
@@ -45,11 +63,13 @@ module RuneBlog::Helpers
|
|
45
63
|
end
|
46
64
|
|
47
65
|
def get_views # read from filesystem
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
66
|
+
# Dir.chdir(::Home) do
|
67
|
+
verify(@root => "#@root is nil",
|
68
|
+
Dir.exist?(@root) => "#@root doesn't exist",
|
69
|
+
Dir.exist?("#@root/views") => "#@root/views doesn't exist")
|
70
|
+
dirs = subdirs("#@root/views/").sort
|
71
|
+
dirs.map {|name| RuneBlog::View.new(name) }
|
72
|
+
# end
|
53
73
|
end
|
54
74
|
|
55
75
|
def new_dotfile(root: "./.blogs/data", current_view: "no_default", editor: "vi")
|
@@ -57,7 +77,7 @@ module RuneBlog::Helpers
|
|
57
77
|
Dir.mkdir(".blogs")
|
58
78
|
x = OpenStruct.new
|
59
79
|
x.root, x.current_view, x.editor = root, current_view, editor
|
60
|
-
write_config(x, RuneBlog::ConfigFile)
|
80
|
+
write_config(x, ".blogs/" + RuneBlog::ConfigFile)
|
61
81
|
end
|
62
82
|
|
63
83
|
def new_sequence
|
data/lib/liveblog.rb
CHANGED
@@ -2,7 +2,34 @@ require 'ostruct'
|
|
2
2
|
require 'pp'
|
3
3
|
require 'date'
|
4
4
|
|
5
|
-
|
5
|
+
require 'livetext'
|
6
|
+
require 'runeblog'
|
7
|
+
|
8
|
+
# ::Home = Dir.pwd unless defined?(::Home)
|
9
|
+
|
10
|
+
=begin
|
11
|
+
123:def title # side-effect
|
12
|
+
133:def pubdate # side-effect
|
13
|
+
153:def tags # side-effect
|
14
|
+
160:def views # side-effect
|
15
|
+
167:def pin # side-effect
|
16
|
+
218:def write_post # side-effect
|
17
|
+
393:def main # side-effect
|
18
|
+
491:def _post_lookup(postid) # side-effect
|
19
|
+
=end
|
20
|
+
|
21
|
+
def post
|
22
|
+
@meta = OpenStruct.new
|
23
|
+
@meta.num = _args[0]
|
24
|
+
# @live = ::Livetext.new
|
25
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def _view_from_cwd
|
29
|
+
md = Dir.pwd.match(%r[.*/views/(.*?)/])
|
30
|
+
return md[1] if md
|
31
|
+
nil
|
32
|
+
end
|
6
33
|
|
7
34
|
def quote
|
8
35
|
_passthru "<blockquote>"
|
@@ -67,28 +94,27 @@ end
|
|
67
94
|
|
68
95
|
### copy_asset
|
69
96
|
|
70
|
-
def copy_asset(asset)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
97
|
+
# def copy_asset(asset)
|
98
|
+
# vdir = @blog.view.dir
|
99
|
+
# return if File.exist?(vdir + "/assets/" + asset)
|
100
|
+
# top = vdir + "/../../assets/"
|
101
|
+
# if File.exist?(top + asset)
|
102
|
+
# system("cp #{top}/#{asset} #{vdir}/assets/#{asset}")
|
103
|
+
# return
|
104
|
+
# end
|
105
|
+
# raise "Can't find #{asset.inspect}"
|
106
|
+
# end
|
80
107
|
|
81
108
|
#############
|
82
109
|
|
83
110
|
def init_liveblog # FIXME - a lot of this logic sucks
|
84
|
-
@blog
|
85
|
-
@
|
86
|
-
@
|
87
|
-
@
|
88
|
-
@
|
89
|
-
@
|
90
|
-
@
|
91
|
-
# @body = ""
|
111
|
+
@blog = $_blog = RuneBlog.new(false)
|
112
|
+
@root = @blog.root
|
113
|
+
@view = @blog.view
|
114
|
+
@view_name = @blog.view.name
|
115
|
+
@vdir = @blog.view.dir
|
116
|
+
@version = RuneBlog::VERSION
|
117
|
+
@theme = @vdir + "/themes/standard/"
|
92
118
|
end
|
93
119
|
|
94
120
|
def _errout(*args)
|
@@ -109,14 +135,19 @@ def _passthru_noline(line)
|
|
109
135
|
_out "<p>" if line.empty? && ! @_nopara
|
110
136
|
end
|
111
137
|
|
112
|
-
def title
|
138
|
+
def title # side-effect
|
139
|
+
raise "'post' was not called" unless @meta
|
113
140
|
title = @_data.chomp
|
114
141
|
@meta.title = title
|
115
|
-
|
142
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
143
|
+
# @live.setvar :title, title
|
144
|
+
setvar :title, title
|
145
|
+
_out %[<h1 class="post-title">#{title}</h1><br>]
|
116
146
|
_optional_blank_line
|
117
147
|
end
|
118
148
|
|
119
|
-
def pubdate
|
149
|
+
def pubdate # side-effect
|
150
|
+
raise "'post' was not called" unless @meta
|
120
151
|
_debug "data = #@_data"
|
121
152
|
# Check for discrepancy?
|
122
153
|
match = /(\d{4}).(\d{2}).(\d{2})/.match @_data
|
@@ -124,6 +155,7 @@ def pubdate
|
|
124
155
|
y, m, d = y.to_i, m.to_i, d.to_i
|
125
156
|
@meta.date = ::Date.new(y, m, d)
|
126
157
|
@meta.pubdate = "%04d-%02d-%02d" % [y, m, d]
|
158
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
127
159
|
_optional_blank_line
|
128
160
|
end
|
129
161
|
|
@@ -135,22 +167,28 @@ def image # primitive so far
|
|
135
167
|
_optional_blank_line
|
136
168
|
end
|
137
169
|
|
138
|
-
def tags
|
170
|
+
def tags # side-effect
|
171
|
+
raise "'post' was not called" unless @meta
|
139
172
|
_debug "args = #{_args}"
|
140
173
|
@meta.tags = _args.dup || []
|
174
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
141
175
|
_optional_blank_line
|
142
176
|
end
|
143
177
|
|
144
|
-
def views
|
178
|
+
def views # side-effect
|
179
|
+
raise "'post' was not called" unless @meta
|
145
180
|
_debug "data = #{_args}"
|
146
181
|
@meta.views = _args.dup # + ["main"]
|
182
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
147
183
|
_optional_blank_line
|
148
184
|
end
|
149
185
|
|
150
|
-
def pin
|
186
|
+
def pin # side-effect
|
187
|
+
raise "'post' was not called" unless @meta
|
151
188
|
_debug "data = #{_args}"
|
152
189
|
# verify only already-specified views?
|
153
190
|
@meta.pinned = _args.dup
|
191
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
154
192
|
_optional_blank_line
|
155
193
|
end
|
156
194
|
|
@@ -166,7 +204,7 @@ end
|
|
166
204
|
|
167
205
|
def list!
|
168
206
|
_out "<ul>"
|
169
|
-
lines = _body.each
|
207
|
+
lines = _body.each
|
170
208
|
loop do
|
171
209
|
line = lines.next
|
172
210
|
line = _format(line)
|
@@ -181,7 +219,9 @@ def list!
|
|
181
219
|
end
|
182
220
|
|
183
221
|
def asset
|
222
|
+
raise "'post' was not called" unless @meta
|
184
223
|
@meta.assets ||= {}
|
224
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
185
225
|
list = _args
|
186
226
|
# For now: copies, doesn't keep record
|
187
227
|
# Later: Add to file and uniq; use in publishing
|
@@ -190,27 +230,35 @@ def asset
|
|
190
230
|
end
|
191
231
|
|
192
232
|
def assets
|
233
|
+
raise "'post' was not called" unless @meta
|
193
234
|
@meta.assets ||= []
|
194
235
|
@meta.assets += _body
|
236
|
+
# STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
195
237
|
_optional_blank_line
|
196
238
|
end
|
197
239
|
|
198
|
-
def write_post
|
240
|
+
def write_post # side-effect
|
241
|
+
raise "'post' was not called" unless @meta
|
242
|
+
# return
|
199
243
|
save = Dir.pwd
|
200
244
|
@postdir.gsub!(/\/\//, "/") # FIXME unneeded?
|
201
245
|
Dir.mkdir(@postdir) unless Dir.exist?(@postdir) # FIXME remember assets!
|
202
246
|
Dir.chdir(@postdir)
|
203
|
-
|
204
|
-
meta.
|
205
|
-
|
206
|
-
|
247
|
+
STDERR.puts "------ cd into #@postdir"
|
248
|
+
@meta.views = @meta.views.join(" ")
|
249
|
+
@meta.tags = @meta.tags.join(" ") rescue ""
|
250
|
+
# STDERR.puts ">>>> #{__method__}: writing #{@live.body.size} bytes to #{Dir.pwd}/body.txt"
|
251
|
+
# File.write("body.txt", @live.body) # Actually HTML...
|
252
|
+
# p Dir.pwd
|
253
|
+
File.write("teaser.txt", @meta.teaser)
|
207
254
|
|
208
255
|
fields = [:num, :title, :date, :pubdate, :views, :tags]
|
209
256
|
|
210
257
|
fname2 = "metadata.txt"
|
211
258
|
f2 = File.open(fname2, "w") do |f2|
|
212
|
-
fields.each {|fld| f2.puts "#{fld}: #{meta.send(fld)}" }
|
259
|
+
fields.each {|fld| f2.puts "#{fld}: #{@meta.send(fld)}" }
|
213
260
|
end
|
261
|
+
STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
214
262
|
Dir.chdir(save)
|
215
263
|
rescue => err
|
216
264
|
puts "err = #{err}"
|
@@ -218,20 +266,29 @@ rescue => err
|
|
218
266
|
end
|
219
267
|
|
220
268
|
def teaser
|
221
|
-
|
269
|
+
raise "'post' was not called" unless @meta
|
222
270
|
@meta.teaser = _body_text
|
271
|
+
STDERR.puts ">>> #{__method__}: @meta = #{@meta.to_h.inspect}"
|
223
272
|
_out @meta.teaser + "\n"
|
273
|
+
STDERR.puts "TEASER cwd = #{Dir.pwd}"
|
274
|
+
# file = @vdir + "/teaser.txt"
|
275
|
+
# File.write(file, @meta.teaser)
|
224
276
|
# FIXME
|
225
277
|
end
|
226
278
|
|
227
279
|
def finalize
|
280
|
+
unless @meta
|
281
|
+
puts @live.body
|
282
|
+
return
|
283
|
+
end
|
228
284
|
if @blog.nil?
|
229
|
-
|
230
|
-
return @live.body
|
285
|
+
return @meta # @live.body
|
231
286
|
end
|
287
|
+
|
232
288
|
@slug = @blog.make_slug(@meta)
|
233
|
-
|
234
|
-
|
289
|
+
slug_dir = @slug
|
290
|
+
@postdir = @blog.view.dir + "/posts/#{slug_dir}"
|
291
|
+
write_post
|
235
292
|
@meta
|
236
293
|
end
|
237
294
|
|
@@ -264,3 +321,364 @@ class Livetext::Functions
|
|
264
321
|
end
|
265
322
|
|
266
323
|
end
|
324
|
+
|
325
|
+
###### experimental...
|
326
|
+
|
327
|
+
class Livetext::Functions
|
328
|
+
|
329
|
+
def _var(name)
|
330
|
+
::Livetext::Vars[name] || "[:#{name} is undefined]"
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
def link
|
335
|
+
file, cdata = self.class.param.split("||", 2)
|
336
|
+
%[<link type="application/atom+xml" rel="alternate" href="#{_var(:host)}#{file}" title="#{_var(:title)}">]
|
337
|
+
end
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
###############
|
342
|
+
|
343
|
+
|
344
|
+
def _var(name) # FIXME later
|
345
|
+
::Livetext::Vars[name] || "[:#{name} is undefined]"
|
346
|
+
end
|
347
|
+
|
348
|
+
def head
|
349
|
+
# Depends on vars: title, desc, host
|
350
|
+
defaults = {}
|
351
|
+
defaults = { "charset" => %[<meta charset="utf-8">],
|
352
|
+
"http-equiv" => %[<meta http-equiv="X-UA-Compatible" content="IE=edge">],
|
353
|
+
"title" => %[<title>\n #{_var(:title)} | #{_var(:desc)}\n </title>],
|
354
|
+
"generator" => %[<meta name="generator" content="Runeblog v #@version">],
|
355
|
+
"og:title" => %[<meta property="og:title" content="#{_var(:title)}">],
|
356
|
+
"og:locale" => %[<meta property="og:locale" content="en_US">],
|
357
|
+
"description" => %[<meta name="description" content="#{_var(:desc)}">],
|
358
|
+
"og:description" => %[<meta property="og:description" content="#{_var(:desc)}">],
|
359
|
+
"linkc" => %[<link rel="canonical" href="#{_var(:host)}">],
|
360
|
+
"og:url" => %[<meta property="og:url" content="#{_var(:host)}">],
|
361
|
+
"og:site_name" => %[<meta property="og:site_name" content="#{_var(:title)}">],
|
362
|
+
"style" => %[<link rel="stylesheet" href="../assets/application.css">],
|
363
|
+
"feed" => %[<link type="application/atom+xml" rel="alternate" href="#{_var(:host)}/feed.xml" title="#{_var(:title)}">],
|
364
|
+
"favicon" => %[<link rel="shortcut icon" type="image/x-icon" href="../assets/favicon.ico">\n <link rel="apple-touch-icon" href="../assets/favicon.ico">]
|
365
|
+
}
|
366
|
+
result = {}
|
367
|
+
lines = _body
|
368
|
+
lines.each do |line|
|
369
|
+
line.chomp
|
370
|
+
word, remain = line.split(" ", 2)
|
371
|
+
case word
|
372
|
+
when "viewport"
|
373
|
+
result["viewport"] = %[<meta name="viewport" content="#{remain}">]
|
374
|
+
when "script"
|
375
|
+
file = remain
|
376
|
+
text = File.read(file)
|
377
|
+
result["script"] = Livetext.new.transform(text)
|
378
|
+
when "style"
|
379
|
+
result["style"] = %[<link rel="stylesheet" href="('/assets/#{remain}')">]
|
380
|
+
# Later: allow other overrides
|
381
|
+
when ""; break
|
382
|
+
else
|
383
|
+
puts "Unknown tag '#{word}'"
|
384
|
+
end
|
385
|
+
end
|
386
|
+
hash = defaults.dup.update(result) # FIXME collisions?
|
387
|
+
_out "<html lang=en_US>"
|
388
|
+
_out "<head>"
|
389
|
+
hash.each_value {|x| _out " " + x }
|
390
|
+
_out "</head>"
|
391
|
+
_out "<body>"
|
392
|
+
end
|
393
|
+
|
394
|
+
########## newer stuff...
|
395
|
+
|
396
|
+
def meta
|
397
|
+
args = _args
|
398
|
+
enum = args.each
|
399
|
+
str = "<meta"
|
400
|
+
arg = enum.next
|
401
|
+
loop do
|
402
|
+
if arg.end_with?(":")
|
403
|
+
str << " " << arg[0..-2] << "="
|
404
|
+
a2 = enum.next
|
405
|
+
str << %["#{a2}"]
|
406
|
+
else
|
407
|
+
STDERR.puts "=== meta error?"
|
408
|
+
end
|
409
|
+
arg = enum.next
|
410
|
+
end
|
411
|
+
str << ">"
|
412
|
+
_out str
|
413
|
+
end
|
414
|
+
|
415
|
+
def main # side-effect
|
416
|
+
_out %[<div class="col-lg-9 col-md-9 col-sm-9 col-xs-12">]
|
417
|
+
which = _args[0]
|
418
|
+
STDERR.puts "--- inside #main: which = #{which.inspect}"
|
419
|
+
case which
|
420
|
+
when "recent_posts"
|
421
|
+
all_teasers # FIXME does nothing yet
|
422
|
+
when "post"
|
423
|
+
self.data = "post-index.lt3"
|
424
|
+
_include
|
425
|
+
end
|
426
|
+
_out %[</div>]
|
427
|
+
end
|
428
|
+
|
429
|
+
def sidebar
|
430
|
+
_out %[<div class="col-lg-3 col-md-3 col-sm-3 col-xs-12">]
|
431
|
+
_body do |line|
|
432
|
+
tag = line.chomp.strip
|
433
|
+
self.data = "sidebar/#{tag.downcase}.lt3"
|
434
|
+
_include
|
435
|
+
end
|
436
|
+
_out %[</div>]
|
437
|
+
end
|
438
|
+
|
439
|
+
def sidebar2
|
440
|
+
_out %[<div class="col-lg-3 col-md-3 col-sm-3 col-xs-12">]
|
441
|
+
_args do |line|
|
442
|
+
tag = line.chomp.strip
|
443
|
+
self.data = "sidebar/#{tag.downcase}.lt3"
|
444
|
+
_include
|
445
|
+
end
|
446
|
+
_out %[</div>]
|
447
|
+
end
|
448
|
+
|
449
|
+
def stylesheet
|
450
|
+
lines = _body
|
451
|
+
url = lines[0]
|
452
|
+
integ = lines[1]
|
453
|
+
cross = lines[2] || "anonymous"
|
454
|
+
_out %[<link rel="stylesheet" href="#{url}" integrity="#{integ}" crossorigin="#{cross}"></link>]
|
455
|
+
end
|
456
|
+
|
457
|
+
def script
|
458
|
+
lines = _body
|
459
|
+
url = lines[0]
|
460
|
+
integ = lines[1]
|
461
|
+
cross = lines[2] || "anonymous"
|
462
|
+
_out %[<script src="#{url}" integrity="#{integ}" crossorigin="#{cross}"></script>]
|
463
|
+
end
|
464
|
+
|
465
|
+
### How this next bit works:
|
466
|
+
###
|
467
|
+
### all_teasers will call _find_recent_posts
|
468
|
+
###
|
469
|
+
### _find_recent_posts will search higher in the directory structure
|
470
|
+
### for where the posts are (0001, 0002, ...) NOTE: This implies you
|
471
|
+
### must be in some specific place when this code is run.
|
472
|
+
### It returns the 20 most recent posts.
|
473
|
+
###
|
474
|
+
### all_teasers will then pick a small number of posts and call _teaser
|
475
|
+
|
476
|
+
### on each one. (The code in _teaser really belongs in a small template
|
477
|
+
### somewhere.)
|
478
|
+
###
|
479
|
+
|
480
|
+
def _find_recent_posts
|
481
|
+
STDERR.puts "--- frp: $FileDir = #{_var(:FileDir)}"
|
482
|
+
@vdir = _var(:FileDir).match(%r[(^.*/views/.*?)/])[1]
|
483
|
+
posts = nil
|
484
|
+
dir_posts = @vdir + "/posts"
|
485
|
+
entries = Dir.entries(dir_posts)
|
486
|
+
STDERR.puts "--- frp: dir_posts = #{dir_posts} ent = #{entries.inspect}"
|
487
|
+
posts = entries.grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
|
488
|
+
posts.select! {|x| File.directory?(x) }
|
489
|
+
# directories that start with four digits
|
490
|
+
posts = posts.sort {|a, b| b.to_i <=> a.to_i } # sort descending
|
491
|
+
posts[0..19] # return 20 at most
|
492
|
+
end
|
493
|
+
|
494
|
+
def all_teasers
|
495
|
+
STDERR.puts "-- inside #all_teasers..."
|
496
|
+
open = <<-HTML
|
497
|
+
<section class="posts">
|
498
|
+
HTML
|
499
|
+
close = <<-HTML
|
500
|
+
</section>
|
501
|
+
HTML
|
502
|
+
STDERR.puts "=== at01"
|
503
|
+
_out open
|
504
|
+
# FIXME: Now do the magic...
|
505
|
+
STDERR.puts "=== at02"
|
506
|
+
posts = _find_recent_posts
|
507
|
+
STDERR.puts "=== at03"
|
508
|
+
wanted = [5, posts.size].min # estimate how many we want?
|
509
|
+
STDERR.puts "=== at04"
|
510
|
+
enum = posts.each
|
511
|
+
STDERR.puts "=== at05"
|
512
|
+
wanted.times do
|
513
|
+
STDERR.puts "=== at06 (loop)"
|
514
|
+
postid = File.basename(enum.next)
|
515
|
+
STDERR.puts "=== at07"
|
516
|
+
postid = postid.to_i
|
517
|
+
STDERR.puts "=== at08"
|
518
|
+
_teaser(postid)
|
519
|
+
STDERR.puts "=== at09"
|
520
|
+
end
|
521
|
+
_out close
|
522
|
+
end
|
523
|
+
|
524
|
+
def _post_lookup(postid) # side-effect
|
525
|
+
# .. = templates, ../.. = views/thisview
|
526
|
+
slug = title = date = teaser_text = nil
|
527
|
+
|
528
|
+
dir_posts = @vdir + "/posts"
|
529
|
+
posts = Dir.entries(dir_posts).grep(/^\d\d\d\d/).map {|x| dir_posts + "/" + x }
|
530
|
+
posts.select! {|x| File.directory?(x) }
|
531
|
+
|
532
|
+
post = posts.select {|x| File.basename(x).to_i == postid }
|
533
|
+
raise "Error: More than one post #{postid}" if post.size > 1
|
534
|
+
postdir = post.first
|
535
|
+
fname = "#{postdir}/teaser.txt"
|
536
|
+
teaser_text = File.read(fname).chomp
|
537
|
+
# FIXME dumb hacks...
|
538
|
+
mdfile = "#{postdir}/metadata.txt"
|
539
|
+
lines = File.readlines(mdfile)
|
540
|
+
title = lines.grep(/title:/).first[7..-1].chomp
|
541
|
+
date = lines.grep(/pubdate:/).first[9..-1].chomp
|
542
|
+
slug = postdir
|
543
|
+
[slug, title, date, teaser_text]
|
544
|
+
end
|
545
|
+
|
546
|
+
def _interpolate(str, context) # FIXME move this later
|
547
|
+
wrapped = "%[" + str.dup + "]" # could fail...
|
548
|
+
eval(wrapped, context)
|
549
|
+
end
|
550
|
+
|
551
|
+
def _teaser(slug)
|
552
|
+
id = slug.to_i
|
553
|
+
text = nil
|
554
|
+
post_entry_name = @theme + "blog-_postentry.lt3"
|
555
|
+
@_post_entry ||= File.read(post_entry_name)
|
556
|
+
slug = title = date = teaser_text = nil
|
557
|
+
slug, title, date, teaser_text = _post_lookup(id)
|
558
|
+
# vdir = File.expand_path("../../..")
|
559
|
+
url = "#@vdir/#{slug}.html"
|
560
|
+
date = Date.parse(date)
|
561
|
+
date = date.strftime("%B %e<br>%Y")
|
562
|
+
text = _interpolate(@_post_entry, binding)
|
563
|
+
# File.write("../../../generated/#{slug}.html", text)
|
564
|
+
_out text
|
565
|
+
end
|
566
|
+
|
567
|
+
def card_iframe
|
568
|
+
title = _data
|
569
|
+
lines = _body
|
570
|
+
url = lines[0].chomp
|
571
|
+
stuff = lines[1..-1].join(" ") # FIXME later
|
572
|
+
text = <<-HTML
|
573
|
+
<div class="card mb-3">
|
574
|
+
<div class="card-body">
|
575
|
+
<h5 class="card-title">#{title}</h5>
|
576
|
+
<iframe src="#{url}" #{stuff}
|
577
|
+
style="border: 0" height="350"
|
578
|
+
frameborder="0" scrolling="no">
|
579
|
+
</iframe>
|
580
|
+
</div>
|
581
|
+
</div>
|
582
|
+
HTML
|
583
|
+
_out text
|
584
|
+
rescue
|
585
|
+
puts @live.body
|
586
|
+
end
|
587
|
+
|
588
|
+
def card1
|
589
|
+
card_title = _data
|
590
|
+
lines = _body
|
591
|
+
lines.map!(&:chomp)
|
592
|
+
card_text = lines[0]
|
593
|
+
url, target, classname, cdata = lines[1].split(",", 4)
|
594
|
+
text = <<-HTML
|
595
|
+
<div class="card bg-dark text-white mb-3">
|
596
|
+
<div class="card-body">
|
597
|
+
<h5 class="card-title">#{card_title}</h5>
|
598
|
+
<p class="card-text">#{card_text}</p>
|
599
|
+
<a href="#{url}" target="#{target}" class="#{classname}">#{cdata}</a>
|
600
|
+
</div>
|
601
|
+
</div>
|
602
|
+
HTML
|
603
|
+
_out text + "\n "
|
604
|
+
rescue
|
605
|
+
puts @live.body
|
606
|
+
end
|
607
|
+
|
608
|
+
def card2
|
609
|
+
card_title = _data
|
610
|
+
open = <<-HTML
|
611
|
+
<div class="card mb-3">
|
612
|
+
<div class="card-body">
|
613
|
+
<h5 class="card-title">#{card_title}</h5>
|
614
|
+
</div>
|
615
|
+
<ul class="list-group list-group-flush">
|
616
|
+
HTML
|
617
|
+
_out open
|
618
|
+
_body do |line|
|
619
|
+
url, target, cdata = line.chomp.split(",", 3)
|
620
|
+
_out %[<li class="list-group-item"><a href="#{url}" target="#{target}">#{cdata}</a> </li>]
|
621
|
+
end
|
622
|
+
close = %[ </ul>\n </div>]
|
623
|
+
_out close
|
624
|
+
rescue
|
625
|
+
puts @live.body
|
626
|
+
end
|
627
|
+
|
628
|
+
def tag_cloud
|
629
|
+
title = _data
|
630
|
+
title = "Tag Cloud" if title.empty?
|
631
|
+
open = <<-HTML
|
632
|
+
<div class="card mb-3">
|
633
|
+
<div class="card-body">
|
634
|
+
<h5 class="card-title">#{title}</h5>
|
635
|
+
HTML
|
636
|
+
_out open
|
637
|
+
_body do |line|
|
638
|
+
line.chomp!
|
639
|
+
url, target, classname, cdata = line.split(",", 4)
|
640
|
+
_out %[<a href="#{url}" target="#{target}" class="#{classname}">#{cdata}</a>]
|
641
|
+
end
|
642
|
+
rescue
|
643
|
+
puts @live.body
|
644
|
+
end
|
645
|
+
|
646
|
+
def navbar
|
647
|
+
title = _var(:title)
|
648
|
+
open = <<-HTML
|
649
|
+
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
650
|
+
<a class="navbar-brand" href="index.html">#{title}</a>
|
651
|
+
<button class="navbar-toggler"
|
652
|
+
type="button"
|
653
|
+
data-toggle="collapse"
|
654
|
+
data-target="#navbarSupportedContent"
|
655
|
+
aria-controls="navbarSupportedContent"
|
656
|
+
aria-expanded="false"
|
657
|
+
aria-label="Toggle navigation">
|
658
|
+
<span class="navbar-toggler-icon"></span>
|
659
|
+
</button>
|
660
|
+
|
661
|
+
<div class="collapse navbar-collapse pull-right"
|
662
|
+
id="navbarSupportedContent">
|
663
|
+
<ul class="navbar-nav mr-auto">
|
664
|
+
HTML
|
665
|
+
close = <<-HTML
|
666
|
+
</ul>
|
667
|
+
</div>
|
668
|
+
</nav>
|
669
|
+
HTML
|
670
|
+
|
671
|
+
first = true
|
672
|
+
_out open
|
673
|
+
_body do |line|
|
674
|
+
href, cdata = line.chomp.strip.split(" ", 2)
|
675
|
+
if first
|
676
|
+
first = false
|
677
|
+
_out %[<li class="nav-item active"> <a class="nav-link" href="#{href}">#{cdata}<span class="sr-only">(current)</span></a> </li>]
|
678
|
+
else
|
679
|
+
_out %[<li class="nav-item"> <a class="nav-link" href="#{href}">#{cdata}</a> </li>]
|
680
|
+
end
|
681
|
+
end
|
682
|
+
_out close
|
683
|
+
end
|
684
|
+
|