infod 0.0.1 → 0.0.2

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.
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