ttl2html 3.1.0 → 3.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7254a4cc200e719bbb09c33d88dea4a22a8360e1c6453085f5331d541320b82
4
- data.tar.gz: 43385ec41709d6b8a552dfe7bb2c2d7186b1142b0655bd8480b2fc0b91b336d8
3
+ metadata.gz: 179d7c92158302822e387bc70e386abc8ebc592c36b2ddf675f52471fda5a087
4
+ data.tar.gz: 3d8a36b2de920b07401a7360b11bdb501c0dfa41ffcae314746919d703d415da
5
5
  SHA512:
6
- metadata.gz: 0be4d1d1550a1eb410ffb8747eeffbd8b3154a297966cb99cde5ecb6c249973a8c345e88b01ab8cd7c1c791064ea78b6708ad7bc1579231b2f5424b8643af709
7
- data.tar.gz: a5ec01247b296e2be84d110e4742412152465f9925223950211ca99a5c9f6112ebe81820fa6a422589f8cf45f5d41ecfb3b619c33e833694b9811cb80fb86541
6
+ metadata.gz: fa1f3bf8f3e62ae2a73474b2469a86818af359f1ce67797f1f29f2738577b9edc12b9d2a91aada8c6d381404518815a33abb830186df2a722e488e80cb49848a
7
+ data.tar.gz: 1084e5c116dac281ec54a4ab79bedf13a545cb989ada95294d937deae6fdfd4663b52eb251927a4b1fea8f79012a46408235887b8ca7bcfeda026727d9bbe2ec
@@ -24,8 +24,7 @@ module TTL2HTML
24
24
  def output_to(file, param = {})
25
25
  param = @param.merge(param)
26
26
  param[:output_file] = file
27
- dir = File.dirname(file)
28
- FileUtils.mkdir_p(dir) if not File.exist?(dir)
27
+ FileUtils.mkdir_p(File.dirname(file))
29
28
  File.open(file, "w") do |io|
30
29
  io.print to_html(param)
31
30
  end
@@ -41,7 +40,9 @@ module TTL2HTML
41
40
  tmpl = File.open(template) { |io| io.read }
42
41
  erb = ERB.new(tmpl, trim_mode: "-")
43
42
  erb.filename = template
44
- erb.result(binding)
43
+ I18n.with_locale(@param[:locale] || I18n.default_locale) do
44
+ erb.result(binding)
45
+ end
45
46
  end
46
47
 
47
48
  def find_template_path(fname)
@@ -51,14 +52,15 @@ module TTL2HTML
51
52
  end
52
53
  @template_path.each do |dir|
53
54
  file = File.join(dir, fname)
54
- return file if File.exist? file
55
+ return file if File.file? file
55
56
  end
56
- return nil
57
+ nil
57
58
  end
58
59
 
59
- def expand_shape(data, uri, prefixes = {})
60
+ def expand_shape(data, uri, prefixes = {}, depth = 0)
60
61
  return nil if not data[uri]
61
62
  return nil if not data[uri]["http://www.w3.org/ns/shacl#property"]
63
+ return nil if depth > 10
62
64
  prefix_used = {}
63
65
  result = data[uri]["http://www.w3.org/ns/shacl#property"].sort_by do |e|
64
66
  e["http://www.w3.org/ns/shacl#order"]
@@ -87,23 +89,35 @@ module TTL2HTML
87
89
  node_or = data[data[node]["http://www.w3.org/ns/shacl#or"].first]
88
90
  node_mode = :or
89
91
  nodes = []
90
- nodes << expand_shape(data, node_or["http://www.w3.org/1999/02/22-rdf-syntax-ns#first"].first, prefixes)
92
+ nodes << expand_shape(data, node_or["http://www.w3.org/1999/02/22-rdf-syntax-ns#first"].first, prefixes, depth + 1)
91
93
  rest = node_or["http://www.w3.org/1999/02/22-rdf-syntax-ns#rest"].first
92
94
  while data[rest] do
93
- nodes << expand_shape(data, data[rest]["http://www.w3.org/1999/02/22-rdf-syntax-ns#first"].first, prefixes)
95
+ nodes << expand_shape(data, data[rest]["http://www.w3.org/1999/02/22-rdf-syntax-ns#first"].first, prefixes, depth + 1)
94
96
  rest = data[rest]["http://www.w3.org/1999/02/22-rdf-syntax-ns#rest"].first
