infod 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/infod.rb +2 -3
  2. data/infod/Es.rb +31 -67
  3. data/infod/{W/source.rb → Es/code.rb} +6 -10
  4. data/infod/Es/css.rb +21 -0
  5. data/infod/{W → Es}/csv.rb +0 -0
  6. data/infod/Es/du.rb +16 -0
  7. data/infod/{W → Es}/feed.rb +13 -11
  8. data/infod/Es/filter.rb +75 -0
  9. data/infod/Es/find.rb +20 -0
  10. data/infod/Es/fs.rb +145 -136
  11. data/infod/Es/glob.rb +22 -0
  12. data/infod/Es/grep.rb +61 -0
  13. data/infod/Es/groonga.rb +47 -56
  14. data/infod/Es/html.rb +271 -0
  15. data/infod/Es/image.rb +114 -0
  16. data/infod/Es/in.rb +68 -0
  17. data/infod/Es/index.rb +183 -0
  18. data/infod/{W → Es}/json.rb +28 -4
  19. data/infod/Es/kv.rb +60 -0
  20. data/infod/Es/ls.rb +58 -0
  21. data/infod/Es/mail.rb +87 -0
  22. data/infod/Es/man.rb +112 -0
  23. data/infod/Es/mime.rb +59 -0
  24. data/infod/Es/out.rb +52 -0
  25. data/infod/{W/page.rb → Es/pager.rb} +7 -3
  26. data/infod/Es/pdf.rb +19 -0
  27. data/infod/Es/rdf.rb +35 -0
  28. data/infod/Es/schema.rb +99 -0
  29. data/infod/Es/search.rb +24 -0
  30. data/infod/Es/sh.rb +21 -0
  31. data/infod/{W → Es}/text.rb +26 -14
  32. data/infod/H.rb +15 -29
  33. data/infod/H/audio.rb +19 -0
  34. data/infod/H/blog.rb +15 -0
  35. data/infod/{W → H}/cal.rb +2 -31
  36. data/infod/H/edit.rb +88 -0
  37. data/infod/{W/examine/examine.rb → H/facets.rb} +17 -17
  38. data/infod/{W → H}/forum.rb +1 -0
  39. data/infod/{W/examine/sw.rb → H/hf.rb} +12 -12
  40. data/infod/H/histogram.rb +78 -0
  41. data/infod/H/mail.rb +92 -0
  42. data/infod/{W/chat.rb → H/microblog.rb} +21 -16
  43. data/infod/H/threads.rb +77 -0
  44. data/infod/H/time.rb +131 -0
  45. data/infod/H/who.rb +30 -0
  46. data/infod/{W → H}/wiki.rb +0 -0
  47. data/infod/K.rb +28 -60
  48. data/infod/N.rb +151 -74
  49. data/infod/Rb.rb +3 -3
  50. data/infod/Th.rb +27 -101
  51. data/infod/Th/404.rb +29 -36
  52. data/infod/Th/500.rb +36 -5
  53. data/infod/Th/GET.rb +48 -118
  54. data/infod/Th/POST.rb +31 -11
  55. data/infod/Th/perf.rb +37 -0
  56. data/infod/Th/util.rb +89 -0
  57. data/infod/Y.rb +24 -7
  58. data/infod/infod.rb +2 -3
  59. metadata +92 -64
  60. data/infod/Es/redis.rb +0 -3
  61. data/infod/Es/sqlite.rb +0 -3
  62. data/infod/Th/local.rb +0 -22
  63. data/infod/W.rb +0 -34
  64. data/infod/W/audio.rb +0 -56
  65. data/infod/W/blog.rb +0 -3
  66. data/infod/W/color.rb +0 -28
  67. data/infod/W/core.rb +0 -77
  68. data/infod/W/css.rb +0 -24
  69. data/infod/W/du.rb +0 -35
  70. data/infod/W/edit.rb +0 -8
  71. data/infod/W/examine/exhibit.rb +0 -34
  72. data/infod/W/examine/hist.rb +0 -55
  73. data/infod/W/examine/history.rb +0 -19
  74. data/infod/W/examine/normal.rb +0 -31
  75. data/infod/W/examine/protovis.rb +0 -30
  76. data/infod/W/examine/time/graph.rb +0 -86
  77. data/infod/W/examine/time/line.rb +0 -24
  78. data/infod/W/find.rb +0 -24
  79. data/infod/W/grep.rb +0 -27
  80. data/infod/W/html.rb +0 -143
  81. data/infod/W/image.rb +0 -61
  82. data/infod/W/kv.rb +0 -66
  83. data/infod/W/ls.rb +0 -50
  84. data/infod/W/mail.rb +0 -248
  85. data/infod/W/pdf.rb +0 -16
  86. data/infod/W/post.rb +0 -9
  87. data/infod/W/rdf.rb +0 -32
  88. data/infod/W/schema.rb +0 -172
  89. data/infod/W/search.rb +0 -33
  90. data/infod/W/shell.rb +0 -30
  91. data/infod/W/table.rb +0 -87
  92. data/infod/W/tree.rb +0 -26
  93. data/infod/W/vfs.rb +0 -175
