infod 0.0.3.2 → 0.0.3.3

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.
@@ -1,3 +1,17 @@
1
+ %w{
2
+ cgi
3
+ date
4
+ digest/sha1
5
+ fileutils
6
+ json
7
+ linkeddata
8
+ mail
9
+ nokogiri
10
+ open-uri
11
+ pathname
12
+ rack
13
+ shellwords}.map{|r|require r}
14
+
1
15
  %w{
2
16
  constants
3
17
  lambda
@@ -13,34 +27,25 @@ csv
13
27
  edit
14
28
  facets
15
29
  feed
16
- find
17
30
  forum
18
31
  fs
19
32
  GET
20
- glob
21
33
  graph
22
34
  groonga
23
- HEAD
24
35
  histogram
25
36
  html
26
37
  HTTP
27
38
  image
28
39
  index
29
- kv
30
40
  ls
31
41
  mail
32
42
  man
33
43
  microblog
34
44
  names
35
- page
36
45
  POST
37
- postscript
38
46
  rdf
39
- ruby
40
47
  schema
41
- sh
42
48
  text
43
49
  threads
44
50
  time
45
- wiki
46
51
  }.map{|e|require_relative e}
@@ -1,23 +1,35 @@
1
+ class FalseClass
2
+ def do; false end
3
+ end
4
+
5
+ class NilClass
6
+ def do; nil end
7
+ def html e=nil,g=nil; "" end
8
+ def R; "".R end
9
+ end
10
+
11
+ class Object
12
+ def id; self end
13
+ def do; yield self end
14
+ def maybeURI; nil end
15
+ def justArray; [self] end
16
+ end
1
17
 
2
18
  def watch f
3
- E::Watch[f]=File.mtime f
19
+ R::Watch[f]=File.mtime f
4
20
  puts 'dev '+f end
5
21
 
6
- class E
22
+ class R
7
23
 
8
24
  def initialize uri
9
25
  @uri = uri.to_s
10
26
  end
11
27
 
12
- def E arg=nil
13
- if arg
14
- E.new arg
15
- else
16
- self
17
- end
28
+ def R uri = nil
29
+ uri ? R.new(uri) : self
18
30
  end
19
31
 
20
- def E.[] u; u.E end
32
+ def R.[] uri; R.new uri end
21
33
 
22
34
  F={}
23
35
  Watch={}
@@ -31,23 +43,23 @@ class E
31
43
  end }
32
44
  end
33
45
 