95
97
  end
96
98
  else
97
- nodes = expand_shape(data, node, prefixes)
99
+ nodes = expand_shape(data, node, prefixes, depth + 1)
98
100
  end
99
101
  #p nodes
100
102
  end
103
+ example = data[property]["http://www.w3.org/2004/02/skos/core#example"].first if data[property]["http://www.w3.org/2004/02/skos/core#example"]
104
+ if example.respond_to?(:datatype) and example.datatype?
105
+ datatype = example.datatype.pname or example.datatype.to_s
106
+ example = example.to_s + "<span class=\"datatype\">^^" + example.datatype.pname + "</span>"
107
+ end
108
+ descriptions = [ get_language_literal(data[property]["http://www.w3.org/ns/shacl#description"]) ]
109
+ if data[property]["http://www.w3.org/ns/shacl#datatype"]
110
+ datatypes = data[property]["http://www.w3.org/ns/shacl#datatype"].map do |datatype|
111
+ datatype.to_s.sub(%r{\Ahttp://www\.w3\.org/2001/XMLSchema#}, 'xsd:')
112
+ end.join(", ")
113
+ descriptions << t('shape-table.datatype') + datatypes
114
+ end
101
115
  {
102
116
  path: path,
103
117
  shorten_path: shorten_path,
104
118
  name: get_language_literal(data[property]["http://www.w3.org/ns/shacl#name"]),
105
- example: data[property]["http://www.w3.org/2004/02/skos/core#example"] ? data[property]["http://www.w3.org/2004/02/skos/core#example"].first : nil,
106
- description: get_language_literal(data[property]["http://www.w3.org/ns/shacl#description"]),
119
+ example: example,
120
+ description: descriptions.compact.join("<br>"),
107
121
  required: data[property]["http://www.w3.org/ns/shacl#minCount"] ? data[property]["http://www.w3.org/ns/shacl#minCount"].first.to_i > 0 : false,
108
122
  repeatable: repeatable,
109
123
  nodeKind: data[property]["http://www.w3.org/ns/shacl#nodeKind"] ? data[property]["http://www.w3.org/ns/shacl#nodeKind"].first : nil,
@@ -114,8 +128,7 @@ module TTL2HTML
114
128
  }
115
129
  end
116
130
  template = "shape-table.html.erb"
117
- tmpl = Template.new(template)
118
- tmpl.to_html_raw(template, { properties: result, prefix: prefix_used })
131
+ to_html_raw(template, { properties: result, prefix: prefix_used })
119
132
  end
120
133
 
121
134
  # helper method:
@@ -126,9 +139,15 @@ module TTL2HTML
126
139
  if dest_uri.absolute?
127
140
  path = dest
128
141
  else
129
- src = Pathname.new(src).relative_path_from(Pathname.new(@param[:output_dir])) if @param[:output_dir]
142
+ dest.sub!(/^\/+/, "")
143
+ #p [:relative_path, src, dest]
144
+ if @param[:output_dir]
145
+ src = Pathname.new(src).relative_path_from(Pathname.new(@param[:output_dir]))
146
+ else
147
+ src = Pathname.new(File.expand_path(src)).relative_path_from(Pathname.new(File.expand_path(".")))
148
+ end
130
149
  path = Pathname(dest).relative_path_from(Pathname(File.dirname src))
131
- if @param[:output_dir] and File.directory?(Pathname.new(@param[:output_dir]) + path)
150
+ if @param[:output_dir] and File.directory?(File.join(@param[:output_dir], path))
132
151
  path = path.to_s + "/"
133
152
  elsif File.directory?(path)
134
153
  path = path.to_s + "/"
@@ -210,6 +229,7 @@ module TTL2HTML
210
229
  type = param[:type] || {}
211
230
  data = param[:data] || {}
212
231
  if /\Ahttps?:\/\// =~ object.to_s
232
+ #p [:format_object_uri, param[:output_file], object]
213
233
  rel_path = relative_path_uri(param[:output_file], object)
214
234
  if param[:data_global][object]
215
235
  result = "<a href=\"#{rel_path}\">#{get_title(param[:data_global][object]) or ERB::Util.html_escape(object)}</a>"
@@ -313,6 +333,7 @@ module TTL2HTML
313
333
  "http://www.w3.org/2000/01/rdf-schema#label",
314
334
  "http://purl.org/dc/terms/title",
315
335
  "http://purl.org/dc/elements/1.1/title",
336
+ "https://schema.org/name",
316
337
  "http://schema.org/name",
317
338
  "http://www.w3.org/2004/02/skos/core#prefLabel"
318
339
  ].each do |prop|
@@ -331,6 +352,7 @@ module TTL2HTML
331
352
  results = []
332
353
  [
333
354
  "http://purl.org/linked-data/cube#order",
355
+ "https://schema.org/position",
334
356
  "http://schema.org/position",
335
357
  ].each do |order_elem|
336
358
  if resource and resource[order_elem]
data/lib/ttl2html/util.rb CHANGED
@@ -42,6 +42,23 @@ module TTL2HTML
42
42
  path << suffix
43
43
  #p [uri, path]
44
44
  path
45
- end
45
+ end
46
+ def safe_output_path(file)
47
+ base = if @config[:output_dir]
48
+ File.expand_path(@config[:output_dir])
49
+ else
50
+ File.expand_path(".")
51
+ end
52
+ target = File.expand_path(file)
53
+ unless target == base || target.start_with?(base + File::SEPARATOR)
54
+ if @config[:output_dir]
55
+ warn "Attempting to write outside of output_dir: #{file}"
56
+ else
57
+ warn "Attempting to write outside of current directory: #{file}"
58
+ end
59
+ return nil
60
+ end
61
+ target
62
+ end
46
63
  end
47
- end
64
+ end
@@ -1 +1 @@
1
- TTL2HTML::VERSION = "3.1.0"
1
+ TTL2HTML::VERSION = "3.2.0"
data/lib/ttl2html.rb CHANGED
@@ -72,42 +72,60 @@ module TTL2HTML
72
72
  $stderr.puts "#{count} triples. #{subjects.size} subjects."
73
73
  @data
74
74
  end
75
+
76
+ QB_ORDER_URI = "http://purl.org/linked-data/cube#order"
77
+ SCHEMA_POSITION_URI = "http://schema.org/position"
78
+ SCHEMA_POSITION_URI_S = "https://schema.org/position"
79
+ SHACL_ORDER_URI = "http://www.w3.org/ns/shacl#order"
80
+ def sort_key_for_resource(resource)
81
+ qb_order = Float::INFINITY
82
+ schema_position = Float::INFINITY
83
+ shacl_order = Float::INFINITY
84
+ if @data[resource.to_s]
85
+ qb_order = @data[resource.to_s][QB_ORDER_URI].first.to_i if @data[resource.to_s][QB_ORDER_URI]
86
+ schema_position = @data[resource.to_s][SCHEMA_POSITION_URI].first.to_i if @data[resource.to_s][SCHEMA_POSITION_URI]
87
+ schema_position = @data[resource.to_s][SCHEMA_POSITION_URI_S].first.to_i if @data[resource.to_s][SCHEMA_POSITION_URI_S]
88
+ shacl_order = @data[resource.to_s][SHACL_ORDER_URI].first.to_i if @data[resource.to_s][SHACL_ORDER_URI]
89
+ end
90
+ if resource.to_s =~ /^_:/ and @data[resource.to_s]
91
+ resource_str = "{" + @data[resource.to_s].sort_by do |p, o|
92
+ [p, o]
93
+ end.join("\t") + "}"
94
+ [ schema_position, qb_order, shacl_order, resource_str ]
95
+ else
96
+ [ schema_position, qb_order, shacl_order, resource.to_s ]
97
+ end
98
+ end
99
+ def format_uri(uri, writer = RDF::Turtle::Writer.new(nil, prefixes: @prefix))
100
+ result = writer.format_uri(RDF::URI(uri))
101
+ if result =~ /^#{RDF::Turtle::Terminals::PN_PREFIX}?:/
102
+ @used_prefixes << result.split(":").first
103
+ end
104
+ result
105
+ end
75
106
  def format_turtle(subject, depth = 1, force = false)
76
- turtle = RDF::Turtle::Writer.new
107
+ turtle_writer = RDF::Turtle::Writer.new(nil, prefixes: @prefix)
77
108
  result = ""
78
109
  #p [:format_turtle, subject, depth, force]
79
110
  return result if !force && @cache[:output_turtle_files].include?(subject)
80
111
  if subject =~ /^_:/
81
112
  result << "[\n#{" "*depth}"
82
113
  else
83
- result << "<#{subject}>\n#{" "*depth}"
114
+ result << format_uri(subject) << "\n#{" "*depth}"
84
115
  end
85
116
  result << @data[subject.to_s].keys.sort.map do |predicate|
86
- str = "<#{predicate}> "
117
+ str = format_uri(predicate, turtle_writer) << " "
87
118
  #p [subject, predicate, @data[subject.to_s][predicate]]
88
119
  str << @data[subject.to_s][predicate].sort_by do |object|
89
120
  #p [subject, predicate, object, depth]
90
- if object.to_s =~ /^_:/ and @data[object.to_s]
91
- qb_order = "http://purl.org/linked-data/cube#order"
92
- schema_position = "http://schema.org/position"
93
- shacl_order = "http://www.w3.org/ns/shacl#order"
94
- [ @data[object.to_s][schema_position] ? @data[object.to_s][schema_position].first.to_i : Float::INFINITY,
95
- @data[object.to_s][qb_order] ? @data[object.to_s][qb_order].first.to_i : Float::INFINITY,
96
- @data[object.to_s][shacl_order] ? @data[object.to_s][shacl_order].first.to_i : Float::INFINITY,
97
- format_turtle(object, depth + 1, true)
98
- ]
99
- else
100
- [Float::INFINITY, Float::INFINITY, Float::INFINITY, object.to_s]
101
- end
121
+ sort_key_for_resource(object)
102
122
  end.map do |object|
103
123
  if /^_:/ =~ object.to_s # blank node:
104
124
  format_turtle(object, depth + 1, force)
105
125
  elsif RDF::URI::IRI =~ object.to_s
106
- turtle.format_uri(RDF::URI.new object)
107
- elsif object.respond_to?(:first) and object.first.kind_of?(Symbol)
108
- turtle.format_literal(RDF::Literal.new(object[1], language: object[0]))
126
+ format_uri(object, turtle_writer)
109
127
  else
110
- turtle.format_literal(object)
128
+ turtle_writer.format_literal(object)
111
129
  end
112
130
  end.join(", ")
113
131
  str
@@ -129,27 +147,37 @@ module TTL2HTML
129
147
  end.join
130
148
  end
131
149
  def collect_inverse_triples(object, triples = Set.new, visited = Set.new)
132
- return triples if object.to_s.start_with?("_:")
133
- return triples unless object.to_s.start_with?(@config[:base_uri].to_s)
134
- return triples unless @data_inverse.key?(object.to_s)
135
150
  return triples if visited.include?(object.to_s)
136
151
  visited << object.to_s
137
- @data_inverse[object.to_s].each do |predicate, subjects|
138
- subjects.each do |subject|
139
- triples << [subject.to_s, predicate.to_s, object.to_s]
140
- collect_inverse_triples_for_bnode(subject.to_s, triples, visited) if subject.to_s.start_with?("_:")
152
+ if @data_inverse.key?(object.to_s)
153
+ @data_inverse[object.to_s].each do |predicate, subjects|
154
+ subjects.each do |subject|
155
+ triples << [subject.to_s, predicate.to_s, object.to_s]
156
+ collect_inverse_triples_for_bnode(subject.to_s, triples, visited) if subject.to_s.start_with?("_:")
157
+ end
141
158
  end
142
159
  end
143
160
  triples
144
161
  end
145
162
  def collect_inverse_triples_for_bnode(node, triples, visited)
146
- return triples unless @data_inverse.key?(node)
147
163
  return triples if visited.include?(node)
148
164
  visited << node
149
- @data_inverse[node].each do |predicate, subjects|
150
- subjects.each do |subject|
165
+ if @data.key?(node)
166
+ @data[node].each do |predicate, objects|
167
+ objects.each do |object|
168
+ triples << [node, predicate.to_s, object]
169
+ if object.to_s.start_with?("_:")
170
+ collect_inverse_triples_for_bnode(object.to_s, triples, visited)
171
+ end
172
+ end
173
+ end
174
+ end
175
+ if @data_inverse.key?(node)
176
+ @data_inverse[node].each do |predicate, subjects|
177
+ subjects.each do |subject|
151
178
  triples << [subject.to_s, predicate.to_s, node]
152
179
  collect_inverse_triples_for_bnode(subject.to_s, triples, visited) if subject.to_s.start_with?("_:")
180
+ end
153
181
  end
154
182
  end
155
183
  triples
@@ -174,13 +202,15 @@ module TTL2HTML
174
202
  def find_inverse_roots(by_subject)
175
203
  all_subjects = by_subject.keys
176
204
  all_objects = by_subject.values.flat_map { |preds| preds.values.flatten }.uniq
177
- all_subjects.reject do |subject|
178
- subject.start_with?("_:") || all_objects.include?(subject)
179
- end.sort
205
+ roots = all_subjects.reject do |subject|
206
+ all_objects.include?(subject)
207
+ end
208
+ roots.sort_by { |subject| sort_key_for_resource(subject) }
180
209
  end
181
210
  def format_inverse_subject(subject, by_subject, ref_count, visited, depth = 1)
211
+ turtle_writer = RDF::Turtle::Writer.new(nil, prefixes: @prefix)
182
212
  props = by_subject[subject]
183
- return format_node(subject) if props.nil? || props.empty?
213
+ return format_node(subject, turtle_writer) if props.nil? || props.empty?
184
214
  indent = " " * (depth - 1)
185
215
  inner = " " * depth
186
216
  if subject.start_with?("_:")
@@ -190,18 +220,18 @@ module TTL2HTML
190
220
  head = "[\n#{inner}"
191
221
  tail = "\n#{indent}]"
192
222
  else
193
- head = "<#{subject}> "
223
+ head = format_uri(subject, turtle_writer) << " "
194
224
  tail = ""
195
225
  end
196
226
  body = props.keys.sort.map do |predicate|
197
227
  objects = props[predicate].sort.map do |object|
198
- format_inverse_object(object, by_subject, ref_count, visited, depth + 1)
228
+ format_inverse_object(object, by_subject, ref_count, visited, depth + 1, turtle_writer)
199
229
  end.join(", ")
200
- "<#{predicate}> #{objects}"
230
+ format_uri(predicate, turtle_writer) << " " << objects
201
231
  end.join(";\n#{inner}")
202
232
  head + body + tail
203
233
  end
204
- def format_inverse_object(object, by_subject, ref_count, visited, depth = 1)
234
+ def format_inverse_object(object, by_subject, ref_count, visited, depth = 1, turtle_writer = RDF::Turtle::Writer.new(nil, prefixes: @prefix))
205
235
  if object.to_s.start_with?("_:") && by_subject.key?(object.to_s)
206
236
  if ref_count[object.to_s] <= 1
207
237
  format_inverse_subject(object.to_s, by_subject, ref_count, visited, depth)
@@ -209,19 +239,16 @@ module TTL2HTML
209
239
  object.to_s
210
240
  end
211
241
  else
212
- format_node(object)
242
+ format_node(object, turtle_writer)
213
243
  end
214
244
  end
215
- def format_node(value)
216
- turtle = RDF::Turtle::Writer.new
245
+ def format_node(value, writer = RDF::Turtle::Writer.new(nil, prefixes: @prefix))
217
246
  if value.to_s.start_with?("_:")
218
247
  value.to_s
219
248
  elsif RDF::URI::IRI =~ value.to_s
220
- "<#{value}>"
221
- elsif value.respond_to?(:first) && value.first.kind_of?(Symbol)
222
- turtle.format_literal(RDF::Literal.new(value[1], language: value[0]))
249
+ format_uri(value, writer)
223
250
  else
224
- turtle.format_literal(value)
251
+ writer.format_literal(value)
225
252
  end
226
253
  end
227
254
 
@@ -234,8 +261,8 @@ module TTL2HTML
234
261
  data = @data.keys.sort_by do|uri|
235
262
  local_path = uri_mapping_to_path(uri, @config, ".html")
236
263
  #p [ local_path.size, local_path.count("/"), local_path ]
237
- [ local_path.size, local_path.count("/"), local_path ]
238
- end.reverse
264
+ [ -(local_path.count("/")), -(local_path.size), local_path ]
265
+ end
239
266
  Parallel.each(data, progress: progressbar_options) do |uri|
240
267
  next if not uri.start_with? @config[:base_uri]
241
268
  yield uri, @data[uri]
@@ -266,7 +293,7 @@ module TTL2HTML
266
293
  end
267
294
  end
268
295
  @config[:orders_with_class] = shapes2orders(shapes)
269
- Dir.mkdir @config[:output_dir] if @config[:output_dir] and not File.exist? @config[:output_dir]
296
+ FileUtils.mkdir_p(@config[:output_dir]) if @config[:output_dir]
270
297
  template = Template.new("default.html.erb", @config)
271
298
  each_data(:output_html_files) do |uri, v|
272
299
  param = @config.dup
@@ -288,11 +315,14 @@ module TTL2HTML
288
315
  if @config[:output_dir]
289
316
  file = File.join(@config[:output_dir], file)
290
317
  end
291
- if template.find_template_path("_default.html.erb")
292
- param[:additional_content] = template.to_html_raw("_default.html.erb", param)
318
+ file = safe_output_path(file)
319
+ if file
320
+ if template.find_template_path("_default.html.erb")
321
+ param[:additional_content] = template.to_html_raw("_default.html.erb", param)
322
+ end
323
+ param[:about_file] = about_file if about_required
324
+ template.output_to(file, param)
293
325
  end
294
- param[:about_file] = about_file if about_required
295
- template.output_to(file, param)
296
326
  end
297
327
  index_html = "index.html"
298
328
  index_html = File.join(@config[:output_dir], "index.html") if @config[:output_dir]
@@ -315,7 +345,9 @@ module TTL2HTML
315
345
  param[:versions] = versions
316
346
  param[:toplevel] = toplevel
317
347
  param[:description] = template.to_html_raw("description.html", {}) if template.find_template_path("description.html")
318
- subjects.sort.each do |subject|
348
+ subjects.sort_by do |subject|
349
+ sort_key_for_resource(subject)
350
+ end.each do |subject|
319
351
  objects = []
320
352
  if @config.has_key? :top_additional_property
321
353
  @config[:top_additional_property].each do |property|
@@ -332,7 +364,8 @@ module TTL2HTML
332
364
  param[:output_file] = index_html
333
365
  param[:index_list] = template.to_html_raw("index-list.html.erb", param)
334
366
  param[:about_file] = about_file if about_required
335
- template.output_to(index_html, param)
367
+ index_html = safe_output_path(index_html)
368
+ template.output_to(index_html, param) if index_html
336
369
  end
337
370
  end
338
371
  if about_required
@@ -377,7 +410,8 @@ module TTL2HTML
377
410
  order: orders,
378
411
  }
