bitclust-core 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/data/bitclust/template.lillia/class +4 -1
  3. data/data/bitclust/template.lillia/class-index +4 -1
  4. data/data/bitclust/template.lillia/doc +4 -1
  5. data/data/bitclust/template.lillia/layout +2 -0
  6. data/data/bitclust/template.lillia/library +4 -1
  7. data/data/bitclust/template.lillia/library-index +4 -1
  8. data/data/bitclust/template.lillia/method +2 -1
  9. data/data/bitclust/template.offline/class +4 -1
  10. data/data/bitclust/template.offline/class-index +4 -1
  11. data/data/bitclust/template.offline/doc +4 -1
  12. data/data/bitclust/template.offline/function +1 -0
  13. data/data/bitclust/template.offline/function-index +4 -1
  14. data/data/bitclust/template.offline/layout +3 -0
  15. data/data/bitclust/template.offline/library +4 -1
  16. data/data/bitclust/template.offline/library-index +4 -1
  17. data/data/bitclust/template.offline/method +1 -0
  18. data/data/bitclust/template/class +4 -1
  19. data/data/bitclust/template/class-index +4 -1
  20. data/data/bitclust/template/doc +4 -1
  21. data/data/bitclust/template/function +4 -1
  22. data/data/bitclust/template/layout +3 -0
  23. data/data/bitclust/template/library +4 -1
  24. data/data/bitclust/template/library-index +4 -1
  25. data/data/bitclust/template/method +1 -0
  26. data/lib/bitclust/classentry.rb +4 -0
  27. data/lib/bitclust/docentry.rb +4 -1
  28. data/lib/bitclust/functionentry.rb +3 -1
  29. data/lib/bitclust/libraryentry.rb +5 -3
  30. data/lib/bitclust/methodentry.rb +3 -1
  31. data/lib/bitclust/preprocessor.rb +74 -14
  32. data/lib/bitclust/rdcompiler.rb +35 -15
  33. data/lib/bitclust/screen.rb +12 -1
  34. data/lib/bitclust/subcommands/preproc_command.rb +1 -1
  35. data/lib/bitclust/subcommands/statichtml_command.rb +12 -1
  36. data/lib/bitclust/syntax_highlighter.rb +318 -0
  37. data/lib/bitclust/version.rb +1 -1
  38. data/test/test_preprocessor.rb +209 -1
  39. data/test/test_rdcompiler.rb +79 -0
  40. data/theme/default/style.css +12 -0
  41. data/theme/default/syntax-highlight.css +209 -0
  42. metadata +5 -3
@@ -11,6 +11,8 @@ require 'bitclust/methodsignature'
11
11
  require 'bitclust/lineinput'
12
12
  require 'bitclust/htmlutils'
13
13
  require 'bitclust/textutils'
14
+ require 'bitclust/messagecatalog'
15
+ require 'bitclust/syntax_highlighter'
14
16
  require 'stringio'
15
17
 
16
18
  module BitClust
@@ -20,6 +22,7 @@ module BitClust
20
22
 
21
23
  include HTMLUtils
22
24
  include TextUtils
25
+ include Translatable
23
26
 
24
27
  def initialize(urlmapper, hlevel = 1, opt = {})
25
28
  @urlmapper = urlmapper
@@ -30,6 +33,7 @@ module BitClust
30
33
  @class = nil
31
34
  @method = nil
32
35
  @option = opt.dup
36
+ init_message_catalog(@catalog)
33
37
  end
34
38
 
35
39
  def compile(src)
@@ -80,7 +84,7 @@ module BitClust
80
84
  @item_stack = []
81
85
  item_list($1.size)
82
86
  raise "@item_stack should be empty. #{@item_stack.inspect}" unless @item_stack.empty?