data/infod.rb CHANGED
@@ -1,13 +1,12 @@
1
1
 
2
2
  # the table of elements
3
3
 
4
- # Es search
4
+ # Es infrastructure
5
5
  # H HTML
6
6
  # K constants
7
7
  # N naming
8
8
  # Rb Ruby native-types
9
9
  # Th HTTP
10
- # W forms and formats
11
10
  # Y lambdas
12
11
 
13
- %w{Y K Rb N W Th H Es}.map{|e| require 'infod/' + e}
12
+ %w{Y K Rb N Es H Th}.map{|e| require 'infod/' + e}
data/infod/Es.rb CHANGED
@@ -1,67 +1,31 @@
1
- %w{fs groonga redis}.map{|e|require_relative 'Es/'+e}
2
-
3
- class E
4
-
5
- # accumulate a graph recursively along set-membership arc
6
- def walk p,m={}
7
- graph m # accumulative graph
8
- o = [] # resources to visit
9
- o.concat m[uri][p] # outgoing arc targets
10
- o.concat (E p).po self # incoming arc sources
11
- o.map{|r| # walk
12
- r.E.walk p,m unless m[r.uri]}
13
- m
14
- end
15
-
16
- # random leaf
17
- def randomLeaf
18
- c.empty? && self || c.r.randomLeaf
19
- end
20
- fn 'set/randomLeaf',->d,e,m{[d.randomLeaf]}
21
- fn 'req/randomLeaf',->e,r{[302, {Location: e.randomLeaf.uri},[]]}
22
-
23
- # Graph -> [Predicate]
24
- def E.graphProperties g
25
- g.values.select{|v|v.respond_to? :keys}.map(&:keys).flatten.uniq
26
- end
27
-
28
- fn 'filter/p',->e,m,_{
29
- a=Hash[*e['p'].split(/,/).map(&:expand).map{|p|[p,true]}.flatten]
30
- m.values.map{|r|
31
- r.delete_if{|p,o|!a[p]}}}
32
-
33
- fn 'filter/frag',->e,m,r{
34
- f = [r.uri].concat m['frag']['res']
35
- m.keys.map{|u|
36
- m.delete u unless f.member? u}}
37
-
38
- fn 'filter/basic',->o,m,_{
39
- d=m.values
40
- o['match'] && (p=o['matchP'].expand
41
- d=d.select{|r|r[p].do{|p|(p.class==Array ? p[0] : p).to_s.match o['match']}})
42
- o['min'] && (min=o['min'].to_f
43
- p=o['minP'].expand
44
- d=d.select{|r|r[p].do{|p|(p.class==Array ? p[0] : p).to_f >= min }})
45
- o['max'] && (max=o['max'].to_f
46
- p=o['maxP'].expand
47
- d=d.select{|r|r[p].do{|p|(p.class==Array ? p[0] : p).to_f <= max }})
48
- o['sort'] && (p=o['sort'].expand
49
- _ = d.partition{|r|r[p]}
50
- d =_[0].sort_by{|r|r[p]}.concat _[1] rescue d)
51
- o['sortN'] && (p=o['sortN'].expand
52
- _ = d.partition{|r|r[p]}
53
- d =_[0].sort_by{|r|
54
- (r[p].class==Array && r[p] || [r[p]])[0].do{|d|
55
- d.class==String && d.to_i || d
56
- }
57
- }.concat _[1])
58
- o.has_key?('reverse') && d.reverse!
59
- m.clear;d.map{|r|m[r['uri']]=r}}
60
-
61
- def self.filter o,m,r
62
- o['filter'].do{|f|f.split(/,/).map{|f|Fn 'filter/'+f,o,m,r}}
63
- Fn'filter/basic',o,m,r if o.has_any_key ['reverse','sort','max','min','match']
64
- m
65
- end
66
-
67
- end
1
+ %w{
2
+ code
3
+ css
4
+ csv
5
+ du
6
+ feed
7
+ filter
8
+ find
9
+ fs
10
+ glob
11
+ grep
12
+ groonga
13
+ html
14
+ image
15
+ in
16
+ index
17
+ json
18
+ kv
19
+ ls
20
+ mail
21
+ man
22
+ mime
23
+ out
24
+ pager
25
+ pdf
26
+ rdf
27
+ schema
28
+ search
29
+ sh
30
+ text
31
+ }.map{|e|require_relative 'Es/'+e}
@@ -1,25 +1,21 @@
1
1
  class E
