infod 0.0.3.1 → 0.0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,13 +4,12 @@ lambda
4
4
  mime
5
5
  404
6
6
  500
7
+ grep
7
8
  audio
8
9
  blog
9
10
  cal
10
11
  code
11
- css
12
12
  csv
13
- du
14
13
  edit
15
14
  facets
16
15
  feed
@@ -20,7 +19,6 @@ fs
20
19
  GET
21
20
  glob
22
21
  graph
23
- grep
24
22
  groonga
25
23
  HEAD
26
24
  histogram
@@ -28,7 +26,6 @@ html
28
26
  HTTP
29
27
  image
30
28
  index
31
- json
32
29
  kv
33
30
  ls
34
31
  mail
@@ -36,13 +33,11 @@ man
36
33
  microblog
37
34
  names
38
35
  page
39
- PATCH
40
36
  POST
41
37
  postscript
42
38
  rdf
43
39
  ruby
44
40
  schema
45
- search
46
41
  sh
47
42
  text
48
43
  threads
@@ -21,8 +21,8 @@ class E
21
21
  if t.e # old triple exists?
22
22
  t.deleteNode # remove triple
23
23
  indexEdit p,o,'' # unindex
24
- end
25
- self[p,oO] unless oO.empty? # add triple
24
+ end # add
25
+ self[p,oO] unless oO.class==String && oO.empty? # 3rd arg is new value, empty-string -> nil
26
26
  else
27
27
  unless t.e # triple exists?
28
28
  indexEdit p,o,nil # index triple
@@ -37,10 +37,12 @@ class E
37
37
  end
38
38
  end
39
39
 
40
- def triplrFsStore
41
- properties.map{|p|
42
- self[p].map{|o|
43
- yield uri, p.uri, o}}
40
+ def triplrDoc &f
41
+ docBase.glob('#*').map{|s| s.triplrResource &f}
42
+ end
43
+
44
+ def triplrResource
45
+ properties.map{|p|self[p].map{|o| yield uri, p.uri, o}}
44
46
  end
45
47
 
46
48
  def deletePredicate p
@@ -22,6 +22,8 @@ class E
22
22
  F={}
23
23
  Watch={}
24
24
 
25
+ NullView = -> d,e {}
26
+
25
27
  def self.dev
26
28
  Watch.each{|f,ts|
27
29
  if ts < File.mtime(f)
@@ -16,6 +16,8 @@ class E
16
16
  F['view/'+MIMEtype+'inode/directory'] = F['view/dir']
17
17
 
18
18
  fn 'view/ls',->i,e{
19
+ e.q['sort'] ||= 'stat:mtime'
20
+ e.q['reverse'] ||= true
19
21
  dir = e['uri'].E
20
22
  path = dir.pathSegment
21
23
  up = (!path || path.uri == '/') ? '/' : dir.parent.url
@@ -30,20 +32,24 @@ class E
30
32
  {_: :a, class: :up, href: up+'?view=ls', c: '&uarr;'},
31
33
  {class: :ls, c: (Fn 'view/table',i,e)},'<br clear=all>',
32
34
  {_: :a, class: :down, href: e['uri'].E.url.t, c: '&darr;'}]}
33
-
34
- # user-patchable default-handler
35
- fn '/GET',->e,r{
36
- x = 'index.html'
37
- i = [e,e.pathSegment].compact.map{|e|e.as x}.find &:e
38
- if i
39
- if e.uri[-1] == '/' # inside dir?
40
- i.env(r).getFile # show index
41
- else # descend to indexed dir
42
- [301, {Location: e.uri.t}, []]
43
- end
44
- else
45
- # default handler
46
- e.response
47
- end}
48
35
 
