json, an output representation, first pass
[software/sisu] / lib / sisu / json.rb
1 # encoding: utf-8
2 =begin
3
4 * Name: SiSU
5
6 ** Description: documents, structuring, processing, publishing, search
7 *** Description: json output logic, flow
8
9 ** Author: Ralph Amissah
10 [ralph@amissah.com]
11 [ralph.amissah@gmail.com]
12
13 ** Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
14 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Ralph Amissah,
15 All Rights Reserved.
16
17 ** License: GPL 3 or later:
18
19 SiSU, a framework for document structuring, publishing and search
20
21 Copyright (C) Ralph Amissah
22
23 This program is free software: you can redistribute it and/or modify it
24 under the terms of the GNU General Public License as published by the Free
25 Software Foundation, either version 3 of the License, or (at your option)
26 any later version.
27
28 This program is distributed in the hope that it will be useful, but WITHOUT
29 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
30 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
31 more details.
32
33 You should have received a copy of the GNU General Public License along with
34 this program. If not, see [http://www.gnu.org/licenses/].
35
36 If you have Internet connection, the latest version of the GPL should be
37 available at these locations:
38 [http://www.fsf.org/licensing/licenses/gpl.html]
39 [http://www.gnu.org/licenses/gpl.html]
40
41 ** SiSU uses:
42 * Standard SiSU markup syntax,
43 * Standard SiSU meta-markup syntax, and the
44 * Standard SiSU object citation numbering and system
45
46 ** Hompages:
47 [http://www.jus.uio.no/sisu]
48 [http://www.sisudoc.org]
49
50 ** Git
51 [http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=summary]
52 [http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=blob;f=lib/sisu/json.rb;hb=HEAD]
53
54 =end
55 module SiSU_JSON
56 require_relative 'se_hub_particulars' # se_hub_particulars.rb
57 include SiSU_Particulars
58 require_relative 'se' # se.rb
59 include SiSU_Env
60 require_relative 'json_shared' # json_shared.rb
61 include SiSU_JSON_Munge
62 require_relative 'json_format' # json_format.rb
63 include SiSU_JSON_Format
64 require_relative 'json_persist' # json_persist.rb
65 require_relative 'shared_metadata' # shared_metadata.rb
66 @@alt_id_count=0
67 @@tablefoot=''
68 class Source
69 def initialize(opt)
70 @opt=opt
71 @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
72 end
73 def read
74 begin
75 @env,@md,@ao_array=@particulars.env,@particulars.md,@particulars.ao_array
76 unless @opt.act[:quiet][:set]==:on
77 tool=if (@opt.act[:verbose_plus][:set]==:on \
78 || @opt.act[:maintenance][:set]==:on)
79 @env.program.web_browser +
80 ' file://' +
81 @md.file.output_path.json.dir + '/' +
82 @md.file.base_filename.json
83 elsif @opt.act[:verbose][:set]==:on
84 @env.program.web_browser +
85 ' file://' +
86 @md.file.output_path.json.dir + '/' +
87 @md.file.base_filename.json
88 else "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
89 end
90 (@opt.act[:verbose][:set]==:on \
91 || @opt.act[:verbose_plus][:set]==:on \
92 || @opt.act[:maintenance][:set]==:on) \
93 ? SiSU_Screen::Ansi.new(
94 @opt.act[:color_state][:set],
95 'JSON',
96 tool
97 ).green_hi_blue
98 : SiSU_Screen::Ansi.new(
99 @opt.act[:color_state][:set],
100 'JSON',
101 tool
102 ).green_title_hi
103 if (@opt.act[:verbose_plus][:set]==:on \
104 || @opt.act[:maintenance][:set]==:on)
105 SiSU_Screen::Ansi.new(
106 @opt.act[:color_state][:set],
107 @opt.fns,
108 '/' + @md.file.output_path.json.dir +
109 '/' + @md.file.base_filename.json
110 ).flow
111 end
112 end
113 SiSU_JSON::Source::Songsheet.new(@particulars).song
114 rescue
115 SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
116 __LINE__.to_s + ':' + __FILE__
117 end
118 ensure
119 SiSU_Env::CreateSite.new(@opt).cp_css
120 Dir.chdir(@opt.f_pth[:pth])
121 end
122 end
123 private
124 class Songsheet
125 def initialize(particulars)
126 @env,@md,@ao_array,@particulars=
127 particulars.env,particulars.md,particulars.ao_array,particulars
128 @file=SiSU_Env::FileOp.new(@md)
129 end
130 def song
131 begin
132 SiSU_JSON::Source::Scroll.new(@particulars).songsheet
133 rescue
134 SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
135 __LINE__.to_s + ':' + __FILE__
136 end
137 ensure
138 end
139 end
140 end
141 class Scroll
142 require_relative 'json_shared' # json_shared.rb #check already called
143 require_relative 'txt_shared' # txt_shared.rb
144 include SiSU_TextUtils
145 require_relative 'css' # css.rb
146 def initialize(particulars)
147 @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
148 @tab="\t"
149 @trans=SiSU_JSON_Munge::Trans.new(@md)
150 @sys=SiSU_Env::SystemCall.new
151 @per=SiSU_JSON_Persist::Persist.new
152 end
153 def songsheet
154 begin
155 pre
156 @data=markup(@ao_array)
157 post
158 publish
159 ensure
160 SiSU_JSON_Persist::Persist.new.persist_init
161 end
162 end
163 protected
164 def embedded_endnotes(dob='')
165 dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
166 '<endnote><number>\1</number><note>\2</note></endnote> ').
167 gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/,
168 '<endnote><symbol>\1</symbol><note>\2</note></endnote> ').
169 gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
170 '<endnote><symbol>\1</symbol><note>\2</note></endnote> ')
171 end
172 def extract_endnotes(dob='')
173 notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
174 notes.flatten.each do |e|
175 s=e.to_s
176 util=SiSU_JSONutils::Clean.new(s)
177 wrap=util.line_json_clean
178 wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<-WOK
179 \\n[\\1.] \\2
180 WOK
181 ).
182 gsub(/^([*+]\d+)\s+(.+?)\s*\Z/m, <<-WOK
183 \\n[\\1.] \\2
184 WOK
185 ).
186 gsub(/^([*+]+)\s+(.+?)\s*\Z/m, <<-WOK
187 \\n[\\1.] \\2
188 WOK
189 ).strip
190 #KEEP alternative presentation of endnotes
191 # wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<WOK
192 ##{Ax[:tab]*1}<p class="endnote" notenumber="\\1">
193 ##{Ax[:tab]*2}\\1. \\2
194 ##{Ax[:tab]*1}</p>
195 #WOK
196 #)
197 @endnotes << wrap
198 end
199 end
200 def json_head
201 #metadata=SiSU_Metadata::Summary.new(@md).json.metadata
202 #@per.head << metadata
203 end
204 def name_tags(dob)
205 tags=''
206 if defined? dob.tags \
207 and dob.tags.length > 0 # insert tags "hypertargets"
208 dob.tags.each do |t|
209 tags=tags << %{<named id="#{t}" />}
210 end
211 end
212 tags
213 end
214 def json_structure(dob,attrib=nil)
215 if dob.is ==:para \
216 || dob.is ==:heading
217 if dob.is==:heading
218 lv=dob.ln
219 dob.ln + 2
220 else lv=nil
221 end
222 extract_endnotes(dob)
223 dob.obj=dob.obj.
224 gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
225 gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>')
226 util=SiSU_JSONutils::Clean.new(dob.obj)
227 wrapped=util.line_json_clean
228 @per.body << Ax[:tab]*1 + '{'
229 if defined? dob.ocn and dob.ocn
230 @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
231 end
232 if lv # main text, contents, body KEEP
233 @per.body <<
234 Ax[:tab]*2 + %{"object": "<h#{lv}>} + wrapped + %{</h#{lv}>} +
235 ((@endnotes.length > 0) ? '",' : '"')
236 else
237 @per.body <<
238 Ax[:tab]*2 + '"object": "' + wrapped +
239 ((@endnotes.length > 0) ? '",' : '"')
240 end
241 if @endnotes.length > 0 # main text, endnotes KEEP
242 @per.body <<
243 Ax[:tab]*2 + '"endnotes": "' +
244 @endnotes.compact.join.strip + '"'
245 end
246 @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
247 @endnotes=[]
248 end
249 end
250 def block_structure(dob)
251 dob=@trans.markup_block(dob)
252 dob.obj=dob.obj.strip.
253 gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
254 gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
255 @per.body << Ax[:tab]*1 + '{'
256 if defined? dob.ocn and dob.ocn
257 @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
258 end
259 @per.body <<
260 Ax[:tab]*2 + '"object": "' + dob.obj + '"'
261 #((@endnotes.length > 0) ? '",' : '"')
262 @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
263 end
264 def group_structure(dob)
265 dob=@trans.markup_group(dob)
266 dob.obj=dob.obj.strip.
267 gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'<en>\1</en>'). #footnote/endnote clean
268 gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'<en>\1</en>') #footnote/endnote clean
269 @per.body << Ax[:tab]*1 + '{'
270 if defined? dob.ocn and dob.ocn
271 @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
272 end
273 @per.body <<
274 Ax[:tab]*2 + '"object": "' + dob.obj + '"'
275 #((@endnotes.length > 0) ? '",' : '"')
276 @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
277 end
278 def poem_structure(dob)
279 dob=@trans.markup_group(dob)
280 dob.obj=dob.obj.strip
281 @per.body << Ax[:tab]*1 + '{'
282 if defined? dob.ocn and dob.ocn
283 @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
284 end
285 @per.body <<
286 Ax[:tab]*2 + '"object": "' + dob.obj + '"'
287 #((@endnotes.length > 0) ? '",' : '"')
288 @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
289 end
290 def code_structure(dob)
291 dob=@trans.markup_group(dob)
292 dob.obj=dob.obj.gsub(/\s\s/,'&#160;&#160;').strip
293 @per.body << Ax[:tab]*1 + '{'
294 if defined? dob.ocn and dob.ocn
295 @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
296 end
297 @per.body <<
298 Ax[:tab]*2 + '"object": "' + dob.obj + '"'
299 #((@endnotes.length > 0) ? '",' : '"')
300 @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
301 end
302 def table_structure(dob)
303 table=SiSU_JSON_Shared::TableJSON.new(dob)
304 @per.body << Ax[:tab]*1 + '{'
305 if defined? dob.ocn and dob.ocn
306 @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
307 end
308 @per.body <<
309 Ax[:tab]*2 + '"object": "' + table.table.obj + '"'
310 #((@endnotes.length > 0) ? '",' : '"')
311 @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
312 end
313 def markup(data)
314 @endnotes=[]
315 @rcdc=false
316 @level,@cont,@copen,@json_contents_close=[],[],[],[]
317 json_head
318 (0..7).each { |x| @cont[x]=@level[x]=false }
319 (4..7).each { |x| @json_contents_close[x]='' }
320 data.each_with_index do |dob,i|
321 dob=@trans.char_enc.utf8(dob) if @sys.locale =~/utf-?8/i #% utf8
322 dob=@trans.markup(dob)
323 if @rcdc==false \
324 and (dob.obj =~/~meta/ \
325 and dob.obj =~/Document Information/)
326 @rcdc=true
327 end
328 if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
329 if not @rcdc
330 x=SiSU_JSON_Format::FormatTextObject.new(@md,dob)
331 if dob.is==:heading
332 json_structure(dob)
333 dob.obj=case dob.ln
334 when 0 then x.heading_body0
335 when 1 then x.heading_body1
336 when 2 then x.heading_body2
337 when 3 then x.heading_body3
338 when 4 then x.heading_body4
339 when 5 then x.heading_body5
340 when 6 then x.heading_body6
341 when 7 then x.heading_body7
342 end
343 else
344 if dob.is ==:verse
345 poem_structure(dob)
346 elsif dob.is ==:group
347 group_structure(dob)
348 elsif dob.is ==:block
349 block_structure(dob)
350 elsif dob.is ==:code
351 code_structure(dob)
352 elsif dob.is ==:table
353 table_structure(dob)
354 elsif dob.is ==:para \
355 and dob.indent.to_s =~/[1-9]/ \
356 and dob.bullet_==true
357 json_structure(dob,"indent_bullet#{dob.indent}")
358 elsif dob.is ==:para \
359 and dob.indent.to_s =~/[1-9]/ \
360 and dob.indent == dob.hang
361 json_structure(dob,"indent#{dob.indent}")
362 elsif dob.is==:para \
363 and dob.hang.to_s =~/[0-9]/ \
364 and dob.indent != dob.hang
365 json_structure(dob,"hang#{dob.hang.to_s}_indent#{dob.indent.to_s}")
366 else json_structure(dob)
367 end
368 end
369 end
370 dob.obj=dob.obj.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'') if dob.obj
371 end
372 end
373 6.downto(4) do |x|
374 y=x - 1; v=x - 3
375 @per.body << "#{Ax[:tab]*5}</content>\n#{Ax[:tab]*y}</contents#{v}>" if @level[x]==true
376 end
377 3.downto(1) do |x|
378 y=x - 1
379 @per.body << "#{Ax[:tab]*y}</heading#{x}>" if @level[x]==true
380 end
381 end
382 def pre
383 @per.head,@per.body=[],[]
384 @per.open = '{'
385 end
386 def post
387 @per.close = '}'
388 end
389 def publish
390 content=[]
391 @per.body[-1] = @per.body[-1].gsub(/,$/, '') #= Ax[:tab]*1 + '}'
392 content << @per.open << @per.head << @per.body << @per.metadata
393 content << @per.tail << @per.close
394 content=content.flatten.compact
395 Output.new(content,@md).json
396 end
397 end
398 class Output
399 def initialize(data,md)
400 @data,@md=data,md
401 @file=SiSU_Env::FileOp.new(@md)
402 end
403 def json
404 SiSU_Env::FileOp.new(@md).mkdir
405 filename_json=@file.write_file.json
406 @data.each do |str|
407 str=str.gsub(/\A\s+\Z/m,'') #str.gsub(/^\s+$/,'')
408 filename_json.puts str unless str.empty?
409 end
410 filename_json.close
411 end
412 end
413 end
414 end
415 __END__