379
412
  end
380
- template.output_to(about_html, param)
413
+ about_html = safe_output_path(about_html)
414
+ template.output_to(about_html, param) if about_html
381
415
  end
382
416
  end
383
417
 
@@ -609,20 +643,29 @@ module TTL2HTML
609
643
  end
610
644
 
611
645
  def output_turtle_files
612
- Dir.mkdir @config[:output_dir] if @config[:output_dir] and not File.exist? @config[:output_dir]
646
+ FileUtils.mkdir_p(@config[:output_dir]) if @config[:output_dir]
613
647
  each_data(:output_turtle_files) do |uri, v|
614
648
  file = uri_mapping_to_path(uri, @config, ".ttl")
615
649
  if @config[:output_dir]
616
- Dir.mkdir @config[:output_dir] if not File.exist? @config[:output_dir]
617
650
  file = File.join(@config[:output_dir], file)
618
651
  end
652
+ file = safe_output_path(file)
653
+ next if not file
619
654
  dir = File.dirname(file)
620
655
  FileUtils.mkdir_p(dir) if not File.exist?(dir)
621
656
  @cache ||= {}
622
657
  @cache[:output_turtle_files] = Set.new
658
+ @used_prefixes = Set.new
623
659
  str = format_turtle(uri)
624
660
  str << format_turtle_inverse(uri)
