infod 0.0.1 → 0.0.2

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 (93) hide show
  1. data/infod.rb +2 -3
  2. data/infod/Es.rb +31 -67
  3. data/infod/{W/source.rb → Es/code.rb} +6 -10
  4. data/infod/Es/css.rb +21 -0
  5. data/infod/{W → Es}/csv.rb +0 -0
  6. data/infod/Es/du.rb +16 -0
  7. data/infod/{W → Es}/feed.rb +13 -11
  8. data/infod/Es/filter.rb +75 -0
  9. data/infod/Es/find.rb +20 -0
  10. data/infod/Es/fs.rb +145 -136
  11. data/infod/Es/glob.rb +22 -0
  12. data/infod/Es/grep.rb +61 -0
  13. data/infod/Es/groonga.rb +47 -56
  14. data/infod/Es/html.rb +271 -0
  15. data/infod/Es/image.rb +114 -0
  16. data/infod/Es/in.rb +68 -0
  17. data/infod/Es/index.rb +183 -0
  18. data/infod/{W → Es}/json.rb +28 -4
  19. data/infod/Es/kv.rb +60 -0
  20. data/infod/Es/ls.rb +58 -0
  21. data/infod/Es/mail.rb +87 -0
  22. data/infod/Es/man.rb +112 -0
  23. data/infod/Es/mime.rb +59 -0
  24. data/infod/Es/out.rb +52 -0
  25. data/infod/{W/page.rb → Es/pager.rb} +7 -3
  26. data/infod/Es/pdf.rb +19 -0
  27. data/infod/Es/rdf.rb +35 -0
  28. data/infod/Es/schema.rb +99 -0
  29. data/infod/Es/search.rb +24 -0
  30. data/infod/Es/sh.rb +21 -0
  31. data/infod/{W → Es}/text.rb +26 -14
  32. data/infod/H.rb +15 -29
  33. data/infod/H/audio.rb +19 -0
  34. data/infod/H/blog.rb +15 -0
  35. data/infod/{W → H}/cal.rb +2 -31
  36. data/infod/H/edit.rb +88 -0
  37. data/infod/{W/examine/examine.rb → H/facets.rb} +17 -17
  38. data/infod/{W → H}/forum.rb +1 -0
  39. data/infod/{W/examine/sw.rb → H/hf.rb} +12 -12
  40. data/infod/H/histogram.rb +78 -0
  41. data/infod/H/mail.rb +92 -0
  42. data/infod/{W/chat.rb → H/microblog.rb} +21 -16
  43. data/infod/H/threads.rb +77 -0
  44. data/infod/H/time.rb +131 -0
  45. data/infod/H/who.rb +30 -0
  46. data/infod/{W → H}/wiki.rb +0 -0
  47. data/infod/K.rb +28 -60
  48. data/infod/N.rb +151 -74
  49. data/infod/Rb.rb +3 -3
  50. data/infod/Th.rb +27 -101
  51. data/infod/Th/404.rb +29 -36
  52. data/infod/Th/500.rb +36 -5
  53. data/infod/Th/GET.rb +48 -118
  54. data/infod/Th/POST.rb +31 -11
  55. data/infod/Th/perf.rb +37 -0
  56. data/infod/Th/util.rb +89 -0
  57. data/infod/Y.rb +24 -7
  58. data/infod/infod.rb +2 -3
  59. metadata +92 -64
  60. data/infod/Es/redis.rb +0 -3
  61. data/infod/Es/sqlite.rb +0 -3
  62. data/infod/Th/local.rb +0 -22
  63. data/infod/W.rb +0 -34
  64. data/infod/W/audio.rb +0 -56
  65. data/infod/W/blog.rb +0 -3
  66. data/infod/W/color.rb +0 -28
  67. data/infod/W/core.rb +0 -77
  68. data/infod/W/css.rb +0 -24
  69. data/infod/W/du.rb +0 -35
  70. data/infod/W/edit.rb +0 -8
  71. data/infod/W/examine/exhibit.rb +0 -34
  72. data/infod/W/examine/hist.rb +0 -55
  73. data/infod/W/examine/history.rb +0 -19
  74. data/infod/W/examine/normal.rb +0 -31
  75. data/infod/W/examine/protovis.rb +0 -30
  76. data/infod/W/examine/time/graph.rb +0 -86
  77. data/infod/W/examine/time/line.rb +0 -24
  78. data/infod/W/find.rb +0 -24
  79. data/infod/W/grep.rb +0 -27
  80. data/infod/W/html.rb +0 -143
  81. data/infod/W/image.rb +0 -61
  82. data/infod/W/kv.rb +0 -66
  83. data/infod/W/ls.rb +0 -50
  84. data/infod/W/mail.rb +0 -248
  85. data/infod/W/pdf.rb +0 -16
  86. data/infod/W/post.rb +0 -9
  87. data/infod/W/rdf.rb +0 -32
  88. data/infod/W/schema.rb +0 -172
  89. data/infod/W/search.rb +0 -33
  90. data/infod/W/shell.rb +0 -30
  91. data/infod/W/table.rb +0 -87
  92. data/infod/W/tree.rb +0 -26
  93. data/infod/W/vfs.rb +0 -175
