infod 0.0.3.1 → 0.0.3.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.
data/infod.rb CHANGED
@@ -4,13 +4,12 @@ lambda
4
4
  mime
5
5
  404
6
6
  500
7
+ grep
7
8
  audio
8
9
  blog
9
10
  cal
10
11
  code
11
- css
12
12
  csv
13
- du
14
13
  edit
15
14
  facets
16
15
  feed
@@ -20,7 +19,6 @@ fs
20
19
  GET
21
20
  glob
22
21
  graph
23
- grep
24
22
  groonga
25
23
  HEAD
26
24
  histogram
@@ -28,7 +26,6 @@ html
28
26
  HTTP
29
27
  image
30
28
  index
31
- json
32
29
  kv
33
30
  ls
34
31
  mail
@@ -36,13 +33,11 @@ man
36
33
  microblog
37
34
  names
38
35
  page
39
- PATCH
40
36
  POST
41
37
  postscript
42
38
  rdf
43
39
  ruby
44
40
  schema
45
- search
46
41
  sh
47
42
  text
48
43
  threads
@@ -16,7 +16,7 @@ r.map{|k,v| s[Header + k] = k == 'uri' ? v : [v] }
16
16
  s[Type] = [E[HTTP+'Response']]
17
17
  s[HTTP+'statusCodeValue'] = [404]
18
18
  s[Header+'HTTP_HOST'] = [E['http://' + s[Header+'HTTP_HOST'][0]]] if s[Header+'HTTP_HOST']
19
- s[Edit] = [E[r['REQUEST_PATH']+'?graph=edit']]
19
+ s[Edit] = [E[r['REQUEST_PATH']+'?graph=create']]
20
20
  s['#query'] = [r.q]
21
21
  s['#seeAlso'] = [e.parent,*e.a('*').glob]
22
22
  r.q['view'] = '404'
@@ -27,9 +27,8 @@ s[HTTP+'statusCodeValue'] = [404]
27
27
  [H.css('/css/404'),{_: :style, c: "a {background-color:#{E.cs}}"},
28
28
  d.html]}
29
29
 
30
- # a placeholder graph
31
- # useful for initializing an editor on an empty resource
32
- fn 'protograph/_',->d,_,m{
30
+ # a resource-placeholder graph
31
+ fn 'protograph/blank',->d,_,m{
33
32
  m[d.uri] = {}
34
33
  rand.to_s.h}
35
34
 
@@ -25,8 +25,9 @@ class E
25
25
  {_: :td, class: :index, c: p[1]},
26
26
  {_: :td, class: :context, c: (p[2]||'').hrefs}].cr}}.cr]}]}]}]]]}
27
27
 
28
- F['/500/GET'] = ->e,r{H([Errors.sort_by{|u,r|r[:time]}.reverse.html,H.css('/css/500')]).hR}
29
- F['/500/test/GET'] = ->e,r{1/0}
28
+ F['/500/GET'] = ->e,r{
29
+ body = H [Errors.sort_by{|u,r|r[:time]}.reverse.html, H.css('/css/500')]
30
+ [200, {'Content-Type'=>'text/html; charset=utf-8'}, [body]]}
30
31
 
