ontopia-tldr 0.0.1-java

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/ChangeLog ADDED
@@ -0,0 +1,7 @@
1
+ # markup: rd
2
+
3
+ = Revision history for ontopia-tldr
4
+
5
+ == 0.0.1 [2013-07-30]
6
+
7
+ * Birthday :-)
data/README ADDED
@@ -0,0 +1,112 @@
1
+ = ontopia-tldr - Tolog Document Retrieval with Ontopia
2
+
3
+ == VERSION
4
+
5
+ This documentation refers to ontopia-tldr version 0.0.1
6
+
7
+
8
+ == DESCRIPTION
9
+
10
+ Ontopia::TLDR is an attempt at bridging the gap between the worlds of formal
11
+ knowledge representation (ontologies, topic maps, etc.) and bibliographic document
12
+ retrieval (bibliographic databases). It allows for retrieving documents from
13
+ bibliographic databases (currently, only Midos[http://progris.de] databases are
14
+ supported) by means of tolog[http://ontopia.net/omnigator/docs/query/tutorial.html],
15
+ Ontopia's[http://ontopia.net] topic map query language.
16
+
17
+ === Deployment
18
+
19
+ Ontopia::TLDR comes as a Sinatra application, so all the standard deployment
20
+ options apply (rackup, Passenger[https://www.phusionpassenger.com/], etc.).
21
+ However, in order to allow for maximum flexibility, you need to supply your
22
+ own <tt>config.ru</tt> file; e.g. (see Ontopia::TLDR for available options):
23
+
24
+ require 'ontopia/tldr'
25
+
26
+ Ontopia::TLDR.set(
27
+ dbm_file: File.expand_path('../tldr.dbm', __FILE__),
28
+ xtm_file: File.expand_path('../tldr.xtm', __FILE__),
29
+
30
+ document_keys: %w[YOUR DOCUMENT KEYS],
31
+ topic_keys: %w[YOUR TOPIC KEYS],
32
+
33
+ title: 'YOUR TITLE'
34
+ )
35
+
36
+ run Ontopia::TLDR
37
+
38
+ Assuming the following directory layout:
39
+
40
+ /srv/tldr
41
+ |
42
+ +-- config.ru
43
+ |
44
+ +-- tldr.dbm
45
+ |
46
+ +-- tldr.xtm
47
+ |
48
+ +-- tmp/
49
+
50
+ Place your database and topic map files there and adjust their paths in the
51
+ <tt>config.ru</tt> file. The <tt>tmp/</tt> directory is used by Passenger
52
+ for the <tt>restart.txt</tt> file.
53
+
54
+ To deploy Ontopia::TLDR with Passenger on Apache, create a symlink in the
55
+ DocumentRoot pointing to the app's <tt>public/</tt> directory (this example
56
+ makes use of current_gem[http://blackwinter.github.com/current_gem]; adjust
57
+ the paths according to your environment):
58
+
59
+ /var/www
60
+ |
61
+ +-- tldr -> /usr/local/jruby/lib/ruby/gems/shared/current/ontopia-tldr/lib/ontopia/tldr/public
62
+
63
+ Then put the following snippet in Apache's VirtualHost configuration:
64
+
65
+ <VirtualHost *:80>
66
+ ...
67
+
68
+ RackBaseURI /tldr
69
+ <Directory /var/www/tldr>
70
+ Options -MultiViews
71
+ PassengerAppRoot /srv/tldr # <-- This (non-standard) line is important
72
+ </Directory>
73
+ </VirtualHost>
74
+
75
+
76
+ == SUPPORTED PLATFORMS
77
+
78
+ Ontopia::TLDR requires JRuby[http://jruby.org]. It has been tested with jruby
79
+ 1.7.4 (1.9.3p392) on OpenJDK 64-Bit Server VM 1.6.0_27-b27 [linux-amd64].
80
+
81
+
82
+ == LINKS
83
+
84
+ <b></b>
85
+ Documentation:: http://blackwinter.github.com/ontopia-tldr
86
+ Source code:: http://github.com/blackwinter/ontopia-tldr
87
+ RubyGem:: http://rubygems.org/gems/ontopia-tldr
88
+ Ontopia:: http://ontopia.net/
89
+ Demo:: http://ixtrieve.fh-koeln.de/ghn
90
+
91
+
92
+ == AUTHORS
93
+
94
+ * Jens Wille <mailto:jens.wille@gmail.com>
95
+
96
+
97
+ == LICENSE AND COPYRIGHT
98
+
99
+ Copyright (C) 2013 Jens Wille
100
+
101
+ ontopia-tldr is free software: you can redistribute it and/or modify it
102
+ under the terms of the GNU Affero General Public License as published by
103
+ the Free Software Foundation, either version 3 of the License, or (at your
104
+ option) any later version.
105
+
106
+ ontopia-tldr is distributed in the hope that it will be useful, but
107
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
108
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
109
+ License for more details.
110
+
111
+ You should have received a copy of the GNU Affero General Public License
112
+ along with ontopia-tldr. If not, see <http://www.gnu.org/licenses/>.
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require File.expand_path(%q{../lib/ontopia/tldr/version}, __FILE__)
2
+
3
+ begin
4
+ require 'hen'
5
+
6
+ Hen.lay! {{
7
+ :gem => {
8
+ :name => %q{ontopia-tldr},
9
+ :version => Ontopia::TLDR::VERSION,
10
+ :summary => %q{Tolog Document Retrieval with Ontopia.},
11
+ :author => %q{Jens Wille},
12
+ :email => %q{jens.wille@gmail.com},
13
+ :license => %q{AGPL},
14
+ :homepage => :blackwinter,
15
+ :platform => 'java',
16
+ :dependencies => %w[json ontopia-topicmaps ruby-nuggets sinatra],
17
+ :extra_files => FileList['*.sample', 'lib/ontopia/tldr/{public,views}/*'].to_a
18
+ }
19
+ }}
20
+ rescue LoadError => err
21
+ warn "Please install the `hen' gem. (#{err})"
22
+ end
data/config.ru.sample ADDED
@@ -0,0 +1,13 @@
1
+ require 'ontopia/tldr'
2
+
3
+ Ontopia::TLDR.set(
4
+ #xtm_file: '...',
5
+ #dbm_file: '...',
6
+
7
+ #document_keys: %w[...],
8
+ #topic_keys: %w[...],
9
+
10
+ #title: '...'
11
+ )
12
+
13
+ run Ontopia::TLDR
@@ -0,0 +1 @@
1
+ require 'ontopia/tldr'
@@ -0,0 +1,378 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # ontopia-tldr -- Tolog Document Retrieval with Ontopia. #
7
+ # #
8
+ # Copyright (C) 2013 Jens Wille #
9
+ # #
10
+ # ontopia-tldr is free software: you can redistribute it and/or modify it #
11
+ # under the terms of the GNU Affero General Public License as published by #
12
+ # the Free Software Foundation, either version 3 of the License, or (at your #
13
+ # option) any later version. #
14
+ # #
15
+ # ontopia-tldr is distributed in the hope that it will be useful, but WITHOUT #
16
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
17
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License #
18
+ # for more details. #
19
+ # #
20
+ # You should have received a copy of the GNU Affero General Public License #
21
+ # along with ontopia-tldr. If not, see <http://www.gnu.org/licenses/>. #
22
+ # #
23
+ ###############################################################################
24
+ #++
25
+
26
+ require 'json'
27
+ require 'sinatra/base'
28
+ require 'nuggets/midos'
29
+ require 'ontopia/topicmaps'
30
+
31
+ module Ontopia
32
+ class TLDR < Sinatra::Base
33
+
34
+ class << self
35
+
36
+ private
37
+
38
+ def jget(*a, &b)
39
+ jroute(:get, *a, &b)
40
+ end
41
+
42
+ def jpost(*a, &b)
43
+ jroute(:post, *a, &b)
44
+ end
45
+
46
+ def jroute(m, r, t, &b)
47
+ e = 'json'; e.prepend('.') unless r.end_with?('/')
48
+ send(m, "#{r}#{e}") { instance_eval(&b); do_json }
49
+ send(m, r, provides: :html) { instance_eval(&b); erb(t) }
50
+ send(m, r, provides: :json) { instance_eval(&b); do_json }
51
+ end
52
+
53
+ end
54
+
55
+ set :root, __FILE__.chomp('.rb')
56
+
57
+ set :otm do
58
+ @__otm__ ||= Ontopia::Topicmaps::Topicmap.new(settings.xtm_file).tap {
59
+ Ontopia::Topicmaps.default_stringifier = :id
60
+ }
61
+ end
62
+
63
+ set :dbm do
64
+ @__dbm__ ||= begin
65
+ dbm, topic_keys = {}, settings.topic_keys
66
+
67
+ topic_index = Hash.new { |h, k| h[k] = {} }
68
+ dbm.define_singleton_method(:topic_index) { topic_index }
69
+
70
+ Nuggets::Midos::Parser.parse_file(settings.dbm_file, settings.dbm_opts) { |id, doc|
71
+ unless (topics = doc.values_at(*topic_keys).compact).empty?
72
+ dbm[id] = doc
73
+ topics.flatten.each { |topic| topic_index[topic][id] = doc }
74
+ end
75
+ }
76
+
77
+ dbm
78
+ end
79
+ end
80
+
81
+ set :topics do
82
+ @__topics__ ||= settings.otm.topics(:name)
83
+ end
84
+
85
+ set :topic_index do
86
+ @__topic_index__ ||= settings.dbm.topic_index
87
+ end
88
+
89
+ set :document_keys, %w[]
90
+ set :topic_keys, %w[]
91
+
92
+ set :title, 'TLDR'
93
+
94
+ set :xtm_file, File.expand_path('../tldr.xtm', __FILE__)
95
+ set :dbm_file, File.expand_path('../tldr.dbm', __FILE__)
96
+ set :dbm_opts, { encoding: 'utf-8', vs: '|' }
97
+
98
+ set :tolog, <<-EOT
99
+ import "http://psi.ontopia.net/tolog/string/" as s
100
+ %s
101
+ select %s from %s?
102
+ EOT
103
+
104
+ set :title_topic, 'TOPIC'
105
+ set :title_query, 'YOUR QUERY'
106
+ set :title_rules, 'CUSTOM INFERENCE RULES (optional)'
107
+
108
+ set :tolog_sample, {
109
+ q: <<-EOT,
110
+ Production($_ : isProducing, $TOPIC : isProductOf),
111
+ topic-name($TOPIC, $PRODUCTNAME),
112
+ value($PRODUCTNAME, $PRODUCTSTRING),
113
+ s:contains($PRODUCTSTRING, "service")
114
+ EOT
115
+ r: <<-EOT
116
+ direct-narrower-term($A, $B) :-
117
+ HierarchicalRelation($A : broaderTermMember,
118
+ $B : narrowerTermMember).
119
+
120
+ strictly-narrower-term($A, $B) :- {
121
+ direct-narrower-term($A, $B) |
122
+ direct-narrower-term($A, $C), strictly-narrower-term($C, $B)
123
+ }.
124
+
125
+ narrower-term($A, $B) :- {
126
+ $A = $B | strictly-narrower-term($A, $B)
127
+ }.
128
+
129
+ narrower-term-1($A, $B) :- {
130
+ $A = $B | direct-narrower-term($A, $B)
131
+ }.
132
+
133
+ narrower-term-2($A, $B) :- {
134
+ narrower-term-1($A, $B) |
135
+ narrower-term-1($A, $C), narrower-term-1($C, $B)
136
+ }.
137
+
138
+ narrower-term-3($A, $B) :- {
139
+ narrower-term-2($A, $B) |
140
+ narrower-term-2($A, $C), narrower-term-1($C, $B)
141
+ }.
142
+
143
+ direct-broader-term($A, $B) :-
144
+ direct-narrower-term($B, $A).
145
+
146
+ strictly-broader-term($A, $B) :-
147
+ strictly-narrower-term($B, $A).
148
+
149
+ broader-term($A, $B) :-
150
+ narrower-term($B, $A).
151
+
152
+ broader-term-1($A, $B) :-
153
+ narrower-term-1($B, $A).
154
+
155
+ broader-term-2($A, $B) :-
156
+ narrower-term-2($B, $A).
157
+
158
+ broader-term-3($A, $B) :-
159
+ narrower-term-3($B, $A).
160
+ EOT
161
+ }
162
+
163
+ tolog_maps_base = <<-EOT
164
+ association-role($ASSOC, $ROLE),
165
+ association-role($ASSOC, $ROLE2),
166
+ role-player($ROLE, $TOPIC2),
167
+ role-player($ROLE2, $TOPIC),
168
+ type($ASSOC, $TYPE),
169
+ $TOPIC /= $TOPIC2
170
+ EOT
171
+
172
+ set :tolog_maps, {
173
+ relations: <<-EOT,
174
+ select $TYPE, $ROLE, $TOPIC from
175
+ #{tolog_maps_base}, $TOPIC2 = %s?
176
+ EOT
177
+ roles: <<-EOT,
178
+ select $ROLE, $TOPIC from
179
+ #{tolog_maps_base}, type($ASSOC, %s)?
180
+ EOT
181
+ types: <<-EOT
182
+ select $TYPE, $TOPIC from
183
+ #{tolog_maps_base}, type($ROLE, %s)?
184
+ EOT
185
+ }
186
+
187
+ helpers ERB::Util
188
+
189
+ not_found do
190
+ @error = 'Not found!'
191
+ erb ''
192
+ end
193
+
194
+ get '/' do
195
+ erb :index
196
+ end
197
+
198
+ jpost '/', :index do
199
+ @query = params[:q]
200
+ @rules = params[:r] || ''
201
+ @param = params[:p] || TITLE_TOPIC
202
+
203
+ if !@query || @query.strip.empty?
204
+ @error = 'Query missing!'
205
+ elsif !@param || @param.strip.empty? || @param =~ /\W/
206
+ @error = 'Invalid projection!'
207
+ elsif (@topics = get_topics).empty?
208
+ @topics = nil
209
+ elsif (@documents = get_documents).empty?
210
+ @documents = nil
211
+ else
212
+ @filter = :documents
213
+ end
214
+ end
215
+
216
+ get '/xtm' do
217
+ do_file(settings.xtm_file, 'xml')
218
+ end
219
+
220
+ jget '/topics', :topics do
221
+ @title = "Topics (#{settings.topics.size})"
222
+ @topics, @filter = settings.topics.keys, :topics
223
+ end
224
+
225
+ jget '/topic/:i', :topic do
226
+ @title = topic_to_s(@topic = params[:i])
227
+ not_found unless settings.topics.include?(@topic)
228
+
229
+ @documents, @filter = settings.topic_index[@topic], :documents
230
+ @relations, @roles, @types = {}, {}, {}
231
+
232
+ get_topic_maps(:relations)
233
+ get_topic_maps(:roles) if @relations.empty?
234
+ get_topic_maps(:types) if @roles.empty?
235
+ end
236
+
237
+ get '/dbm' do
238
+ do_file(settings.dbm_file, 'txt')
239
+ end
240
+
241
+ jget '/documents', :documents do
242
+ @title = "Documents (#{settings.dbm.size})"
243
+ @documents, @filter = settings.dbm, :documents
244
+ end
245
+
246
+ jget '/document/:i', :document do
247
+ @title = "##{@id = params[:i].to_i}"
248
+ not_found unless @document = settings.dbm[@id]
249
+ end
250
+
251
+ private
252
+
253
+ def do_json
254
+ content_type :json
255
+
256
+ JSON.fast_generate({
257
+ d: @document || @documents,
258
+ e: @error,
259
+ i: @id,
260
+ l: @relations,
261
+ o: @roles,
262
+ p: @param,
263
+ q: @query,
264
+ r: @rules,
265
+ t: @topic || @topics,
266
+ y: @types
267
+ }.delete_if { |_, v| !v })
268
+ end
269
+
270
+ def do_file(file, type)
271
+ File.readable?(file) ? send_file(file, type: type) : not_found
272
+ end
273
+
274
+ def get_topics(query = @query, param = @param, rules = @rules)
275
+ settings.otm.query(settings.tolog % [rules, "$#{param}", query])
276
+ rescue => err
277
+ @error = err.to_s
278
+ []
279
+ end
280
+
281
+ def get_topic_maps(name, topic = @topic, hash = nil, str = nil)
282
+ hash ||= instance_variable_get("@#{name}")
283
+ str ||= Ontopia::Topicmaps.id_stringifier
284
+
285
+ query = settings.tolog_maps[name] % topic
286
+ keys = settings.otm.extract_query_projection(query)
287
+
288
+ settings.otm.query_maps(query).each { |map|
289
+ values = map.values_at(*keys).map!(&str)
290
+ topic, key = values.pop, values.pop
291
+
292
+ (values.inject(hash) { |h, k| h[k] ||= {} }[key] ||= []) << topic
293
+ }
294
+ rescue => err
295
+ @error = err.to_s
296
+ end
297
+
298
+ def get_documents(topics = @topics)
299
+ settings.topic_index.values_at(*topics).compact.inject(&:merge)
300
+ end
301
+
302
+ def render_topics(topics = @topics)
303
+ _ul(topics.sort, id: :topics) { |topic|
304
+ _li(link_to_topic(topic), ' (', settings.topic_index[topic].size, ')')
305
+ }
306
+ end
307
+
308
+ def render_documents(documents = @documents)
309
+ _ul(documents.sort_by { |k,| k }, id: :documents) { |id, doc|
310
+ _li(link_to_document(id, doc))
311
+ }
312
+ end
313
+
314
+ def render_topics_hash(hash)
315
+ _ul(hash.map { |k, v| [topic_to_s(k), k, v] }.sort) { |name, key, value|
316
+ _li(link_to_topic(key, name),
317
+ value.is_a?(Hash) ? render_topics_hash(value) :
318
+ _ul(value.sort.uniq) { |topic| _li(link_to_topic(topic)) })
319
+ }
320
+ end
321
+
322
+ def topic_to_s(topic)
323
+ h(settings.topics[topic] || topic.tr('_', ' '))
324
+ end
325
+
326
+ def doc_to_s(id, doc)
327
+ a, t, u, y = doc.values_at(*settings.document_keys)
328
+
329
+ a = a.join('; ') if a.is_a?(Array)
330
+ s = [a, t].compact.join(': ')
331
+
332
+ if s.empty?
333
+ s = "##{id}"
334
+ elsif u
335
+ s << " – #{u}"
336
+ end
337
+
338
+ s << " (#{y})" if y
339
+
340
+ h(s)
341
+ end
342
+
343
+ def link_to_topic(topic, text = topic_to_s(topic))
344
+ _a(text, href: url("/topic/#{h(topic)}"))
345
+ end
346
+
347
+ def link_to_document(id, doc)
348
+ _a(doc_to_s(id, doc), href: url("/document/#{h(id)}"))
349
+ end
350
+
351
+ def _a(*args)
352
+ _tag(:a, *args)
353
+ end
354
+
355
+ def _ul(list, *args)
356
+ _tag(:ul, *args) { |t| list.each { |*i| t << yield(*i) } }
357
+ end
358
+
359
+ def _li(*args)
360
+ _tag(:li, *args)
361
+ end
362
+
363
+ def _tag(name, *args)
364
+ a = args.pop.map { |k, v| %Q{#{h(k)}="#{h(v)}"} } if args.last.is_a?(Hash)
365
+
366
+ t = ["<#{name}#{a.unshift(nil).join(' ') if a}>"]
367
+
368
+ args.each { |s| t << s }
369
+ yield t if block_given?
370
+
371
+ t << "</#{name}>"
372
+ t.join
373
+ end
374
+
375
+ end
376
+ end
377
+
378
+ require_relative 'tldr/version'