clwiki 3.2.2 → 3.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a05ff0b1a136c335b3f6167e0f9012108bd49c5bf92fe94b11d4f93844d8510f
4
- data.tar.gz: d466ab9845678b7e3ee806248d880135946b8ec0015b3e3c932a7cc186164ed2
3
+ metadata.gz: 02100a0da4730f0b55e02af7d6002d4b28e4a08e1ea533d3eeb83879e2897bf5
4
+ data.tar.gz: 8aba5f51a34813c34918b85929b4d3ad503e46dfb57a65996adf3ca87b648d33
5
5
  SHA512:
6
- metadata.gz: ef48b158dde373c1063c343d8d276c46507b7db98d02a80de076c9387cd1e345b9b707af6ab1740fb25cf2f566013ca715fbed23aafbac6b96758c34be14051c
7
- data.tar.gz: 64baf2efec9c90eb5c61f09e35d82eefc9466742dbdea00c835858c76172c15f8d8d9507ff4f0ed84a95b50dd46f0cb28920f8dbcab78f175f520b3a99a1d340
6
+ metadata.gz: 13bbeaa5aea8dcd25047d0d2d0bfe4af2ab6e6e0f4dd234911af9d2b7fa942167181508be37e9f7272efa20dad02326f7fce85df0c8be12946571b7d0dcfbf1d
7
+ data.tar.gz: 78813c39844cda040d32324449836f695f2fc81dd168e5b080433f0586e75dabd33644c10086b2f5b9f3d45202e84042925e06302e4efd6b7c482e6ad38cfff9
@@ -0,0 +1,7 @@
1
+ module CLabs
2
+ class WikiDiffFormatter
3
+ def self.format_diff(diff)
4
+ "<b>Diff</b><br><pre>\n#{CGI.escapeHTML(diff)}\n</pre><br><hr=width\"50%\">"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # to create your own custom footer, see any of the files in the ./footer
2
+ # directory and imitate.
3
+
4
+ module ClWiki
5
+ class CustomFooter
6
+ end
7
+ end
@@ -0,0 +1,18 @@
1
+ module ClWiki
2
+ class CustomFooters
3
+ include Singleton
4
+
5
+ def register(class_ref)
6
+ @footers ||= []
7
+ @footers << class_ref
8
+ end
9
+
10
+ def process_footers(page)
11
+ String.new.tap do |content|
12
+ @footers&.each do |f|
13
+ content << f.footer_html(page)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ # to create your own custom formatter, see any of the files in the ./format
2
+ # directory and imitate.
3
+
4
+ module ClWiki
5
+ class CustomFormatter
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ module ClWiki
2
+ class CustomFormatters
3
+ include Singleton
4
+
5
+ def register(class_ref)
6
+ @formatters ||= []
7
+ @formatters << class_ref
8
+ end
9
+
10
+ def unregister(class_ref)
11
+ @formatters.delete(class_ref)
12
+ end
13
+
14
+ def process_formatters(content, page)
15
+ @formatters&.each do |f|
16
+ if content&.match?(f.match_re)
17
+ content.gsub!(f.match_re) { |match| f.format_content(match, page) }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
data/lib/cl_wiki/file.rb CHANGED
@@ -121,98 +121,4 @@ module ClWiki
121
121
  end
122
122
  end
123
123
  end