36
+ fn 'protograph/du',->d,q,m{
37
+ d.pathSegment.do{|path|
38
+ GREP_DIRS.find{|p|path.uri.match p}.do{|ok|
39
+ e = [d,path].compact.find &:e
40
+ q['view'] ||= 'table'
41
+ q['sort'] = Stat+'size'
42
+ q['reverse'] = true
43
+ m[e.uri] = e if e
44
+ rand.to_s.h}}}
45
+
46
+ fn 'graph/du',->e,_,m{
47
+ `du -a #{m.values[0].sh}`.each_line{|l|
48
+ s,p = l.chomp.split /\t/ # size, path
49
+ p = p.unpathFs # path -> URI
50
+ m[p.uri] = {'uri' => p.uri,
51
+ Posix+'util#du' => E[p.uri+'?graph=du#du'],
52
+ Stat+'size' => [s.to_i]}}
53
+ m }
54
+
49
55
  end
@@ -6,9 +6,19 @@ class E
6
6
  rescue LoadError => e
7
7
  end
8
8
 
9
- MessagePath = ->id{
10
- h = id.h # hash identifier
11
- '/msg/' + h[0..1] + '/' + h[2] + '/' + id}
9
+ MessagePath = ->id{ h = id.h # hash identifier
10
+ '/msg/' + h[0..2] + '/' + id}
11
+
12
+ GREP_DIRS.push /^\/m\/[^\/]+\// # allow grep within a single address
13
+
14
+ F['/m/GET'] = -> e,r{
15
+ if m = e.pathSegment.uri.match(/^\/m\/([^\/]+)$/)
16
+ r.q['set'] = 'depth'
17
+ r.q['view'] ||= 'threads'
18
+ e.response
19
+ else
20
+ false
21
+ end}
12
22
 
13
23
  def triplrTmail &f
14
24
  (TMail::Mail.load node).do{|m| # load
@@ -24,49 +34,48 @@ class E
24
34
  yield e, Date, m.date.iso8601 if m.date
25
35
  yield e, Title, m.subject.to_utf8
26
36
  yield e, Creator, E[creator]
27
- yield e, SIOC+'has_discussion', E[e+'?graph=thread']
28
-
29
- yield creator, SIOC+'name', m.friendly_from.to_utf8
37
+ yield e, SIOC+'has_discussion', E[e+'?graph=thread&view=timegraph#discussion']
38
+ yield creator, Name, m.friendly_from.to_utf8
30
39
  yield creator, DC+'identifier', E['mailto:'+from]
31
- posts = '/m/'+from+'#posts'
32
- yield creator, SIOC+'creator_of', E[posts]
33
- yield posts, Type, E[LDP+'Container']
34
- yield posts, LDP+'firstPage', E['/index/sioc:has_creator/'+CGI.escape(creator)]
35
- yield e, SIOC+'reply_to', E[URI.escape "mailto:#{m.header['x-original-to']||from}?References=<#{e}>&In-Reply-To=<#{e}>&Subject=#{m.subject.to_utf8}"]
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']
36
42
 
37
43
  %w{to cc bcc}.map{|to|
38
44
  m.send(to).do{|to| to.map{|to|
39
45
  to = to.to_utf8
40
- r = '/m/'+to+'#'+to
41
- yield e, To, E[r]
42
- yield r, SIOC+'container_of', E['/index/sioc:addressed_to/'+CGI.escape(r)]}}}
46
+ yield e, To, E['/m/'+to+'#'+to]
47
+ }}}
43
48
 
44
49
  %w{in_reply_to references}.map{|ref|
45
50
  m.send(ref).do{|refs| refs.map{|r|
46
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]]]}}
47
53
 
48
- # RDF:HTML with self-contained minimal styling
54
+ # RDF:HTML message-body
49
55
  yield e, Content,
50
56
  H([{_: :pre, class: :mail, style: 'white-space: pre-wrap',
51
57
  c: m.concat_message(e.E,0,&f).gsub(/^\s*(&gt;)(&gt;|\s)*\n/,"").lines.to_a.map{|l| # skip quoted empty-lines
52
- l.match(/(^\s*(&gt;|On[^\n]+(said|wrote))[^\n]*)\n/) ? {_: :span, class: :q, c: l} : l # wrap quoted lines
53
- }},
54
- {_: :style, c: "pre.mail .q {background-color:#00f;color:#fff}\npre.mail a{background-color:#ef3}\npre.mail img {max-width:100%}"}])}
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)])}
55
60
  rescue Exception => e
56
61
  puts e
