runeblog 0.3.02

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.
Files changed (141) hide show
  1. checksums.yaml +7 -0
  2. data/README.lt3 +279 -0
  3. data/README.md +312 -0
  4. data/bin/blog +200 -0
  5. data/bin/mkwidget +164 -0
  6. data/data/EDITOR +1 -0
  7. data/data/ROOT +1 -0
  8. data/data/VIEW +1 -0
  9. data/data/features.txt +18 -0
  10. data/data/global.lt3 +20 -0
  11. data/data/universal.lt3 +18 -0
  12. data/empty_view/assets/austin-pano.jpg +0 -0
  13. data/empty_view/assets/sky2.jpg +0 -0
  14. data/empty_view/config/exper/2svg.lt3 +38 -0
  15. data/empty_view/config/exper/gen_svg.rb +60 -0
  16. data/empty_view/config/exper/meta.html +10 -0
  17. data/empty_view/config/exper/s2.html +25 -0
  18. data/empty_view/config/exper/varmint.rb +50 -0
  19. data/empty_view/config/facebook/credentials.txt +7 -0
  20. data/empty_view/config/facebook/facebook.rb +42 -0
  21. data/empty_view/config/facebook/fb.html +10 -0
  22. data/empty_view/config/facebook/fb.js.lt3 +15 -0
  23. data/empty_view/config/reddit/credentials.txt +6 -0
  24. data/empty_view/config/reddit/notes.txt +4 -0
  25. data/empty_view/config/reddit/reddit_post_url.py +34 -0
  26. data/empty_view/config/reddit/redpost.rb +43 -0
  27. data/empty_view/config/reddit/the-graffiti-wall.html +91 -0
  28. data/empty_view/config/twitter/credentials.txt +3 -0
  29. data/empty_view/config/twitter/tw.html +12 -0
  30. data/empty_view/config/twitter/tw.js +5 -0
  31. data/empty_view/config/twitter/twitter.rb +35 -0
  32. data/empty_view/posts/GIT_IS_DUMB +1 -0
  33. data/empty_view/remote/assets/GIT_IS_DUMB +1 -0
  34. data/empty_view/remote/banner/navbar/GIT_IS_DUMB +0 -0
  35. data/empty_view/remote/etc/GIT_IS_DUMB +1 -0
  36. data/empty_view/remote/permalink/GIT_IS_DUMB +1 -0
  37. data/empty_view/remote/widgets/ad/GIT_IS_DUMB +2 -0
  38. data/empty_view/remote/widgets/links/GIT_IS_DUMB +2 -0
  39. data/empty_view/remote/widgets/news/GIT_IS_DUMB +2 -0
  40. data/empty_view/remote/widgets/pages/GIT_IS_DUMB +2 -0
  41. data/empty_view/remote/widgets/pinned/GIT_IS_DUMB +2 -0
  42. data/empty_view/settings/features.txt +18 -0
  43. data/empty_view/settings/publish.txt +5 -0
  44. data/empty_view/settings/recent.txt +6 -0
  45. data/empty_view/settings/view.txt +4 -0
  46. data/empty_view/themes/standard/README +59 -0
  47. data/empty_view/themes/standard/banner/banner.lt3 +5 -0
  48. data/empty_view/themes/standard/banner/navbar/about.lt3 +18 -0
  49. data/empty_view/themes/standard/banner/navbar/contact.lt3 +18 -0
  50. data/empty_view/themes/standard/banner/navbar/faq.lt3 +1 -0
  51. data/empty_view/themes/standard/banner/navbar/list.data +3 -0
  52. data/empty_view/themes/standard/banner/top.lt3 +20 -0
  53. data/empty_view/themes/standard/blog/generate.lt3 +21 -0
  54. data/empty_view/themes/standard/blog/head.lt3 +16 -0
  55. data/empty_view/themes/standard/blog/index.lt3 +17 -0
  56. data/empty_view/themes/standard/blog/post_entry.lt3 +21 -0
  57. data/empty_view/themes/standard/etc/blog.css.lt3 +62 -0
  58. data/empty_view/themes/standard/etc/externals.lt3 +24 -0
  59. data/empty_view/themes/standard/etc/favicon.ico +0 -0
  60. data/empty_view/themes/standard/etc/misc.js +20 -0
  61. data/empty_view/themes/standard/post/generate.lt3 +38 -0
  62. data/empty_view/themes/standard/post/head.lt3 +7 -0
  63. data/empty_view/themes/standard/post/index.lt3 +24 -0
  64. data/empty_view/themes/standard/post/permalink.lt3 +32 -0
  65. data/empty_view/themes/standard/widgets/README +4 -0
  66. data/empty_view/themes/standard/widgets/ad/ad.lt3 +22 -0
  67. data/empty_view/themes/standard/widgets/ad/ad1.png +0 -0
  68. data/empty_view/themes/standard/widgets/ad/ad2.png +0 -0
  69. data/empty_view/themes/standard/widgets/ad/ad3.png +0 -0
  70. data/empty_view/themes/standard/widgets/ad/ad4.png +0 -0
  71. data/empty_view/themes/standard/widgets/bydates/README +2 -0
  72. data/empty_view/themes/standard/widgets/bydates/bydates.rb +18 -0
  73. data/empty_view/themes/standard/widgets/bydates/card.css +1 -0
  74. data/empty_view/themes/standard/widgets/bydates/custom.rb +1 -0
  75. data/empty_view/themes/standard/widgets/bydates/main.css +2 -0
  76. data/empty_view/themes/standard/widgets/links/README +2 -0
  77. data/empty_view/themes/standard/widgets/links/card.css +1 -0
  78. data/empty_view/themes/standard/widgets/links/custom.rb +1 -0
  79. data/empty_view/themes/standard/widgets/links/links.rb +90 -0
  80. data/empty_view/themes/standard/widgets/links/list.data +3 -0
  81. data/empty_view/themes/standard/widgets/links/main.css +2 -0
  82. data/empty_view/themes/standard/widgets/news/README +2 -0
  83. data/empty_view/themes/standard/widgets/news/card.css +1 -0
  84. data/empty_view/themes/standard/widgets/news/custom.rb +1 -0
  85. data/empty_view/themes/standard/widgets/news/list.data +4 -0
  86. data/empty_view/themes/standard/widgets/news/main.css +2 -0
  87. data/empty_view/themes/standard/widgets/news/news.rb +88 -0
  88. data/empty_view/themes/standard/widgets/pages/README +2 -0
  89. data/empty_view/themes/standard/widgets/pages/card.css +1 -0
  90. data/empty_view/themes/standard/widgets/pages/custom.rb +1 -0
  91. data/empty_view/themes/standard/widgets/pages/disclaim.lt3 +10 -0
  92. data/empty_view/themes/standard/widgets/pages/faq.lt3 +40 -0
  93. data/empty_view/themes/standard/widgets/pages/like-dislike.lt3 +11 -0
  94. data/empty_view/themes/standard/widgets/pages/list.data +4 -0
  95. data/empty_view/themes/standard/widgets/pages/local.rb +0 -0
  96. data/empty_view/themes/standard/widgets/pages/main.css +2 -0
  97. data/empty_view/themes/standard/widgets/pages/other-stuff.lt3 +10 -0
  98. data/empty_view/themes/standard/widgets/pages/pages.rb +95 -0
  99. data/empty_view/themes/standard/widgets/pinned/README +2 -0
  100. data/empty_view/themes/standard/widgets/pinned/card.css +1 -0
  101. data/empty_view/themes/standard/widgets/pinned/custom.rb +1 -0
  102. data/empty_view/themes/standard/widgets/pinned/main.css +2 -0
  103. data/empty_view/themes/standard/widgets/pinned/pinned.rb +99 -0
  104. data/empty_view/themes/standard/widgets/search/README +2 -0
  105. data/empty_view/themes/standard/widgets/search/card.css +1 -0
  106. data/empty_view/themes/standard/widgets/search/custom.rb +1 -0
  107. data/empty_view/themes/standard/widgets/search/main.css +2 -0
  108. data/empty_view/themes/standard/widgets/search/search.rb +18 -0
  109. data/empty_view/themes/standard/widgets/sitemap/README +2 -0
  110. data/empty_view/themes/standard/widgets/sitemap/card.css +1 -0
  111. data/empty_view/themes/standard/widgets/sitemap/custom.rb +1 -0
  112. data/empty_view/themes/standard/widgets/sitemap/main.css +2 -0
  113. data/empty_view/themes/standard/widgets/sitemap/sitemap.rb +18 -0
  114. data/empty_view/themes/standard/widgets/tag-cloud/OLD-example.lt3 +12 -0
  115. data/empty_view/themes/standard/widgets/tag-cloud/README +2 -0
  116. data/empty_view/themes/standard/widgets/tag-cloud/card.css +1 -0
  117. data/empty_view/themes/standard/widgets/tag-cloud/custom.rb +1 -0
  118. data/empty_view/themes/standard/widgets/tag-cloud/main.css +2 -0
  119. data/empty_view/themes/standard/widgets/tag-cloud/tag-cloud.lt3 +3 -0
  120. data/empty_view/themes/standard/widgets/tag-cloud/tag-cloud.rb +18 -0
  121. data/lib/Javascript.stuff +69 -0
  122. data/lib/helpers-blog.rb +155 -0
  123. data/lib/helpers-repl.rb +201 -0
  124. data/lib/liveblog.rb +825 -0
  125. data/lib/logging.rb +44 -0
  126. data/lib/lowlevel.rb +73 -0
  127. data/lib/pathmagic.rb +14 -0
  128. data/lib/post.rb +211 -0
  129. data/lib/processing.rb +60 -0
  130. data/lib/publish.rb +73 -0
  131. data/lib/repl.rb +597 -0
  132. data/lib/runeblog.rb +773 -0
  133. data/lib/runeblog_version.rb +50 -0
  134. data/lib/view.rb +69 -0
  135. data/runeblog.gemspec +42 -0
  136. data/test/austin.rb +158 -0
  137. data/test/fakeimage.jpg +0 -0
  138. data/test/general_test.rb +304 -0
  139. data/test/make_blog.rb +196 -0
  140. data/test/test +3 -0
  141. metadata +242 -0