625
- open(file, "w") do |io|
661
+ File.open(file, "w") do |io|
662
+ @used_prefixes.each do |prefix|
663
+ if prefix.empty?
664
+ io.puts "@prefix : <#{@prefix[nil]}>."
665
+ else
666
+ io.puts "@prefix #{prefix}: <#{@prefix[prefix.to_sym]}>."
667
+ end
668
+ end
626
669
  io.puts str.strip
627
670
  end
628
671
  end
@@ -642,30 +685,42 @@ module TTL2HTML
642
685
  end.each do |uri, v|
643
686
  html_file = uri_mapping_to_path(uri, @config, ".html")
644
687
  html_file = File.join(@config[:output_dir], html_file) if @config[:output_dir]
645
- dirs << File.dirname(html_file)
646
- File.unlink html_file if File.exist? html_file
688
+ html_file = safe_output_path(html_file)
689
+ if html_file and File.file? html_file
690
+ dirs << File.dirname(html_file)
691
+ File.unlink html_file
692
+ end
647
693
  ttl_file = uri_mapping_to_path(uri, @config, ".ttl")
648
694
  ttl_file = File.join(@config[:output_dir], ttl_file) if @config[:output_dir]
649
- File.unlink ttl_file if File.exist? ttl_file
650
- dir = uri.sub(@config[:base_uri], "")
651
- dir = File.join(@config[:output_dir], dir) if @config[:output_dir]
652
- dirs << dir
695
+ ttl_file = safe_output_path(ttl_file)
696
+ if ttl_file and File.file? ttl_file
697
+ dirs << File.dirname(ttl_file)
698
+ File.unlink ttl_file
699
+ end
653
700
  end