57
62
  end
58
63
 
59
64
  def triplrMailMessage &f
60
- insertDocs :triplrTmail, @r['SERVER_NAME'], [To,SIOC+'has_creator',SIOC+'reply_of'], &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
61
76
  end
62
- =begin
63
- there's another mail library called Mail, as of v2.5.4 takes 50x as long as tmail (apt-get install ruby-tmail)
64
- HEAD 200 http://m/m/2013/12/01/?nocache=&triplr=triplrMail curl/7.33.0 5.4003388
65
- HEAD 200 http://m/m/2013/12/01/?nocache=&triplr=triplrTmail curl/7.33.0 0.1198720
66
-
67
- almost a copy of above works but identifiers are not wrapped in <> - with caching it might be fast enough..
68
77
 
69
- =end
78
+ F['view/'+MIMEtype+'message/rfc822'] = NullView # hide containing file in default render
70
79
 
71
80
  end
72
81
 
@@ -94,7 +103,7 @@ module TMail
94
103
  else # just a part
95
104
  unicode_body.do{|b|
96
105
  if content_type && content_type.match(/html/)
97
- (b.split /<body[^>]*>/)[-1].split(/<\/body>/)[0]
106
+ E::F['cleanHTML'][b]
98
107
  else
99
108
  b.hrefs true
100
109
  end}
@@ -16,13 +16,13 @@ class E
16
16
  if !name || name.empty? || name.match(/\//)
17
17
  if section
18
18
  # enumerate section children
19
- (H [H.css('/css/man'),{_: :style, c: "a {background-color: #{E.cs}}"},
19
+ body = H [H.css('/css/man'),{_: :style, c: "a {background-color: #{E.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|
23
23
  [{_: :h3, c: g},
24
- m.map{|n|[{_: :a, href: '/man/'+section+'/'+n, c: n },' ']}]}
25
- ]).hR
24
+ m.map{|n|[{_: :a, href: '/man/'+section+'/'+n, c: n },' ']}]}]
25
+ [200, {'Content-Type'=>'text/html; charset=utf-8'}, [body]]
26
26
  else
27
27
  e.response
28
28
  end
@@ -26,7 +26,7 @@ class E
26
26
 
27
27
  def tw g
28
28
  no.readlines.shuffle.each_slice(22){|s|
29
- E['https://twitter.com/search/realtime?q='+s.map{|u|'from:'+u.chomp}.intersperse('+OR+').join].insertDocs :triplrTweets, g}
29
+ E['https://twitter.com/search/realtime?q='+s.map{|u|'from:'+u.chomp}.intersperse('+OR+').join].addDocs :triplrTweets, g, nil, FeedArchiver}
30
30
  end
31
31
 
32
32
  def triplrTweets
@@ -36,7 +36,7 @@ class E
36
36
  yield s, Type, E[SIOCt+'MicroblogPost']
37
37
  yield s, Type, E[SIOC+'Post']
38
38
  yield s, Creator, E(base+'/'+t.css('.username b')[0].inner_text)
39
- yield s, SIOC+'name',t.css('.fullname')[0].inner_text
39
+ yield s, Name,t.css('.fullname')[0].inner_text
40
40
  yield s, Atom+"/link/image", E(t.css('.avatar')[0].attr('src'))
41
41
  yield s, Date, Time.at(t.css('[data-time]')[0].attr('data-time').to_i).iso8601
42
42
  content = t.css('.tweet-text')[0]
