infod 0.0.3.1 → 0.0.3.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.
@@ -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