infod 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/infod.rb +52 -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 +123 -0
- data/infod/{Es/grep.rb → grep.rb} +2 -2
- data/infod/{Es/groonga.rb → groonga.rb} +41 -33
- 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} +38 -25
- data/infod/infod.rb +52 -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 +90 -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} +78 -45
- 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} +22 -7
- 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} +17 -27
- data/infod/{H/time.rb → time.rb} +14 -34
- data/infod/{H/who.rb → whois.rb} +6 -4
- data/infod/{H/wiki.rb → wiki.rb} +0 -0
- metadata +54 -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/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,90 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
class E
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'tmail'
|
6
|
+
rescue LoadError => e
|
7
|
+
end
|
8
|
+
|
9
|
+
def triplrTmail &f
|
10
|
+
messagePath = ->id{
|
11
|
+
h = id.h # hash
|
12
|
+
'/msg/' + h[0..1] + '/' + h[2] + '/' + id}
|
13
|
+
|
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
|
+
yield e, DC+'identifier', id # original ID
|
19
|
+
yield e, DC+'source', self # original file
|
20
|
+
yield e, Type, E[SIOCt + 'MailMessage']
|
21
|
+
yield e, Type, E[SIOC + 'Post']
|
22
|
+
yield e, Date, m.date.iso8601 if m.date
|
23
|
+
yield e, Title, m.subject.to_utf8
|
24
|
+
yield e, SIOC+'name', m.friendly_from.to_utf8
|
25
|
+
yield e, Creator, E['/m/'+m.from[0].to_utf8]
|
26
|
+
m.header['x-original-to'].do{|f|
|
27
|
+
yield e, SIOC+'reply_to', E[URI.escape "mailto:#{f}?References=<#{e}>&In-Reply-To=<#{e}>&Subject=#{m.subject.to_utf8}"] }
|
28
|
+
%w{to cc bcc}.map{|to|
|
29
|
+
m.send(to).do{|to| to.map{|to|
|
30
|
+
yield e, To, E['/m/'+to.to_utf8]}}}
|
31
|
+
%w{in_reply_to references}.map{|ref|
|
32
|
+
m.send(ref).do{|refs| refs.map{|r|
|
33
|
+
yield e, SIOC+'reply_of', E[messagePath[r[1..-2]]]}}}
|
34
|
+
# minimal local markup to use as HTML-literal even if decoupled from specialized view
|
35
|
+
yield e, Content, H([{_: :pre, class: :mail, style: 'white-space: pre-wrap',
|
36
|
+
c: m.concat_message(e.E,0,&f).gsub(/^\s*(>)(>|\s)*\n/,"").lines.to_a.map{|l| # < skip quoted emptylines v tag quoted lines
|
37
|
+
{_: :span, class: ((l.match /(^\s*(>|On[^\n]+(said|wrote))[^\n]*)\n/) ? 'q' : 'u'), c: [ l.chomp, "\n" ]}}},
|
38
|
+
{_: :style, c: "pre.mail .q {background-color:#0018ff;color:#fff}\npre.mail a {background-color: #91acb3;color:#fff}\npre.mail img {max-width:100%}"}])}
|
39
|
+
rescue Exception => e
|
40
|
+
puts e
|
41
|
+
end
|
42
|
+
|
43
|
+
def triplrMailMessage &f
|
44
|
+
insertDocs :triplrTmail, nil, [To,SIOC+'reply_of'], &f
|
45
|
+
end
|
46
|
+
=begin
|
47
|
+
there's another mail library called Mail, as of v2.5.4 takes 50x as long as tmail (apt-get install ruby-tmail)
|
48
|
+
HEAD 200 http://m/m/2013/12/01/?nocache=&triplr=triplrMail curl/7.33.0 5.4003388
|
49
|
+
HEAD 200 http://m/m/2013/12/01/?nocache=&triplr=triplrTmail curl/7.33.0 0.1198720
|
50
|
+
|
51
|
+
almost a copy of above works but identifiers are not wrapped in <> - with caching it might be fast enough..
|
52
|
+
|
53
|
+
=end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
module TMail
|
58
|
+
class Mail
|
59
|
+
def unicode_body
|
60
|
+
unquoted_body.to_utf8
|
61
|
+
end
|
62
|
+
def concat_message i, partCount=0, &f
|
63
|
+
if multipart?
|
64
|
+
parts.map{|part|
|
65
|
+
if part.multipart? # and even more nested parts..
|
66
|
+
part.concat_message i, partCount, &f
|
67
|
+
elsif !attachment?(part) && part.sub_type != 'html'
|
68
|
+
part.unicode_body.hrefs true
|
69
|
+
else # attachment
|
70
|
+
a = i.a('.attache').mk # create container
|
71
|
+
p = a.as(part['content-type']['name'] || (partCount.to_s + '.' + (E::MIME.invert[part.content_type] || '.bin').to_s))
|
72
|
+
p.w part.body if !p.e # write attachment into message container
|
73
|
+
partCount += 1 # display images
|
74
|
+
yield i.uri, E::SIOC+'attachment', p
|
75
|
+
'<a href="'+p.uri+'">'+(part.main_type=='image' ? '<img src="'+p.uri+'">' : '')+p.uri.label+"</a><br>\n"
|
76
|
+
end
|
77
|
+
}.join
|
78
|
+
else # just a part
|
79
|
+
unicode_body.do{|b|
|
80
|
+
if content_type && content_type.match(/html/)
|
81
|
+
(b.split /<body[^>]*>/)[-1].split(/<\/body>/)[0]
|
82
|
+
else
|
83
|
+
b.hrefs true
|
84
|
+
end}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
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,11 +31,10 @@ 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 }
|
34
|
+
!uri.empty? && uri.split(/#/)[0].do{|u|u.E.do{|d| d.dirname.as d.bare }} || E['']
|
44
35
|
end
|
45
36
|
|
46
|
-
#
|
37
|
+
# and w/ URI-lib
|
47
38
|
def docBaseURI
|
48
39
|
u = URI uri
|
49
40
|
s = u.scheme
|
@@ -79,22 +70,27 @@ class E
|
|
79
70
|
end
|
80
71
|
alias_method :dir, :dirname
|
81
72
|
|
82
|
-
#
|
83
|
-
def
|
84
|
-
|
73
|
+
# add hostname to URI if missing
|
74
|
+
def hostURL e
|
75
|
+
host = 'http://'+e['SERVER_NAME']
|
76
|
+
if uri.index('/') == 0
|
77
|
+
host + uri
|
78
|
+
else
|
79
|
+
uri
|
80
|
+
end
|
85
81
|
end
|
86
82
|
|
87
|
-
# local
|
83
|
+
# locator for local data about global URI
|
88
84
|
def localURL e
|
89
85
|
# path
|
90
|
-
if uri.index('/') == 0
|
86
|
+
if uri.index('/') == 0 # already a local path
|
91
87
|
uri
|
92
88
|
# host match
|
93
|
-
elsif uri.index('http://'+e['SERVER_NAME']+'/') == 0
|
89
|
+
elsif e && uri.index('http://'+e['SERVER_NAME']+'/') == 0
|
94
90
|
pathSegment.uri
|
95
91
|
# non-local
|
96
92
|
else
|
97
|
-
|
93
|
+
URIURL + (CGI.escape uri)
|
98
94
|
end
|
99
95
|
end
|
100
96
|
|
@@ -116,6 +112,10 @@ class E
|
|
116
112
|
uri.expand.E
|
117
113
|
end
|
118
114
|
|
115
|
+
def shorten
|
116
|
+
uri.shorten.E
|
117
|
+
end
|
118
|
+
|
119
119
|
def prependURI u
|
120
120
|
E u.to_s + uri
|
121
121
|
end
|
@@ -129,7 +129,7 @@ class E
|
|
129
129
|
end
|
130
130
|
|
131
131
|
def concatURI b
|
132
|
-
u.appendURI b.E.
|
132
|
+
u.appendURI b.E.shortPath
|
133
133
|
end
|
134
134
|
|
135
135
|
alias_method :a, :appendURI
|
@@ -140,6 +140,19 @@ class E
|
|
140
140
|
uri.path?
|
141
141
|
end
|
142
142
|
|
143
|
+
def shortPath
|
144
|
+
@shortPath ||=
|
145
|
+
(if path?
|
146
|
+
if uri.match /^\//
|
147
|
+
uri
|
148
|
+
else
|
149
|
+
'/' + uri.shorten
|
150
|
+
end
|
151
|
+
else
|
152
|
+
'/E/' + uri.h.dive[0..5] + (Base64.urlsafe_encode64 uri)
|
153
|
+
end)
|
154
|
+
end
|
155
|
+
|
143
156
|
# URI -> path
|
144
157
|
def path
|
145
158
|
@path ||=
|
@@ -170,15 +183,21 @@ class E
|
|
170
183
|
end
|
171
184
|
|
172
185
|
# literals to URIs
|
173
|
-
|
186
|
+
# currently used for iso8601 dates mapping to paths, so date-range queries can be done w/ just dir/fs tooling
|
187
|
+
# could also use as a "trie" for autocomplete or sorting strings
|
174
188
|
def E.literal o
|
175
189
|
E['/'].literal o
|
176
190
|
end
|
191
|
+
|
192
|
+
Literal={}
|
193
|
+
[Purl+'dc/elements/1.1/date',
|
194
|
+
Date,DC+'created',DC+'modified',
|
195
|
+
].map{|f|Literal[f]=true}
|
177
196
|
|
178
197
|
def literal o
|
179
198
|
|
180
199
|
# already a URI
|
181
|
-
return
|
200
|
+
return o if o.class == E
|
182
201
|
|
183
202
|
# blob for non-strings
|
184
203
|
return literalBlob o unless o.class == String
|
@@ -196,7 +215,7 @@ class E
|
|
196
215
|
|
197
216
|
# pathname for short literals
|
198
217
|
def literalURI o
|
199
|
-
E "/l/"+
|
218
|
+
E "/l/"+o.gsub(/[\.:\-T+]/,'/')+'/'+o if Literal[uri] && o
|
200
219
|
end
|
201
220
|
|
202
221
|
def literalBlobURI o
|
@@ -225,13 +244,16 @@ class E
|
|
225
244
|
{'uri' => uri}
|
226
245
|
end
|
227
246
|
|
247
|
+
# implementation-specific internal pathnames not on the web
|
248
|
+
F['/E/GET'] = F[E404]
|
249
|
+
|
228
250
|
end
|
229
251
|
|
230
252
|
class Hash
|
231
253
|
def uri
|
232
|
-
self["uri"]
|
254
|
+
self["uri"]||""
|
233
255
|
end
|
234
|
-
|
256
|
+
alias_method :url, :uri
|
235
257
|
def label
|
236
258
|
self[E::Label] || uri.label
|
237
259
|
end
|
@@ -253,18 +275,25 @@ class String
|
|
253
275
|
self[4..-1]
|
254
276
|
end
|
255
277
|
|
256
|
-
# expand qname-style identifier to URI
|
278
|
+
# expand qname/CURIE-style identifier to URI
|
257
279
|
Expand={}
|
258
280
|
def expand
|
259
|
-
# memoize lookups
|
260
281
|
(Expand.has_key? self) ?
|
261
282
|
Expand[self] :
|
262
283
|
(Expand[self] =
|
263
284
|
match(/([^:]+):([^\/].*)/).do{|e|
|
264
|
-
|
285
|
+
( E::Prefix[e[1]] || e[1]+':' )+e[2]} ||
|
265
286
|
self )
|
266
287
|
end
|
267
288
|
|
289
|
+
# shrink URI to qname/CURIE/prefix'd identifier
|
290
|
+
def shorten
|
291
|
+
E::Prefix.map{|p,f|
|
292
|
+
return p + ':' + self[f.size..-1] if (index f) == 0
|
293
|
+
}
|
294
|
+
self
|
295
|
+
end
|
296
|
+
|
268
297
|
def sh
|
269
298
|
Shellwords.escape self
|
270
299
|
end
|
@@ -277,29 +306,33 @@ class String
|
|
277
306
|
# path -> URI || literal
|
278
307
|
def unpath
|
279
308
|
|
280
|
-
# URI
|
309
|
+
# HTTP URI
|
281
310
|
if m = (match /^\/([a-z]+:)\/+(.*)/)
|
282
311
|
(m[1] + '//' + m[2]).E
|
283
312
|
|
284
|
-
#
|
313
|
+
# CURIE
|
314
|
+
elsif m = (match /^\/([^\/:]+:[^\/]+)/)
|
315
|
+
m[1].expand.E
|
316
|
+
|
317
|
+
# opaque URI w/ optional extension
|
318
|
+
elsif match /^\/E\/..\//
|
319
|
+
self[9..-1].match(/([^.]+)(.*)/).do{|c|
|
320
|
+
(Base64.urlsafe_decode64 c[1]) + c[2]
|
321
|
+
}.E
|
322
|
+
|
323
|
+
# String literal
|
285
324
|
elsif match /^\/E\/blob/
|
286
325
|
self.E.r
|
287
326
|
|
288
|
-
# JSON literal
|
327
|
+
# JSON literal
|
289
328
|
elsif match /^\/E\/json/
|
290
329
|
self.E.r true
|
291
330
|
|
292
|
-
#
|
331
|
+
# literal in basename
|
293
332
|
elsif match /^\/l\//
|
294
333
|
File.basename self
|
295
334
|
|
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
|
335
|
+
# plain path
|
303
336
|
else
|
304
337
|
self.E
|
305
338
|
end
|