@@ -56,7 +56,7 @@ class E
56
56
  [r[Date][0].match(/T([0-9:]{5})/).do{|m|m[1]},
57
57
  {_: :span, :class => :nick, c: {_: :a, href: r[Atom+'/link/alternate'].do{|a|a[0].uri}||r.url,
58
58
  c: [r[Atom+"/link/image"].do{|p| {_: :img, src: p[0].uri, style: "#{rand(2).zero? ? 'left' : 'right'}: 0"}},
59
- {_: :span, c: r[SIOC+'name']||r[Creator]||'#'}]}},' ',
59
+ {_: :span, c: r[Name]||r[Creator]||'#'}]}},' ',
60
60
  {_: :span, :class => :tw, # skip redundant title fields
61
61
  c: [((r[Title].to_s == r[Content].to_s || r.uri.match(/twitter/)) && '' ||
62
62
  {_: :a, :class => :title, href: r.url, c: r[Title]}), # skip quoted mail-lines & abbreviate
@@ -79,6 +79,7 @@ class E
79
79
  nfo: 'text/nfo',
80
80
  nt: 'text/ntriples',
81
81
  ntriples: 'text/ntriples',
82
+ org: 'application/org',
82
83
  owl: 'application/rdf+xml',
83
84
  pdf: 'application/pdf',
84
85
  pl: 'application/perl',
@@ -1,9 +1,10 @@
1
- %w{base64 cgi shellwords}.each{|r|require(r)}
1
+ %w{cgi shellwords}.each{|r|require(r)}
2
2
 
3
3
  class E
4
4
 
5
5
  attr_reader :uri
6
6
  alias_method :url, :uri
7
+ alias_method :maybeURI, :uri
7
8
 
8
9
  def env r=nil
9
10
  r ? (@r = r
@@ -58,7 +59,7 @@ class E
58
59
  end
59
60
  alias_method :dir, :dirname
60
61
 
61
- # add hostname to URI if missing
62
+ # add hostname to URI (if missing)
62
63
  def hostURL e
63
64
  host = 'http://'+e['SERVER_NAME']
64
65
  if uri.index('/') == 0
@@ -70,15 +71,12 @@ class E
70
71
 
71
72
  # pointer to local data about global URI
72
73
  def localURL e
73
- # path
74
- if uri.index('/') == 0 # already a local path
75
- uri
76
- # host match
74
+ if uri.index('/') == 0
75
+ uri # already a local path
77
76
  elsif e && uri.index('http://'+e['SERVER_NAME']+'/') == 0
78
- pathSegment.uri
79
- # non-local
77
+ pathSegment.uri # host match, unchanged local path
80
78
  else
81
- URIURL + (CGI.escape uri)
79
+ '/' + uri # URI -> local path
82
80
  end
83
81
  end
84
82
 
@@ -87,7 +85,6 @@ class E
87
85
  m && m[2] && m[2].E || nil
88
86
  end
89
87
 
90
- # URI extension :: E -> string
91
88
  def ext
92
89
  File.extname(uri).tail||''
93
90
  end
@@ -124,39 +121,25 @@ class E
124
121
  alias_method :+, :appendURI
125
122
  alias_method :as, :appendSlashURI
126
123
 
127
- def path?
128
- uri.path?
129
- end
130
-
131
124
  def shortPath
132
125
  @shortPath ||=
133
- (if path?
134
- if uri.match /^\//
135
- uri
136
- else
137
- '/' + uri.shorten
138
- end
126
+ (if uri.match /^\//
127
+ uri
139
128
  else
140
- '/E/' + uri.h.dive[0..5] + (Base64.urlsafe_encode64 uri)
129
+ '/' + uri.shorten
141
130
  end)
142
131
  end
143
132
 
144
- # URI -> path
145
133
  def path
146
- @path ||=
147
- (if path?
148
- if uri.match /^\//
149
- uri
150
- else
151
- '/' + uri
152
- end
153
- else
154
- '/E/' + uri.h.dive[0..5] + (Base64.urlsafe_encode64 uri)
155
- end)
134
+ if uri.match /^\//
135
+ uri
136
+ else
137
+ '/' + uri
138
+ end
156
139
  end
157
140
 
158
141
  def u
159
- # data-storage path for resource
142
+ # path for data about this resource
160
143
  @u ||= E (f ? dirname + '/.' + (File.basename path) : path.t + '._')
161
144
  end
162
145
 
@@ -170,56 +153,22 @@ class E
170
153
  d.force_encoding('UTF-8').sh
171
154
  end
172
155
 
173
- # literals to URIs
174
- # currently used for iso8601 dates mapping to paths, so date-range queries (depth-first subtrees) can be done w/ dir/fs tools
175
- # could also use as a "trie" for autocomplete + sorted-strings
176
156
  def E.literal o
177
- E['/'].literal o
157
+ ''.E.literal o
178
158
  end
179
-
180
- Literal={}
181
- [Purl+'dc/elements/1.1/date',
182
- Date,DC+'created',DC+'modified',
183
- ].map{|f|Literal[f]=true}
184
159
 
185
160
  def literal o
186
-
187
- # already a URI
188
161
  return o if o.class == E
189
-
190
- # blob for non-strings
191
- return literalBlob o unless o.class == String
192
-
193
- # whitelisted predicateURIs to paths
194
- return literalURI o if (Literal[uri] || o.size<=88) && !o.match(/\//)
195
-
196
- # string matches URI format
197
- return E o if o.match %r{\A[a-z]+://[^\s]+\Z}
198
-
199
- # blob
200
- literalBlob o
201
-
202
- end
203
-
204
- # pathname for short literals
205
- def literalURI o
206
- E "/l/"+o.gsub(/[\.:\-T+]/,'/')+'/'+o if Literal[uri] && o
207
- end
208
-
209
- def literalBlobURI o
210
- if o.class == String
211
- E "/E/blob/"+o.h.dive
212
- else
213
- E "/E/json/"+[o].to_json.h.dive
214
- end
215
- end
216
-
217
- def literalBlob o
218
- u = literalBlobURI o
162
+ u = (if o.class == String
163
+ E "/E/blob/"+o.h.dive
164
+ else
165
+ E "/E/json/"+[o].to_json.h.dive
166
+ end)
219
167
  u.w o, !o.class == String unless u.f
168
+ u
220
169
  end
221
170
 
222
- # spaceship
171
+ # spaceship comparison-operator
223
172
  def <=> c
224
173
  to_s <=> c.to_s
225
174
  end
@@ -232,7 +181,7 @@ class E
232
181
  {'uri' => uri}
233
182
  end
234
183
 
235
- # implementation-specific internal pathnames not on the web
184
+ # internal pathnames not on the web (cached representations, index databases)
236
185
  F['/E/GET'] = F[E404]
237
186
 
238
187
  end
@@ -242,6 +191,7 @@ class Hash
242
191
  self["uri"]||""
243
192
  end
244
193
  alias_method :url, :uri
194
+ alias_method :maybeURI, :uri
245
195
  def label
246
196
  self[E::Label] || uri.label
247
197
  end
@@ -274,7 +224,7 @@ class String
274
224
  self )
275
225
  end
276
226
 
277
- # shrink URI to qname/CURIE/prefix'd identifier
227
+ # shrink URI to qname/CURIE/prefixed identifier
278
228
  def shorten
279
229
  E::Prefix.map{|p,f|
280
230
  return p + ':' + self[f.size..-1] if (index f) == 0
@@ -298,16 +248,10 @@ class String
298
248
  if m = (match /^\/([a-z]+:)\/+(.*)/)
299
249
  (m[1] + '//' + m[2]).E
300
250
 
301
- # CURIE
251
+ # prefix-shortened URI
302
252
  elsif m = (match /^\/([^\/:]+:[^\/]+)/)
303
253
  m[1].expand.E
304
254
 
305
- # opaque URI w/ optional extension
306
- elsif match /^\/E\/..\//
307
- self[9..-1].match(/([^.]+)(.*)/).do{|c|
308
- (Base64.urlsafe_decode64 c[1]) + c[2]
309
- }.E
310
-
311
255
  # String literal
312
256
  elsif match /^\/E\/blob/
313
257
  self.E.r
@@ -316,10 +260,6 @@ class String
316
260
  elsif match /^\/E\/json/
317
261
  self.E.r true
318
262
 
319
- # literal in basename
320
- elsif match /^\/l\//
321
- File.basename self
322
-
323
263
  # plain path
324
264
  else
325
265
  self.E
@@ -331,10 +271,6 @@ class String
331
271
  E.new self
332
272
  end
333
273
 
334
- def path?
335
- (match /^(\.|\/|https?:\/)/) && true || false
336
- end
337
-
338
274
  def frag
339
275
  split(/#/).pop()
340
276
  end