infod 0.0.3.2 → 0.0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/infod +1 -1
- data/infod.rb +14 -9
- data/infod/404.rb +19 -6
- data/infod/500.rb +2 -2
- data/infod/GET.rb +18 -16
- data/infod/HTTP.rb +5 -7
- data/infod/POST.rb +27 -20
- data/infod/audio.rb +1 -1
- data/infod/blog.rb +23 -6
- data/infod/cal.rb +2 -2
- data/infod/code.rb +2 -2
- data/infod/constants.rb +5 -3
- data/infod/csv.rb +5 -5
- data/infod/edit.rb +24 -28
- data/infod/facets.rb +4 -4
- data/infod/feed.rb +12 -12
- data/infod/forum.rb +1 -1
- data/infod/fs.rb +57 -109
- data/infod/graph.rb +37 -17
- data/infod/grep.rb +4 -4
- data/infod/groonga.rb +14 -14
- data/infod/histogram.rb +5 -5
- data/infod/html.rb +41 -38
- data/infod/image.rb +7 -9
- data/infod/index.rb +13 -43
- data/infod/infod.rb +14 -9
- data/infod/lambda.rb +32 -20
- data/infod/ls.rb +32 -9
- data/infod/mail.rb +104 -94
- data/infod/man.rb +6 -6
- data/infod/microblog.rb +12 -12
- data/infod/mime.rb +8 -15
- data/infod/names.rb +89 -235
- data/infod/rdf.rb +9 -15
- data/infod/schema.rb +17 -17
- data/infod/text.rb +58 -15
- data/infod/threads.rb +12 -9
- data/infod/time.rb +5 -6
- metadata +41 -59
- data/infod/HEAD.rb +0 -23
- data/infod/find.rb +0 -19
- data/infod/glob.rb +0 -25
- data/infod/kv.rb +0 -56
- data/infod/page.rb +0 -19
- data/infod/postscript.rb +0 -26
- data/infod/ruby.rb +0 -57
- data/infod/sh.rb +0 -19
- data/infod/webid.rb +0 -0
- data/infod/wiki.rb +0 -18
data/infod/facets.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#watch __FILE__
|
2
|
-
class
|
2
|
+
class R
|
3
3
|
=begin
|
4
4
|
faceted-filter, implemented via dynamically-generated style-sheets
|
5
5
|
|
@@ -58,11 +58,11 @@ class E
|
|
58
58
|
|
59
59
|
fn 'view/facetSelect',->m,e{
|
60
60
|
[(H.js '/js/facets.select'),(H.js '/js/mu'),(H.css '/css/facets'),
|
61
|
-
|
61
|
+
R.graphProperties(m).map{|e|[{c: e},' ']},
|
62
62
|
{_: 'button', c: 'Go'}]}
|
63
63
|
|
64
64
|
fn 'view/facets',->m,e{
|
65
|
-
e.q['a'].do{|a|
|
66
|
-
|
65
|
+
e.q['a'].do{|a|F['facets'][a,m,e]} ||
|
66
|
+
F['view/facetSelect'][m,e]}
|
67
67
|
|
68
68
|
end
|
data/infod/feed.rb
CHANGED
@@ -34,20 +34,20 @@ module FeedParse
|
|
34
34
|
puts "no HTTP URIs found #{u}"
|
35
35
|
u = '/junk/'+u.gsub('/','.')
|
36
36
|
end
|
37
|
-
yield u,
|
38
|
-
yield u,
|
37
|
+
yield u, R::Type, (R::SIOCt+'BlogPost').R
|
38
|
+
yield u, R::Type, (R::SIOC+'Post').R
|
39
39
|
|
40
40
|
#links
|
41
41
|
inner.scan(%r{<(link|enclosure|media)([^>]+)>}mi){|e|
|
42
42
|
e[1].match(/(href|url|src)=['"]?([^'">\s]+)/).do{|url|
|
43
|
-
yield(u,
|
44
|
-
|
43
|
+
yield(u,R::Atom+'/link/'+((r=e[1].match(/rel=['"]?([^'">\s]+)/)) ? r[1] : e[0]), url[2].R)}}
|
44
|
+
|
45
45
|
#elements
|
46
46
|
inner.scan(%r{<([a-z]+:)?([a-z]+)([\s][^>]*)?>(.*?)</\1?\2>}mi){|e|
|
47
47
|
yield u, # s
|
48
|
-
(x[e[0]&&e[0].chop]||
|
48
|
+
(x[e[0]&&e[0].chop]||R::RSS)+e[1], # p
|
49
49
|
e[3].extend(FeedParse).guess.do{|o|# o
|
50
|
-
o.match(/\A(\/|http)[\S]+\Z/) ? o.
|
50
|
+
o.match(/\A(\/|http)[\S]+\Z/) ? o.R : R::F['cleanHTML'][o]
|
51
51
|
}}
|
52
52
|
else
|
53
53
|
puts "no post-identifiers found #{u}"
|
@@ -58,19 +58,19 @@ module FeedParse
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
class
|
61
|
+
class R
|
62
62
|
|
63
63
|
Atom = W3+'2005/Atom'
|
64
64
|
RSS = Purl+'rss/1.0/'
|
65
65
|
RSSm = RSS+'modules/'
|
66
|
-
Feed = (
|
66
|
+
Feed = (R RSS+'channel')
|
67
67
|
|
68
|
-
def listFeeds; (nokogiri.css 'link[rel=alternate]').map{|u|
|
68
|
+
def listFeeds; (nokogiri.css 'link[rel=alternate]').map{|u|R (URI uri).merge(u.attr :href)} end
|
69
69
|
alias_method :feeds, :listFeeds
|
70
70
|
|
71
71
|
# add existing resources to index
|
72
72
|
#
|
73
|
-
# 'http:/'.
|
73
|
+
# 'http:/'.R.take.select{|e|e.ext=='e'}.map{|r|R::FeedArchiver[r,r.graph,'localhost']}
|
74
74
|
|
75
75
|
FeedArchiver = -> doc, graph, host {
|
76
76
|
doc.roonga host
|
@@ -79,7 +79,7 @@ class E
|
|
79
79
|
t = t[0].gsub(/[-T]/,'/').sub /(.00.00|Z)$/, '' # trim normalized timezones and non-unique symbols
|
80
80
|
stop = /\b(at|blog|com(ments)?|html|info|org|photo|p|post|r|status|tag|twitter|wordpress|www|1999|2005)\b/
|
81
81
|
b = (u.sub(/http:\/\//,'.').gsub(/\W/,'..').gsub(stop,'').sub(/\d{12,}/,'')+'.').gsub /\.+/,'.'
|
82
|
-
doc.ln
|
82
|
+
doc.ln R["http://#{host}/news/#{t}#{b}e"]}}
|
83
83
|
doc}
|
84
84
|
|
85
85
|
GREP_DIRS.push /^\/news\/\d{4}/
|
@@ -97,7 +97,7 @@ class E
|
|
97
97
|
Nokogiri::HTML.parse(o).do{|o|
|
98
98
|
o.css('.md').do{|o|yield s,p,o}
|
99
99
|
yield s,Creator,o.css('a')[-4].child.to_s.strip
|
100
|
-
yield s,Type,(SIOCt+'BoardPost').
|
100
|
+
yield s,Type,(SIOCt+'BoardPost').R
|
101
101
|
} : (yield s,p,o)}
|
102
102
|
end
|
103
103
|
|
data/infod/forum.rb
CHANGED
data/infod/fs.rb
CHANGED
@@ -1,119 +1,83 @@
|
|
1
1
|
#watch __FILE__
|
2
|
+
class R
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def node
|
12
|
-
Pathname.new FSbase + path
|
13
|
-
end
|
14
|
-
alias_method :no, :node
|
15
|
-
|
16
|
-
def inside
|
17
|
-
node.expand_path.to_s.index(FSbase) == 0
|
18
|
-
end
|
19
|
-
|
20
|
-
def siblings
|
21
|
-
parent.c
|
22
|
-
end
|
23
|
-
|
24
|
-
def children
|
25
|
-
node.c.map &:E
|
26
|
-
end
|
27
|
-
alias_method :c, :children
|
28
|
-
|
29
|
-
|
30
|
-
# node exists?
|
31
|
-
def exist?
|
32
|
-
node.exist?
|
33
|
-
end
|
34
|
-
alias_method :e, :exist?
|
35
|
-
|
36
|
-
# directory?
|
37
|
-
def d?
|
38
|
-
node.directory?
|
4
|
+
def [] p; predicate p end
|
5
|
+
def []= p,o
|
6
|
+
if o
|
7
|
+
setFs p,o
|
8
|
+
else
|
9
|
+
(predicate p).map{|o|
|
10
|
+
unsetFs p,o}
|
11
|
+
end
|
39
12
|
end
|
40
13
|
|
41
|
-
|
42
|
-
|
43
|
-
node.
|
14
|
+
def predicate p, short = true
|
15
|
+
p = predicatePath p, short
|
16
|
+
p.node.take.map{|n|
|
17
|
+
if n.file? # literal
|
18
|
+
o = n.R
|
19
|
+
case o.ext
|
20
|
+
when "json"
|
21
|
+
o.r true
|
22
|
+
else
|
23
|
+
o.r
|
24
|
+
end
|
25
|
+
else # resource
|
26
|
+
R[n.to_s.unpath p.d.size]
|
27
|
+
end}
|
28
|
+
end
|
29
|
+
|
30
|
+
def setFs p, o, undo = false, short = true
|
31
|
+
p = predicatePath p, short # s+p URI
|
32
|
+
t,literal = p.objectPath o # s+p+o URI
|
33
|
+
puts "#{undo ? :- : :+} <#{t}>"
|
34
|
+
if o.class == R # resource
|
35
|
+
if undo
|
36
|
+
t.delete if t.e # undo
|
37
|
+
else
|
38
|
+
unless t.e
|
39
|
+
if o.f # file?
|
40
|
+
o.ln t # link
|
41
|
+
else
|
42
|
+
t.mk # dirent
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else # literal
|
47
|
+
if undo
|
48
|
+
t.delete if t.e # remove
|
49
|
+
else
|
50
|
+
t.w literal unless t.e # write
|
51
|
+
end
|
52
|
+
end
|
44
53
|
end
|
45
|
-
alias_method :f, :file?
|
46
54
|
|
47
|
-
|
48
|
-
def mtime
|
49
|
-
node.stat.mtime if e
|
50
|
-
end
|
51
|
-
alias_method :m, :mtime
|
55
|
+
def unsetFs p,o; setFs p,o,true end
|
52
56
|
|
53
57
|
def triplrInode
|
54
58
|
if d?
|
55
59
|
yield uri, Posix+'dir#parent', parent
|
56
|
-
c.map{|c| yield uri, Posix + 'dir#child',
|
60
|
+
c.map{|c| yield uri, Posix + 'dir#child', R[c.uri.gsub('?','%3F').gsub('#','23')]}
|
57
61
|
end
|
58
62
|
node.stat.do{|s|[:size,:ftype,:mtime].map{|p| yield uri, Stat+p.to_s, (s.send p)}}
|
59
63
|
end
|
60
64
|
|
61
65
|
def triplrSymlink
|
62
66
|
realpath.do{|t|
|
63
|
-
target = t.to_s.index(FSbase)==0 ? t.
|
67
|
+
target = t.to_s.index(FSbase)==0 ? t.R : t.to_s
|
64
68
|
yield uri, '/linkTarget', target }
|
65
69
|
end
|
66
|
-
|
67
|
-
def realpath
|
68
|
-
node.realpath
|
69
|
-
rescue Errno::ENOENT
|
70
|
-
nil
|
71
|
-
end
|
72
|
-
|
73
|
-
def mk
|
74
|
-
e || FileUtils.mkdir_p(d)
|
75
|
-
self
|
76
|
-
end
|
77
70
|
|
78
|
-
|
79
|
-
|
80
|
-
t = t.
|
71
|
+
def ln t, y=:link
|
72
|
+
t = t.R
|
73
|
+
t = t.uri[0..-2].R if t.uri[-1] == '/'
|
81
74
|
if !t.e # destination exist?
|
82
75
|
t.dirname.mk
|
83
|
-
FileUtils.
|
76
|
+
FileUtils.send y, node, t.node
|
84
77
|
end
|
85
78
|
end
|
86
79
|
|
87
|
-
|
88
|
-
def ln_s t
|
89
|
-
t = t.E # cast bare URI/string to resource
|
90
|
-
if !t.e # destination exist?
|
91
|
-
t.dirname.mk
|
92
|
-
FileUtils.symlink node, t.node
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def touch
|
97
|
-
FileUtils.touch node
|
98
|
-
self
|
99
|
-
end
|
100
|
-
|
101
|
-
def deleteNode
|
102
|
-
node.deleteNode if e
|
103
|
-
self
|
104
|
-
end
|
105
|
-
|
106
|
-
def size
|
107
|
-
node.size
|
108
|
-
end
|
109
|
-
|
110
|
-
def read
|
111
|
-
f ? r : get
|
112
|
-
end
|
113
|
-
|
114
|
-
def get
|
115
|
-
(open uri).read
|
116
|
-
end
|
80
|
+
def ln_s t; ln t, :symlink end
|
117
81
|
|
118
82
|
def r p=false
|
119
83
|
if f
|
@@ -131,21 +95,11 @@ class E
|
|
131
95
|
self
|
132
96
|
end
|
133
97
|
|
134
|
-
def writeFile c
|
135
|
-
File.open(d,'w'){|f|f << c}
|
136
|
-
end
|
137
|
-
|
138
|
-
def readFile
|
139
|
-
File.open(d).read
|
140
|
-
end
|
141
|
-
|
142
98
|
end
|
143
99
|
|
144
100
|
class Pathname
|
145
101
|
|
146
|
-
def
|
147
|
-
to_s.force_encoding('UTF-8').unpathFs
|
148
|
-
end
|
102
|
+
def R; to_s.force_encoding('UTF-8').unpath end
|
149
103
|
|
150
104
|
def c
|
151
105
|
return [] unless directory?
|
@@ -160,9 +114,3 @@ class Pathname
|
|
160
114
|
end
|
161
115
|
|
162
116
|
end
|
163
|
-
|
164
|
-
class File::Stat
|
165
|
-
def utime
|
166
|
-
mtime.to_i
|
167
|
-
end
|
168
|
-
end
|
data/infod/graph.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
#watch __FILE__
|
2
|
-
class
|
2
|
+
class R
|
3
3
|
=begin
|
4
4
|
graph construction is two-pass:
|
5
5
|
|
6
|
-
the first-pass will signify if the second-pass needs to be run. an
|
6
|
+
the first-pass will signify if the second-pass needs to be run. an ETag is be derived from the return-value, ideal fingerprint sources include filestats, mtime checks, extremely trivial SPARQL queries, SHA160 hashes of in-RAM entities.. <http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-25#section-2.3>
|
7
7
|
|
8
|
-
second-pass might fetch RDF from a SPARQL store. this lib was developed as an alternative to relying on (large, hard-to-implement, must be running, configured & connectable) SPARQL stores by using the filesystem as much as possible, to experiment with hybrids like SPARQLING up a set of files to be returned in standard Apache-as-static-fileserver fashion, and to webize
|
8
|
+
second-pass might fetch RDF from a SPARQL store. this lib was developed as an alternative to relying on (large, hard-to-implement, must be running, configured & connectable) SPARQL stores by using the filesystem as much as possible, to experiment with hybrids like SPARQLING up a set of files to be returned in standard Apache-as-static-fileserver fashion, and to webize non-RDF filesystem-content like email, directories, URLs in plain-text etc
|
9
9
|
|
10
10
|
triple streams - a source function yields triples up to the caller as it finds them,
|
11
|
-
a function providing
|
12
|
-
these can be stacked into pipelines. see the data-massaging stream-
|
11
|
+
a function providing a block (consumes yielded values) is a sink, both is a filter
|
12
|
+
these can be stacked into pipelines. see the data-massaging stream-processing in feed.rb
|
13
13
|
|
14
14
|
=end
|
15
15
|
|
@@ -31,7 +31,7 @@ class E
|
|
31
31
|
graph = fromStream({},triplr)
|
32
32
|
docs = {}
|
33
33
|
graph.map{|u,r|
|
34
|
-
e = u.
|
34
|
+
e = u.R # resource
|
35
35
|
doc = e.ef # doc
|
36
36
|
doc.e || # exists - we're nondestructive here
|
37
37
|
(docs[doc.uri] ||= {} # init doc-graph
|
@@ -40,7 +40,7 @@ class E
|
|
40
40
|
r[p].do{|v|v.map{|o| # values exist?
|
41
41
|
e.index p,o}}})} # index triple
|
42
42
|
docs.map{|d,g| # resources in docs
|
43
|
-
d = d.
|
43
|
+
d = d.R; puts "<#{d.docBase}>"
|
44
44
|
d.w g,true # write
|
45
45
|
hook[d,g,host] if hook} # insert-hook
|
46
46
|
graph.triples &b if b # emit triples
|
@@ -56,7 +56,7 @@ class E
|
|
56
56
|
g.delete '#'
|
57
57
|
else
|
58
58
|
g['#'][RDFs+'member'] = set
|
59
|
-
g['#'][Type] =
|
59
|
+
g['#'][Type] = R[HTTP+'Response']
|
60
60
|
set.map{|u| g[u.uri] = u } # thunk
|
61
61
|
end
|
62
62
|
F['docsID'][g,q]}
|
@@ -71,8 +71,8 @@ class E
|
|
71
71
|
t = ::Date.parse "#{m[2]}-#{m[3]}-#{m[4]}"
|
72
72
|
pp = m[1] + (t-1).strftime('%Y/%m/%d') + m[5]
|
73
73
|
np = m[1] + (t+1).strftime('%Y/%m/%d') + m[5]
|
74
|
-
u[Prev] = {'uri' => pp} if pp.
|
75
|
-
u[Next] = {'uri' => np} if np.
|
74
|
+
u[Prev] = {'uri' => pp} if pp.R.e || R['http://' + e.env['SERVER_NAME'] + pp].e
|
75
|
+
u[Next] = {'uri' => np} if np.R.e || R['http://' + e.env['SERVER_NAME'] + np].e }
|
76
76
|
s }
|
77
77
|
|
78
78
|
# fs-derived ID for a resource-set
|
@@ -86,30 +86,44 @@ class E
|
|
86
86
|
# update configuration such as q['graph'] = 'hexastore' and return false or call #response..
|
87
87
|
fn 'graph/',->e,q,m{
|
88
88
|
# force thunks
|
89
|
-
m.values.map{|r|(r.env e.env).graphFromFile m if r.class ==
|
89
|
+
m.values.map{|r|(r.env e.env).graphFromFile m if r.class == R }
|
90
90
|
# cleanup unexpanded thunks
|
91
|
-
m.delete_if{|u,r|r.class==
|
91
|
+
m.delete_if{|u,r|r.class==R}}
|
92
92
|
|
93
93
|
def graphFromFile g={}
|
94
94
|
return unless e
|
95
95
|
doc = self
|
96
96
|
unless ext=='e' # already native-format
|
97
|
-
|
98
|
-
doc
|
99
|
-
unless doc.e && doc.m > m; # freshness check
|
97
|
+
doc = R '/cache/RDF/' + uri.h.dive
|
98
|
+
unless doc.e && doc.m > m # up-to-date?
|
100
99
|
graph = {}
|
101
|
-
[:triplrInode
|
100
|
+
[:triplrInode,:triplrMIME].map{|t| fromStream graph, t}
|
102
101
|
doc.w graph, true
|
103
102
|
end
|
104
103
|
end
|
105
104
|
g.mergeGraph doc.r true
|
106
105
|
end
|
107
106
|
|
107
|
+
def ef; @ef ||= docBase.a('.e') end
|
108
|
+
|
108
109
|
def graph g={}
|
109
110
|
docs.map{|d|d.graphFromFile g} # tripleStream -> graph
|
110
111
|
g
|
111
112
|
end
|
112
113
|
|
114
|
+
def docs
|
115
|
+
base = docBase
|
116
|
+
[(base if pathSegment!='/' && base.e), # doc-base
|
117
|
+
(self if base != self && e && uri[-1]!='/'), # requested path
|
118
|
+
base.glob(".{e,html,n3,nt,owl,rdf,ttl,txt}"), # docs
|
119
|
+
((d? && uri[-1]=='/' && uri.size>1) ? c : []) # trailing slash -> child resources
|
120
|
+
].flatten.compact
|
121
|
+
end
|
122
|
+
|
123
|
+
def triplrDoc &f; docBase.glob('#*').map{|s| s.triplrResource &f} end
|
124
|
+
|
125
|
+
def triplrResource; predicates.map{|p| self[p].map{|o| yield uri, p.uri, o}} end
|
126
|
+
|
113
127
|
def triplrJSON
|
114
128
|
yield uri, '/application/json', (JSON.parse read) if e
|
115
129
|
rescue Exception => e
|
@@ -119,12 +133,18 @@ class E
|
|
119
133
|
to_h.to_json *a
|
120
134
|
end
|
121
135
|
|
122
|
-
fn Render+'application/json',->d,_=nil{
|
136
|
+
fn Render+'application/json',->d,_=nil{d.to_json}
|
123
137
|
|
124
138
|
end
|
125
139
|
|
126
140
|
class Hash
|
127
141
|
|
142
|
+
def except *ks
|
143
|
+
clone.do{|h|
|
144
|
+
ks.map{|k|h.delete k}
|
145
|
+
h}
|
146
|
+
end
|
147
|
+
|
128
148
|
def graph g
|
129
149
|
g.merge!({uri=>self})
|
130
150
|
end
|
data/infod/grep.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
#watch __FILE__
|
2
|
-
class
|
2
|
+
class R
|
3
3
|
|
4
4
|
fn 'view/'+Posix+'util#grep',-> d,e {{_: :form, c: [{_: :input, name: :q, style: 'font-size:2em'},{_: :input, type: :hidden, name: :set, value: :grep}]}}
|
5
5
|
|
6
6
|
GREP_DIRS=[]
|
7
7
|
|
8
8
|
fn 'set/grep',->e,q,m{
|
9
|
-
q['q'].do{|query| m[e.uri+'#grep'] = {Type =>
|
9
|
+
q['q'].do{|query| m[e.uri+'#grep'] = {Type => R[Posix+'util#grep']}
|
10
10
|
path = e.pathSegment
|
11
11
|
GREP_DIRS.find{|p|path.uri.match p}.do{|allow|
|
12
12
|
[e,path].compact.select(&:e).map{|e|
|
13
|
-
`grep -irl #{query.sh} #{e.sh} | head -n 200`}.map{|r|r.lines.to_a.map{|r|r.chomp.
|
13
|
+
`grep -irl #{query.sh} #{e.sh} | head -n 200`}.map{|r|r.lines.to_a.map{|r|r.chomp.unpath}}.flatten
|
14
14
|
}||(puts "no grep available on #{path}")}}
|
15
15
|
|
16
16
|
fn 'view/grep',->d,e{
|
@@ -52,7 +52,7 @@ class E
|
|
52
52
|
# match?
|
53
53
|
!g.empty? &&
|
54
54
|
[# link to resource
|
55
|
-
r.
|
55
|
+
r.R.do{|e|{_: :a, href: e.url, c: e}}, '<br>',
|
56
56
|
# show 3 matches per resource
|
57
57
|
[g[-1*(g.size.max 3)..-1].map{|l|
|
58
58
|
# exerpt
|