runeblog 0.1.76 → 0.1.78
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 +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
|
+
|