34
- # call lambda @id
35
- def y *a
36
- F[uri][*a]
46
+ # util, prefix, cleaner -> tripleStream
47
+ def triplrStdOut e,f='/',g=/^\s*(.*?)\s*$/,a=sh
48
+ `#{e} #{a}|grep :`.each_line{|i|
49
+ i = i.split /:/
50
+ yield uri, (f + (i[0].match(g)||[0,i[0]])[1]. # s
51
+ gsub(/\s/,'_').gsub(/\//,'-').gsub(/[\(\)]+/,'')), # p
52
+ i.tail.join(':').strip.do{|v|v.match(/^[0-9\.]+$/) ? v.to_f : v.hrefs}} # o
53
+ rescue
37
54
  end
38
55
 
39
56
  end
40
57
 
41
58
  # URI -> function
42
-
43
59
  def fn u,y
44
- E::F[u.to_s] = y
45
- end
46
-
47
- def Fn a,*g
48
- E::F[a][*g]
60
+ R::F[u.to_s] = y
49
61
  end
50
62
 
51
- def E e
52
- E.new e
63
+ def R uri
64
+ R.new uri
53
65
  end
@@ -1,14 +1,14 @@
1
1
  #watch __FILE__
2
- class E
2
+ class R
3
3
 
4
4
  fn 'view/dir',->i,e{
5
- a = -> i { i = i.E
5
+ a = -> i { i = i.R
6
6
  {_: :a, href: i.localURL(e), c: i.uri.match(/(gif|jpe?g|png)$/i) ? {_: :img, src: i.uri+'?y=scaleImage&px=233'} : i.uri.sub(/.*\//,'')}}
7
7
 
8
8
  [(H.once e, 'dir', (H.css '/css/ls')),
9
9
  i.map{|u,r|
10
- url = r.E.localURL e
11
- {class: :dir, style: "background-color: #{E.cs}", # dir wrapper
10
+ url = r.R.localURL e
11
+ {class: :dir, style: "background-color: #{R.cs}", # dir wrapper
12
12
  c: [{c: [{_: :a, href: url.t + '?view=ls', c: r.uri.sub('http://'+e['SERVER_NAME'],'')},
13
13
  {_: :a, href: url.t, c: '/'}]},
14
14
  r[Posix+'dir#child'].do{|c|c.map{|c|a[c]}}]}}]}
@@ -18,7 +18,7 @@ class E
18
18
  fn 'view/ls',->i,e{
19
19
  e.q['sort'] ||= 'stat:mtime'
20
20
  e.q['reverse'] ||= true
21
- dir = e['uri'].E
21
+ dir = e['uri'].R
22
22
  path = dir.pathSegment
23
23
  up = (!path || path.uri == '/') ? '/' : dir.parent.url
24
24
  i = i.dup
@@ -30,8 +30,31 @@ class E
30
30
  r.delete_if{|p,o|!f[p]}}
31
31
  [(H.css '/css/ls'),
32
32
  {_: :a, class: :up, href: up+'?view=ls', c: '↑'},
33
- {class: :ls, c: (Fn 'view/table',i,e)},'<br clear=all>',
34
- {_: :a, class: :down, href: e['uri'].E.url.t, c: '&darr;'}]}
33
+ {class: :ls, c: F['view/table'][i,e]},'<br clear=all>',
34
+ {_: :a, class: :down, href: e['uri'].R.url.t, c: '&darr;'}]}
35
+
36
+ fn 'set/find',->e,q,m,x=''{
37
+ q['q'].do{|q|
38
+ r = '-iregex ' + ('.*' + q + '.*' + x).sh
39
+ s = q['size'].do{|s| s.match(/^\d+$/) && '-size +' + s + 'M'} || ""
40
+ t = q['day'].do{|d| d.match(/^\d+$/) && '-ctime -' + d } || ""
41
+ [e,e.pathSegment].compact.select(&:e).map{|e|
42
+ `find #{e.sh} #{t} #{s} #{r} | head -n 1000`.
43
+ lines.map{|l|l.chomp.unpath}}.compact.flatten}}
44
+
45
+ fn 'set/glob',->d,e=nil,_=nil{
46
+ p = [d,d.pathSegment].compact.map(&:glob).flatten[0..4e2].compact.partition &:inside
47
+ p[0] }
48
+
49
+ fn 'view/find',->i,e{
50
+ {_: :form, method: :GET, action: e['REQUEST_PATH'].t,
51
+ c: [{_: :input, name: :set, value: :find, type: :hidden},
52
+ {_: :input, name: :view, value: :ls, type: :hidden},
53
+ {_: :input, name: :q, style: 'float: left;font-size:1.3em'}]}}
54
+
55
+ fn 'req/randomFile',->e,r{
56
+ g = F['set/glob'][e]
57
+ !g.empty? ? [302, {Location: g[rand g.length].uri}, []] : [404]}
35
58
 
36
59
  fn 'protograph/du',->d,q,m{
37
60
  d.pathSegment.do{|path|
@@ -46,9 +69,9 @@ class E
46
69
  fn 'graph/du',->e,_,m{
47
70
  `du -a #{m.values[0].sh}`.each_line{|l|
48
71
  s,p = l.chomp.split /\t/ # size, path
49
- p = p.unpathFs # path -> URI
72
+ p = p.unpath # path -> URI
50
73
  m[p.uri] = {'uri' => p.uri,
51
- Posix+'util#du' => E[p.uri+'?graph=du#du'],
74
+ Posix+'util#du' => R[p.uri+'?graph=du#du'],
52
75
  Stat+'size' => [s.to_i]}}
53
76
  m }
54
77
 
@@ -1,115 +1,125 @@
1
1
  #watch __FILE__
2
- class E
2
+ class R
3
3
 
4
- begin
5
- require 'tmail'
6
- rescue LoadError => e
7
- end
8
-
9
- MessagePath = ->id{ h = id.h # hash identifier
10
- '/msg/' + h[0..2] + '/' + id}
4
+ MessagePath = ->id{'/msg/' + id.h[0..2] + '/' + id}
11
5
 
12
6
  GREP_DIRS.push /^\/m\/[^\/]+\// # allow grep within a single address
13
7
 
14
8
  F['/m/GET'] = -> e,r{
9
+ # set overview(summary) view and start a depth-first view of message tree of this address
15
10
  if m = e.pathSegment.uri.match(/^\/m\/([^\/]+)$/)
16
- r.q['set'] = 'depth'
11
+ r.q['set'] ||= 'depth'
17
12
  r.q['view'] ||= 'threads'
18
13
  e.response
19
14
  else
20
15
  false
21
16
  end}
22
17
 
23
- def triplrTmail &f
24
- (TMail::Mail.load node).do{|m| # load
25
- d = m.message_id; return unless d # parse successful?
26
- id = d[1..-2] # message-ID
27
- e = MessagePath[id] # webized ID
28
- from = m.from[0].to_utf8 # author
29
- creator = '/m/'+from+'#'+from # author URI
30
- yield e, DC+'identifier', id # original ID
31
- yield e, DC+'source', self # original file
32
- yield e, Type, E[SIOCt + 'MailMessage']
33
- yield e, Type, E[SIOC + 'Post']
34
- yield e, Date, m.date.iso8601 if m.date
35
- yield e, Title, m.subject.to_utf8
36
- yield e, Creator, E[creator]
37
- yield e, SIOC+'has_discussion', E[e+'?graph=thread&view=timegraph#discussion']
38
- yield creator, Name, m.friendly_from.to_utf8
39
- yield creator, DC+'identifier', E['mailto:'+from]
40
- yield e, SIOC+'reply_to',
41
- E[URI.escape("mailto:#{m.header['x-original-to']||from}?References=<#{id}>&In-Reply-To=<#{id}>&Subject=#{m.subject.to_utf8}&")+'#reply']
42
-
43
- %w{to cc bcc}.map{|to|
44
- m.send(to).do{|to| to.map{|to|
45
- to = to.to_utf8
46
- yield e, To, E['/m/'+to+'#'+to]
47
- }}}
48
-
49
- %w{in_reply_to references}.map{|ref|
50
- m.send(ref).do{|refs| refs.map{|r|
51
- yield e, SIOC+'reply_of', E[MessagePath[r[1..-2]]]}}}
52
- m.in_reply_to.do{|refs| refs.map{|r|yield e, SIOC+'has_parent', E[MessagePath[r[1..-2]]]}}
53
-
54
- # RDF:HTML message-body
55
- yield e, Content,
56
- H([{_: :pre, class: :mail, style: 'white-space: pre-wrap',
57
- c: m.concat_message(e.E,0,&f).gsub(/^\s*(&gt;)(&gt;|\s)*\n/,"").lines.to_a.map{|l| # skip quoted empty-lines
58
- l.match(/(^\s*(&gt;|On[^\n]+(said|wrote))[^\n]*)\n/) ? {_: :span, class: :q, depth: l.scan(/(&gt;)/).size, c: l} : l # quotes
59
- }},(H.css '/css/mail',true)])}
60
- rescue Exception => e
61
- puts e
62
- end
18
+ IndexMail = ->doc, graph, host {
19
+ graph.map{|u,r|
20
+ a = [] # address references
21
+ r[Creator].do{|c|a.concat c}
22
+ r[To].do{|t|a.concat t}
23
+ r[Date].do{|t|
24
+ st = '/' + t[0][0..18].gsub('-','/').sub('T','.') + '.' + u.h[0..1] + '.e'
25
+ a.map{|rel|
26
+ doc.ln R[rel.uri.split('#')[0]+st]}}}}
63
27
 
64
28
  def triplrMailMessage &f
65
- # indexing function, called on previously-unseen doc-graphs
66
- ix = ->doc, graph, host {
67
- graph.map{|u,r|
68
- a = [] # addresses
69
- r[Creator].do{|c|a.concat c}
70
- r[To].do{|t|a.concat t}
71
- r[Date].do{|t|
72
- st = '/'+t[0].gsub('-','/').sub('T','.').sub(/\+.*/,'.'+u.h[0..1]+'.e')
73
- a.map{|rel|
74
- doc.ln E[rel.uri.split('#')[0]+st]}}}}
75
- addDocs :triplrTmail, @r['SERVER_NAME'], [SIOC+'reply_of'], ix, &f
29
+ addDocs :triplrMail, @r['SERVER_NAME'], [SIOC+'reply_of'], IndexMail, &f
76
30
  end
77
31
 
78
- F['view/'+MIMEtype+'message/rfc822'] = NullView # hide containing file in default render
32
+ def mail
33
+ Mail.read node if f
34
+ end
79
35
 
80
- end
36
+ def triplrMail
37
+ m = mail ; return unless m # mail
38
+ id = m.message_id ; return unless id # message-ID
39
+ e = MessagePath[id.gsub(/[<>]/,'')] # message URI
40
+ yield e, DC+'identifier', id # origin-domain ID
41
+ yield e, DC+'source', self # source-file URI
42
+ [R[SIOCt+'MailMessage'], # SIOC types
43
+ R[SIOC+'Post']].map{|t|yield e, Type, t} # RDF types
44
+
45
+ m.from.do{|f| # any authors?
46
+ f.justArray.map{|f| # each author
47
+ f = f.to_utf8
48
+ creator = '/m/'+f+'#'+f # author URI
49
+ yield e, Creator, R[creator] # message -> author
50
+ yield creator, DC+'identifier', R['mailto:'+f] # author ID
51
+ yield e, SIOC+'reply_to', # reply URI
52
+ R[URI.escape("mailto:#{m.reply_to.do{|t|t[0]}||f}?References=<#{id}>&In-Reply-To=<#{id}>&Subject=#{m.subject}&")+'#reply']}}
53
+
54
+ yield e, Date, m.date.iso8601 if m.date # date
55
+
56
+ m.subject.do{|s|yield e, Title, s.to_utf8} # subject
57
+
58
+ yield e, SIOC+'has_discussion', # thread
59
+ R[e+'?graph=thread&view=timegraph#discussion'] if m.in_reply_to || m.references
60
+
61
+ %w{to cc bcc}.map{|to| # reciever fields
62
+ m.send(to).do{|to| # has field?
63
+ to.justArray.map{|to| # each recipient
64
+ to.do{|to| # non-nil?
65
+ to = to.to_utf8 # UTF-8
66
+ yield e, To, R['/m/'+to+'#'+to]}}}} # recipient URI
67
+
68
+ %w{in_reply_to references}.map{|ref| # reference predicates
69
+ m.send(ref).do{|rs| rs.justArray.map{|r| # indirect-references
70
+ yield e, SIOC+'reply_of', R[MessagePath[r]]}}} # reference URI
71
+
72
+ m.in_reply_to.do{|r| # direct-reference predicate
73
+ yield e, SIOC+'has_parent', R[MessagePath[r]]} # reference URI
74
+
75
+ parts = m.all_parts.push m # parts
76
+
77
+ parts.select{|p| # text parts
78
+ (!p.mime_type || p.mime_type=='text/plain') &&
79
+ Mail::Encodings.defined?(p.body.encoding) # decodable?
80
+ }.map{|p|
81
+ yield e, Content,
82
+ H([{_: :pre, class: :mail, style: 'white-space: pre-wrap', # wrap body
83
+ c: p.decoded.to_utf8.hrefs.gsub(/^\s*(&gt;)(&gt;|\s)*\n/,"").lines.to_a.map{|l| # skip quoted*empty lines
84
+ l.match(/(^\s*(&gt;|On[^\n]+(said|wrote))[^\n]*)\n/) ? # quoted?
85
+ {_: :span, class: :q, depth: l.scan(/(&gt;)/).size, c: l} : l # wrap quotes
86
+ }},(H.css '/css/mail',true)])}
87
+
88
+ attache = -> { e.R.a('.attache').mk } # filesystem container for attachments & parts
89
+
90
+ htmlCount = 0
91
+ parts.select{|p|p.mime_type=='text/html'}.map{|p| # HTML content
92
+ html = attache[].as "page#{htmlCount}.html" # name
93
+ yield e, DC+'hasFormat', html # message -> HTML resource
94
+ html.w p.decoded if !html.e # write content
95
+ htmlCount += 1 }
96
+ # attached
97
+ m.attachments.select{|p|Mail::Encodings.defined?(p.body.encoding)}.map{|p|
98
+ name = p.filename.do{|f|f.to_utf8.do{|f|!f.empty? && f}} || (rand.to_s.h + '.' + (MIME.invert[p.mime_type] || 'bin').to_s)
99
+ file = attache[].as name # name
100
+ file.w p.body.decoded if !file.e # write
101
+ yield e, SIOC+'attachment', file # message -> attached resource
102
+ if p.main_type=='image' # image reference in HTML
103
+ yield e, Content, H({_: :a, href: file.uri, c: [{_: :img, src: file.uri},p.filename]})
104
+ end }
81
105
 
82
- module TMail
83
- class Mail
84
- def unicode_body
85
- unquoted_body.to_utf8
86
- end
87
- def concat_message i, partCount=0, &f
88
- if multipart?
89
- parts.map{|part|
90
- if part.multipart? # and even more nested parts..
91
- part.concat_message i, partCount, &f
92
- elsif !attachment?(part) && part.sub_type != 'html'
93
- part.unicode_body.hrefs true
94
- else # attachment
95
- a = i.a('.attache').mk # create container
96
- p = a.as(part['content-type']['name'] || (partCount.to_s + '.' + (E::MIME.invert[part.content_type] || '.bin').to_s))
97
- p.w part.body if !p.e # write attachment into message container
98
- partCount += 1 # display images
99
- yield i.uri, E::SIOC+'attachment', p
100
- '<a href="'+p.uri+'">'+(part.main_type=='image' ? '<img src="'+p.uri+'">' : '')+p.uri.label+"</a><br>\n"
101
- end
102
- }.join
103
- else # just a part
104
- unicode_body.do{|b|
105
- if content_type && content_type.match(/html/)
106
- E::F['cleanHTML'][b]
107
- else
108
- b.hrefs true
109
- end}
110
- end
111
- end
112
106
  end
113
- end
114
107
 
115
- class String; def is_binary_data?; true; end; end
108
+ F['view/'+MIMEtype+'message/rfc822'] = NullView # hide container-resource in default view
109
+ =begin
110
+ USAGE(context)
111
+
112
+ admin (irb) move messages among filesystems
113
+ p = R['/m/semantic-web@w3.org'].take.map{|g|'.' + g.graph.values.find{|r|r.has_key?(R::DC+'source')}[R::DC+'source'][0].R.path}
114
+ `rsync -avRz #{p.join ' '} h:/www/`
115
+
116
+ view (rb) default to overview of directory
117
+ F['/mail/GET'] = -> e,r {
118
+ r.q['view'] ||= 'threads' if e.uri[-1] == '/'
119
+ false }
120
+
121
+ home (sh) current day-dir in Markdown
122
+ echo "[today](/?y=day&view=threads)" > TODAY.md
123
+
124
+ =end
125
+ end
@@ -1,5 +1,5 @@
1
1
  #watch __FILE__
2
- class E
2
+ class R
3
3
 
4
4
  fn '/man/GET',->e,r{
5
5
  manPath = '/usr/share/man'
@@ -16,7 +16,7 @@ class E
16
16
  if !name || name.empty? || name.match(/\//)
17
17
  if section
18
18
  # enumerate section children
19
- body = H [H.css('/css/man'),{_: :style, c: "a {background-color: #{E.cs}}"},
19
+ body = H [H.css('/css/man'),{_: :style, c: "a {background-color: #{R.cs}}"},
20
20
  Pathname(manPath+'/man'+section).c.map{|p|
21
21
  n = p.basename.to_s.sub /\.[0-9][a-z]*\...$/,''
22
22
  }.group_by{|e|e[0].match(/[a-zA-Z]/) ? e[0].downcase : '0-9'}.sort.map{|g,m|
@@ -37,8 +37,8 @@ class E
37
37
  return false
38
38
  else
39
39
 
40
- roff = man.E
41
- htmlBase = roff.dir.to_s.sub(/.*\/share/,'').E
40
+ roff = man.R
41
+ htmlBase = roff.dir.to_s.sub(/.*\/share/,'').R
42
42
  html = htmlBase.as roff.bare + '.html'
43
43
  cached = html.e && html.m > (Pathname man).stat.mtime
44
44
 
@@ -59,7 +59,7 @@ class E
59
59
 
60
60
  # add CSS link
61
61
  body.add_child H H.css('/css/man')
62
- body.add_child H[{_: :style, c: "a {background-color:#{E.cs}}"}]
62
+ body.add_child H[{_: :style, c: "a {background-color:#{R.cs}}"}]
63
63
 
64
64
  # add localization links
65
65
  (body.css('h1')[0] ||
@@ -69,7 +69,7 @@ class E
69
69
 
70
70
  # webize image paths
71
71
  body.css('img').map{|i|
72
- p = (i.attr 'src').unpathFs
72
+ p = (i.attr 'src').unpath
73
73
  i.replace H[{_: :img, src: p}]}
74
74
 
75
75
  # inspect plaintext