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.
- data/infod.rb +1 -6
- data/infod/404.rb +3 -4
- data/infod/500.rb +3 -2
- data/infod/GET.rb +23 -14
- data/infod/HEAD.rb +1 -1
- data/infod/HTTP.rb +24 -40
- data/infod/POST.rb +18 -16
- data/infod/audio.rb +12 -4
- data/infod/blog.rb +1 -1
- data/infod/code.rb +2 -2
- data/infod/constants.rb +6 -6
- data/infod/csv.rb +27 -4
- data/infod/edit.rb +58 -42
- data/infod/feed.rb +55 -27
- data/infod/fs.rb +6 -4
- data/infod/glob.rb +3 -4
- data/infod/graph.rb +66 -50
- data/infod/grep.rb +12 -9
- data/infod/groonga.rb +35 -50
- data/infod/html.rb +82 -55
- data/infod/image.rb +1 -1
- data/infod/index.rb +23 -73
- data/infod/infod.rb +1 -6
- data/infod/kv.rb +8 -6
- data/infod/lambda.rb +2 -0
- data/infod/ls.rb +21 -15
- data/infod/mail.rb +36 -27
- data/infod/man.rb +3 -3
- data/infod/microblog.rb +3 -3
- data/infod/mime.rb +1 -0
- data/infod/names.rb +28 -92
- data/infod/page.rb +10 -4
- data/infod/rdf.rb +11 -4
- data/infod/ruby.rb +2 -1
- data/infod/schema.rb +4 -20
- data/infod/sh.rb +3 -5
- data/infod/text.rb +5 -3
- data/infod/threads.rb +12 -13
- data/infod/time.rb +16 -14
- data/infod/webid.rb +0 -0
- metadata +3 -7
- data/infod/PATCH.rb +0 -5
- data/infod/css.rb +0 -21
- data/infod/du.rb +0 -16
- data/infod/json.rb +0 -38
- data/infod/search.rb +0 -16
data/infod/edit.rb
CHANGED
@@ -1,73 +1,89 @@
|
|
1
|
-
|
1
|
+
watch __FILE__
|
2
2
|
class E
|
3
3
|
|
4
4
|
Prototypes = {
|
5
5
|
SIOCt+'MicroblogPost' => [Content],
|
6
|
-
SIOCt+'BlogPost' => [
|
7
|
-
'
|
6
|
+
SIOCt+'BlogPost' => [Title, Content],
|
7
|
+
SIOCt+'WikiArticle' => [Title, Content],
|
8
8
|
}
|
9
9
|
|
10
|
-
|
10
|
+
# 404 -> create resource
|
11
|
+
F['protograph/create'] = -> e,env,g {
|
12
|
+
env['view'] = 'create'
|
13
|
+
F['protograph/blank'][e,env,g]}
|
11
14
|
|
12
|
-
|
13
|
-
e.fromStream g, :triplrFsStore}
|
14
|
-
|
15
|
-
# select a prototype graph
|
16
|
-
# , or go blank
|
15
|
+
# prototype select
|
17
16
|
fn 'view/create',->g,e{
|
18
|
-
[
|
19
|
-
Prototypes.map{|
|
17
|
+
[{_: :style, c: 'a {display:block;font-size:2em}'},{_: :b, c: :type},
|
18
|
+
Prototypes.map{|t,ps|
|
19
|
+
{_: :a, href: e['REQUEST_PATH']+'?graph=edit&prototype='+(CGI.escape t), c: t.label}}]}
|
20
20
|
|
21
|
+
# editable triples
|
22
|
+
F['protograph/edit'] = -> e,env,g {
|
23
|
+
env['view'] ||= 'edit' # use edit-view
|
24
|
+
g[e.uri+'#'] = {} # add current resource
|
25
|
+
rand.to_s.h}
|
26
|
+
|
27
|
+
fn 'graph/edit',->e,env,g{
|
28
|
+
e.fromStream g, :triplrDoc} # add fs-sourced triples
|
29
|
+
|
30
|
+
=begin HTML <form> RDF editor
|
31
|
+
arg
|
32
|
+
prototype - initialize fields for a resource-type
|
33
|
+
predicate - initialize field for a particular predicate
|
34
|
+
=end
|
21
35
|
fn 'view/edit',->g,e{
|
36
|
+
|
37
|
+
# render a triple
|
22
38
|
triple = ->s,p,o{
|
23
39
|
if s && p && o
|
24
40
|
s = s.E
|
25
41
|
p = p.E
|
26
|
-
oE = p.literal o
|
27
|
-
|
28
|
-
[(case p
|
42
|
+
oE = p.literal o # cast literal to URI
|
43
|
+
id = s.concatURI(p).concatURI oE # triple identifier
|
44
|
+
[(case p.uri # more to support here.. http://dev.w3.org/html5/markup/input.html#input
|
29
45
|
when Content
|
30
|
-
{_: :textarea, name: id, c: o, rows:
|
46
|
+
[{_: :textarea, name: id, c: o, rows: 16, cols: 80},
|
47
|
+
'<br>',o]
|
31
48
|
when Date
|
32
49
|
{_: :input, name: id, type: :datetime, value: o.empty? ? Time.now.iso8601 : o}
|
33
50
|
else
|
34
51
|
{_: :input, name: id, value: o, size: 54}
|
35
52
|
end
|
36
|
-
),"<br>\n"]
|
53
|
+
),"<br>\n"]
|
37
54
|
end}
|
38
|
-
|
39
|
-
ps = []
|
40
|
-
e.q['prototype'].do{|pr|
|
41
|
-
|
42
|
-
|
43
|
-
e.q['p'].do{|p| ps.push p }
|
55
|
+
|
56
|
+
ps = [] # predicates to go editable on
|
57
|
+
e.q['prototype'].do{|pr|
|
58
|
+
Prototypes[pr].do{|v|ps.concat v }} # prototype imports
|
59
|
+
e.q['predicate'].do{|p|ps.push p } # explicit predicate
|
44
60
|
|
45
|
-
[
|
61
|
+
[{_: :style, c: ".abbr {display: none}\ntd {vertical-align:top}"},
|
46
62
|
{_: :form, name: :editor, method: :POST, action: e['REQUEST_PATH'],
|
47
63
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
64
|
+
c: [{_: :a, class: :edit, c: '+add field',
|
65
|
+
href: e['uri']+'?graph=blank&view=addP', style: 'background-color:#0f0;border-radius:5em;color:#000;padding:.5em'},
|
66
|
+
g.map{|s,r| # subject
|
67
|
+
uri = s.E.localURL e
|
68
|
+
{_: :table, style: 'background-color:#eee',
|
69
|
+
c: [{_: :tr, c: {_: :td, colspan: 2, c: {_: :a, class: :uri, id: s, c: s, href: uri}}},
|
70
|
+
{_: :input, type: :hidden, name: s.E.concatURI(Edit.E).concatURI(E['/']), value: e['uri']+'?graph=edit'},
|
71
|
+
r.keys.-([Edit]).concat(ps).uniq.map{|p| # resource + prototype/initialize predicates
|
72
|
+
{_: :tr,
|
73
|
+
c: [{_: :td, c: {_: :a, title: p, href: p, c: p.abbrURI}}, # property
|
74
|
+
{_: :td,
|
75
|
+
c: [r[p].do{|o| # objects
|
76
|
+
(o.class == Array ? o : [o]).map{|o| # each object
|
77
|
+
triple[s,p,o]}}, # existing triples
|
78
|
+
triple[s,p,'']]}]}}]}}, # new triple
|
79
|
+
{_: :input, type: :submit, value: 'save'}]}]}
|
63
80
|
|
64
81
|
# select a property to edit
|
65
82
|
fn 'view/addP',->g,e{
|
66
|
-
[
|
67
|
-
[Date,Title,Creator,Content,Label].map{|p|{_: :a, href: p, c: p.label+' '}},
|
68
|
-
|
83
|
+
[[Date,Title,Creator,Content,Label].map{|p|[{_: :a, href: p, c: p},'<br>']},
|
69
84
|
{_: :form, action: e['REQUEST_PATH'], method: :GET,
|
70
|
-
c: [{_: :input, type: :url, name: :
|
85
|
+
c: [{_: :input, type: :url, name: :predicate, pattern: '^http.*$', size: 64},
|
86
|
+
{_: :input, type: :hidden, name: :graph, value: :edit},
|
71
87
|
{_: :input, type: :submit, value: 'property'}]}]}
|
72
88
|
|
73
89
|
end
|
data/infod/feed.rb
CHANGED
@@ -14,33 +14,45 @@ module FeedParse
|
|
14
14
|
end) end
|
15
15
|
|
16
16
|
def parse
|
17
|
-
|
18
|
-
#prefix table
|
19
|
-
x={}
|
17
|
+
x={} # populate XMLns prefix table
|
20
18
|
match(/<(rdf|rss|feed)([^>]+)/i)[2].scan(/xmlns:?([a-z]+)?=["']?([^'">\s]+)/){|m|x[m[0]]=m[1]}
|
21
19
|
|
22
|
-
#
|
23
|
-
scan(%r{<(rss:|atom:)?(item|entry)([\s][^>]*)?>(
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
yield u,
|
40
|
-
(
|
41
|
-
|
42
|
-
|
43
|
-
}
|
20
|
+
# scan for resources
|
21
|
+
scan(%r{<(?<ns>rss:|atom:)?(?<tag>item|entry)(?<attrs>[\s][^>]*)?>(?<inner>.*?)</\k<ns>?\k<tag>>}mi){|m|
|
22
|
+
# identifier search
|
23
|
+
attrs = m[2]
|
24
|
+
inner = m[3]
|
25
|
+
u = attrs.do{|a| # RDF-style identifier (RSS 1.0)
|
26
|
+
a.match(/about=["']?([^'">\s]+)/).do{|s|
|
27
|
+
s[1] }} ||
|
28
|
+
(inner.match(/<link>([^<]+)/) || # <link> child-node or href attribute
|
29
|
+
inner.match(/<link[^>]+rel=["']?alternate["']?[^>]+href=["']?([^'">\s]+)/) ||
|
30
|
+
inner.match(/<(?:gu)?id[^>]*>([^<]+)/)).do{|s| s[1]} # <id> child
|
31
|
+
|
32
|
+
if u
|
33
|
+
if !u.match /^http/
|
34
|
+
puts "no HTTP URIs found #{u}"
|
35
|
+
u = '/junk/'+u.gsub('/','.')
|
36
|
+
end
|
37
|
+
yield u, E::Type, (E::SIOCt+'BlogPost').E
|
38
|
+
yield u, E::Type, (E::SIOC+'Post').E
|
39
|
+
|
40
|
+
#links
|
41
|
+
inner.scan(%r{<(link|enclosure|media)([^>]+)>}mi){|e|
|
42
|
+
e[1].match(/(href|url|src)=['"]?([^'">\s]+)/).do{|url|
|
43
|
+
yield(u,E::Atom+'/link/'+((r=e[1].match(/rel=['"]?([^'">\s]+)/)) ? r[1] : e[0]), url[2].E)}}
|
44
|
+
|
45
|
+
#elements
|
46
|
+
inner.scan(%r{<([a-z]+:)?([a-z]+)([\s][^>]*)?>(.*?)</\1?\2>}mi){|e|
|
47
|
+
yield u, # s
|
48
|
+
(x[e[0]&&e[0].chop]||E::RSS)+e[1], # p
|
49
|
+
e[3].extend(FeedParse).guess.do{|o|# o
|
50
|
+
o.match(/\A(\/|http)[\S]+\Z/) ? o.E : E::F['cleanHTML'][o]
|
51
|
+
}}
|
52
|
+
else
|
53
|
+
puts "no post-identifiers found #{u}"
|
54
|
+
end
|
55
|
+
}
|
44
56
|
|
45
57
|
nil
|
46
58
|
end
|
@@ -56,8 +68,24 @@ class E
|
|
56
68
|
def listFeeds; (nokogiri.css 'link[rel=alternate]').map{|u|E (URI uri).merge(u.attr :href)} end
|
57
69
|
alias_method :feeds, :listFeeds
|
58
70
|
|
59
|
-
|
60
|
-
|
71
|
+
# add existing resources to index
|
72
|
+
#
|
73
|
+
# 'http:/'.E.take.select{|e|e.ext=='e'}.map{|r|E::FeedArchiver[r,r.graph,'localhost']}
|
74
|
+
|
75
|
+
FeedArchiver = -> doc, graph, host {
|
76
|
+
doc.roonga host
|
77
|
+
graph.map{|u,r|
|
78
|
+
r[Date].do{|t| # link doc to date-index
|
79
|
+
t = t[0].gsub(/[-T]/,'/').sub /(.00.00|Z)$/, '' # trim normalized timezones and non-unique symbols
|
80
|
+
stop = /\b(at|blog|com(ments)?|html|info|org|photo|p|post|r|status|tag|twitter|wordpress|www|1999|2005)\b/
|
81
|
+
b = (u.sub(/http:\/\//,'.').gsub(/\W/,'..').gsub(stop,'').sub(/\d{12,}/,'')+'.').gsub /\.+/,'.'
|
82
|
+
doc.ln E["http://#{host}/news/#{t}#{b}e"]}}
|
83
|
+
doc}
|
84
|
+
|
85
|
+
GREP_DIRS.push /^\/news\/\d{4}/
|
86
|
+
|
87
|
+
def getFeed g; addDocs :triplrFeed, g, nil, FeedArchiver end
|
88
|
+
def getFeedReddit g; addDocs :triplrFeedReddit, g, nil, FeedArchiver end
|
61
89
|
|
62
90
|
def triplrFeed &f
|
63
91
|
dateNorm :contentURIresolve,:triplrFeedNormalize,:triplrFeedRaw,&f
|
data/infod/fs.rb
CHANGED
@@ -50,10 +50,12 @@ class E
|
|
50
50
|
end
|
51
51
|
alias_method :m, :mtime
|
52
52
|
|
53
|
-
def triplrInode
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
def triplrInode
|
54
|
+
if d?
|
55
|
+
yield uri, Posix+'dir#parent', parent
|
56
|
+
c.map{|c| yield uri, Posix + 'dir#child', E[c.uri.gsub('?','%3F').gsub('#','23')]}
|
57
|
+
end
|
58
|
+
node.stat.do{|s|[:size,:ftype,:mtime].map{|p| yield uri, Stat+p.to_s, (s.send p)}}
|
57
59
|
end
|
58
60
|
|
59
61
|
def triplrSymlink
|
data/infod/glob.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#watch __FILE__
|
2
2
|
class E
|
3
3
|
|
4
|
-
# glob :: pattern -> [E]
|
5
4
|
def glob p=""
|
6
5
|
(Pathname.glob d + p).map &:E
|
7
6
|
end
|
@@ -16,10 +15,10 @@ class E
|
|
16
15
|
|
17
16
|
def docs
|
18
17
|
base = docBase
|
19
|
-
[(base if pathSegment!='/' && base.e),
|
20
|
-
(self if base != self && e && uri[-1]!='/'),
|
18
|
+
[(base if pathSegment!='/' && base.e), # doc-base
|
19
|
+
(self if base != self && e && uri[-1]!='/'), # requested path
|
21
20
|
base.glob(".{e,html,n3,nt,owl,rdf,ttl,txt}"), # docs
|
22
|
-
((d? && uri[-1]=='/' && uri.size>1) ? c : []) # trailing slash
|
21
|
+
((d? && uri[-1]=='/' && uri.size>1) ? c : []) # trailing slash -> child resources
|
23
22
|
].flatten.compact
|
24
23
|
end
|
25
24
|
|
data/infod/graph.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
#watch __FILE__
|
2
2
|
class E
|
3
3
|
=begin
|
4
|
-
graph
|
4
|
+
graph construction is two-pass:
|
5
5
|
|
6
|
-
|
7
|
-
the first-pass will determine if the second-pass needs to run. an eTag will be derived from the return-value and any graph additions preserved for the next pass. ideal fingerprint sources include filestats, mtime checks, extremely trivial SPARQL queries, SHA160 hashes of in-RAM entities. you can define only a second or first-pass and get default behaviour for the other. for more ideas see <http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-25#section-2.3>
|
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>
|
8
7
|
|
9
|
-
|
10
|
-
a second-pass might query a CBD (concise-bounded description) from a SPARQL store. infod was originally developed as an alternative to fragility & latency of 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 "touch" a file on successful POSTs so a store only has to be queried occasionally, and to facilitate simply hooking up bits of Ruby code to names rather than try to shoehorn what you're trying to say into some QueryLang where you're additionally without standard library functions necessitating more roundtrips and latency via marshalling/unmarshalling, parsing, loopback network-abstraction, nascent RDF-via-SPARQL-as-ORM-libs.. but go nuts experimenting w/ graph-handlers for this stuff,,i do..
|
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 all sorts of non-RDF like email, directories, plain-text etc
|
11
9
|
|
12
|
-
triple streams
|
13
|
-
|
14
|
-
these can be
|
10
|
+
triple streams - a source function yields triples up to the caller as it finds them,
|
11
|
+
a function providing just a block (consume yielded values) is a sink, both is a filter
|
12
|
+
these can be stacked into pipelines. see the data-massaging stream-processors in feed.rb
|
15
13
|
|
16
14
|
=end
|
17
15
|
|
@@ -29,36 +27,32 @@ class E
|
|
29
27
|
* behave as normal triplr to caller, with
|
30
28
|
side-effect of import/indexing to knowledgebase
|
31
29
|
=end
|
32
|
-
def
|
30
|
+
def addDocs triplr, host, p=nil, hook=nil, &b
|
33
31
|
graph = fromStream({},triplr)
|
34
32
|
docs = {}
|
35
33
|
graph.map{|u,r|
|
36
|
-
e = u.E
|
37
|
-
doc = e.ef
|
38
|
-
doc.e ||
|
39
|
-
(docs[doc.uri] ||= {}
|
40
|
-
docs[doc.uri][u] = r
|
41
|
-
p.map{|p|
|
42
|
-
r[p].do{|v|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
d
|
47
|
-
if
|
48
|
-
|
49
|
-
d.roonga host # text index
|
50
|
-
puts "#{doc} < #{g.keys.join ' '}"
|
51
|
-
end}
|
52
|
-
graph.triples &b if b # emit the triples
|
34
|
+
e = u.E # resource
|
35
|
+
doc = e.ef # doc
|
36
|
+
doc.e || # exists - we're nondestructive here
|
37
|
+
(docs[doc.uri] ||= {} # init doc-graph
|
38
|
+
docs[doc.uri][u] = r # add to graph
|
39
|
+
p && p.map{|p| # index predicate
|
40
|
+
r[p].do{|v|v.map{|o| # values exist?
|
41
|
+
e.index p,o}}})} # index triple
|
42
|
+
docs.map{|d,g| # resources in docs
|
43
|
+
d = d.E; puts "+doc #{d}"
|
44
|
+
d.w g,true # write
|
45
|
+
hook[d,g,host] if hook} # insert-hook
|
46
|
+
graph.triples &b if b # emit triples
|
53
47
|
self
|
54
48
|
end
|
55
49
|
|
56
|
-
# default protograph - identity
|
50
|
+
# default protograph - identity < lazy-expandable resource-thunks
|
57
51
|
# Resource, Query, Graph -> graphID
|
58
52
|
fn 'protograph/',->e,q,g{
|
59
53
|
g['#'] = {'uri' => '#'}
|
60
54
|
set = (q['set'] && F['set/'+q['set']] || F['set/'])[e,q,g]
|
61
|
-
if set.empty?
|
55
|
+
if !set || set.empty?
|
62
56
|
g.delete '#'
|
63
57
|
else
|
64
58
|
g['#'][RDFs+'member'] = set
|
@@ -96,31 +90,19 @@ class E
|
|
96
90
|
# cleanup unexpanded thunks
|
97
91
|
m.delete_if{|u,r|r.class==E}}
|
98
92
|
|
99
|
-
fn 'filter/set',->e,m,r{
|
100
|
-
# filter to RDFs set-members, gone will be:
|
101
|
-
# data about docs containing the data
|
102
|
-
# other fragments in a doc not matching search when indexed per-fragment
|
103
|
-
f = m['#'].do{|c| c[RDFs+'member'].do{|m| m.map &:uri }} || [] # members
|
104
|
-
m.keys.map{|u| m.delete u unless f.member? u}} # trim
|
105
|
-
|
106
93
|
def graphFromFile g={}
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
_ = E '/E/rdf/' + [triplr,uri].h.dive
|
117
|
-
unless _.e && _.m > m; # up to date?
|
118
|
-
e = {} ; puts "< #{uri}"
|
119
|
-
[:triplrInode,triplr].each{|t| fromStream e, t }
|
120
|
-
_.w e, true
|
94
|
+
return unless e
|
95
|
+
doc = self
|
96
|
+
unless ext=='e' # already native-format
|
97
|
+
triplr = @r.do{|r|r.q['triplr'].do{|t| (respond_to? t) && t }} || :triplrMIME
|
98
|
+
doc = E '/E/rdf/' + [triplr,uri].h.dive
|
99
|
+
unless doc.e && doc.m > m; # freshness check
|
100
|
+
graph = {}
|
101
|
+
[:triplrInode,triplr].each{|t| fromStream graph, t }
|
102
|
+
doc.w graph, true
|
121
103
|
end
|
122
104
|
end
|
123
|
-
g.mergeGraph
|
105
|
+
g.mergeGraph doc.r true
|
124
106
|
end
|
125
107
|
|
126
108
|
def graph g={}
|
@@ -128,4 +110,38 @@ class E
|
|
128
110
|
g
|
129
111
|
end
|
130
112
|
|
113
|
+
def triplrJSON
|
114
|
+
yield uri, '/application/json', (JSON.parse read) if e
|
115
|
+
rescue Exception => e
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_json *a
|
119
|
+
to_h.to_json *a
|
120
|
+
end
|
121
|
+
|
122
|
+
fn Render+'application/json',->d,_=nil{[d].to_json}
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
class Hash
|
127
|
+
|
128
|
+
def graph g
|
129
|
+
g.merge!({uri=>self})
|
130
|
+
end
|
131
|
+
|
132
|
+
def mergeGraph g
|
133
|
+
g.triples{|s,p,o|
|
134
|
+
self[s] = {'uri' => s} unless self[s].class == Hash
|
135
|
+
self[s][p] ||= []
|
136
|
+
self[s][p].push o unless self[s][p].member? o } if g
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
def triples &f
|
141
|
+
map{|s,r|
|
142
|
+
r.map{|p,o|
|
143
|
+
o.class == Array ? o.each{|o| yield s,p,o} : yield(s,p,o) unless p=='uri'} if r.class == Hash
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
131
147
|
end
|
data/infod/grep.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
#watch __FILE__
|
2
2
|
class E
|
3
3
|
|
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
|
+
|
6
|
+
GREP_DIRS=[]
|
7
|
+
|
4
8
|
fn 'set/grep',->e,q,m{
|
5
|
-
q['
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
q['q'].do{|query| m[e.uri+'#grep'] = {Type => E[Posix+'util#grep']}
|
10
|
+
path = e.pathSegment
|
11
|
+
GREP_DIRS.find{|p|path.uri.match p}.do{|allow|
|
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.unpathFs}}.flatten
|
14
|
+
}||(puts "no grep available on #{path}")}}
|
10
15
|
|
11
16
|
fn 'view/grep',->d,e{
|
12
17
|
w = e.q['q']
|
@@ -24,8 +29,7 @@ class E
|
|
24
29
|
# sequential pattern
|
25
30
|
p = /#{w.join '.*'}/i
|
26
31
|
|
27
|
-
[H.css('/css/
|
28
|
-
F['view/'+Search][e.q,e],
|
32
|
+
[H.css('/css/grep'),
|
29
33
|
{_: :style, c: c.values.map{|i|
|
30
34
|
# word color
|
31
35
|
b = rand(16777216)
|
@@ -54,8 +58,7 @@ class E
|
|
54
58
|
# exerpt
|
55
59
|
l[0..403].gsub(a){|g|
|
56
60
|
H({_: :span, class: "w w#{c[g.downcase]}",c: g})}
|
57
|
-
},"<br>"]]}
|
58
|
-
{_: :a, class: :down, href: e['REQUEST_PATH']+e.q.except('view').qs, style: "background-color: #{E.cs}",c: '↓'}]
|
61
|
+
},"<br>"]]}]
|
59
62
|
end }
|
60
63
|
|
61
64
|
end
|