@@ -0,0 +1,50 @@
1
+ if !defined?(RuneBlog::Path)
2
+
3
+ # if ! (Object.constants.include?(:RuneBlog) && RuneBlog.constants.include?(:Path))
4
+
5
+ class RuneBlog
6
+ VERSION = "0.3.02"
7
+
8
+ path = Gem.find_files("runeblog").grep(/runeblog-/).first
9
+ Path = File.dirname(path)
10
+ end
11
+
12
+ # skeleton
13
+
14
+ class RuneBlog
15
+ module Helpers
16
+ end
17
+
18
+ class Default
19
+ end
20
+
21
+ class View
22
+ end
23
+
24
+ class Publishing
25
+ end
26
+
27
+ class Post
28
+ end
29
+ end
30
+
31
+ # Refactor, move stuff elsewhere?
32
+
33
+ def make_exception(sym, str)
34
+ log!(enter: __method__, args: [sym, str], level: 3)
35
+ return if Object.constants.include?(sym)
36
+ Object.const_set(sym, StandardError.dup)
37
+ define_method(sym) do |*args|
38
+ msg = str
39
+ args.each.with_index {|arg, i| msg.sub!("$#{i+1}", arg) }
40
+ Object.class_eval(sym.to_s).new(msg)
41
+ end
42
+ end
43
+
44
+ def prefix(num)
45
+ log!(enter: __method__, args: [num], level: 3)
46
+ "#{'%04d' % num.to_i}"
47
+ end
48
+
49
+
50
+ end
@@ -0,0 +1,69 @@
1
+ require 'logging'
2
+
3
+ class RuneBlog::View
4
+ attr_reader :name, :state, :globals
5
+ attr_accessor :publisher
6
+
7
+ include RuneBlog::Helpers
8
+
9
+ def initialize(name)
10
+ log!(enter: __method__, args: [name], level: 3)
11
+ raise NoBlogAccessor if RuneBlog.blog.nil?
12
+ @blog = RuneBlog.blog
13
+ @name = name
14
+ @publisher = RuneBlog::Publishing.new(name)
15
+ @can_publish = true # FIXME
16
+ @blog.view = self
17
+ gfile = @blog.root/"views/#{name}/themes/standard/global.lt3"
18
+ return unless File.exist?(gfile) # Hackish!! how is View.new called from create_view??
19
+
20
+ live = Livetext.customize(call: ".nopara")
21
+ live.xform_file(gfile)
22
+ @globals = live.vars
23
+ end
24
+
25
+ def dir
26
+ @blog.root + "/views/#@name/"
27
+ end
28
+
29
+ def local_index
30
+ dir + "/remote/index.html"
31
+ end
32
+
33
+ def index
34
+ dir + "index.html"
35
+ end
36
+
37
+ def to_s
38
+ @name
39
+ end
40
+
41
+ def publishable_files
42
+ log!(enter: __method__, level: 2)
43
+ vdir = dir()
44
+ remote = local_index()
45
+ files = [remote]
46
+ others = Dir.entries(vdir/:remote) - %w[. ..]
47
+ others.map! {|x| "#{vdir}/remote/#{x}" }
48
+
49
+ assets = Dir.entries("#{vdir}/assets") - %w[. ..]
50
+ assets.map! {|x| "#{vdir}/assets/#{x}" }
51
+ assets.reject! {|x| File.directory?(x) }
52
+ # assets.reject! {|x| ! recent?(x) }
53
+ files = files + others
54
+ all = files.dup
55
+ dirty = files.reject {|f| ! recent?(f) }
56
+ [dirty, all, assets]
57
+ end
58
+
59
+ def can_publish?
60
+ @can_publish
61
+ end
62
+
63
+ def recent?(file)
64
+ File.mtime(file) > File.mtime("#{self.dir()}/last_published")
65
+ rescue
66
+ true
67
+ end
68
+ end
69
+
@@ -0,0 +1,42 @@
1
+ require 'date'
2
+ require 'find'
3
+
4
+ $LOAD_PATH << "lib"
5
+
6
+ require "runeblog_version"
7
+
8
+ Gem.post_install do |spec|
9
+ Dir.chdir(RuneBlog::Path)
10
+ system("livetext -i liveblog.rb")
11
+ end
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ system("rm -f *.gem")
15
+ s.name = 'runeblog'
16
+ s.version = RuneBlog::VERSION
17
+ s.date = Date.today.strftime("%Y-%m-%d")
18
+ s.summary = "A command-line blogging system"
19
+ s.description = "A blog system based on Ruby and Livetext"
20
+ s.authors = ["Hal Fulton"]
21
+ s.email = 'rubyhacker@gmail.com'
22
+ s.executables << "blog"
23
+ s.add_runtime_dependency 'livetext', '~> 0.9', '>= 0.9.01'
24
+ s.add_runtime_dependency 'rubytext', '~> 0.1', '>= 0.1.20'
25
+
26
+ s.add_development_dependency 'minitest', '~> 5.10', '>= 5.10.0'
27
+
28
+ # Files...
29
+ main = Find.find("bin").to_a +
30
+ Find.find("lib").to_a
31
+ data = Find.find("data").to_a
32
+ test = Find.find("test").to_a
33
+ misc = %w[./README.lt3 ./README.md ./runeblog.gemspec]
34
+ empty_view = Find.find("empty_view").to_a
35
+
36
+ s.files = main + misc + data + test + empty_view
37
+ s.homepage = 'https://github.com/Hal9000/runeblog'
38
+ s.license = "Ruby"
39
+ s.post_install_message = "\n Success! Run 'blog' command and type h for help.\n "
40
+ end
41
+
42
+ spec
@@ -0,0 +1,158 @@
1
+ $LOAD_PATH << "./lib"
2
+
3
+ major, minor = RUBY_VERSION.split(".").values_at(0,1)
4
+ ver = major.to_i*10 + minor.to_i
5
+ abort "Need Ruby 2.4 or greater" unless ver >= 24
6
+
7
+ # Home = Dir.pwd
8
+
9
+ require 'date'
10
+
11
+ require 'runeblog'
12
+ require 'repl'
13
+
14
+ def bold(str)
15
+ "\e[1m#{str}\e[0m"
16
+ end
17
+
18
+ def getch
19
+ # sleep 5
20
+ end
21
+
22
+ def debug(str = "")
23
+ t = Time.now
24
+ time = t.to_f.to_s
25
+ n = time.index(".")
26
+ msec = time[n..(n+2)]
27
+ time = t.strftime("%H:%M:%S") + msec
28
+ STDERR.puts "#{'%-11s' % time} #{str}"
29
+ end
30
+
31
+ @fake_date = Date.today - 20
32
+
33
+ def make_post(x, title, teaser, body, views=[])
34
+ debug " make_post #{bold(title)}"
35
+ pubdate = @fake_date.strftime("%Y-%m-%d")
36
+ @fake_date += (rand(2) + 1)
37
+ x.create_new_post(title, true, teaser: teaser, body: body, views: views,
38
+ pubdate: pubdate)
39
+ end
40
+
41
+ def show_lines(text)
42
+ lines = text.split("\n")
43
+ str = "#{lines.size} lines\n"
44
+ lines.each {|line| str << " #{line.inspect}\n" }
45
+ str
46
+ end
47
+
48
+ # "Main"...
49
+
50
+ t0 = Time.now
51
+
52
+ puts
53
+ debug bold("Generating test blog...")
54
+
55
+ system("rm -rf .blogs")
56
+ RuneBlog.create_new_blog_repo(".blogs")
57
+ x = RuneBlog.new(".blogs")
58
+
59
+ debug("create_view: #{bold('around_austin')}")
60
+ x.create_view("around_austin") # FIXME remember view title!
61
+
62
+ #### FIXME
63
+
64
+ vars = <<-VARS
65
+ author Hal Fulton
66
+ title Around Austin
67
+ subtitle The view from downtown...
68
+ domain foo.com
69
+ VARS
70
+ vfile = ".blogs/views/around_austin/settings/view.txt"
71
+ File.open(vfile, "w") {|f| f.puts vars }
72
+
73
+ ####
74
+
75
+ debug("-- change_view: #{bold('around_austin')}")
76
+ x.change_view("around_austin") # 1 2 7 8 9
77
+
78
+ make_post(x, "What's at Stubbs...", <<-EXCERPT, <<-BODY)
79
+ Stubbs has been around for longer than civilization.
80
+ EXCERPT
81
+ That's a good thing. But their music isn't always the greatest.
82
+ BODY
83
+
84
+ make_post(x, "The new amphitheatre is overrated", <<-EXCERPT, <<-BODY)
85
+ It used to be that all major concerts played the Erwin Center.
86
+ EXCERPT
87
+ .pin around_austin
88
+ Now, depending on what you consider "major," blah blah blah...
89
+ BODY
90
+
91
+ make_post(x, "The graffiti wall", <<-EXCERPT, <<-BODY)
92
+ RIP, Hope Gallery
93
+ EXCERPT
94
+
95
+ .dropcap It's been a while since I was there. They say it was torn down
96
+ while I wasn't looking. Never tagged anything there, of course, nor
97
+ anywhere else. Spraypainting public places isn't my thing, but in this
98
+ case I condoned it because it was sort of there for that purpose.
99
+
100
+ This fake entry is a long one so as to demonstrate both drop-caps
101
+ (above) and an inset quote. Blah blah blah. Lorem ipsum dolor and
102
+ a partridge in a pear tree.
103
+
104
+ .inset left 20
105
+ Wherever you go, there you are. Last night I saw upon the stair
106
+ a little man who was not there. He wasn't there again today; I
107
+ wish, I wish he'd go away. As far as we know, our computer has
108
+ never had an undetected error.
109
+ |On a clean disk, you can seek forever.
110
+ And never let it be denied that
111
+ pobbles are happier without their toes. And may your snark never
112
+ be a boojum. How do you know you aren't dreaming right now? When
113
+ you see a butterfly, think of Chuang Tzu.
114
+ .end
115
+
116
+ Contact light. Houston, this is Tranquility Base. The Eagle has
117
+ landed. That's one small step for (a) man, one giant leap for
118
+ mankind.
119
+
120
+ Here's the PDF of $$link["Ruby for the Old-Time C Programmer"|http://rubyhacker.com/blog2/rubydino.pdf]
121
+
122
+ Pity this busy monster, manunkind, not. Pity rather... Listen:
123
+ There's a hell of a universe next door; let's go.
124
+ BODY
125
+
126
+ make_post(x, "The Waller Creek project", <<-EXCERPT, <<-BODY)
127
+ Will it ever be finished?
128
+ EXCERPT
129
+ Blah blah Waller Creek blah blah...
130
+ BODY
131
+
132
+ make_post(x, "Life on Sabine Street", <<-EXCERPT, <<-BODY)
133
+ It's like Pooh Corner, except not.
134
+ EXCERPT
135
+ This is about Sabine St, blah blah lorem ipsum dolor...
136
+ BODY
137
+
138
+ make_post(x, "Remember Modest Mouse?", <<-EXCERPT, <<-BODY)
139
+ They date to the 90s or before.
140
+ EXCERPT
141
+ But I first heard of them
142
+ in 2005.
143
+ BODY
144
+
145
+ debug
146
+ debug "** generate_index #{bold("around_austin")}"
147
+ x.generate_index("around_austin")
148
+
149
+ debug("** generate_view: #{bold('around_austin')}")
150
+ x.generate_view("around_austin")
151
+
152
+ debug bold("...finished.\n")
153
+
154
+ t1 = Time.now
155
+
156
+ elapsed = t1 - t0
157
+ puts "Elapsed: #{'%3.2f' % elapsed} secs\n "
158
+
Binary file
@@ -0,0 +1,304 @@
1
+ $LOAD_PATH << "."
2
+ # require "test_helper"
3
+
4
+ require "minitest/autorun"
5
+ # require "minitest/fail_fast"
6
+
7
+ require 'runeblog'
8
+ require 'lib/repl'
9
+ require 'rubytext'
10
+
11
+ major, minor = RUBY_VERSION.split(".").values_at(0,1)
12
+ ver = major.to_i*10 + minor.to_i
13
+ abort "Need Ruby 2.4 or greater" unless ver >= 24
14
+
15
+ RubyText.start
16
+
17
+ class TestREPL < Minitest::Test
18
+ include RuneBlog::REPL
19
+
20
+ def show_lines(text)
21
+ lines = text.split("\n")
22
+ str = "#{lines.size} lines\n"
23
+ lines.each {|line| str << " #{line.inspect}\n" }
24
+ str
25
+ end
26
+
27
+ def setup
28
+ # To be strictly correct in testing (though slower),
29
+ # run make_blog here.
30
+ system("ruby test/make_blog.rb") if ARGV.first == "new"
31
+ @blog = RuneBlog.new
32
+ end
33
+
34
+ # Note: "Bang" methods depend on the data subtree
35
+
36
+ def test_001_cmd_help
37
+ # puts __method__
38
+ out = cmd_help(nil, true)
39
+ assert out.is_a?(String), "Expected a string returned"
40
+ lines = out.split("\n").length
41
+ assert lines > 15, "Expecting lengthy help message"
42
+ end
43
+
44
+ def test_002_cmd_version
45
+ # puts __method__
46
+ out = cmd_version(nil, true)
47
+ assert out.is_a?(String), "Expected a string returned"
48
+ lines = out
49
+ assert lines =~ /\d+\.\d+\.\d+/m,
50
+ "Couldn't find version number; found #{out.inspect}"
51
+ end
52
+
53
+ def test_003_list_views!
54
+ # puts __method__
55
+ out = cmd_list_views(nil, true)
56
+ assert out.is_a?(String), "Expected a string returned"
57
+ lines = out.split("\n").length
58
+ assert lines >= 2, "Expecting at least 2 lines"
59
+ end
60
+
61
+ def test_004_change_view!
62
+ # puts __method__
63
+ out = cmd_change_view(nil, true) # no param, but testing
64
+ assert out.is_a?(String), "Expected a string; got: #{out.inspect}"
65
+ assert out =~ /alpha_view/m, "Expecting 'alpha_view' as default; got: #{out.inspect}"
66
+ end
67
+
68
+ def test_005_lsd!
69
+ # puts __method__
70
+ out = cmd_list_drafts(nil, true)
71
+ assert out.is_a?(String), "Expected a string returned"
72
+ nlines = out.split("\n").length
73
+ exp = 10
74
+ assert nlines == exp, "Expecting #{exp} lines, got #{nlines}; #{show_lines(out)}"
75
+ end
76
+
77
+ def test_006_lsp!
78
+ # puts __method__
79
+ out = cmd_list_posts(nil, true)
80
+ assert out.is_a?(String), "Expected a string returned; got: #{out.inspect}"
81
+ lines = out.split("\n").length
82
+ assert lines == 6, "Expecting 6 lines; got #{lines.size}; #{show_lines(out)}"
83
+ end
84
+
85
+ def test_007_parser
86
+ # puts __method__
87
+ parse_tests = {
88
+ # Loading/trailing blanks as well
89
+ "kill 81 82 83" => [:cmd_kill, "81 82 83"],
90
+ " kill 81 82 83" => [:cmd_kill, "81 82 83"],
91
+ "kill 81 82 83 " => [:cmd_kill, "81 82 83"],
92
+ " kill 81 82 83 " => [:cmd_kill, "81 82 83"],
93
+ "help" => [:cmd_help, nil],
94
+ "h" => [:cmd_help, nil],
95
+ "version" => [:cmd_version, nil],
96
+ "v" => [:cmd_version, nil],
97
+ "list views" => [:cmd_list_views, nil],
98
+ "lsv" => [:cmd_list_views, nil],
99
+ "new view foobar" => [:cmd_new_view, "foobar"],
100
+ "new post" => [:cmd_new_post, nil],
101
+ "p" => [:cmd_new_post, nil],
102
+ "post" => [:cmd_new_post, nil],
103
+ "change view beta_view" => [:cmd_change_view, "beta_view"],
104
+ "cv" => [:cmd_change_view, nil], # 0-arity
105
+ "cv myview" => [:cmd_change_view, "myview"],
106
+ "list posts" => [:cmd_list_posts, nil],
107
+ "lsp" => [:cmd_list_posts, nil],
108
+ "list drafts" => [:cmd_list_drafts, nil],
109
+ "lsd" => [:cmd_list_drafts, nil],
110
+ "rm 999" => [:cmd_remove_post, "999"],
111
+ "kill 101 102 103" => [:cmd_kill, "101 102 103"],
112
+ "edit 104" => [:cmd_edit_post, "104"],
113
+ "ed 105" => [:cmd_edit_post, "105"],
114
+ "e 106" => [:cmd_edit_post, "106"],
115
+ "preview" => [:cmd_preview, nil],
116
+ "browse" => [:cmd_browse, nil],
117
+ "relink" => [:cmd_relink, nil],
118
+ "rebuild" => [:cmd_rebuild, nil],
119
+ "publish" => [:cmd_publish, nil],
120
+ "q" => [:cmd_quit, nil],
121
+ "quit" => [:cmd_quit, nil]
122
+ # Later: too many/few params
123
+ }
124
+
125
+ parse_tests.each_pair do |cmd, expected|
126
+ result = RuneBlog::REPL.choose_method(cmd)
127
+ assert result == expected, "Expected #{expected.inspect} but got #{result.inspect}"
128
+ end
129
+ end
130
+
131
+ def test_008_current_view!
132
+ # puts __method__
133
+ assert @blog.view.to_s == "alpha_view", "Current view wrong (#{@blog.view}, not alpha_view)"
134
+ end
135
+
136
+ def test_009_change_view!
137
+ # puts __method__
138
+ assert @blog.change_view("beta_view")
139
+ assert @blog.view.to_s == "beta_view", "Current view wrong (#{@blog.view}, not beta_view)"
140
+ assert @blog.change_view("alpha_view")
141
+ assert @blog.view.to_s == "alpha_view", "Current view wrong (#{@blog.view}, not alpha_view)"
142
+ end
143
+
144
+ def test_010_accessors!
145
+ # puts __method__
146
+ sorted_views = @blog.views.map(&:to_s).sort
147
+ assert sorted_views == ["alpha_view", "beta_view", "gamma_view", "test_view"],
148
+ "Got: #{sorted_views.inspect}"
149
+ end
150
+
151
+ def test_011_create_delete_view!
152
+ # puts __method__
153
+ @blog.create_view("anotherview")
154
+ sorted_views = @blog.views.map(&:to_s).sort
155
+ assert sorted_views == ["alpha_view", "anotherview", "beta_view", "gamma_view", "test_view"],
156
+ "After create: #{sorted_views.inspect}"
157
+ @blog.delete_view("anotherview", true)
158
+ sorted_views = @blog.views.map(&:to_s).sort
159
+ assert sorted_views == ["alpha_view", "beta_view", "gamma_view", "test_view"],
160
+ "After delete: #{sorted_views.inspect}"
161
+ end
162
+
163
+ def test_012_create_remove_post!
164
+ # puts __method__
165
+ @blog.change_view("beta_view")
166
+ assert @blog.view.to_s == "beta_view", "Expected beta_view"
167
+ nposts = @blog.posts.size
168
+ ndrafts = @blog.drafts.size
169
+ title = "Uninteresting title"
170
+ num = @blog.create_new_post(title, true)
171
+
172
+ assert @blog.posts.size == nposts + 1, "Don't see new post"
173
+ @blog.remove_post(num)
174
+ assert @blog.posts.size == nposts, "Failed to delete post"
175
+
176
+ assert @blog.drafts.size == ndrafts + 1, "Don't see new draft"
177
+ @blog.delete_draft(num)
178
+ assert @blog.drafts.size == ndrafts, "Failed to delete draft"
179
+ @blog.change_view("alpha_view")
180
+ end
181
+
182
+ def xtest_013_slug_tests
183
+ hash = { "abcxyz" => "abcxyz", # 0-based
184
+ "abc'xyz" => "abcxyz",
185
+ 'abc"xyz' => "abcxyz",
186
+ '7%sol' => "7sol",
187
+ "only a test" => "only-a-test",
188
+ "abc xyz" => "abc--xyz", # change this behavior?
189
+ "ABCxyZ" => "abcxyz",
190
+ }
191
+ hash.each_pair.with_index do |keys, i|
192
+ real, fixed = *keys
193
+ meta = OpenStruct.new
194
+ meta.title = real
195
+ meta.num = 99
196
+ result = @blog.make_slug(meta)[5..-1] # Skip num (test_013...)
197
+ assert result == fixed, "Case #{i}: expected: #{fixed.inspect}, got #{result.inspect}"
198
+ end
199
+ end
200
+
201
+ def xtest_014_remove_nonexistent_post!
202
+ @blog.change_view("alpha_view")
203
+ out = cmd_remove_post(99, true)
204
+ assert out =~ /Post 99 not found/, "Expected error about nonexistent post, got: #{out}"
205
+ end
206
+
207
+ def xtest_015_kill_multiple_posts!
208
+ @blog.change_view("alpha_view")
209
+ out = cmd_list_posts(nil, true)
210
+ before = out.split("\n").length
211
+ cmd_kill("1 2 7", true)
212
+ out = cmd_list_posts(nil, true)
213
+ after = out.split("\n").length
214
+ expecting = before - 3
215
+ assert after == expecting, "list_posts saw #{before} posts, now #{after} (not #{expecting})"
216
+ @blog.undelete_post(1)
217
+ @blog.undelete_post(2)
218
+ @blog.undelete_post(7)
219
+ end
220
+
221
+ if File.exist?("testing.publish") # FIXME!!!
222
+
223
+ def xtest_016_can_publish
224
+ # puts __method__
225
+ x = OpenStruct.new
226
+ x.user, x.server, x.docroot, x.docroot, x.path, x.proto =
227
+ "root", "rubyhacker.com", "/var/www", "whatever", "http"
228
+ dep = RuneBlog::Publishing.new(x)
229
+ result = dep.remote_login?
230
+ assert result == true, "Valid login doesn't work"
231
+ result = dep.remote_permissions?
232
+ assert result == true, "Valid mkdir doesn't work"
233
+ end
234
+
235
+ def xtest_017_cannot_publish_wrong_user
236
+ # puts __method__
237
+ x = OpenStruct.new
238
+ x.user, x.server, x.docroot, x.docroot, x.path, x.proto =
239
+ "bad_user", "rubyhacker.com", "/var/www", "whatever", "http"
240
+ dep = RuneBlog::Publishing.new(x)
241
+ result = dep.remote_login?
242
+ assert result.nil?, "Expected to detect login error (bad user)"
243
+ end
244
+
245
+ def xtest_018_cannot_publish_bad_server
246
+ # puts __method__
247
+ x = OpenStruct.new
248
+ x.user, x.server, x.docroot, x.docroot, x.path, x.proto =
249
+ "root", "nonexistent123.com", "/var/www", "whatever", "http"
250
+ dep = RuneBlog::Publishing.new(x)
251
+ result = dep.remote_login?
252
+ assert result.nil?, "Expected to detect login error (bad server)"
253
+ end
254
+
255
+ end # conditional tests
256
+
257
+ def xtest_019_exception_existing_blog
258
+ # puts __method__
259
+ assert_raises(BlogAlreadyExists) { RuneBlog.create_new_blog_repo }
260
+ end
261
+
262
+ def xtest_020_exception_missing_blog_accessor
263
+ # puts __method__
264
+ save = RuneBlog.blog
265
+ RuneBlog.blog = nil
266
+ assert_raises(NoBlogAccessor) { RuneBlog::Post.load(1) }
267
+ RuneBlog.blog = save
268
+ end
269
+
270
+ def xtest_021_exception_cant_assign_view
271
+ # puts __method__
272
+ assert_raises(CantAssignView) { @blog.view = 99 }
273
+ end
274
+
275
+ def xtest_022_exception_no_such_view
276
+ # puts __method__
277
+ assert_raises(NoSuchView) { @blog.view = 'not_a_view_name' }
278
+ end
279
+
280
+ def xtest_023_exception_view_already_exists
281
+ # puts __method__
282
+ assert_raises(ViewAlreadyExists) { @blog.create_view('alpha_view') }
283
+ end
284
+
285
+ def xtest_024_exception_livetext_error # FIXME Doesn't work! Change Livetext
286
+ # puts __method__
287
+ testfile = "testfile.lt3"
288
+ path = @blog.root + "/drafts/" + testfile
289
+ cmd = "echo .no_such_command > #{path}"
290
+ system(cmd)
291
+ # system("ls -l #{path}")
292
+ save = STDERR
293
+ STDERR.reopen("/dev/null")
294
+ assert_raises(LivetextError) { @blog.process_post(testfile) }
295
+ STDERR.reopen(save)
296
+ File.rm(path)
297
+ end
298
+
299
+ # later tests...
300
+ # new view asks for publishing info and writes it
301
+ # (how to mimic user input? test some other way?)
302
+
303
+ end
304
+