654
701
  index_html = "index.html"
655
702
  index_html = File.join(@config[:output_dir], "index.html") if @config[:output_dir]
656
- if @config[:top_class] and File.exist? index_html
703
+ index_html = safe_output_path(index_html)
704
+ if index_html and @config[:top_class] and File.file? index_html
657
705
  File.unlink index_html
658
706
  end
659
707
  about_html = (@config[:about_file] || "about.html")
660
708
  about_html = File.join(@config[:output_dir], about_html) if @config[:output_dir]
661
- File.unlink about_html if File.exist? about_html
709
+ about_html = safe_output_path(about_html)
710
+ if about_html and File.file? about_html
711
+ File.unlink about_html
712
+ end
662
713
 
663
714
  dirs = dirs.uniq.sort_by{|e| -(e.size) }
664
715
  #p dirs
665
716
  dirs.each do |dir|
666
- next if dir == "." # failsafe...
667
- next if dir == @config[:output_dir] # failsafe...
668
- FileUtils.remove_entry_secure(dir) if File.exist? dir
717
+ dir = safe_output_path(dir)
718
+ next unless dir
719
+ next if dir == File.expand_path(".") # failsafe...
720
+ next if @config[:output_dir] and dir == File.expand_path(@config[:output_dir]) # failsafe...
721
+ if dir and File.exist?(dir) and File.directory?(dir)
722
+ FileUtils.remove_entry_secure(dir)
723
+ end
669
724
  end