124
-
125
- class Metadata
126
- def self.split_file_contents(content)
127
- idx = content =~ /\n{3}/m
128
- metadata = []
129
-
130
- if idx
131
- metadata = content[0..(idx - 1)].split(/\n/)
132
- valid_metadata?(metadata) ? content = content[(idx + 3)..-1] : metadata = []
133
- end
134
- [self.new(metadata), content]
135
- end
136
-
137
- def self.valid_metadata?(lines)
138
- lines.map { |ln| ln.scan(/\A(\w+):?/) }.flatten.
139
- map { |k| supported_keys.include?(k) }.uniq == [true]
140
- end
141
-
142
- def self.supported_keys
143
- %w[mtime encrypted owner]
144
- end
145
-
146
- def initialize(lines = [])
147
- @hash = {}
148
- @keys = Metadata.supported_keys
149
- parse_lines(lines)
150
- end
151
-
152
- def [](key)
153
- @hash[key]
154
- end
155
-
156
- def []=(key, value)
157
- raise "Unexpected key: #{key}" unless @keys.include?(key)
158
-
159
- @hash[key] = value
160
- end
161
-
162
- def has?(key)
163
- @hash.key?(key)
164
- end
165
-
166
- def to_s
167
- @hash.collect { |k, v| "#{k}: #{v}" }.join("\n") + "\n\n\n"
168
- end
169
-
170
- def to_h
171
- @hash
172
- end
173
-
174
- private
175
-
176
- def parse_lines(lines)
177
- lines.each do |ln|
178
- key, value = ln.split(': ')
179
- @hash[key] = value.chomp if @keys.include?(key)
180
- end
181
- end
182
- end
183
-
184
- class Util
185
- def self.raise_if_mtime_not_equal(mtime_to_compare, file_name)
186
- # reading the instance .mtime appears to take Windows DST into account,
187
- # whereas the static File.mtime(filename) method does not
188
- current_mtime = ::File.open(file_name, &:mtime)
189
- compare_read_times!(mtime_to_compare, current_mtime)
190
- end
191
-
192
- def self.compare_read_times!(a, b)
193
- # ignore usec
194
- a = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec)
195
- b = Time.new(b.year, b.month, b.day, b.hour, b.min, b.sec)
196
- if a != b
197
- raise FileModifiedSinceRead, "File has been modified since it was last read. #{dump_time(a)} != #{dump_time(b)}"
198
- end
199
- end
200
-
201
- def self.dump_time(time)
202
- String.new.tap do |s|
203
- s << time.to_s
204
- s << ".#{time.usec}" if time.respond_to?(:usec)
205
- end
206
- end
207
-
208
- def self.convert_to_native_path(path)
209
- path.gsub(%r{/}, ::File::SEPARATOR).gsub(/\\/, ::File::SEPARATOR)
210
- end
211
- end
212
-
213
- class FileError < RuntimeError
214
- end
215
-
216
- class FileModifiedSinceRead < FileError
217
- end
218
124
  end
@@ -0,0 +1,5 @@
1
+ module ClWiki
2
+ class FileError < RuntimeError
3
+
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module ClWiki
2
+ class FileModifiedSinceRead < FileError
3
+ end
4
+ end
@@ -0,0 +1,60 @@
1
+ module ClWiki
2
+ class Metadata
3
+ def self.split_file_contents(content)
4
+ idx = content =~ /\n{3}/m
5
+ metadata = []
6
+
7
+ if idx
8
+ metadata = content[0..(idx - 1)].split(/\n/)
9
+ valid_metadata?(metadata) ? content = content[(idx + 3)..-1] : metadata = []
10
+ end
11
+ [self.new(metadata), content]
12
+ end
13
+
14
+ def self.valid_metadata?(lines)
15
+ lines.map { |ln| ln.scan(/\A(\w+):?/) }.flatten.
16
+ map { |k| supported_keys.include?(k) }.uniq == [true]
17
+ end
18
+
19
+ def self.supported_keys
20
+ %w[mtime encrypted owner]
21
+ end
22
+
23
+ def initialize(lines = [])
24
+ @hash = {}
25
+ @keys = Metadata.supported_keys
26
+ parse_lines(lines)
27
+ end
28
+
29
+ def [](key)
30
+ @hash[key]
31
+ end
32
+
33
+ def []=(key, value)
34
+ raise "Unexpected key: #{key}" unless @keys.include?(key)
35
+
36
+ @hash[key] = value
37
+ end
38
+
39
+ def has?(key)
40
+ @hash.key?(key)
41
+ end
42
+
43
+ def to_s
44
+ @hash.collect { |k, v| "#{k}: #{v}" }.join("\n") + "\n\n\n"
45
+ end
46
+
47
+ def to_h
48
+ @hash
49
+ end
50
+
51
+ private
52
+
53
+ def parse_lines(lines)
54
+ lines.each do |ln|
55
+ key, value = ln.split(': ')
56
+ @hash[key] = value.chomp if @keys.include?(key)
57
+ end
58
+ end
59
+ end
60
+ end
data/lib/cl_wiki/page.rb CHANGED
@@ -149,249 +149,4 @@ module ClWiki
149
149
  ClWiki::MemoryIndexer.instance.page_exists?(page_name)
150
150
  end
151
151
  end
