infod 0.0.2 → 0.0.3.0
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.
- data/infod.rb +51 -12
- data/infod/{Th/404.rb → 404.rb} +4 -16
- data/infod/500.rb +53 -0
- data/infod/GET.rb +104 -0
- data/infod/HEAD.rb +23 -0
- data/infod/HTTP.rb +105 -0
- data/infod/{Th/PATCH.rb → PATCH.rb} +0 -0
- data/infod/POST.rb +34 -0
- data/infod/audio.rb +30 -0
- data/infod/blog.rb +34 -0
- data/infod/cal.rb +72 -0
- data/infod/{Es/code.rb → code.rb} +7 -4
- data/infod/constants.rb +55 -0
- data/infod/{Es/css.rb → css.rb} +0 -0
- data/infod/{Es/csv.rb → csv.rb} +0 -0
- data/infod/{Es/du.rb → du.rb} +0 -0
- data/infod/edit.rb +73 -0
- data/infod/{H/facets.rb → facets.rb} +20 -11
- data/infod/{Es/feed.rb → feed.rb} +17 -16
- data/infod/{Es/find.rb → find.rb} +2 -3
- data/infod/forum.rb +13 -0
- data/infod/{Es/fs.rb → fs.rb} +5 -2
- data/infod/glob.rb +26 -0
- data/infod/graph.rb +131 -0
- data/infod/{Es/grep.rb → grep.rb} +3 -3
- data/infod/{Es/groonga.rb → groonga.rb} +35 -26
- data/infod/{H/histogram.rb → histogram.rb} +23 -16
- data/infod/html.rb +231 -0
- data/infod/{Es/image.rb → image.rb} +16 -26
- data/infod/{Es/index.rb → index.rb} +44 -49
- data/infod/infod.rb +51 -12
- data/infod/json.rb +38 -0
- data/infod/{Es/kv.rb → kv.rb} +3 -9
- data/infod/{Y.rb → lambda.rb} +18 -1
- data/infod/ls.rb +49 -0
- data/infod/mail.rb +108 -0
- data/infod/{Es/man.rb → man.rb} +3 -15
- data/infod/{H/microblog.rb → microblog.rb} +22 -31
- data/infod/{K.rb → mime.rb} +68 -52
- data/infod/{N.rb → names.rb} +77 -56
- data/infod/page.rb +13 -0
- data/infod/postscript.rb +26 -0
- data/infod/rdf.rb +51 -0
- data/infod/{Rb.rb → ruby.rb} +18 -33
- data/infod/{Es/schema.rb → schema.rb} +23 -8
- data/infod/{Es/search.rb → search.rb} +5 -11
- data/infod/{Es/sh.rb → sh.rb} +0 -0
- data/infod/{Es/text.rb → text.rb} +33 -29
- data/infod/{H/threads.rb → threads.rb} +20 -27
- data/infod/{H/time.rb → time.rb} +14 -34
- data/infod/{H/wiki.rb → wiki.rb} +0 -0
- metadata +53 -64
- data/config.ru +0 -3
- data/infod/Es.rb +0 -31
- data/infod/Es/filter.rb +0 -75
- data/infod/Es/glob.rb +0 -22
- data/infod/Es/html.rb +0 -271
- data/infod/Es/in.rb +0 -68
- data/infod/Es/json.rb +0 -68
- data/infod/Es/ls.rb +0 -58
- data/infod/Es/mail.rb +0 -87
- data/infod/Es/mime.rb +0 -59
- data/infod/Es/out.rb +0 -52
- data/infod/Es/pager.rb +0 -34
- data/infod/Es/pdf.rb +0 -19
- data/infod/Es/rdf.rb +0 -35
- data/infod/H.rb +0 -15
- data/infod/H/audio.rb +0 -19
- data/infod/H/blog.rb +0 -15
- data/infod/H/cal.rb +0 -81
- data/infod/H/edit.rb +0 -88
- data/infod/H/forum.rb +0 -4
- data/infod/H/hf.rb +0 -114
- data/infod/H/mail.rb +0 -92
- data/infod/H/who.rb +0 -30
- data/infod/Th.rb +0 -36
- data/infod/Th/500.rb +0 -41
- data/infod/Th/GET.rb +0 -62
- data/infod/Th/HEAD.rb +0 -5
- data/infod/Th/POST.rb +0 -39
- data/infod/Th/perf.rb +0 -37
- data/infod/Th/uid.rb +0 -24
- data/infod/Th/util.rb +0 -89
data/infod/mail.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
class E
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'tmail'
|
6
|
+
rescue LoadError => e
|
7
|
+
end
|
8
|
+
|
9
|
+
MessagePath = ->id{
|
10
|
+
h = id.h # hash identifier
|
11
|
+
'/msg/' + h[0..1] + '/' + h[2] + '/' + id}
|
12
|
+
|
13
|
+
def triplrTmail &f
|
14
|
+
(TMail::Mail.load node).do{|m| # load
|
15
|
+
d = m.message_id; return unless d # parse successful?
|
16
|
+
id = d[1..-2] # message-ID
|
17
|
+
e = MessagePath[id] # webized ID
|
18
|
+
from = m.from[0].to_utf8 # author
|
19
|
+
creator = '/m/'+from+'#'+from # author URI
|
20
|
+
yield e, DC+'identifier', id # original ID
|
21
|
+
yield e, DC+'source', self # original file
|
22
|
+
yield e, Type, E[SIOCt + 'MailMessage']
|
23
|
+
yield e, Type, E[SIOC + 'Post']
|
24
|
+
yield e, Date, m.date.iso8601 if m.date
|
25
|
+
yield e, Title, m.subject.to_utf8
|
26
|
+
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
|
30
|
+
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
|
+
|
36
|
+
m.header['x-original-to'].do{|f|
|
37
|
+
yield e, SIOC+'reply_to', E[URI.escape "mailto:#{f}?References=<#{e}>&In-Reply-To=<#{e}>&Subject=#{m.subject.to_utf8}"] }
|
38
|
+
|
39
|
+
%w{to cc bcc}.map{|to|
|
40
|
+
m.send(to).do{|to| to.map{|to|
|
41
|
+
to = to.to_utf8
|
42
|
+
r = '/m/'+to+'#'+to
|
43
|
+
yield e, To, E[r]
|
44
|
+
yield r, SIOC+'container_of', E['/index/sioc:addressed_to/'+CGI.escape(r)]}}}
|
45
|
+
|
46
|
+
%w{in_reply_to references}.map{|ref|
|
47
|
+
m.send(ref).do{|refs| refs.map{|r|
|
48
|
+
yield e, SIOC+'reply_of', E[MessagePath[r[1..-2]]]}}}
|
49
|
+
|
50
|
+
# RDF:HTML with self-contained minimal styling
|
51
|
+
yield e, Content,
|
52
|
+
H([{_: :pre, class: :mail, style: 'white-space: pre-wrap',
|
53
|
+
c: m.concat_message(e.E,0,&f).gsub(/^\s*(>)(>|\s)*\n/,"").lines.to_a.map{|l| # skip quoted empty-lines
|
54
|
+
l.match(/(^\s*(>|On[^\n]+(said|wrote))[^\n]*)\n/) ? {_: :span, class: :q, c: l} : l # wrap quoted lines
|
55
|
+
}},
|
56
|
+
{_: :style, c: "pre.mail .q {background-color:#00f;color:#fff}\npre.mail a{background-color:#ef3}\npre.mail img {max-width:100%}"}])}
|
57
|
+
rescue Exception => e
|
58
|
+
puts e
|
59
|
+
end
|
60
|
+
|
61
|
+
def triplrMailMessage &f
|
62
|
+
insertDocs :triplrTmail, @r['SERVER_NAME'], [To,SIOC+'has_creator',SIOC+'reply_of'], &f
|
63
|
+
end
|
64
|
+
=begin
|
65
|
+
there's another mail library called Mail, as of v2.5.4 takes 50x as long as tmail (apt-get install ruby-tmail)
|
66
|
+
HEAD 200 http://m/m/2013/12/01/?nocache=&triplr=triplrMail curl/7.33.0 5.4003388
|
67
|
+
HEAD 200 http://m/m/2013/12/01/?nocache=&triplr=triplrTmail curl/7.33.0 0.1198720
|
68
|
+
|
69
|
+
almost a copy of above works but identifiers are not wrapped in <> - with caching it might be fast enough..
|
70
|
+
|
71
|
+
=end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
module TMail
|
76
|
+
class Mail
|
77
|
+
def unicode_body
|
78
|
+
unquoted_body.to_utf8
|
79
|
+
end
|
80
|
+
def concat_message i, partCount=0, &f
|
81
|
+
if multipart?
|
82
|
+
parts.map{|part|
|
83
|
+
if part.multipart? # and even more nested parts..
|
84
|
+
part.concat_message i, partCount, &f
|
85
|
+
elsif !attachment?(part) && part.sub_type != 'html'
|
86
|
+
part.unicode_body.hrefs true
|
87
|
+
else # attachment
|
88
|
+
a = i.a('.attache').mk # create container
|
89
|
+
p = a.as(part['content-type']['name'] || (partCount.to_s + '.' + (E::MIME.invert[part.content_type] || '.bin').to_s))
|
90
|
+
p.w part.body if !p.e # write attachment into message container
|
91
|
+
partCount += 1 # display images
|
92
|
+
yield i.uri, E::SIOC+'attachment', p
|
93
|
+
'<a href="'+p.uri+'">'+(part.main_type=='image' ? '<img src="'+p.uri+'">' : '')+p.uri.label+"</a><br>\n"
|
94
|
+
end
|
95
|
+
}.join
|
96
|
+
else # just a part
|
97
|
+
unicode_body.do{|b|
|
98
|
+
if content_type && content_type.match(/html/)
|
99
|
+
(b.split /<body[^>]*>/)[-1].split(/<\/body>/)[0]
|
100
|
+
else
|
101
|
+
b.hrefs true
|
102
|
+
end}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class String; def is_binary_data?; true; end; end
|
data/infod/{Es/man.rb → man.rb}
RENAMED
@@ -54,18 +54,6 @@ class E
|
|
54
54
|
preconv = %w{hu pt tr}.member?(superLang) ? "" : "-k"
|
55
55
|
pageCmd = "zcat #{man} | groff #{preconv} -T html -man -P -D -P #{imagePath}"
|
56
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
57
|
page = Nokogiri::HTML.parse page
|
70
58
|
body = page.css('body')[0]
|
71
59
|
|
@@ -88,9 +76,9 @@ class E
|
|
88
76
|
# HTMLize hyperlinks
|
89
77
|
# markup commands
|
90
78
|
body.xpath('//text()').map{|a|
|
91
|
-
a.replace a.to_s.gsub('>','>').hrefs.gsub /\b([^<>\s(]+)\(/mi, '<b>\1</b>('
|
92
|
-
}
|
93
|
-
|
79
|
+
a.replace a.to_s.gsub('>','>').hrefs.gsub /\b([^<>\s(]+)\(/mi, '<b>\1</b>('}
|
80
|
+
body.css('font').map{|f|f.remove_attribute 'color'}
|
81
|
+
|
94
82
|
qs = r['QUERY_STRING'].do{|q| q.empty? ? '' : '?' + q}
|
95
83
|
# href-ize commands
|
96
84
|
body.css('b').map{|b|
|
@@ -19,14 +19,14 @@ class E
|
|
19
19
|
yield s, Content, m[3].hrefs(true)
|
20
20
|
yield s, Type, E[SIOCt+'InstantMessage']
|
21
21
|
yield s, Type, E[SIOC+'Post']
|
22
|
-
yield s, '
|
23
|
-
|
22
|
+
yield s, SIOC+'link', (m[3].match(/http:\//) ? 'true' : 'false')
|
23
|
+
} rescue nil
|
24
24
|
}
|
25
25
|
end
|
26
26
|
|
27
|
-
def tw g
|
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].
|
29
|
+
E['https://twitter.com/search/realtime?q='+s.map{|u|'from:'+u.chomp}.intersperse('+OR+').join].insertDocs :triplrTweets, g}
|
30
30
|
end
|
31
31
|
|
32
32
|
def triplrTweets
|
@@ -47,38 +47,29 @@ class E
|
|
47
47
|
}
|
48
48
|
end
|
49
49
|
|
50
|
-
fn 'head/chat',->d,e{
|
51
|
-
t = d.map{|_,r|r[Date]}.flatten.compact.map &:to_time
|
52
|
-
c = d.map{|_,r|r[Content]}.compact.size
|
53
|
-
[{_: :title, c: "#{c} post#{c!=1 && 's'} #{t.min} -> #{t.max}"},
|
54
|
-
(Fn 'head.formats',e)]}
|
55
|
-
|
56
50
|
fn 'view/chat',->d,e{
|
57
|
-
Fn'
|
51
|
+
Fn'baseview/chat',d,e,->{d.map{|u,r|Fn 'itemview/chat',r,e}}}
|
58
52
|
|
59
|
-
fn '
|
60
|
-
|
61
|
-
r[
|
62
|
-
r[
|
63
|
-
[{_: :a, id: line},
|
64
|
-
{_: :a, :class => :date, href: r.url, c: r[Date][0].match(/T([0-9:]{5})/)[1]},
|
53
|
+
fn 'itemview/chat',->r,e{
|
54
|
+
r[Type] && [*r[Type]].map{|t|t.respond_to?(:uri) && t.uri}.include?(SIOCt+'MailMessage') && r[:mail]=true
|
55
|
+
r[Content] && r[Date] && r[Date][0] &&
|
56
|
+
[r[Date][0].match(/T([0-9:]{5})/).do{|m|m[1]},
|
65
57
|
{_: :span, :class => :nick, c: {_: :a, href: r[Atom+'/link/alternate'].do{|a|a[0].uri}||r.url,
|
66
|
-
c: [r[Atom+"/link/image"].do{|p| {_: :img,
|
58
|
+
c: [r[Atom+"/link/image"].do{|p| {_: :img, src: p[0].uri, style: "#{rand(2).zero? ? 'left' : 'right'}: 0"}},
|
67
59
|
{_: :span, c: r[SIOC+'name']||r[Creator]||'#'}]}},' ',
|
68
|
-
{_: :span, :class => :tw,
|
69
|
-
c: [r[
|
70
|
-
|
71
|
-
((r[Title].to_s==r[Content].to_s || r.uri.match(/twitter/)) && '' ||
|
72
|
-
{_: :a, href: r.url, c: r[Title],:class => r[:mail] ? :titleMail : :title}),
|
60
|
+
{_: :span, :class => :tw, # skip redundant title fields
|
61
|
+
c: [((r[Title].to_s == r[Content].to_s || r.uri.match(/twitter/)) && '' ||
|
62
|
+
{_: :a, :class => :title, href: r.url, c: r[Title]}), # skip quoted mail-lines & abbreviate
|
73
63
|
r[:mail] ? (r[Content].map{|c|c.lines.to_a.grep(/^[^&@_]+$/)[0..21]}) : r[Content],
|
74
|
-
]},
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
64
|
+
]},"<br>\n"]}
|
65
|
+
|
66
|
+
F['view/'+SIOCt+'BoardPost']=->d,e{
|
67
|
+
d.map{|u,r|
|
68
|
+
{class: :BoardPost, style: "background-color:#ff4500;color:#fff;float:left;border-radius:.8em;padding:.4em;max-width:42em;margin:.5em",
|
69
|
+
c: F['itemview/chat'][r,e]}}}
|
70
|
+
|
71
|
+
fn 'baseview/chat',->d,e,c{
|
72
|
+
[(H.once e,'chat.head',(H.css '/css/tw'),{_: :style, c: "body {background-color: #{E.c}}\n"}),c.()]}
|
82
73
|
|
83
74
|
F['view/'+SIOCt+'InstantMessage']=F['view/chat']
|
84
75
|
F['view/'+SIOCt+'MicroblogPost']=F['view/chat']
|
data/infod/{K.rb → mime.rb}
RENAMED
@@ -1,37 +1,49 @@
|
|
1
1
|
#watch __FILE__
|
2
2
|
class E
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# no link-follow
|
5
|
+
def mime
|
6
|
+
@mime ||=
|
7
|
+
(t = ext.downcase.to_sym
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
9
|
+
if node.symlink?
|
10
|
+
"inode/symlink"
|
11
|
+
elsif d?
|
12
|
+
"inode/directory"
|
13
|
+
elsif MIME[t]
|
14
|
+
MIME[t]
|
15
|
+
elsif Rack::Mime::MIME_TYPES[t='.'+t.to_s]
|
16
|
+
Rack::Mime::MIME_TYPES[t]
|
17
|
+
elsif base.index('msg.')==0
|
18
|
+
"message/rfc822"
|
19
|
+
elsif e
|
20
|
+
`file --mime-type -b #{sh}`.chomp
|
21
|
+
else
|
22
|
+
"application/octet-stream"
|
23
|
+
end)
|
24
|
+
end
|
25
|
+
|
26
|
+
# recursively-dereferenced links
|
27
|
+
def mimeP
|
28
|
+
@mime ||=
|
29
|
+
(p = realpath
|
30
|
+
unless p
|
31
|
+
nil
|
32
|
+
else
|
33
|
+
t = ((File.extname p).tail || '').downcase.to_sym
|
34
|
+
if p.directory?
|
35
|
+
"inode/directory"
|
36
|
+
elsif MIME[t]
|
37
|
+
MIME[t]
|
38
|
+
elsif Rack::Mime::MIME_TYPES[t='.'+t.to_s]
|
39
|
+
Rack::Mime::MIME_TYPES[t]
|
40
|
+
elsif (File.basename p).index('msg.')==0
|
41
|
+
"message/rfc822"
|
42
|
+
else
|
43
|
+
`file --mime-type -b #{Shellwords.escape p.to_s}`.chomp
|
44
|
+
end
|
45
|
+
end )
|
46
|
+
end
|
35
47
|
|
36
48
|
MIME={
|
37
49
|
aif: 'audio/aif',
|
@@ -40,6 +52,7 @@ class E
|
|
40
52
|
avi: 'video/avi',
|
41
53
|
e: 'application/json+rdf',
|
42
54
|
coffee: 'text/plain',
|
55
|
+
conf: 'text/plain',
|
43
56
|
css: 'text/css',
|
44
57
|
csv: 'text/comma-separated-values',
|
45
58
|
doc: 'application/word',
|
@@ -70,12 +83,14 @@ class E
|
|
70
83
|
pdf: 'application/pdf',
|
71
84
|
pl: 'application/perl',
|
72
85
|
png: 'image/png',
|
86
|
+
ps: 'application/postscript',
|
73
87
|
py: 'application/python',
|
74
88
|
rb: 'application/ruby',
|
75
89
|
ru: 'application/ruby',
|
76
90
|
rdf: 'application/rdf+xml',
|
77
91
|
rtf: 'text/rtf',
|
78
92
|
ssv: 'text/semicolon-separated-values',
|
93
|
+
tex: 'text/x-tex',
|
79
94
|
textile: 'application/textile',
|
80
95
|
tsv: 'text/tab-separated-values',
|
81
96
|
ttl: 'text/turtle',
|
@@ -87,9 +102,6 @@ class E
|
|
87
102
|
xlsx: 'application/excel',
|
88
103
|
}
|
89
104
|
|
90
|
-
VideoFile = /(avi|flv|mkv|mpg|mp4|wmv)$/i
|
91
|
-
AudioFile = /(aif|wav|flac|mp3|m4a|aac|ogg)$/i
|
92
|
-
|
93
105
|
MIMEsource={
|
94
106
|
'application/atom+xml' => [:triplrFeed],
|
95
107
|
'application/markdown' => [:triplrMarkdown],
|
@@ -97,18 +109,21 @@ class E
|
|
97
109
|
'application/rdf+xml' => [:triplrRDF,:rdfxml],
|
98
110
|
'application/json' => [:triplrJSON],
|
99
111
|
'application/pdf' => [:triplrPDF],
|
112
|
+
'application/postscript'=> [:triplrPS],
|
100
113
|
'application/textile' => [:triplrTextile],
|
101
114
|
'application/uri' => [:triplrUriList],
|
102
115
|
'application/word' => [:triplrWord],
|
103
116
|
'audio/mp4' => [:triplrStdOut,'faad -i',Audio],
|
104
117
|
'audio/mpeg' => [:triplrStdOut,'id3info',Audio,/\((.*?)\)$/],
|
105
118
|
'audio' => [:triplrStdOut,'sndfile-info',Audio],
|
119
|
+
'image' => [:triplrImage],
|
106
120
|
'inode/symlink' => [:triplrSymlink],
|
107
|
-
'message/rfc822' => [:
|
121
|
+
'message/rfc822' => [:triplrMailMessage],
|
108
122
|
'text/ansi' => [:triplrANSI],
|
109
123
|
'text/comma-separated-values'=>[:triplrCSV,/,/],
|
110
124
|
'text/log' => [:triplrIRC],
|
111
125
|
'text/man' => [:triplrMan],
|
126
|
+
'text/n3' => [:triplrRDF, :n3],
|
112
127
|
'text/nfo' => [:triplrHref,'cp437'],
|
113
128
|
'text/ntriples' => [:triplrRDF, :ntriples],
|
114
129
|
'text/plain' => [:triplrHref],
|
@@ -116,6 +131,7 @@ class E
|
|
116
131
|
'text/semicolon-separated-values'=>[:triplrCSV,/;/],
|
117
132
|
'text/tab-separated-values'=>[:triplrCSV,/\t/],
|
118
133
|
'text/turtle' => [:triplrRDF,:turtle],
|
134
|
+
'text/x-tex' => [:triplrTeX],
|
119
135
|
}
|
120
136
|
|
121
137
|
# prefer a view even if requested file exists
|
@@ -124,6 +140,7 @@ class E
|
|
124
140
|
'application/markdown' => true,
|
125
141
|
'application/json+rdf' => true,
|
126
142
|
'application/org' => true,
|
143
|
+
'application/postscript' => true,
|
127
144
|
'application/textile' => true,
|
128
145
|
'application/uri' => true,
|
129
146
|
'application/word' => true,
|
@@ -134,6 +151,14 @@ class E
|
|
134
151
|
'text/man'=>true,
|
135
152
|
'text/nfo'=>true,
|
136
153
|
'text/rtf'=>true,
|
154
|
+
'text/x-tex'=>true,
|
155
|
+
}
|
156
|
+
|
157
|
+
# cache triplr output
|
158
|
+
MIMEcache={
|
159
|
+
'audio' => true,
|
160
|
+
'image' => true,
|
161
|
+
# '' =>
|
137
162
|
}
|
138
163
|
|
139
164
|
%w{c c++ fortran haskell makefile pascal perl php python ruby}.map{|t|
|
@@ -141,25 +166,16 @@ class E
|
|
141
166
|
MIMEcook[m+t] = true
|
142
167
|
}}
|
143
168
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
"rdf" => W3+"1999/02/22-rdf-syntax-ns#",
|
148
|
-
"rdfs" => RDFs,
|
149
|
-
"sioc" => SIOC,
|
150
|
-
"stat" => Stat,
|
151
|
-
}
|
152
|
-
|
153
|
-
# literal to pathname types
|
154
|
-
Literal={}
|
155
|
-
[Purl+'dc/elements/1.1/date',
|
156
|
-
Date,
|
157
|
-
DC+'created',
|
158
|
-
Modified,
|
159
|
-
].map{|f|Literal[f]=true}
|
169
|
+
def render mime, graph, e
|
170
|
+
E[Render+ mime].y graph, e
|
171
|
+
end
|
160
172
|
|
161
|
-
def
|
162
|
-
|
173
|
+
def triplrMIME &b
|
174
|
+
mimeP.do{|mime|
|
175
|
+
yield uri, E::Type, (E MIMEtype+mimeP)
|
176
|
+
(MIMEsource[mimeP]||
|
177
|
+
MIMEsource[mimeP.split(/\//)[0]]).do{|s|
|
178
|
+
send *s,&b }}
|
163
179
|
end
|
164
180
|
|
165
181
|
end
|
data/infod/{N.rb → names.rb}
RENAMED
@@ -1,25 +1,17 @@
|
|
1
1
|
%w{base64 cgi shellwords}.each{|r|require(r)}
|
2
2
|
|
3
|
-
def E e
|
4
|
-
E.new e
|
5
|
-
end
|
6
|
-
|
7
3
|
class E
|
8
4
|
|
9
|
-
|
5
|
+
attr_reader :uri
|
6
|
+
alias_method :url, :uri
|
10
7
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
self
|
16
|
-
end
|
8
|
+
def env r=nil
|
9
|
+
r ? (@r = r
|
10
|
+
self) : @r
|
17
11
|
end
|
18
|
-
|
19
|
-
attr_reader :uri
|
20
12
|
|
21
|
-
def
|
22
|
-
|
13
|
+
def == u
|
14
|
+
to_s == u.to_s
|
23
15
|
end
|
24
16
|
|
25
17
|
def basename
|
@@ -39,20 +31,7 @@ class E
|
|
39
31
|
def ttl; @ttl||= docBase.a('.ttl') end
|
40
32
|
|
41
33
|
def docBase
|
42
|
-
uri.split(/#/)[0].E.do{|d|
|
43
|
-
d.dirname.as d.bare }
|
44
|
-
end
|
45
|
-
|
46
|
-
# same as above, but w/ URI errors
|
47
|
-
def docBaseURI
|
48
|
-
u = URI uri
|
49
|
-
s = u.scheme
|
50
|
-
p = u.path
|
51
|
-
p = '/' if p.empty?
|
52
|
-
((s ? s + '://' : '') + # scheme
|
53
|
-
u.host + # host
|
54
|
-
File.dirname(p).t + # path
|
55
|
-
File.basename(p)[0..-(File.extname(p).size+1)]).E # doc
|
34
|
+
!uri.empty? && uri.split(/#/)[0].do{|u|u.E.do{|d| d.dirname.as d.bare }} || E['']
|
56
35
|
end
|
57
36
|
|
58
37
|
def frag
|
@@ -79,22 +58,27 @@ class E
|
|
79
58
|
end
|
80
59
|
alias_method :dir, :dirname
|
81
60
|
|
82
|
-
#
|
83
|
-
def
|
84
|
-
|
61
|
+
# add hostname to URI if missing
|
62
|
+
def hostURL e
|
63
|
+
host = 'http://'+e['SERVER_NAME']
|
64
|
+
if uri.index('/') == 0
|
65
|
+
host + uri
|
66
|
+
else
|
67
|
+
uri
|
68
|
+
end
|
85
69
|
end
|
86
70
|
|
87
|
-
# local
|
71
|
+
# pointer to local data about global URI
|
88
72
|
def localURL e
|
89
73
|
# path
|
90
|
-
if uri.index('/') == 0
|
74
|
+
if uri.index('/') == 0 # already a local path
|
91
75
|
uri
|
92
76
|
# host match
|
93
|
-
elsif uri.index('http://'+e['SERVER_NAME']+'/') == 0
|
77
|
+
elsif e && uri.index('http://'+e['SERVER_NAME']+'/') == 0
|
94
78
|
pathSegment.uri
|
95
79
|
# non-local
|
96
80
|
else
|
97
|
-
|
81
|
+
URIURL + (CGI.escape uri)
|
98
82
|
end
|
99
83
|
end
|
100
84
|
|
@@ -116,6 +100,10 @@ class E
|
|
116
100
|
uri.expand.E
|
117
101
|
end
|
118
102
|
|
103
|
+
def shorten
|
104
|
+
uri.shorten.E
|
105
|
+
end
|
106
|
+
|
119
107
|
def prependURI u
|
120
108
|
E u.to_s + uri
|
121
109
|
end
|
@@ -129,7 +117,7 @@ class E
|
|
129
117
|
end
|
130
118
|
|
131
119
|
def concatURI b
|
132
|
-
u.appendURI b.E.
|
120
|
+
u.appendURI b.E.shortPath
|
133
121
|
end
|
134
122
|
|
135
123
|
alias_method :a, :appendURI
|
@@ -140,6 +128,19 @@ class E
|
|
140
128
|
uri.path?
|
141
129
|
end
|
142
130
|
|
131
|
+
def shortPath
|
132
|
+
@shortPath ||=
|
133
|
+
(if path?
|
134
|
+
if uri.match /^\//
|
135
|
+
uri
|
136
|
+
else
|
137
|
+
'/' + uri.shorten
|
138
|
+
end
|
139
|
+
else
|
140
|
+
'/E/' + uri.h.dive[0..5] + (Base64.urlsafe_encode64 uri)
|
141
|
+
end)
|
142
|
+
end
|
143
|
+
|
143
144
|
# URI -> path
|
144
145
|
def path
|
145
146
|
@path ||=
|
@@ -170,15 +171,21 @@ class E
|
|
170
171
|
end
|
171
172
|
|
172
173
|
# literals to URIs
|
173
|
-
|
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
|
174
176
|
def E.literal o
|
175
177
|
E['/'].literal o
|
176
178
|
end
|
179
|
+
|
180
|
+
Literal={}
|
181
|
+
[Purl+'dc/elements/1.1/date',
|
182
|
+
Date,DC+'created',DC+'modified',
|
183
|
+
].map{|f|Literal[f]=true}
|
177
184
|
|
178
185
|
def literal o
|
179
186
|
|
180
187
|
# already a URI
|
181
|
-
return
|
188
|
+
return o if o.class == E
|
182
189
|
|
183
190
|
# blob for non-strings
|
184
191
|
return literalBlob o unless o.class == String
|
@@ -196,7 +203,7 @@ class E
|
|
196
203
|
|
197
204
|
# pathname for short literals
|
198
205
|
def literalURI o
|
199
|
-
E "/l/"+
|
206
|
+
E "/l/"+o.gsub(/[\.:\-T+]/,'/')+'/'+o if Literal[uri] && o
|
200
207
|
end
|
201
208
|
|
202
209
|
def literalBlobURI o
|
@@ -225,13 +232,16 @@ class E
|
|
225
232
|
{'uri' => uri}
|
226
233
|
end
|
227
234
|
|
235
|
+
# implementation-specific internal pathnames not on the web
|
236
|
+
F['/E/GET'] = F[E404]
|
237
|
+
|
228
238
|
end
|
229
239
|
|
230
240
|
class Hash
|
231
241
|
def uri
|
232
|
-
self["uri"]
|
242
|
+
self["uri"]||""
|
233
243
|
end
|
234
|
-
|
244
|
+
alias_method :url, :uri
|
235
245
|
def label
|
236
246
|
self[E::Label] || uri.label
|
237
247
|
end
|
@@ -253,18 +263,25 @@ class String
|
|
253
263
|
self[4..-1]
|
254
264
|
end
|
255
265
|
|
256
|
-
# expand qname-style identifier to URI
|
266
|
+
# expand qname/CURIE-style identifier to URI
|
257
267
|
Expand={}
|
258
268
|
def expand
|
259
|
-
# memoize lookups
|
260
269
|
(Expand.has_key? self) ?
|
261
270
|
Expand[self] :
|
262
271
|
(Expand[self] =
|
263
272
|
match(/([^:]+):([^\/].*)/).do{|e|
|
264
|
-
|
273
|
+
( E::Prefix[e[1]] || e[1]+':' )+e[2]} ||
|
265
274
|
self )
|
266
275
|
end
|
267
276
|
|
277
|
+
# shrink URI to qname/CURIE/prefix'd identifier
|
278
|
+
def shorten
|
279
|
+
E::Prefix.map{|p,f|
|
280
|
+
return p + ':' + self[f.size..-1] if (index f) == 0
|
281
|
+
}
|
282
|
+
self
|
283
|
+
end
|
284
|
+
|
268
285
|
def sh
|
269
286
|
Shellwords.escape self
|
270
287
|
end
|
@@ -277,29 +294,33 @@ class String
|
|
277
294
|
# path -> URI || literal
|
278
295
|
def unpath
|
279
296
|
|
280
|
-
# URI
|
297
|
+
# HTTP URI
|
281
298
|
if m = (match /^\/([a-z]+:)\/+(.*)/)
|
282
299
|
(m[1] + '//' + m[2]).E
|
283
300
|
|
284
|
-
#
|
301
|
+
# CURIE
|
302
|
+
elsif m = (match /^\/([^\/:]+:[^\/]+)/)
|
303
|
+
m[1].expand.E
|
304
|
+
|
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
|
+
# String literal
|
285
312
|
elsif match /^\/E\/blob/
|
286
313
|
self.E.r
|
287
314
|
|
288
|
-
# JSON literal
|
315
|
+
# JSON literal
|
289
316
|
elsif match /^\/E\/json/
|
290
317
|
self.E.r true
|
291
318
|
|
292
|
-
#
|
319
|
+
# literal in basename
|
293
320
|
elsif match /^\/l\//
|
294
321
|
File.basename self
|
295
322
|
|
296
|
-
#
|
297
|
-
elsif match /^\/E\/..\//
|
298
|
-
self[9..-1].match(/([^.]+)(.*)/).do{|c|
|
299
|
-
(Base64.urlsafe_decode64 c[1]) + c[2]
|
300
|
-
}.E
|
301
|
-
|
302
|
-
# path
|
323
|
+
# plain path
|
303
324
|
else
|
304
325
|
self.E
|
305
326
|
end
|