31
32
  F['view/'+COGS+'Exception']=->e,r{
32
33
  e.values.map{|e|
@@ -10,7 +10,7 @@ class E
10
10
 
11
11
  elsif file = [self,pathSegment].compact.find(&:f)
12
12
 
13
- # file exists, but client might not accept its MIME, or want it transformed to another MIME
13
+ # file exists. check if client or server want it transformed to another MIME
14
14
  a = @r.accept.values.flatten
15
15
  accepted = a.empty? || (a.member? file.mimeP) || (a.member? '*/*')
16
16
  (!accepted || MIMEcook[file.mimeP] || @r.q.has_key?('view')) ?
@@ -23,7 +23,7 @@ class E
23
23
 
24
24
  def getFile
25
25
  @r['ETag'] = [m,size].h
26
- maybeSend mimeP,->{self},:link
26
+ maybeSend mimeP,->{self}
27
27
  end
28
28
 
29
29
  def resource
@@ -42,13 +42,13 @@ class E
42
42
 
43
43
  m = {}
44
44
 
45
- # graph identity (model)
45
+ # graph-identity (model)
46
46
  g = @r.q['graph']
47
47
  graphID = (g && F['protograph/' + g] || F['protograph/'])[self,@r.q,m]
48
48
 
49
49
  return F[E404][self,@r] if m.empty?
50
50
 
51
- # response identity (view)
51
+ # response-identity (view)
52
52
  @r['ETag'] ||= [@r.q['view'].do{|v|F['view/' + v] && v}, graphID, @r.format, Watch].h
53
53
 
54
54
  maybeSend @r.format, ->{
@@ -78,18 +78,13 @@ class E
78
78
  !((m=@r['HTTP_IF_NONE_MATCH']) && m.strip.split(/\s*,\s*/).include?(@r['ETag']))
79
79
  end
80
80
 
81
- def maybeSend m, b, iR = false; c = 200
82
- send? ? # does agent have this version?
83
- b[].do{|b| # continue with response
84
-
85
- h = {'Content-Type'=> m,
86
- 'ETag'=> @r['ETag']}
87
-
81
+ def maybeSend m, b; c = 200
82
+ send? ?
83
+ b[].do{|b| # continue
84
+ h = {'Content-Type'=> m, 'ETag'=> @r['ETag']}
88
85
  h.update({'Cache-Control' => 'no-transform'}) if m.match /^(audio|image|video)/ # already compresed
89
- h.update({'Link' => '<' + @r['uri'] + '?view>; rel=meta'}) if iR # link to description
90
- # h.update({'MS-Author-Via' => 'SPARQL'}) # authoring preference
91
86
 
92
- # frontend-specific response handlers
87
+ # frontend-specific handlers
93
88
  b.class == E ? (Nginx ? # nginx chosen?
94
89
  [c,h.update({'X-Accel-Redirect' => '/fs' + b.path}),[]] : # Nginx handler
95
90
  Apache ? # Apache chosen?
@@ -101,4 +96,18 @@ class E
101
96
  [304,{},[]] # client has response
102
97
  end
103
98
 
99
+ # user-patchable default handler - use index.html or defer to internal default-handler #response
100
+ fn '/GET',->e,r{
101
+ x = 'index.html'
102
+ i = [e,e.pathSegment].compact.map{|e|e.as x}.find &:e
103
+ if i && !r['REQUEST_URI'].match(/\?/)
104
+ if e.uri[-1] == '/' # inside dir?
105
+ i.env(r).getFile # show index
106
+ else # descend into dir
107
+ [301, {Location: e.uri.t}, []]
108
+ end
109
+ else
110
+ e.response
111
+ end}
112
+
104
113
  end
@@ -10,7 +10,7 @@ class E
10
10
 
11
11
  # HEAD response-codes on a (.u) list of URIs
12
12
  def checkURIs
13
- r = uris.select{|u|u.to_s.match /^http/}.map{|u|
13
+ r = uris.map{|u|
14
14
  c = [`curl -IsA 404? "#{u}"`.lines.to_a[0].match(/\d{3}/)[0].to_i,u] # HEAD
15
15
  puts c.join ' '
16
16
  c } # status, uri tuple
@@ -4,15 +4,18 @@ require 'rack'
4
4
  class E
5
5
 
6
6
  def E.call e
7
- dev
8
- e.extend Th
7
+ e.extend Th # add HTTP utility functions to environment table
8
+ dev # see if watched files were changed
9
9
  e['HTTP_X_FORWARDED_HOST'].do{|h| e['SERVER_NAME'] = h }
10
- p = e['REQUEST_PATH'].force_encoding 'UTF-8'
10
+ path = CGI.unescape e['REQUEST_PATH'].force_encoding('UTF-8').gsub '+','%2B'
11
+ resource = E['http://'+e['SERVER_NAME']+path]
11
12
 
12
- uri = CGI.unescape((p.index(URIURL) == 0) ? p[URIURL.size..-1] : ('http://'+e['SERVER_NAME']+(p.gsub '+','%2B'))).E.env e
13
-
14
- uri.inside ? ( e['uri'] = uri.uri
15
- uri.send e.verb ) : [403,{},[]]
13
+ if resource.inside
14
+ e['uri'] = resource.uri
15
+ (resource.env e).send e['REQUEST_METHOD']
16
+ else
17
+ [403,{},[]]
18
+ end
16
19
 
17
20
  rescue Exception => x
18
21
  F['E500'][x,e]
@@ -20,37 +23,22 @@ class E
20
23
 
21
24
  end
22
25
 
23
- class String
24
-
25
- # querystring parse
26
- def qp
27
- d={}
28
- split(/&/).map{|e|
29
- k,v=e.split(/=/,2).map{|x|
30
- CGI.unescape x}
31
- d[k]=v}
32
- d
33
- end
34
-
35
- def hR
36
- [200, {'Content-Type'=>'text/html; charset=utf-8'}, [self]]
37
- end
38
-
39
- end
40
-
41
26
  module Th
42
27
 
43
- # query-string
44
- def qs
45
- (['GET','HEAD'].member? verb) ? self['QUERY_STRING'] : self['rack.input'].read
46
- end
47
-
48
- # parsed query-string
28
+ # Query-String -> Hash
49
29
  def q
50
- @q ||= (qs||'').qp
30
+ @q ||=
31
+ (if q = self['QUERY_STRING']
32
+ h = {}
33
+ q.split(/&/).map{|e| k,v = e.split(/=/,2).map{|x| CGI.unescape x }
34
+ h[k] = v }
35
+ h
36
+ else
37
+ {}
38
+ end)
51
39
  end
52
40
 
53
- # Accept header -> Hash
41
+ # Accept -> Hash
54
42
  def accept_ k=''
55
43
  d={}
56
44
  self['HTTP_ACCEPT'+k].do{|k|
@@ -66,7 +54,7 @@ module Th
66
54
  end
67
55
 
68
56
  def conneg
69
- # extension
57
+ # specific format-variant URI
70
58
  { '.html' => 'text/html',
71
59
  '.jsonld' => 'application/ld+json',
72
60
  '.nt' => 'text/ntriples',
@@ -75,7 +63,7 @@ module Th
75
63
  }[File.extname self['uri']].do{|mime|
76
64
  return mime}
77
65
 
78
- # Accept header
66
+ # Accept formats
79
67
  accept.sort.reverse.map{|q,mimes|
80
68
  mimes.map{|mime|
81
69
  return mime if E::F[E::Render+mime]}}
@@ -84,15 +72,11 @@ module Th
84
72
 
85
73
  def accept; @accept ||= accept_ end
86
74
 
87
- def verb
88
- self['REQUEST_METHOD']
89
- end
90
-
91
75
  end
92
76
 
93
77
  class Hash
94
78
 
95
- # unparse querystring
79
+ # Hash -> Query-String
96
80
  def qs
97
81
  '?'+map{|k,v|k.to_s+'='+(v ? (CGI.escape [*v][0].to_s) : '')}.intersperse("&").join('')
98
82
  end
@@ -1,34 +1,36 @@
1
- #watch __FILE__
1
+ watch __FILE__
2
2
  class E
3
3
 
4
4
  def POST
5
5
  type = @r['CONTENT_TYPE']
6
6
  case type
7
7
  when /^application\/sparql-update/
8
-
8
+ puts "SPARQL"
9
9
  when /^application\/x-www-form-urlencoded/
10
- ch = nil
10
+ changed = false
11
11
  (Rack::Request.new @r).params.map{|k,v|
12
- s, p, o = (CGI.unescape k).split S
12
+ s, p, o = (CGI.unescape k).split /\/\._/
13
13
  if s && p && o
14
- oP = o
15
14
  s, p, o = [s, p, o].map &:unpath
16
- s = s.uri[0..-2].E if s.uri[-1] == '/'
17
- p = p.uri[0..-2].E if p.uri[-1] == '/'
18
- if oP.E == (E.literal v) && s.uri.match(/^http/) && p.uri.match(/^http/)
19
- puts "POST <#{s}> <#{p}> <#{o}>"
20
- s[p,o,v]
21
- ch = true
15
+ if s.uri.match(/^http/) && p.uri.match(/^http/)
16
+ oO = v.match(/\A(\/|http)[\S]+\Z/) ? v.E : F['cleanHTML'][v]
17
+ if o != oO
18
+ changed = true
19
+ s[p,o,oO]
20
+ end
22
21
  end
23
22
  end}
24
- if ch # state changed
23
+ if changed
25
24
  g = {}
26
- fromStream g, :triplrFsStore
27
- ef.w g, true
25
+ fromStream g, :triplrDoc
26
+ if g.empty?
27
+ ef.deleteNode
28
+ else
29
+ ef.w g, true
30
+ end
28
31
  end
29
32
  end
30
-
31
- [303,{'Location'=>uri},[]]
33
+ [303,{'Location'=>uri+'?graph=edit'},[]]
32
34
  end
33
35
 
34
36
  end
@@ -3,12 +3,20 @@ class E
3
3
  VideoFile = /(avi|flv|mkv|mpg|mp4|wmv)$/i
4
4
  AudioFile = /(aif|wav|flac|mp3|m4a|aac|ogg)$/i
5
5
 
6
- fn 'set/audio',->d,e,m{d.take.select{|e|e.ext.match AudioFile}}
7
- fn 'set/video',->d,e,m{d.take.select{|e|e.ext.match VideoFile}}
6
+ fn 'set/audio',->d,e,m{
7
+ e['view'] = 'audio'
8
+ d.take.select{|e|e.ext.match AudioFile}}
8
9
 
10
+ fn 'set/video',->d,e,m{
11
+ e['view'] = 'audio'
12
+ e['video'] = true
13
+ d.take.select{|e|e.ext.match VideoFile}}
14
+
15
+ # table of audio-resource properties
9
16
  AudioK = {}
10
- %w{Album-Movie-Show_title Lead_performers-Soloists Title-songname-content_description}.
11
- map{|a|Audio + a}.concat(['uri', Stat+'mtime', Stat+'size']).map{|p|AudioK[p] = true}
17
+ %w{Album-Movie-Show_title Lead_performers-Soloists Title-songname-content_description}.map{|a|Audio + a}.
18
+ concat(['uri', Stat+'mtime', Stat+'size']).
19
+ map{|p|AudioK[p] = true}
12
20
 
13
21
  fn 'view/audio',->d,e{ d = d.dup
14
22
 
@@ -21,7 +21,7 @@ class E
21
21
  when /reddit/ # minimal view
22
22
  F['view/'+SIOCt+'BoardPost'][{u => r},e]
23
23
  when /universalhub/ # logo + trim spacehogging tagjunk
24
- c = Nokogiri::HTML.parse r[Content][0]
24
+ c = Nokogiri::HTML.fragment r[Content][0]
25
25
  c.css('section').map{|x|x.remove}
26
26
  {c: [{_: :a, href: r['http://purl.org/rss/1.0/link'][0].E.uri,
27
27
  c: [{_: :img, src: '/logos/uhub.png',style: 'position:absolute;top:-93px'},
@@ -27,8 +27,8 @@ class E
27
27
  # triplr/view mappings
28
28
  [ma,mt].map{|m|
29
29
  MIMEsource[m] ||= [:triplrSourceCode]
30
+ fn 'view/'+m, F['view/code']}}
30
31
 
31
- fn 'view/'+m, F['view/code']
32
- }}
32
+ MIMEsource['text/css'] ||= [:triplrSourceCode] # i hear CSS is Turing complete now, http://inamidst.com/whits/2014/formats
33
33
 
34
34
  end
@@ -1,7 +1,6 @@
1
1
  class E
2
2
 
3
3
  FSbase = `pwd`.chomp ; BaseLen = FSbase.size
4
- URIURL = '/@' # non-HTTP URI path resolution-prefix
5
4
  S = /\._/ # data path-separator
6
5
 
7
6
  W3 = 'http://www.w3.org/'
@@ -15,23 +14,24 @@ class E
15
14
  DC = Purl + 'dc/terms/'
16
15
  Date = DC + 'date'
17
16
  Title = DC + 'title'
18
- Name = FOAF + 'name'
17
+ Name = SIOC + 'name'
19
18
  To = SIOC + 'addressed_to'
20
19
  Creator = SIOC + 'has_creator'
21
20
  Content = SIOC + 'content'
22
21
  XHV = W3 + '1999/xhtml/vocab#'
23
22
  RDFns = W3 + "1999/02/22-rdf-syntax-ns#"
23
+ RDFs = W3 + '2000/01/rdf-schema#'
24
+ # RDFns = W3 + 'ns/rdf#'
25
+ # RDFs = W3 + 'ns/rdfs#'
24
26
  EXIF = W3 + '2003/12/exif/ns#'
25
27
  WF = W3 + '2005/01/wf/flow#'
26
28
  HTTP = W3 + '2011/http#'
27
29
  Header = W3 + '2011/http-headers#'
28
30
  LDP = W3 + 'ns/ldp#'
29
- Next = LDP+'nextPage'
30
- Prev = LDP+'prevPage'
31
+ Next = LDP + 'nextPage'
32
+ Prev = LDP + 'prevPage'
31
33
  Posix = W3 + 'ns/posix/'
32
34
  Type = RDFns+ "type"
33
- # Type = W3 + "ns/rdf#type"
34
- RDFs = W3 + 'ns/rdfs#'
35
35
  PAC = DIG + '2008/PAC/ontology/pac#'
36
36
  COGS = Deri + 'cogs#'
37
37
  CSV = Deri + 'scsv#'
@@ -1,13 +1,36 @@
1
+ #watch __FILE__
1
2
  class E
2
3
 
3
4
  # CSV -> tripleStream
4
5
  def triplrCSV d
5
6
  d = @r.q['delim']||d
6
- open(node).readlines.map{|l|l.chomp.split(d) rescue []}.do{|t|
7
- t[0].do{|x|
8
- t[1..-1].each_with_index{|r,ow|r.each_with_index{|v,i|
9
- yield uri+'#r'+ow.to_s,x[i],v
7
+ open(node).readlines.map{|l|l.chomp.split(d) rescue []}.do{|lines|
8
+ lines[0].do{|fields| # ok, we have at least one line..
9
+ yield uri+'#', Type, E[CSV+'Table']
10
+ yield uri+'#', CSV+'rowCount', lines.size
11
+ yield uri+'#', COGS+'View', E[uri+'?view=csv']
12
+ lines[1..-1].each_with_index{|row,line|
13
+ row.each_with_index{|field,i|
14
+ id = uri + '#row:' + line.to_s
15
+ yield id, fields[i], field
16
+ yield id, Type, E[CSV+'Row']
10
17
  }}}}
11
18
  end
12
19
 
20
+ F['view/csv'] = -> d,e {
21
+ # ignore non-rows
22
+ d.delete_if{|s,r|
23
+ !(r.class==Hash &&
24
+ r[Type].do{|t|
25
+ t.class == Array &&
26
+ t.map(&:maybeURI).member?(CSV+'Row')})}
27
+ # done w/ the type-tag
28
+ d.values.map{|r|r.delete Type}
29
+
30
+ [F['view/p'][d,e],
31
+ {_: :style, c: 'table.tab .abbr, table.tab .scheme {display: inline}'}
32
+ ]}
33
+
34
+ F['view/'+CSV+'Row'] = NullView
35
+
13
36
  end