152
-
153
- class PageFormatter
154
- FIND_PAGE_NAME = 'Find'
155
- FIND_RESULTS_NAME = 'Find Results'
156
-
157
- attr_reader :full_name
158
- attr_accessor :content
159
-
160
- def initialize(content = nil, full_name = nil)
161
- @content = content
162
- self.full_name = full_name
163
- @wiki_index = nil
164
- end
165
-
166
- def full_name=(value)
167
- @full_name = value
168
- if @full_name
169
- @full_name = @full_name[1..-1] if @full_name[0..1] == '//'
170
- end
171
- end
172
-
173
- def header(full_page_name, page = nil)
174
- search_text = ::File.basename(full_page_name)
175
- page_path, page_name = ::File.split(full_page_name)
176
- page_path = '/' if page_path == '.'
177
- dirs = page_path.split('/')
178
- dirs = dirs[1..-1] if !dirs.empty? && dirs[0].empty?
179
- full_dirs = (0..dirs.length - 1).each { |i| full_dirs[i] = ('/' + dirs[0..i].join('/')) }
180
- head = String.new("<div class='wikiHeader'>")
181
- head << core_footer_links(full_page_name, -1).sub('wikiFooter', 'wikiFooter wikiFooterFloat')
182
- if [FIND_PAGE_NAME, FIND_RESULTS_NAME].include?(full_page_name)
183
- head << "<span class='pageName'>#{full_page_name}</span>"
184
- else
185
- head << "<span class='pageName'><a href='find?search_text=#{search_text}'>#{page_name}</a></span><br/>"
186
- full_dirs.each do |dir|
187
- head << "'<span class='pageTag'>'"
188
- head << "<a href=#{cgifn}?page=#{dir}>#{File.split(dir)[-1]}</a></span>"
189
- end
190
- head << '<br/>'
191
- head << "<span class='wikiPageData'>#{page_update_time(page)}</span><br/>" if page
192
- end
193
- head << '</div>'
194
- end
195
-
196
- def page_update_time(page)
197
- mod_time = page.mtime
198
- if mod_time
199
- update_format = $wiki_conf.page_update_format.gsub(/ /, '&nbsp;')
200
- mod_time.strftime(update_format)
201
- else
202
- ''
203
- end
204
- end
205
-
206
- def process_custom_footers(page)
207
- Dir["#{::File.dirname(__FILE__)}/footer/footer.*"].sort.each do |fn|
208
- require fn
209
- end
210
-
211
- ClWiki::CustomFooters.instance.process_footers(page)
212
- end
213
-
214
- def footer(page)
215
- return String.new unless page.is_a? ClWiki::Page
216
- custom_footer = process_custom_footers(page)
217
- custom_footer << core_footer_links(page.page_name)
218
- end
219
-
220
- def core_footer_links(wiki_name, tab_index=0)
221
- # refactor string constants
222
- footer = String.new("<div class='wikiFooter'>")
223
- footer << '<ul>'
224
- if $wiki_conf.editable
225
- unless [FIND_PAGE_NAME, FIND_RESULTS_NAME].include?(wiki_name)
226
- footer << "<li><span class='wikiAction'><a href='#{wiki_name}/edit' tabindex=#{tab_index}>Edit</a></span></li>"
227
- end
228
- end
229
- footer << "<li><span class='wikiAction'><a href='find' tabindex=#{tab_index}>Find</a></span></li>"
230
- if $wiki_conf.publishTag
231
- footer << "<li><span class='wikiAction'><a href='recent' tabindex=#{tab_index}>Recent</a></span></li>"
232
- else
233
- footer << "<li><span class='wikiAction'><a href='FrontPage' tabindex=#{tab_index}>Home</a></span></li>"
234
- end
235
- footer << '</ul></div>'
236
- footer
237
- end
238
-
239
- def src_url
240
- "file://#{ClWiki::Page.read_file_full_path_and_name(@full_name)}"
241
- end
242
-
243
- def reload_url(with_global_edit_links = false)
244
- result = "#{full_url}?page=#{@full_name}"
245
- result << (with_global_edit_links ? '&globaledits=true' : '&globaledits=false')
246
- end
247
-
248
- def mailto_url
249
- "mailto:?Subject=wikifyi:%20#{@full_name}&Body=#{reload_url}"
250
- end
251
-
252
- def gsub_words
253
- @content.gsub(%r{<.+?>|</.+?>|\w+}) { |word| yield word }
254
- end
255
-
256
- def format_links
257
- no_wiki_link_in_effect = false
258
- inside_html_tags = false
259
-
260
- gsub_words do |word|
261
- if (word[0, 1] == '<') && (word[-1, 1] == '>')
262
- # refactor to class,local constant, instead of global
263
- if /<NoWikiLinks>/i.match?(word)
264
- no_wiki_link_in_effect = true
265
- word = ''
266
- # refactor to class,local constant, instead of global
267
- elsif /<\/NoWikiLinks>/i.match?(word)
268
- no_wiki_link_in_effect = false
269
- word = ''
270
- end
271
-
272
- if /<html>/i.match?(word)
273
- inside_html_tags = true
274
- word = ''
275
- elsif /<\/html>/i.match?(word)
276
- inside_html_tags = false
277
- word = ''
278
- end
279
- elsif is_wiki_name?(word)
280
- if !no_wiki_link_in_effect && !inside_html_tags
281
- # code smell here y'all
282
- word = convert_to_link(word) unless block_given?
283
- end
284
- end
285
- if block_given?
286
- yield word
287
- else
288
- word
289
- end
290
- end
291
- end
292
-
293
- def self.only_html(str)
294
- only_one_tag = /\A[^<]*<[^<>]*>[^>]*\z/
295
- header_tag_line = %r{\A\s*<h.>.*</h.>\s*\z}
296
- (str =~ only_one_tag) || (str =~ header_tag_line)
297
- # str.scan(/<.*>/).to_s == str.chomp
298
- end
299
-
300
- def starts_with_path_char(path)
301
- (path[0..0] == '/') || (path[0..1] == '//')
302
- end
303
-
304
- def cgifn
305
- $wiki_conf&.cgifn
306
- end
307
-
308
- def full_url
309
- ($wiki_conf.url_prefix + cgifn) if $wiki_conf
310
- end
311
-
312
- def convert_to_link(page_name)
313
- if ClWiki::Page.page_exists?(page_name)
314
- "<a href='#{page_name}'>#{page_name}</a>"
315
- else
316
- @wiki_index ||= ClWiki::MemoryIndexer.instance
317
- hits = @wiki_index.search(page_name, titles_only: true)
318
-
319
- result = case hits.length
320
- when 0
321
- page_name
322
- when 1
323
- "<a href='#{hits[0]}'>#{page_name}</a>"
324
- else
325
- "<a href='find?search_text=#{page_name}'>#{page_name}</a>"
326
- end
327
-
328
- if $wiki_conf.editable && (hits.empty? || $wiki_conf.global_edits)
329
- result << "<a href='#{page_name}/edit'>?</a>"
330
- end
331
- result
332
- end
333
- end
334
-
335
- def is_wiki_name?(string)
336
- return false if string.empty?
337
-
338
- /\A[0-9]*[A-Z][a-z]\w*?[A-Z][a-z]\w*\z/.match?(string)
339
- end
340
- end
341
-
342
- class CustomFooters
343
- include Singleton
344
-
345
- def register(class_ref)
346
- @footers ||= []
347
- @footers << class_ref
348
- end
349
-
350
- def process_footers(page)
351
- String.new.tap do |content|
352
- @footers&.each do |f|
353
- content << f.footer_html(page)
354
- end
355
- end
356
- end
357
- end
358
-
359
- # to create your own custom footer, see any of the files in the ./footer
360
- # directory and imitate.
361
- class CustomFooter
362
- end
363
-
364
- class CustomFormatters
365
- include Singleton
366
-
367
- def register(class_ref)
368
- @formatters ||= []
369
- @formatters << class_ref
370
- end
371
-
372
- def unregister(class_ref)
373
- @formatters.delete(class_ref)
374
- end
375
-
376
- def process_formatters(content, page)
377
- @formatters&.each do |f|
378
- if content&.match?(f.match_re)
379
- content.gsub!(f.match_re) { |match| f.format_content(match, page) }
380
- end
381
- end
382
- end
383
- end
384
-
385
- # to create your own custom formatter, see any of the files in the ./format
386
- # directory and imitate.
387
- class CustomFormatter
388
- end
389
- end
390
-
391
- module CLabs
392
- class WikiDiffFormatter
393
- def self.format_diff(diff)
394
- "<b>Diff</b><br><pre>\n#{CGI.escapeHTML(diff)}\n</pre><br><hr=width\"50%\">"
395
- end
396
- end
397
152
  end