670
725
  end
671
726
  end
data/locales/en.yml CHANGED
@@ -45,6 +45,7 @@ en:
45
45
  non-repeatable: "Non repeatable"
46
46
  blank-node-structure: "The structural contents of a blank node are as follows:"
47
47
  blank-node-or-structure: "The structural contents of a blank node are either of the followings:"
48
+ datatype: "Datatype: "
48
49
  triples:
49
50
  inverse_refered: "Referred to as '%{property}' from:"
50
51
  blank_node: "Blank node"
data/locales/ja.yml CHANGED
@@ -45,6 +45,7 @@ ja:
45
45
  non-repeatable: 繰り返し無し
46
46
  blank-node-structure: ブランクノードの内容は以下の内容からなる構造を持ちます。
47
47
  blank-node-or-structure: ブランクノードの内容は以下のいずれかの内容からなる構造を持ちます。
48
+ datatype: "データ型: "
48
49
  triples:
49
50
  inverse_refered: "'%{property}'としての参照元:"
50
51
  blank_node: "空ノード"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ttl2html
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masao Takaku
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-04-12 00:00:00.000000000 Z
10
+ date: 2026-05-04 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: nokogiri
@@ -210,7 +210,9 @@ files:
210
210
  homepage: https://github.com/masao/ttl2html
211
211
  licenses:
212
212
  - MIT
213
- metadata: {}
213
+ metadata:
214
+ bug_tracker_uri: https://github.com/masao/ttl2html/issues
215
+ documentation_uri: https://ttl2html-doc.readthedocs.io/
214
216
  rdoc_options: []
215
217
  require_paths:
216
218
  - lib
@@ -225,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
227
  - !ruby/object:Gem::Version
226
228
  version: '0'
227
229
  requirements: []
228
- rubygems_version: 4.0.3
230
+ rubygems_version: 4.0.10
229
231
  specification_version: 4
230
232
  summary: ttl2html
231
233
  test_files: []