2
2
 
3
- # show available querystring aliases
4
- fn '/qs/GET',->e,r{H([H.css('/css/404'),F['?'].html]).hR}
5
-
6
3
  def triplrSourceCode
7
- # MIME strip x-
8
4
  m = mime.split(/\//)[-1].sub(/^x-/,'')
9
-
10
5
  # show line numbers?
11
6
  n = @r.has_key?('n') && "--line-number-ref=#{uri.sh}"
12
-
13
- yield uri,Content,
14
- `source-highlight -f html -o STDOUT -i #{sh} -s #{m} #{n}`
15
- end
7
+ if size < 512e3
8
+ yield uri,Content,
9
+ `source-highlight -f html -o STDOUT -i #{sh} -s #{m} #{n}`
10
+ end
11
+ end
16
12
 
17
13
  fn 'view/code',->d,e{[{_: :style, c: 'body{background-color:white;color:black}'},
18
14
  d.values.map{|r|[r.E.do{|e|[{_: :a,name: e.uri},e.html(e.base,true)]},'<br>',
19
15
  r[Content]]}]}
20
16
 
21
17
  # ls /usr/share/source-highlight/*.lang | xargs -i basename {} .lang | tr "\n" " "
22
- %w{ada applescript asm awk bat bib bison caml changelog c clipper cobol conf cpp csharp css desktop diff d erlang errors flex fortran function glsl haskell haskell_literate haxe html html_simple java javascript key_string langdef latex ldap lisp log logtalk lsm lua m4 makefile manifest nohilite number outlang oz pascal pc perl php postscript prolog properties proto python ruby scala script_comment sh slang sml spec sql style symbols tcl texinfo todo url vala vbscript xml}
18
+ %w{ada applescript asm awk bat bib bison caml changelog c clipper cobol conf cpp csharp css desktop diff d erlang errors flex fortran function glsl haskell haskell_literate haxe html html_simple java javascript key_string langdef latex ldap lisp log logtalk lsm lua m4 makefile manifest nohilite number outlang oz pascal pc perl php postscript prolog properties proto python ruby scala script_comment sh shellscript slang sml spec sql style symbols tcl texinfo todo url vala vbscript xml}
23
19
  .map{|l|
24
20
  ma = 'application/' + l
25
21
  mt = 'text/x-' + l
data/infod/Es/css.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'nokogiri'
2
+ class E
3
+
4
+ def nokogiri; Nokogiri::HTML.parse read end
5
+
6
+ MIMEsource['text/css'] ||= [:triplrSourceCode]
7
+
8
+ end
9
+
10
+ class H
11
+
12
+ def H.css a,inline=false
13
+ p = a + '.css'
14
+ if inline
15
+ {_: :style, c: p.E.r}
16
+ else
17
+ {_: :link, href: p, rel: :stylesheet, type: E::MIME[:css]}
18
+ end
19
+ end
20
+
21
+ end
File without changes
data/infod/Es/du.rb ADDED
@@ -0,0 +1,16 @@
1
+ class E
2
+
3
+ fn 'protograph/du',->d,_,m{
4
+ e = [d,d.pathSegment].compact.find &:e
5
+ m[e.uri] = e if e
6
+ rand.to_s.h }
7
+
8
+ fn 'graph/du',->e,_,m{
9
+ `du -a #{m.values[0].sh}`.each_line{|l|
10
+ s,p = l.chomp.split /\t/ # size, path
11
+ p = p.unpathFs # path -> URI
12
+ m[p.uri] = {'uri' => p.uri,
13
+ Stat+'size' => [s.to_i]}}
14
+ m }
15
+
16
+ end
@@ -20,16 +20,18 @@ module FeedParse
20
20
  #items
21
21
  scan(%r{<(rss:|atom:)?(item|entry)([\s][^>]*)?>(.*?)</\1?\2>}mi){|m|
22
22
 
23
- #URI
24
- u = m[2] && (u=m[2].match /about=["']?([^'">\s]+)/) && u[1] ||
25
- m[3] && (((u=m[3].match /<(gu)?id[^>]*>([^<]+)/) || (u=m[3].match /<(link)>([^<]+)/)) && u[2])
26
- yield u,E::Type,(E::SIOC+'Post').E
23
+ # TODO (gu)id field is often unresolvable. maybe use link[rel=alternate] as identifier instead since it's resolvable & HTTP
24
+
25
+ # find identifier
26
+ u = m[2] && (u = m[2].match /about=["']?([^'">\s]+)/) && u[1] ||
27
+ m[3] && (((u = m[3].match /<(gu)?id[^>]*>([^<]+)/) || (u = m[3].match /<(link)>([^<]+)/)) && u[2])
28
+
29
+ yield u, E::Type, (E::SIOC+'Post').E
27
30
 
28
31
  #links
29
32
  m[3].scan(%r{<(link|enclosure|media)([^>]+)>}mi){|e|
30
- yield(u, # s
31
- E::Atom+'/link/'+((r=e[1].match(/rel=['"]?([^'">\s]+)/)) ? r[1] : e[0]), # p
32
- e[1].match(/(href|url|src)=['"]?([^'">\s]+)/)[2].E)} # o
33
+ e[1].match(/(href|url|src)=['"]?([^'">\s]+)/).do{|url|
34
+ yield(u,E::Atom+'/link/'+((r=e[1].match(/rel=['"]?([^'">\s]+)/)) ? r[1] : e[0]), url[2].E)}}
33
35
 
34
36
  #elements
35
37
  m[3].scan(%r{<([a-z]+:)?([a-z]+)([\s][^>]*)?>(.*?)</\1?\2>}mi){|e|
@@ -61,7 +63,6 @@ class E
61
63
  end
62
64
 
63
65
  def triplrFeedReddit &f
64
- require 'nokogiri'
65
66
  triplrFeed {|s,p,o|
66
67
  p == Content ?
67
68
  Nokogiri::HTML.parse(o).do{|o|
@@ -109,8 +110,9 @@ class E
109
110
  d[Title].do{|t|{_: :title, c: t}},
110
111
  d[Creator].do{|c|{_: :author, c: c[0]}},
111
112
  {_: :content, type: :xhtml,
112
- c: {xmlns:"http://www.w3.org/1999/xhtml", c: d[Content]}}
113
- ].intersperse("\n")}
114
- }.intersperse("\n")]}])}
113
+ c: {xmlns:"http://www.w3.org/1999/xhtml",
114
+ c: d[Content]}}].cr
115
+ }}.cr
116
+ ]}])}
115
117
 
116
118
  end
@@ -0,0 +1,75 @@
1
+ class E
2
+
3
+ # narrow to specified properties
4
+ fn 'filter/p',->e,m,_{
5
+ a=Hash[*e['p'].split(/,/).map(&:expand).map{|p|[p,true]}.flatten]
6
+ m.values.map{|r|
7
+ r.delete_if{|p,o|!a[p]}}}
8
+
9
+ fn 'filter/frag',->e,m,r{
10
+ f = [r.uri].concat m['frag']['res']
11
+ m.keys.map{|u|
12
+ m.delete u unless f.member? u}}
13
+
14
+ fn 'filter/basic',->o,m,_{
15
+ d=m.values
16
+ o['match'] && (p=o['matchP'].expand
17
+ d=d.select{|r|r[p].do{|p|(p.class==Array ? p[0] : p).to_s.match o['match']}})
18
+ o['min'] && (min=o['min'].to_f
19
+ p=o['minP'].expand
20
+ d=d.select{|r|r[p].do{|p|(p.class==Array ? p[0] : p).to_f >= min }})
21
+ o['max'] && (max=o['max'].to_f
22
+ p=o['maxP'].expand
23
+ d=d.select{|r|r[p].do{|p|(p.class==Array ? p[0] : p).to_f <= max }})
24
+ o['sort'] && (p=o['sort'].expand
25
+ _ = d.partition{|r|r[p]}
26
+ d =_[0].sort_by{|r|r[p]}.concat _[1] rescue d)
27
+ o['sortN'] && (p=o['sortN'].expand
28
+ _ = d.partition{|r|r[p]}
29
+ d =_[0].sort_by{|r|
30
+ (r[p].class==Array && r[p] || [r[p]])[0].do{|d|
31
+ d.class==String && d.to_i || d
32
+ }
33
+ }.concat _[1])
34
+ o.has_key?('reverse') && d.reverse!
35
+ m.clear;d.map{|r|m[r['uri']]=r}}
36
+
37
+ fn 'filter/map',->o,m,_{
38
+ o.except('filter','graph','view').map{|p,n|
39
+ p=p.expand
40
+ n=n.expand
41
+ p!=n &&
42
+ m.values.map{|r|
43
+ r[p].do{|o|
44
+ r[n]=o
45
+ r.delete p }}}}
46
+
47
+ fn 'view/map',->d,e{
48
+ [H.js('/js/normal'),(H.once e,:mu,(H.js '/js/mu')),
49
+ '<style>.b {display:inline-block;font-weight:bold;padding-right:.8em;text-align:right;min-width:12em}
50
+ .exerpt {display:inline-block;max-height:1em;overflow:hidden;max-width:44em;font-size: .9em} </style>',
51
+ {_: :form, c:
52
+ [d.values.map(&:keys).flatten.uniq.-(['uri']).do{|ps|
53
+ ps.map{|p|
54
+ [{class: :b, c: p},{_: :select, name: p, c:
55
+ (ps + [Date,Creator,Content,Title]).map{|q|
56
+ {_: :option, c: q}.
57
+ update(p==q ? {selected: :selected}:{})}},
58
+ {class: :exerpt, c: d.values.map{|r|r[p]}.flatten.uniq.html},
59
+ '<br>']}},
60
+ {_: :input, type: :hidden, name: :view, value: :tab},
61
+ {_: :input, type: :hidden, name: :filter, value: :map},
62
+ {_: :input, type: :submit}
63
+ ]}]}
64
+
65
+ def self.filter o,m,r
66
+ o['filter'].do{|f|f.split(/,/).map{|f|Fn 'filter/'+f,o,m,r}}
67
+ Fn'filter/basic',o,m,r if o.has_any_key ['reverse','sort','max','min','match']
68
+ m
69
+ end
70
+
71
+ def E.graphProperties g
72
+ g.values.select{|v|v.respond_to? :keys}.map(&:keys).flatten.uniq
73
+ end
74
+
75
+ end
data/infod/Es/find.rb ADDED
@@ -0,0 +1,20 @@
1
+ #watch __FILE__
2
+ class E
3
+
4
+ fn 'set/find',->e,q,m,x=''{
5
+ q['q'].do{|q|
6
+ r = '-iregex ' + ('.*' + q + '.*' + x).sh
7
+ s = q['size'].do{|s| s.match(/^\d+$/) && '-size +' + s + 'M'}
8
+ t = q['day'].do{|d| d.match(/^\d+$/) && '-ctime -' + d }
9
+ [e,e.pathSegment].compact.select(&:e).map{|e|
10
+ `find #{e.sh} #{t} #{s} #{r} | head -n 1000`.
11
+ lines.map{|l|l.chomp.unpathFs}}.compact.flatten}}
12
+
13
+ fn 'view/find',->i,e{
14
+ {_: :form, method: :GET, action: e['REQUEST_PATH'].t,
15
+ c: [{_: :input, name: :set, value: :find, type: :hidden},
16
+ {_: :input, name: :triplr, value: :id, type: :hidden},
17
+ {_: :input, name: :view, value: :ls, type: :hidden},
18
+ {_: :input, name: :q, style: 'float: left;font-size:1.3em'}]}}
19
+
20
+ end
data/infod/Es/fs.rb CHANGED
@@ -1,154 +1,163 @@
1
+ #watch __FILE__
2
+
3
+ %w{date digest/sha1 fileutils json open-uri pathname}.each{|r|require(r)}
4
+
1
5
  class E
2
6
 
3
- # POSIX-filesystem index for triples
4
- #
7
+ def d
8
+ node.to_s
9
+ end
10
+
11
+ def node
12
+ Pathname.new FSbase + path
13
+ end
14
+ alias_method :no, :node
15
+
16
+ def siblings
17
+ parent.c
18
+ end
19
+
20
+ def children
21
+ node.c.map &:E
22
+ end
23
+ alias_method :c, :children
24
+
25
+
26
+ # node exists?
27
+ def exist?
28
+ node.exist?
29
+ end
30
+ alias_method :e, :exist?
31
+
32
+ # directory?
33
+ def d?
34
+ node.directory?
35
+ end
36
+
37
+ # file?
38
+ def file?
39
+ node.file?
40
+ end
41
+ alias_method :f, :file?
5
42
 
6
- # index a triple
7
- def index p,o
8
- # normalize predicate typeclass (accept URI string or resources)
9
- indexEdit E(p),
10
- # literal -> URI conversion
11
- (o.class == E ? o : E(p).literal(o)),
12
- nil
43
+ # modification time
44
+ def mtime
45
+ node.stat.mtime if e
13
46
  end
47
+ alias_method :m, :mtime
14
48
 
15
- # index a triple - no input-cleanup
16
- def indexEdit p,o,a
17
- return if @noIndex
18
- p.pIndex.noIndex[o,self,a]
49
+ def triplrInode children=true
50
+ e && (d? && (yield uri, Posix + 'dir#parent', parent
51
+ children && c.map{|c| yield uri, Posix + 'dir#child', c})
52
+ node.stat.do{|s|[:size,:ftype,:mtime].map{|p| yield uri, Stat+p.to_s, (s.send p)}})
53
+ end
54
+
55
+ def triplrSymlink
56
+ realpath.do{|t|
57
+ target = t.to_s.index(FSbase)==0 ? t.E : t.to_s
58
+ yield uri, '/linkTarget', target }
59
+ end
60
+
61
+ def realpath
62
+ node.realpath
63
+ rescue Errno::ENOENT
64
+ nil
19
65
  end
20
- def noIndex
21
- @noIndex = 1
66
+
67
+ def mk
68
+ e || FileUtils.mkdir_p(d)
22
69
  self
23
70
  end
24
71
 
25
- # subtree traverse
26
- fn 'set/subtree',->d,r,m{
27
- c =(r['c'].do{|c|c.to_i + 1} || 3).max(100) # one extra for start of next-page
28
- o = r['d'] =~ /^a/ ? :asc : :desc # direction
29
- ('/'.E.take c, o, d.uri).do{|s| # take subtree
30
- desc, asc = o == :desc ? # orient pagination hints
31
- [s.pop, s[0]] : [s[0], s.pop]
32
- m['prev'] = {'uri' => 'prev', 'url' => desc.url,'d' => 'desc'}
33
- m['next'] = {'uri' => 'next', 'url' => asc.url, 'd' => 'asc'}
34
- s }}
35
-
36
- # subtree traverse index on p+o cursor
37
- fn 'set/index',->d,r,m,f=:rangePO{
38
- (# predicate
39
- (f == :rangeP ? d : r['p']).expand.E.
40
- # query
41
- send f,
42
- # count
43
- (r['c']&&
44
- r['c'].to_i.max(808)+1 || 22),
45
- # direction
46
- (r['d']&&
47
- r['d'].match(/^(a|de)sc$/) &&
48
- r['d'].to_sym ||
49
- :desc),
50
- # offset
51
- r['offset'],
52
- # object
53
- (d if f == :rangePO)
54
- ).do{|s|
55
- # pagination pointers
56
- a,b = s[0], s.size > 1 && s.pop
57
- desc,asc = r['d'] && r['d']=='asc' && [a,b]||[b,a]
58
- # insert pointers in response-graph
59
- m['prev']={'uri' => 'prev','url' => d.url,'d' => 'desc','offset' => desc.uri} if desc
60
- m['next']={'uri' => 'next','url' => d.url,'d' => 'asc', 'offset' => asc.uri} if asc
61
- s }}
62
- F['set/indexPO']=F['set/index']
63
- fn 'set/indexP',->d,r,m{Fn 'set/index',d,r,m,:rangeP}
64
-
65
- # predicate index
66
- def pIndex
67
- '/index'.E.s self
68
- end
69
-
70
- # predicate-object index
71
- def poIndex o
72
- pIndex.s o
73
- end
74
-
75
- # predicate-object index lookup
76
- def po o
77
- pIndex[o.class == E ? o : literal(o)]
78
- end
79
-
80
- # range query - predicate
81
- def rangeP n=8,d=:desc,s=nil,o=nil
82
- puts "rangeP #{uri} count #{n} dir #{d} cursor #{s}"
83
- pIndex.subtree(n,d,s).map &:ro
84
- end
85
-
86
- # range query - predicate-object
87
- def rangePO n=8,d=:desc,s=nil,o
88
- puts "rangePO #{uri} #{o} count #{n} dir #{d} cursor #{s}"
89
- poIndex(o).subtree(n,d,s).map &:ro
90
- end
91
-
92
- # E -> [node]
93
- def subtree *a
94
- u.take *a
95
- end
96
-
97
- # E -> [E]
98
- def take *a
99
- no.take(*a).map &:E
72
+ # create link
73
+ def ln t
74
+ t = t.E # cast bare URI/string to resource
75
+ if !t.e # destination exist?
76
+ t.dirname.mk
77
+ FileUtils.link node, t.node
78
+ end
100
79
  end
101
80
 
102
- end
81
+ # create symlink
82
+ def ln_s t
83
+ t = t.E # cast bare URI/string to resource
84
+ if !t.e # destination exist?
85
+ t.dirname.mk
86
+ FileUtils.symlink node, t.node
87
+ end
88
+ end
89
+
90
+ def touch
91
+ FileUtils.touch node
92
+ self
93
+ end
94
+
95
+ def deleteNode
96
+ node.deleteNode if e
97
+ self
98
+ end
99
+
100
+ def size
101
+ node.size
102
+ end
103
+
104
+ def read
105
+ f ? r : get
106
+ end
107
+
108
+ def get
109
+ (open uri).read
110
+ end
111
+
112
+ def r p=false
113
+ if f
114
+ p ? (JSON.parse readFile) : readFile
115
+ else
116
+ puts "tried to open #{d}"
117
+ nil
118
+ end
119
+ rescue Exception => e
120
+ puts e
121
+ end
122
+
123
+ def w o,s=false
124
+ dirname.mk
125
+ writeFile (s ? o.to_json : o)
126
+ self
127
+ end
128
+
129
+ def writeFile c
130
+ File.open(d,'w'){|f|f << c}
131
+ end
103
132
 
133
+ def readFile
134
+ File.open(d).read
135
+ end
136
+
137
+ end
104
138
 
105
139
  class Pathname
106
140
 
107
- # take N els from fs tree in sorted, depth-first order
108
- def take count=1000, direction=:desc, offset=nil
109
-
110
- # construct offset-path
111
- offset = to_s + offset.gsub(/\/+/,'/').E.path if offset
112
-
113
- # in-range indicator
114
- ok = false
115
-
116
- # result set
117
- set=[]
118
-
119
- # asc/desc operators
120
- v,m={asc: [:id,:>=],
121
- desc: [:reverse,:<=]}[direction]
122
-
123
- # visitation function
124
- visit=->nodes{
125
-
126
- # sort nodes in asc or desc order
127
- nodes.sort_by(&:to_s).send(v).each{|n|
128
- ns = n.to_s
129
- # have we got enough nodes?
130
- return if 0 >= count
131
-
132
- # continue if
133
- (# already in-range
134
- ok ||
135
- # no offset specified
136
- !offset ||
137
- # offset satisfies in-range operator
138
- (sz = [ns,offset].map(&:size).min
139
- ns[0..sz-1].send(m,offset[0..sz-1]))) && (
140
- if !(c = n.c).empty? # has children?
141
- visit.(c) # visit children
142
- else
143
- count = count - 1 # decrement wanted-nodes count
144
- set.push n # add node to result-set
145
- ok = true # iterator is now within range
146
- end )}}
147
-
148
- visit.(c) # start
149
-
150
- # result set
151
- set
141
+ def E
142
+ to_s.force_encoding('UTF-8').unpathFs
152
143
  end
153
144
 
145
+ def c
146
+ return [] unless directory?
147
+ children.delete_if{|n| n.basename.to_s.match /^\./}
148
+ rescue
149
+ []
150
+ end
151
+
152
+ def deleteNode
153
+ FileUtils.send file? ? :rm : :rmdir, self
154
+ parent.deleteNode if parent.c.empty?
155
+ end
156
+
157
+ end
158
+
159
+ class File::Stat
160
+ def utime
161
+ mtime.to_i
162
+ end
154
163
  end