@@ -0,0 +1,190 @@
1
+ module ClWiki
2
+ class PageFormatter
3
+ FIND_PAGE_NAME = 'Find'
4
+ FIND_RESULTS_NAME = 'Find Results'
5
+
6
+ attr_reader :full_name
7
+ attr_accessor :content
8
+
9
+ def initialize(content = nil, full_name = nil)
10
+ @content = content
11
+ self.full_name = full_name
12
+ @wiki_index = nil
13
+ end
14
+
15
+ def full_name=(value)
16
+ @full_name = value
17
+ if @full_name
18
+ @full_name = @full_name[1..-1] if @full_name[0..1] == '//'
19
+ end
20
+ end
21
+
22
+ def header(full_page_name, page = nil)
23
+ search_text = ::File.basename(full_page_name)
24
+ page_path, page_name = ::File.split(full_page_name)
25
+ page_path = '/' if page_path == '.'
26
+ dirs = page_path.split('/')
27
+ dirs = dirs[1..-1] if !dirs.empty? && dirs[0].empty?
28
+ full_dirs = (0..dirs.length - 1).each { |i| full_dirs[i] = ('/' + dirs[0..i].join('/')) }
29
+ head = String.new("<div class='wikiHeader'>")
30
+ head << core_footer_links(full_page_name, -1).sub('wikiFooter', 'wikiFooter wikiFooterFloat')
31
+ if [FIND_PAGE_NAME, FIND_RESULTS_NAME].include?(full_page_name)
32
+ head << "<span class='pageName'>#{full_page_name}</span>"
33
+ else
34
+ head << "<span class='pageName'><a href='find?search_text=#{search_text}'>#{page_name}</a></span><br/>"
35
+ full_dirs.each do |dir|
36
+ head << "'<span class='pageTag'>'"
37
+ head << "<a href=#{cgifn}?page=#{dir}>#{File.split(dir)[-1]}</a></span>"
38
+ end
39
+ head << '<br/>'
40
+ head << "<span class='wikiPageData'>#{page_update_time(page)}</span><br/>" if page
41
+ end
42
+ head << '</div>'
43
+ end
44
+
45
+ def page_update_time(page)
46
+ mod_time = page.mtime
47
+ if mod_time
48
+ update_format = $wiki_conf.page_update_format.gsub(/ /, '&nbsp;')
49
+ mod_time.strftime(update_format)
50
+ else
51
+ ''
52
+ end
53
+ end
54
+
55
+ def process_custom_footers(page)
56
+ Dir["#{::File.dirname(__FILE__)}/footer/footer.*"].sort.each do |fn|
57
+ require fn
58
+ end
59
+
60
+ ClWiki::CustomFooters.instance.process_footers(page)
61
+ end
62
+
63
+ def footer(page)
64
+ return String.new unless page.is_a? ClWiki::Page
65
+ custom_footer = process_custom_footers(page)
66
+ custom_footer << core_footer_links(page.page_name)
67
+ end
68
+
69
+ def core_footer_links(wiki_name, tab_index = 0)
70
+ # refactor string constants
71
+ footer = String.new("<div class='wikiFooter'>")
72
+ footer << '<ul>'
73
+ if $wiki_conf.editable
74
+ unless [FIND_PAGE_NAME, FIND_RESULTS_NAME].include?(wiki_name)
75
+ footer << "<li><span class='wikiAction'><a href='#{wiki_name}/edit' tabindex=#{tab_index}>Edit</a></span></li>"
76
+ end
77
+ end
78
+ footer << "<li><span class='wikiAction'><a href='find' tabindex=#{tab_index}>Find</a></span></li>"
79
+ if $wiki_conf.publishTag
80
+ footer << "<li><span class='wikiAction'><a href='recent' tabindex=#{tab_index}>Recent</a></span></li>"
81
+ else
82
+ footer << "<li><span class='wikiAction'><a href='FrontPage' tabindex=#{tab_index}>Home</a></span></li>"
83
+ end
84
+ footer << '</ul></div>'
85
+ footer
86
+ end
87
+
88
+ def src_url
89
+ "file://#{ClWiki::Page.read_file_full_path_and_name(@full_name)}"
90
+ end
91
+
92
+ def reload_url(with_global_edit_links = false)
93
+ result = "#{full_url}?page=#{@full_name}"
94
+ result << (with_global_edit_links ? '&globaledits=true' : '&globaledits=false')
95
+ end
96
+
97
+ def mailto_url
98
+ "mailto:?Subject=wikifyi:%20#{@full_name}&Body=#{reload_url}"
99
+ end
100
+
101
+ def gsub_words
102
+ @content.gsub(%r{<.+?>|</.+?>|\w+}) { |word| yield word }
103
+ end
104
+
105
+ def format_links
106
+ no_wiki_link_in_effect = false
107
+ inside_html_tags = false
108
+
109
+ gsub_words do |word|
110
+ if (word[0, 1] == '<') && (word[-1, 1] == '>')
111
+ # refactor to class,local constant, instead of global
112
+ if /<NoWikiLinks>/i.match?(word)
113
+ no_wiki_link_in_effect = true
114
+ word = ''
115
+ # refactor to class,local constant, instead of global
116
+ elsif /<\/NoWikiLinks>/i.match?(word)
117
+ no_wiki_link_in_effect = false
118
+ word = ''
119
+ end
120
+
121
+ if /<html>/i.match?(word)
122
+ inside_html_tags = true
123
+ word = ''
124
+ elsif /<\/html>/i.match?(word)
125
+ inside_html_tags = false
126
+ word = ''
127
+ end
128
+ elsif is_wiki_name?(word)
129
+ if !no_wiki_link_in_effect && !inside_html_tags
130
+ # code smell here y'all
131
+ word = convert_to_link(word) unless block_given?
132
+ end
133
+ end
134
+ if block_given?
135
+ yield word
136
+ else
137
+ word
138
+ end
139
+ end
140
+ end
141
+
142
+ def self.only_html(str)
143
+ only_one_tag = /\A[^<]*<[^<>]*>[^>]*\z/
144
+ header_tag_line = %r{\A\s*<h.>.*</h.>\s*\z}
145
+ (str =~ only_one_tag) || (str =~ header_tag_line)
146
+ # str.scan(/<.*>/).to_s == str.chomp
147
+ end
148
+
149
+ def starts_with_path_char(path)
150
+ (path[0..0] == '/') || (path[0..1] == '//')
151
+ end
152
+
153
+ def cgifn
154
+ $wiki_conf&.cgifn
155
+ end
156
+
157
+ def full_url
158
+ ($wiki_conf.url_prefix + cgifn) if $wiki_conf
159
+ end
160
+
161
+ def convert_to_link(page_name)
162
+ if ClWiki::Page.page_exists?(page_name)
163
+ "<a href='#{page_name}'>#{page_name}</a>"
164
+ else
165
+ @wiki_index ||= ClWiki::MemoryIndexer.instance
166
+ hits = @wiki_index.search(page_name, titles_only: true)
167
+
168
+ result = case hits.length
169
+ when 0
170
+ page_name
171
+ when 1
172
+ "<a href='#{hits[0]}'>#{page_name}</a>"
173
+ else
174
+ "<a href='find?search_text=#{page_name}'>#{page_name}</a>"
175
+ end
176
+
177
+ if $wiki_conf.editable && (hits.empty? || $wiki_conf.global_edits)
178
+ result << "<a href='#{page_name}/edit'>?</a>"
179
+ end
180
+ result
181
+ end
182
+ end
183
+
184
+ def is_wiki_name?(string)
185
+ return false if string.empty?
186
+
187
+ /\A[0-9]*[A-Z][a-z]\w*?[A-Z][a-z]\w*\z/.match?(string)
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,30 @@
1
+ module ClWiki
2
+ class Util
3
+ def self.raise_if_mtime_not_equal(mtime_to_compare, file_name)
4
+ # reading the instance .mtime appears to take Windows DST into account,
5
+ # whereas the static File.mtime(filename) method does not
6
+ current_mtime = ::File.open(file_name, &:mtime)
7
+ compare_read_times!(mtime_to_compare, current_mtime)
8
+ end
9
+
10
+ def self.compare_read_times!(a, b)
11
+ # ignore usec
12
+ a = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec)
13
+ b = Time.new(b.year, b.month, b.day, b.hour, b.min, b.sec)
14
+ if a != b
15
+ raise FileModifiedSinceRead, "File has been modified since it was last read. #{dump_time(a)} != #{dump_time(b)}"
16
+ end
17
+ end
18
+
19
+ def self.dump_time(time)
20
+ String.new.tap do |s|
21
+ s << time.to_s
22
+ s << ".#{time.usec}" if time.respond_to?(:usec)
23
+ end
24
+ end
25
+
26
+ def self.convert_to_native_path(path)
27
+ path.gsub(%r{/}, ::File::SEPARATOR).gsub(/\\/, ::File::SEPARATOR)
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClWiki
4
- VERSION = '3.2.2'
4
+ VERSION = '3.2.4'
5
5
  end