data/infod/Es/ls.rb ADDED
@@ -0,0 +1,58 @@
1
+ #watch __FILE__
2
+ class E
3
+
4
+ fn 'view/dir',->i,e{
5
+
6
+ # item link + preview
7
+ a = -> i { i = i.E
8
+ {_: :a, href: i.localURL(e),
9
+ c: i.uri.match(/(gif|jpe?g|png)$/i) ? {_: :img, src: i.uri+'?y=scaleImage&px=233'} : i.uri.sub(/.*\//,'')}}
10
+
11
+ [(H.once e, 'dir', (H.css '/css/ls')),
12
+ i.map{|u,r|
13
+ if r[Posix+'dir#child']
14
+ url = r.E.localURL e
15
+ {class: :dir, style: "background-color: #{E.cs}", # dir wrapper
16
+ c: [{c: [{_: :a, href: url.t+'?view=ls&triplr=id', # link to "ls"
17
+ c: r.uri.sub( 'http://'+e['SERVER_NAME'],'')},
18
+ {_: :a, href: url.t, c: '/'}]},
19
+ r[Posix+'dir#child'].map{|c|a[c]}]}
20
+ else
21
+ a[r]
22
+ end
23
+ }]}
24
+
25
+ F['view/'+MIMEtype+'inode/directory'] = F['view/dir']
26
+
27
+ fn 'view/ls',->i,e{
28
+ dir = e['uri'].E
29
+ path = dir.pathSegment
30
+ up = (if !path || path.uri == '/'
31
+ '/'
32
+ else
33
+ dir.parent.url.t+'?view=ls&triplr=id'
34
+ end)
35
+
36
+ [(H.css '/css/ls'),
37
+ {_: :a, class: :up, href: up, c: '↑'},
38
+ {class: :ls,
39
+ c: (Fn 'view/table',i,e)},
40
+ (Fn 'view/find',i,e),'<br clear=all>',
41
+ {_: :a, class: :down, href: e['uri'].E.url.t + e.q.except('triplr','view').qs, c: '&darr;'}]}
42
+
43
+ # user-patchable default-handler
44
+ fn '/GET',->e,r{
45
+ x = 'index.html'
46
+ i = [e,e.pathSegment].compact.map{|e|e.as x}.find &:e
47
+ if i
48
+ if e.uri[-1] == '/' # inside dir?
49
+ i.env(r).getFile # show index
50
+ else # descend to indexed dir
51
+ [301, {Location: e.uri.t}, []]
52
+ end
53
+ else
54
+ # default handler
55
+ e.response
56
+ end}
57
+
58
+ end
data/infod/Es/mail.rb ADDED
@@ -0,0 +1,87 @@
1
+ class E
2
+
3
+ # TMail version: 1.2.7.1-4 from:
4
+ # apt-get install ruby-tmail
5
+
6
+ def triplrTmail ; require 'tmail'
7
+
8
+ # read message
9
+ i = -> i {E i[1..-2]} # Message-ID -> E
10
+ (TMail::Mail.load node).do{|m| # parse
11
+ d = m.message_id; return unless d # parse successful?
12
+ e = i[d] # Message resource
13
+
14
+ # index previously unseen mail
15
+ e.e || ( # Message-ID locatable?
16
+ ln e # create message-id path
17
+ self.index Creator, m.from[0].E # index From
18
+ m.to.do{|t|self.index To, t[0].E} # index To
19
+
20
+ %w{in_reply_to references}.map{|p| m.send(p).do{|os| os.map{|o|
21
+ e.index SIOC+'reply_of', i[o]}}}) # index references
22
+
23
+ # yield triples
24
+ yield e.uri, Type, E[SIOCt + 'MailMessage']
25
+ yield e.uri, Type, E[SIOC + 'Post']
26
+ yield e.uri, Date, m.date.iso8601 if m.date
27
+ yield e.uri, Content, m.decentBody
28
+ [[:subject,Title],
29
+ [:to,To,true],
30
+ [:cc,To,true],
31
+ [:bcc,To,true],
32
+ [:friendly_from,SIOC+'name'],
33
+ [:from,Creator,true],
34
+ [:reply_to,'/mail/reply_to',true],
35
+ [:in_reply_to,'/parent',true,true],
36
+ [:in_reply_to,SIOC+'reply_of',true,true],
37
+ [:references,SIOC+'reply_of',true,true],
38
+ ].each{|a| m.send(a[0]).do{|o| [*o].map{|o|
39
+ yield e.uri,a[1], # skip empty String values
40
+ (a[2] ? (a[3] ? i[o] : o.E) : o.to_utf8) unless o.match(/\A[, \n]*\Z/)}}}}
41
+
42
+ rescue Exception => e
43
+ puts [:mail,uri,e].join(' ')
44
+ end
45
+
46
+ alias_method :triplrMail, :triplrTmail
47
+
48
+ # pure-ruby mail is only 10x (vs 100x) slower than C-ext based TMail w/ new parser
49
+ # API is mostly identical, URIs strings arent <>-wrapped
50
+ # TODO replace this msg with triplrMail if anyone wants it
51
+
52
+ end
53
+
54
+ module TMail
55
+ class Mail
56
+ def unicode_body
57
+ unquoted_body.to_utf8
58
+ end
59
+ def decentBody
60
+ unHTML=->t{t.split(/<body[^>]*>/)[-1].split(/<\/body>/)[0]}
61
+ if multipart?
62
+ parts.collect{ |part|
63
+ c = part["content-type"]
64
+ if part.multipart?
65
+ part.decentBody
66
+ elsif header.nil?
67
+ ""
68
+ elsif !attachment?(part) && c.sub_type != 'html'
69
+ part.unicode_body.hrefs(true)
70
+ else
71
+ (c["name"]||'attach').do{|a|
72
+ message_id ? (message_id[1..-2]+'/'+a).E.do{|i|
73
+ i.w part.body if !i.e
74
+ '<a href='+i.url+'>'+(part.main_type=='image' ? '<img src="'+i.url+'">' : a)+"</a><br>\n"
75
+ } : ""};end
76
+ }.join
77
+
78
+ else
79
+ unicode_body.do{|b|content_type&&content_type.match(/html/) ? unHTML.(b) : b.hrefs(true)}
80
+ end
81
+ rescue
82
+ ''
83
+ end
84
+ end
85
+ end
86
+
87
+ class String; def is_binary_data?; true; end; end
data/infod/Es/man.rb ADDED
@@ -0,0 +1,112 @@
1
+ #watch __FILE__
2
+ class E
3
+
4
+ fn '/man/GET',->e,r{
5
+ manPath = '/usr/share/man'
6
+
7
+ # eat selector
8
+ name = e.pathSegment.uri.sub('/man/','/').tail
9
+
10
+ # section requested?
11
+ section = nil
12
+ name.match(/^([0-9])(\/|$)/).do{|p|
13
+ section = p[1]
14
+ name = p.post_match }
15
+
16
+ if !name || name.empty? || name.match(/\//)
17
+ if section
18
+ # enumerate section children
19
+ (H [H.css('/css/man'),{_: :style, c: "a {background-color: #{E.cs}}"},
20
+ Pathname(manPath+'/man'+section).c.map{|p|
21
+ n = p.basename.to_s.sub /\.[0-9][a-z]*\...$/,''
22
+ }.group_by{|e|e[0].match(/[a-zA-Z]/) ? e[0].downcase : '0-9'}.sort.map{|g,m|
23
+ [{_: :h3, c: g},
24
+ m.map{|n|[{_: :a, href: '/man/'+section+'/'+n, c: n },' ']}]}
25
+ ]).hR
26
+ else
27
+ e.response
28
+ end
29
+ else
30
+ acceptLang = r['HTTP_ACCEPT_LANGUAGE'].do{|a|a.split(/,/)[0]}
31
+ lang = r.q['lang'] || acceptLang
32
+ superLang = lang.do{|l| (l.split /[_-]/)[0] }
33
+ langSH = lang.do{|l| '-L ' + l.sub('-','_').sh }
34
+ man = `man #{langSH} -w #{section} #{name.sh}`.chomp
35
+
36
+ if man.empty?
37
+ return false
38
+ else
39
+
40
+ roff = man.E
41
+ htmlBase = roff.dir.to_s.sub(/.*\/share/,'').E
42
+ html = htmlBase.as roff.bare + '.html'
43
+ cached = html.e && html.m > (Pathname man).stat.mtime
44
+
45
+ if !cached
46
+
47
+ locales = Pathname(manPath).c.select{|p|p.basename.to_s.do{|b| !b.match(/^man/) && !b.match(/\./) }}.map{|p|File.basename p}
48
+ localesAvail = locales.select{|l|
49
+ File.exist? manPath + '/' + l + '/' + roff.uri.split('/')[-2..-1].join('/')}
50
+
51
+ imagePath = htmlBase.d + '/images'
52
+ FileUtils.mkdir_p imagePath unless File.exist? imagePath
53
+
54
+ preconv = %w{hu pt tr}.member?(superLang) ? "" : "-k"
55
+ pageCmd = "zcat #{man} | groff #{preconv} -T html -man -P -D -P #{imagePath}"
56
+ page = `#{pageCmd}`#.to_utf8
57
+
58
+ [[:name,name],
59
+ [:acceptLang,acceptLang],
60
+ [:lang, lang],
61
+ [:langSH, langSH],
62
+ [:superLang, superLang],
63
+ [:roff,man],
64
+ [:htmlBase,htmlBase.d],
65
+ [:imagePath,imagePath],
66
+ [:localizations,localesAvail],
67
+ [:pageCmd,pageCmd]].map{|p| puts [" "*(13-p[0].size),*p].join ' ' }
68
+
69
+ page = Nokogiri::HTML.parse page
70
+ body = page.css('body')[0]
71
+
72
+ # add CSS link
73
+ body.add_child H H.css('/css/man')
74
+ body.add_child H[{_: :style, c: "a {background-color:#{E.cs}}"}]
75
+
76
+ # add localization links
77
+ (body.css('h1')[0] ||
78
+ body.css('p')[0]
79
+ ).add_previous_sibling H localesAvail.map{|l|
80
+ {_: :a, class: :lang, href: r['REQUEST_PATH']+'?lang='+l, c: l}}
81
+
82
+ # webize image paths
83
+ body.css('img').map{|i|
84
+ p = (i.attr 'src').unpathFs
85
+ i.replace H[{_: :img, src: p}]}
86
+
87
+ # inspect plaintext
88
+ # HTMLize hyperlinks
89
+ # markup commands
90
+ body.xpath('//text()').map{|a|
91
+ a.replace a.to_s.gsub('&gt;','>').hrefs.gsub /\b([^<>\s(]+)\(/mi, '<b>\1</b>('
92
+ }
93
+
94
+ qs = r['QUERY_STRING'].do{|q| q.empty? ? '' : '?' + q}
95
+ # href-ize commands
96
+ body.css('b').map{|b|
97
+ b.next.do{|n|
98
+ n.to_s.match(/\(([0-9])\)(.*)/).do{|section|
99
+ name, s = b.inner_text, section[1]
100
+ n.replace section[2]
101
+ b.replace " <a href='/man/#{s}/#{name}#{qs}'><b>#{name}</b>(#{s})</a>"}}}
102
+
103
+ html.w page
104
+ end
105
+
106
+ # response
107
+ html.env(r).getFile
108
+ end
109
+ end
110
+ }
111
+
112
+ end
data/infod/Es/mime.rb ADDED
@@ -0,0 +1,59 @@
1
+ #watch __FILE__
2
+ class E
3
+
4
+ # MIME-type, no link-following
5
+ def mime
6
+ @mime ||=
7
+ (t = ext.downcase.to_sym
8
+
9
+ if node.symlink?
10
+ "inode/symlink"
11
+
12
+ elsif d?
13
+ "inode/directory"
14
+
15
+ elsif MIME[t]
16
+ MIME[t]
17
+
18
+ elsif Rack::Mime::MIME_TYPES[t='.'+t.to_s]
19
+ Rack::Mime::MIME_TYPES[t]
20
+
21
+ elsif base.index('msg.')==0
22
+ "message/rfc822"
23
+
24
+ elsif e
25
+ `file --mime-type -b #{sh}`.chomp
26
+
27
+ else
28
+ "application/octet-stream"
29
+ end)
30
+ end
31
+
32
+ # MIME-type of recursively-dereferenced path
33
+ def mimeP
34
+ @mime ||=
35
+ (p = realpath
36
+
37
+ unless p
38
+ nil
39
+ else
40
+ t = ((File.extname p).tail || '').downcase.to_sym
41
+
42
+ if p.directory?
43
+ "inode/directory"
44
+
45
+ elsif MIME[t]
46
+ MIME[t]
47
+
48
+ elsif Rack::Mime::MIME_TYPES[t='.'+t.to_s]
49
+ Rack::Mime::MIME_TYPES[t]
50
+
51
+ elsif (File.basename p).index('msg.')==0
52
+ "message/rfc822"
53
+
54
+ else
55
+ `file --mime-type -b #{Shellwords.escape p.to_s}`.chomp
56
+ end
57
+ end )
58
+ end
59
+ end
data/infod/Es/out.rb ADDED
@@ -0,0 +1,52 @@
1
+ class E
2
+
3
+ def render mime, graph, e
4
+ E[Render+ mime].y graph, e
5
+ end
6
+
7
+ fn '/E/GET',->e,r{[301,{Location: '/'},[]]}
8
+
9
+ def response
10
+
11
+ q = @r.q # query-string
12
+ g = q['graph'] # graph-function selector
13
+
14
+ # empty response graph
15
+ m = {}
16
+
17
+ # identify graph
18
+ graphID = (F['protograph/' + g] || F['protograph/'])[self,q,m]
19
+
20
+ return F[E404][self,@r] if m.empty?
21
+
22
+ # identify response
23
+ @r['ETag'] ||= [graphID, q, @r.format, Watch].h
24
+
25
+ maybeSend @r.format, ->{
26
+
27
+ # response
28
+ r = E'/E/req/' + @r['ETag'].dive
29
+ if r.e # response exists
30
+ r # cached response
31
+ else
32
+
33
+ # graph
34
+ c = E '/E/graph/' + graphID.dive
35
+ if c.e # graph exists
36
+ m.merge! c.r true
37
+ else
38
+ # construct graph
39
+ (F['graph/' + g] || F['graph/'])[self,q,m]
40
+ # cache graph
41
+ c.w m,true
42
+ end
43
+
44
+ # graph sort/filter
45
+ E.filter q, m, self
46
+
47
+ # cache response
48
+ r.w render @r.format, m, @r
49
+ end }
50
+ end
51
+
52
+ end
@@ -1,8 +1,12 @@
1
1
  #watch __FILE__
2
2
  class E
3
3
 
4
- fn 'head/page',->d,e{ v = e.q['v']
5
- Fn 'head' + (v != 'page' && '/' + v), d, e}
4
+ fn 'head/page',->d,e{
5
+ v = e.q['v']
6
+ unless v == 'page'
7
+ h = F['head/'+v] || F['head']
8
+ h[d,e]
9
+ end}
6
10
 
7
11
  fn 'view/page',->d,e{
8
12
  # try daydirs if no pagination data provided
@@ -25,6 +29,6 @@ class E
25
29
 
26
30
  [(H.js '/js/pager'),(H.once e,:mu,(H.js '/js/mu')), # n/p key shortcuts
27
31
  c,(H (F['view/'+e.q['v']]||F['view']).(d,e)), # content
28
- '<br clear=all>',c]}
32
+ '<br clear=all>',{class: :bottom, c: c}]}
29
33
 
30
34
  end
data/infod/Es/pdf.rb ADDED
@@ -0,0 +1,19 @@
1
+ class E
2
+
3
+ def triplrPDF &f
4
+
5
+ text = docBase.a '.txt'
6
+ unless text.e && text.m > m
7
+ puts "PDF #{uri}"
8
+ `pdftotext #{sh}`
9
+ end
10
+
11
+ # metadata
12
+ triplrStdOut 'pdfinfo', &f
13
+
14
+ # body
15
+ yield uri, Content, `cat #{text.sh}`
16
+
17
+ end
18
+
19
+ end
data/infod/Es/rdf.rb ADDED
@@ -0,0 +1,35 @@
1
+ #watch __FILE__
2
+ class E
3
+
4
+ def self.renderRDF d,f
5
+ require 'linkeddata'
6
+ (RDF::Writer.for f).buffer{|w|
7
+ d.values.each{|r| r.triples{|s,p,o|
8
+ s = RDF::URI s
9
+ p = RDF::URI p
10
+ o = ([E,Hash].member?(o.class) ? (RDF::URI o.uri) : (RDF::Literal o)) rescue nil
11
+ (w << (RDF::Statement.new s,p,o) if o ) rescue nil
12
+ }}}
13
+ end
14
+
15
+ def triplrRDF format=:rdfa, localFile=true ; require 'linkeddata'
16
+ location = (localFile && f) ? d : uri
17
+ puts [:RDF,location].join ' '
18
+ RDF::Reader.open(location, :format => format){|r|
19
+ r.each_triple{|s,p,o|
20
+ yield s.to_s, p.to_s, [RDF::Node, RDF::URI].member?(o.class) ? E(o) : o.value.do{|v|v.class == String ? v.to_utf8 : v}}}
21
+ end
22
+
23
+ [['application/ld+json',:jsonld],
24
+ ['application/json+ld',:jsonld],
25
+ ['application/jsonld',:jsonld],
26
+ ['application/rdf+xml',:rdfxml],
27
+ ['application/rdfxml',:rdfxml],
28
+ ['text/ntriples',:ntriples],
29
+ ['text/turtle',:turtle],
30
+ ['text/rdf+n3',:n3],
31
+ ['text/n3',:n3]
32
+ ].map{|mime|
33
+ F[Render+mime[0]] = ->d,a=nil{E.renderRDF d, mime[1]}}
34
+
35
+ end