83
- when %r<\A//emlist\{>
87
+ when %r<\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{>
84
88
  emlist
85
89
  when /\A:\s/
86
90
  dlist
@@ -133,7 +137,7 @@ module BitClust
133
137
  raise "@item_stack should be empty. #{@item_stack.inspect}" unless @item_stack.empty?
134
138
  when /\A:\s/
135
139
  dlist
136
- when %r<\A//emlist\{>
140
+ when %r<\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{>
137
141
  emlist
138
142
  when /\A\s+\S/
139
143
  list
@@ -221,7 +225,7 @@ module BitClust
221
225
  # empty lines separate paragraphs.
222
226
  def dd_with_p
223
227
  line '<dd>'
224
- while /\A(?:\s|\z)/ =~ @f.peek or %r!\A//emlist\{! =~ @f.peek
228
+ while /\A(?:\s|\z)/ =~ @f.peek or %r!\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{! =~ @f.peek
225
229
  case @f.peek
226
230
  when /\A$/
227
231
  @f.gets
@@ -231,8 +235,8 @@ module BitClust
231
235
  line compile_text(line.strip)
232
236
  end
233
237
  line '</p>'
234
- when %r!\A//emlist\{!
235
- emlist
238
+ when %r!\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{!
239
+ emlist
236
240
  else
237
241
  raise 'must not happen'
238
242
  end
@@ -243,14 +247,14 @@ module BitClust
243
247
  # empty lines do not separate paragraphs.
244
248
  def dd_without_p
245
249
  line '<dd>'
246
- while /\A[ \t]/ =~ @f.peek or %r!\A//emlist\{! =~ @f.peek
250
+ while /\A[ \t]/ =~ @f.peek or %r!\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{! =~ @f.peek
247
251
  case @f.peek
248
252
  when /\A[ \t\z]/
249
253
  @f.while_match(/\A[ \t\z]/) do |line|
250
254
  line compile_text(line.strip)
251
255
  end
252
- when %r!\A//emlist\{!
253
- emlist
256
+ when %r!\A//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{!
257
+ emlist
254
258
  end
255
259
  end
256
260
  line '</dd>'
@@ -261,12 +265,28 @@ module BitClust
261
265
  end
262
266
 
263
267
  def emlist
264
- @f.gets # discard "//emlist{"
265
- line '<pre>'
266
- @f.until_terminator(%r<\A//\}>) do |line|
267
- line escape_html(line.rstrip)
268
+ command = @f.gets
269
+ if %r!\A//emlist\[(?<caption>[^\[\]]+?)?\]\[(?<lang>\w+?)\]! =~ command
270
+ line "<pre class=\"highlight #{lang}\">"
271
+ line "<span class=\"caption\">#{escape_html(caption)}</span>" if caption
272
+ line "<code>"
273
+ src = ""
274
+ @f.until_terminator(%r<\A//\}>) do |line|
275
+ src << line
276
+ end
277
+ if lang == "ruby"
278
+ string BitClust::SyntaxHighlighter.new(src).highlight
279
+ else
280
+ string src
281
+ end
282
+ line '</code></pre>'
283
+ else
284
+ line '<pre>'
285
+ @f.until_terminator(%r<\A//\}>) do |line|
286
+ line escape_html(line.rstrip)
287
+ end
288
+ line '</pre>'
268
289
  end
269
- line '</pre>'
270
290
  end
271
291
 
272
292
  def list
@@ -294,7 +314,7 @@ module BitClust
294
314
  end
295
315
 
296
316
  def read_paragraph(f)
297
- f.span(%r<\A(?!---|=|//emlist\{)\S>)
317
+ f.span(%r<\A(?!---|=|//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{)\S>)
298
318
  end
299
319
 
300
320
  def see
@@ -349,7 +369,7 @@ module BitClust
349
369
  end
350
370
 
351
371
  def read_entry_paragraph(f)
352
- f.span(%r<\A(?!---|=|//emlist\{|@[a-z])\S>)
372
+ f.span(%r<\A(?!---|=|//emlist(?:\[(?:[^\[\]]+?)?\]\[\w+?\])?\{|@[a-z])\S>)
353
373
  end
354
374
 
355
375
  def method_signature(sig_line, first)
@@ -285,7 +285,7 @@ module BitClust
285
285
 
286
286
  def google_tag_manager
287
287
  tracking_id = @conf[:gtm_tracking_id]
288
- return "" unless tracking_id
288
+ return "\b" unless tracking_id
289
289
  <<-HTML.chomp
290
290
  <!-- Global Site Tag (gtag.js) - Google Analytics -->
291
291
  <script async src="https://www.googletagmanager.com/gtag/js?id=#{tracking_id}"></script>
@@ -299,6 +299,17 @@ module BitClust
299
299
  HTML
300
300
  end
301
301
 
302
+ def meta_robots
303
+ content = @conf[:meta_robots_content]
304
+ return "\b" unless content
305
+ return "\b" if content.empty?
306
+ %Q(<meta name="robots" content="#{content.join(',')}">)
307
+ end
308
+
309
+ def meta_description
310
+ %Q(<meta name="description" content="">)
311
+ end
312
+
302
313
  private
303
314
 
304
315
  def default_encoding
@@ -13,7 +13,7 @@ module BitClust
13
13
  @parser.banner = "Usage: #{File.basename($0, '.*')} <file>..."
14
14
  @parser.on('--param=KVPAIR', 'Set parameter by key/value pair.') {|pair|
15
15
  key, value = pair.split('=', 2)
16
- params[key] = value
16
+ @params[key] = value
17
17
  }
18
18
  end
19
19
 
@@ -63,6 +63,10 @@ module BitClust
63
63
  @bitclust_html_base + "/" + @css_url
64
64
  end
65
65
 
66
+ def custom_css_url(filename)
67
+ @bitclust_html_base + "/" + filename
68
+ end
69
+
66
70
  def favicon_url
67
71
  @bitclust_html_base + "/" + @favicon_url
68
72
  end
@@ -99,6 +103,7 @@ module BitClust
99
103
  @themedir = srcdir_root + "theme/default"
100
104
  @suffix = ".html"
101
105
  @gtm_tracking_id = nil
106
+ @meta_robots_content = ["noindex"]
102
107
  @parser.banner = "Usage: #{File.basename($0, '.*')} statichtml [options]"
103
108
  @parser.on('-o', '--outputdir=PATH', 'Output directory') do |path|
104
109
  begin
@@ -129,6 +134,9 @@ module BitClust
129
134
  @parser.on('--tracking-id=ID', 'Google Tag Manager Tracking ID') do |id|
130
135
  @gtm_tracking_id = id
131
136
  end
137
+ @parser.on('--meta-robots-content=VALUE1,VALUE2,...', Array, 'HTML <meta> element: <meta name="robots" content="VALUE1,VALUE2..."') do |values|
138
+ @meta_robots_content = values
139
+ end
132
140
  @parser.on('--[no-]quiet', 'Be quiet') do |quiet|
133
141
  @verbose = !quiet
134
142
  end
@@ -174,6 +182,8 @@ module BitClust
174
182
  create_index_html(@outputdir)
175
183
  FileUtils.cp(@manager_config[:themedir] + @manager_config[:css_url],
176
184
  @outputdir.to_s, {:verbose => @verbose, :preserve => true})
185
+ FileUtils.cp(@manager_config[:themedir] + "syntax-highlight.css",
186
+ @outputdir.to_s, {:verbose => @verbose, :preserve => true})
177
187
  FileUtils.cp(@manager_config[:themedir] + @manager_config[:favicon_url],
178
188
  @outputdir.to_s, {:verbose => @verbose, :preserve => true})
179
189
  Dir.mktmpdir do |tmpdir|
@@ -201,7 +211,8 @@ module BitClust
201
211
  :tochm_mode => true,
202
212
  :fs_casesensitive => @fs_casesensitive,
203
213
  :canonical_base_url => @canonical_base_url,
204
- :gtm_tracking_id => @gtm_tracking_id
214
+ :gtm_tracking_id => @gtm_tracking_id,
215
+ :meta_robots_content => @meta_robots_content,
205
216
  }
206
217
  @manager_config[:urlmapper] = URLMapperEx.new(@manager_config)
207
218
  @urlmapper = @manager_config[:urlmapper]
@@ -0,0 +1,318 @@
1
+ require "ripper"
2
+ require "bitclust/htmlutils"
3
+
4
+ module BitClust
5
+ class SyntaxHighlighter < Ripper::Filter
6
+ include BitClust::HTMLUtils
7
+
8
+ COLORS = {
9
+ CHAR: "sc", # ?a
10
+ __end__: "k", # __END__
11
+ backref: "vg", # $` $& $' $1 ...
12
+ backtick: "sb", # `
13
+ comma: nil, # ,
14
+ comment: "c1", # #...
15
+ const: "no", # Const
16
+ cvar: "vc", # @@var
17
+ embdoc: nil, # (=begin) document (=end)
18
+ embdoc_beg: "cm", # =begin
19
+ embdoc_end: nil, # =end
20
+ embexpr_beg: "si", # #{
21
+ embexpr_end: "si", # (#{) }
22
+ embvar: "n", # ("...) # (var")
23
+ float: "mf", # 1.23 (float)
24
+ gvar: "vg", # $var
25
+ heredoc_beg: "no", # <<EOS
26
+ heredoc_end: "no", # EOS
27
+ ident: nil, # identifier
28
+ ignored_nl: nil, # ignored \n
29
+ int: "mi", # 1 (integer)
30
+ ivar: "vi", # @var
31
+ kw: "k", # keyword
32
+ label: "ss", # label:
33
+ lbrace: "p", # {
34
+ lbracket: "p", # [
35
+ lparen: "p", # (
36
+ nl: nil, # \n
37
+ op: "o", # operator
38
+ period: "p", # .
39
+ qwords_beg: "sx", # %w(
40
+ rbrace: "p", # }
41
+ rbracket: "p", # ]
42
+ regexp_beg: "sr", # / (regexp/)
43
+ regexp_end: nil, # (/regexp) /
44
+ rparen: "p", # )
45
+ semicolon: nil, # ;
46
+ sp: nil, # space
47
+ symbeg: "ss", # :
48
+ tlambda: "o", # ->
49
+ tlambeg: "p", # (->) {
50
+ tstring_beg: nil, # " (string")
51
+ tstring_content: nil, # (") string (")
52
+ tstring_end: nil, # ("string) "
53
+ words_beg: "sx", # %W(
54
+ words_sep: nil # (%W() )
55
+ }
56
+ LABELS = {
57
+ }
58
+
59
+ KEYWORDS = %w[
60
+ BEGIN END alias begin break case defined\? do else elsif end
61
+ ensure for if in next redo rescue raise retry return super then
62
+ undef unless until when while yield
63
+ ]
64
+
65
+ KEYWORDS_PSEUDO = %w[
66
+ loop include extend raise
67
+ alias_method attr catch throw private module_function
68
+ public protected true false nil __FILE__ __LINE__
69
+ ]
70
+
71
+ BUILTINS_G = %w[
72
+ attr_reader attr_writer attr_accessor
73
+
74
+ __id__ __send__ abort ancestors at_exit autoload binding callcc
75
+ caller catch chomp chop class_eval class_variables clone
76
+ const_defined\? const_get const_missing const_set constants
77
+ display dup eval exec exit extend fail fork format freeze
78
+ getc gets global_variables gsub hash id included_modules
79
+ inspect instance_eval instance_method instance_methods
80
+ instance_variable_get instance_variable_set instance_variables
81
+ lambda load local_variables loop method method_missing
82
+ methods module_eval name object_id open p print printf
83
+ private_class_method private_instance_methods private_methods proc
84
+ protected_instance_methods protected_methods public_class_method
85
+ public_instance_methods public_methods putc puts raise rand
86
+ readline readlines require require_relative scan select self send set_trace_func
87
+ singleton_methods sleep split sprintf srand sub syscall system
88
+ taint test throw to_a to_s trace_var trap untaint untrace_var warn
89
+ ]
90
+
91
+ BUILTINS_Q = %w[
92
+ autoload block_given const_defined eql equal frozen
93
+ include instance_of is_a iterator kind_of method_defined
94
+ nil private_method_defined protected_method_defined
95
+ public_method_defined respond_to tainted
96
+ ]
97
+
98
+ BUILTINS_B = %w[chomp chop exit gsub sub]
99
+
100
+ def initialize(*args)
101
+ super
102
+ @stack = []
103
+ @name_buffer = []
104
+ end
105
+
106
+ def on_default(event, token, data)
107
+ event_name = event.to_s.sub(/\Aon_/, "") # :on_event --> "event"
108
+ style = COLORS[event_name.to_sym]
109
+ data << (style ? "<span class=\"#{style}\">#{escape_html(token)}</span>" : token)
110
+ data
111
+ end
112
+
113
+ def on_embdoc_beg(token, data)
114
+ style = COLORS[:embdoc_beg]
115
+ data << "<span class=\"#{style}\">#{token}"
116
+ data
117
+ end
118
+
119
+ def on_embdoc_end(token, data)
120
+ data << "#{token}</span>"
121
+ data
122
+ end
123
+
124
+ def on_ident(token, data)
125
+ case
126
+ when @stack.last == :symbol
127
+ data << "#{token}</span>"
128
+ @stack.pop
129
+ when @stack.last == :def
130
+ @stack.pop
131
+ data << "<span class=\"nf\">#{token}</span>"
132
+ when @stack.last == :embexpr
133
+ data << "<span class=\"n\">#{token}</span>"
134
+ when @stack.last == :heredoc
135
+ style = COLORS[:heredoc_beg]
136
+ data << "<span class=\"#{style}\">#{token}"
137
+ when @stack.last == :method_call
138
+ data << "<span class=\"nf\">#{token}</span>"
139
+ @stack.pop
140
+ when BUILTINS_G.include?(token)
141
+ data << "<span class=\"nb\">#{token}</span>"
142
+ else
143
+ data << token
144
+ end
145
+ data
146
+ end
147
+
148
+ def on_const(token, data)
149
+ case
150
+ when @stack.last == :class
151
+ @name_buffer << token
152
+ when @stack.last == :module
153
+ @name_buffer << token
154
+ else
155
+ on_default(:on_const, token, data)
156
+ end
157
+ data
158
+ end
159
+
160
+ def on_kw(token, data)
161
+ case
162
+ when @stack.last == :symbol
163
+ data << "#{token}</span>"
164
+ @stack.pop
165
+ when token == "module"
166
+ @stack.push(:module)
167
+ on_default(:on_kw, token, data)
168
+ when token == "class"
169
+ @stack.push(:class)
170
+ on_default(:on_kw, token, data)
171
+ when token == "def"
172
+ @stack.push(:def)
173
+ on_default(:on_kw, token, data)
174
+ when token == "self"
175
+ data << "<span class=\"nc\">#{token}</span>"
176
+ else
177
+ on_default(:on_kw, token, data)
178
+ end
179
+ data
180
+ end
181
+
182
+ def on_period(token, data)
183
+ @stack.push(:method_call)
184
+ on_default(:on_period, token, data)
185
+ end
186
+
187
+ def on_op(token, data)
188
+ case
189
+ when token == "::" && [:class, :module].include?(@stack.last)
190
+ @name_buffer << token
191
+ else
192
+ on_default(:on_op, token, data)
193
+ end
194
+ data
195
+ end
196
+
197
+ def on_sp(token, data)
198
+ case
199
+ when @name_buffer.empty?
200
+ return on_default(:on_sp, token, data)
201
+ when @stack.last == :module
202
+ name = @name_buffer.join
203
+ data << "<span class=\"nn\">#{name}</span>"
204
+ @stack.pop
205
+ @name_buffer.clear
206
+ when @stack.last == :class
207
+ namespace = @name_buffer.values_at(0..-3).join
208
+ operator = @name_buffer[-2]
209
+ name = @name_buffer.last
210
+ data << "<span class=\"nn\">#{namespace}</span>"
211
+ data << "<span class=\"o\">#{operator}</span>"
212
+ data << "<span class=\"nc\">#{name}</span>"
213
+ @stack.pop
214
+ @name_buffer.clear
215
+ end
216
+ on_default(:on_sp, token, data)
217
+ end
218
+
219
+ def on_nl(token, data)
220
+ case
221
+ when @name_buffer.empty?
222
+ return on_default(:on_nl, token, data)
223
+ when @stack.last == :module
224
+ name = @name_buffer.join
225
+ data << "<span class=\"nn\">#{name}</span>"
226
+ @stack.pop
227
+ @name_buffer.clear
228
+ when @stack.last == :class
229
+ namespace = @name_buffer.values_at(0..-3).join
230
+ operator = @name_buffer[-2]
231
+ name = @name_buffer.last
232
+ data << "<span class=\"nn\">#{namespace}</span>"
233
+ data << "<span class=\"o\">#{operator}</span>"
234
+ data << "<span class=\"nc\">#{name}</span>"
235
+ @stack.pop
236
+ @name_buffer.clear
237
+ end
238
+ on_default(:on_nl, token, data)
239
+ end
240
+
241
+ def on_regexp_beg(token, data)
242
+ style = COLORS[:regexp_beg]
243
+ data << "<span class=\"#{style}\">#{token}"
244
+ data
245
+ end
246
+
247
+ def on_regexp_end(token, data)
248
+ data << "#{token}</span>"
249
+ data
250
+ end
251
+
252
+ def on_symbeg(token, data)
253
+ style = COLORS[:symbeg]
254
+ data << "<span class=\"#{style}\">#{token}"
255
+ @stack << :symbol
256
+ data
257
+ end
258
+
259
+ def on_tstring_beg(token, data)
260
+ if token == "'"
261
+ data << "<span class=\"s1\">#{token}"
262
+ @stack << :string1
263
+ else
264
+ data << "<span class=\"s2\">#{token}</span>"
265
+ @stack << :string2
266
+ end
267
+ data
268
+ end
269
+
270
+ def on_tstring_content(token, data)
271
+ case
272
+ when @stack.last == :heredoc
273
+ data << "<span class=\"sh\">#{escape_html(token)}</span>"
274
+ when @stack.last == :string1
275
+ data << escape_html(token)
276
+ when @stack.last == :string2
277
+ data << "<span class=\"s2\">#{escape_html(token)}</span>"
278
+ else
279
+ on_default(:on_tstring_content, token, data)
280
+ end
281
+ data
282
+ end
283
+
284
+ def on_tstring_end(token, data)
285
+ if token == "'"
286
+ data << "#{token}</span>"
287
+ else
288
+ data << "<span class=\"s2\">#{token}</span>"
289
+ end
290
+ @stack.pop
291
+ data
292
+ end
293
+
294
+ def on_heredoc_beg(token, data)
295
+ @stack.push(:heredoc)
296
+ on_default(:on_heredoc_beg, token, data)
297
+ end
298
+
299
+ def on_heredoc_end(token, data)
300
+ @stack.pop
301
+ on_default(:on_heredoc_end, token, data)
302
+ end
303
+
304
+ def on_embexpr_beg(token, data)
305
+ @stack.push(:embexpr)
306
+ on_default(:on_embexpr_beg, token, data)
307
+ end
308
+
309
+ def on_embexpr_end(token, data)
310
+ @stack.pop
311
+ on_default(:on_embexpr_end, token, data)
312
+ end
313
+
314
+ def highlight
315
+ parse("")
316
+ end
317
+ end
318
+ end