data/lib/cl_wiki_lib.rb CHANGED
@@ -4,6 +4,25 @@ require File.expand_path('cl_wiki/configuration', __dir__)
4
4
  require File.expand_path('cl_wiki/user_base', __dir__)
5
5
  require File.expand_path('cl_wiki/public_user', __dir__)
6
6
  require File.expand_path('cl_wiki/memory_indexer', __dir__)
7
+
8
+ require File.expand_path('cl_wiki/file_error', __dir__)
9
+ require File.expand_path('cl_wiki/file_modified_since_read', __dir__)
7
10
  require File.expand_path('cl_wiki/file', __dir__)
11
+
12
+ require File.expand_path('cl_wiki/util', __dir__)
13
+
14
+ require File.expand_path('cl_wiki/custom_footer', __dir__)
15
+ require File.expand_path('cl_wiki/custom_footers', __dir__)
16
+ require File.expand_path('cl_wiki/custom_formatter', __dir__)
17
+ require File.expand_path('cl_wiki/custom_formatters', __dir__)
18
+
19
+ Dir[File.join(__dir__, 'cl_wiki', 'format', '*.rb')].each do |fn|
20
+ require fn
21
+ end
22
+
23
+
24
+ require File.expand_path('cl_wiki/metadata', __dir__)
25
+ require File.expand_path('cl_wiki/page_formatter', __dir__)
26
+
8
27
  require File.expand_path('cl_wiki/page', __dir__)
9
28
  require File.expand_path('cl_wiki/version', __dir__)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clwiki
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.2
4
+ version: 3.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - chrismo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-22 00:00:00.000000000 Z
11
+ date: 2023-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bcrypt
@@ -82,18 +82,28 @@ files:
82
82
  - config/initializers/clwiki.rb
83
83
  - config/routes.rb
84
84
  - lib/cl_wiki.rb
85
+ - lib/cl_wiki/c_labs/wiki_diff_formatter.rb
85
86
  - lib/cl_wiki/configuration.rb
87
+ - lib/cl_wiki/custom_footer.rb
88
+ - lib/cl_wiki/custom_footers.rb
89
+ - lib/cl_wiki/custom_formatter.rb
90
+ - lib/cl_wiki/custom_formatters.rb
86
91
  - lib/cl_wiki/engine.rb
87
92
  - lib/cl_wiki/file.rb
88
- - lib/cl_wiki/format/format_blockquote.rb
89
- - lib/cl_wiki/format/format_graphviz_di_graph.rb
90
- - lib/cl_wiki/format/format_opml.rb
91
- - lib/cl_wiki/format/format_pre_blockquote.rb
92
- - lib/cl_wiki/format/format_simple_table.rb
93
+ - lib/cl_wiki/file_error.rb
94
+ - lib/cl_wiki/file_modified_since_read.rb
95
+ - lib/cl_wiki/format_blockquote.rb
96
+ - lib/cl_wiki/format_graphviz_di_graph.rb
97
+ - lib/cl_wiki/format_opml.rb
98
+ - lib/cl_wiki/format_pre_blockquote.rb
99
+ - lib/cl_wiki/format_simple_table.rb
93
100
  - lib/cl_wiki/memory_indexer.rb
101
+ - lib/cl_wiki/metadata.rb
94
102
  - lib/cl_wiki/page.rb
103
+ - lib/cl_wiki/page_formatter.rb
95
104
  - lib/cl_wiki/public_user.rb
96
105
  - lib/cl_wiki/user_base.rb
106
+ - lib/cl_wiki/util.rb
97
107
  - lib/cl_wiki/version.rb
98
108
  - lib/cl_wiki_lib.rb
99
109
  - lib/tasks/index.rake