Class: RDF::KV
- Inherits:
-
Object
- Object
- RDF::KV
- Defined in:
- lib/rdf/kv/version.rb,
lib/rdf/kv.rb
Defined Under Namespace
Classes: Error
Constant Summary collapse
- VERSION =
"0.1.8"
Instance Attribute Summary collapse
-
#callback ⇒ Object
readonly
Returns the value of attribute callback.
-
#graph ⇒ Object
readonly
Returns the value of attribute graph.
-
#prefixes ⇒ Object
(also: #namespaces)
readonly
Returns the value of attribute prefixes.
-
#subject ⇒ Object
readonly
Returns the value of attribute subject.
Instance Method Summary collapse
-
#initialize(subject: nil, graph: nil, prefixes: {}, callback: nil) ⇒ KV
constructor
Initialize the processor.
-
#process(data) ⇒ RDF::Changeset
A changeset containing the results.
Constructor Details
#initialize(subject: nil, graph: nil, prefixes: {}, callback: nil) ⇒ KV
Initialize the processor.
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/rdf/kv.rb', line 277 def initialize subject: nil, graph: nil, prefixes: {}, callback: nil # look at all of our pretty assertions raise ArgumentError, 'subject must be an RDF::Resource' unless subject.is_a? RDF::Resource raise ArgumentError, 'graph must be an RDF::Resource' unless graph.nil? or graph.is_a? RDF::Resource raise ArgumentError, 'prefixes must be hashable' unless prefixes.respond_to? :to_h raise ArgumentError, 'callback must be callable' unless callback.nil? or callback.respond_to? :call @subject = subject @graph = graph @callback = callback @prefixes = DEFAULT_NS.merge(prefixes.to_h.map do |k, v| k = k.to_s.to_sym unless k.is_a? Symbol # coerce to uri v = RDF::URI(v.to_s) unless v.is_a? RDF::Resource # now coerce to vocabulary v = RDF::Vocabulary.new v unless v.is_a? RDF::Vocabulary [k, v] end.to_h) end |
Instance Attribute Details
#callback ⇒ Object (readonly)
Returns the value of attribute callback.
265 266 267 |
# File 'lib/rdf/kv.rb', line 265 def callback @callback end |
#graph ⇒ Object (readonly)
Returns the value of attribute graph.
265 266 267 |
# File 'lib/rdf/kv.rb', line 265 def graph @graph end |
#prefixes ⇒ Object (readonly) Also known as: namespaces
Returns the value of attribute prefixes.
265 266 267 |
# File 'lib/rdf/kv.rb', line 265 def prefixes @prefixes end |
#subject ⇒ Object (readonly)
Returns the value of attribute subject.
265 266 267 |
# File 'lib/rdf/kv.rb', line 265 def subject @subject end |
Instance Method Details
#process(data) ⇒ RDF::Changeset
Note:
This operation may change the state of the processor, so while this object can be reused for multiple hashes, it is unwise to reuse it across requests.
Returns A changeset containing the results.
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
# File 'lib/rdf/kv.rb', line 310 def process data raise ArgumentError, 'data must be a hash' unless data.is_a? Hash macros = GENERATED.dup maybe = {} # candidates neither = {} # discard pile data.each do |k, *v| # step 0: get the values to a homogeneous list k = k.to_s v = v.flatten.map(&:to_s) # step 1: pull out all the macro declarations if (m = /#{DECLARATION}/o.match k) name = m[1].to_sym sigil = !!(m[2] && !m[2].empty?) # skip over generated macros next if GENERATED.key? name # step 1.0.1: create [content, deref flag] pairs (macros[name] ||= []).concat v.map { |x| [x, sigil] } elsif (m = /(?:^\s*\S+\s+\S+.*?$|[:\$])/.match k) (maybe[k] ||= []).concat v else (neither[k] ||= []).concat v end end # step 2: dereference all the macros (that asked to be dereferenced) begin macros = massage_macros macros rescue Exception => e # XXX we should do something more here raise Error.new e end # step 3: apply special control macros (which modify self) begin SPECIALS.each do |k, macro| instance_exec macros[k], ¯o if macros[k] end rescue Exception => e # again this should be nicer raise Error.new e end # this will be our output patch = RDF::Changeset.new maybe.each do |k, v| # this will return an array now k = deref_content(k, macros).compact v = v.compact.map(&:strip).uniq # this is only this way because of macros k.each do |template| tokens = GRAMMAR.match(template) or next tokens = tokens.captures raise 'INTERNAL ERROR: Regexp captures do not match template' unless tokens.length == MAP.length # i had something much cleverer here but of course it didn't DWIW contents = {} MAP.each_index { |i| contents[MAP[i]] ||= tokens[i] } contents.compact! contents[:modifier] = (contents[:modifier] || '').chars.map do |c| [c, true] end.to_h if contents[:designator] sigil, symbol = contents[:designator].split '', 2 symbol = resolve_term symbol if sigil == ?^ contents[:designator] = symbol.to_s.empty? ? [sigil] : [sigil, symbol] else contents[:designator] = [contents[:modifier][?!] ? ?: : ?'] end %i[term1 term2 graph].filter { |t| contents[t] }.each do |which| tmp = resolve_term contents[which] tmp = callback.call(tmp) if callback contents[which] = tmp end # these are the values we actually use; ensure they are duplicated values = (contents[:deref] ? deref_content(v, macros) : v).dup g = coerce_term(contents[:graph]) || graph # initialize the triple s, p, o = nil # shorthand for reverse if reverse = !!contents[:modifier][?!] # literals make no sense on reverse statements # (XXX this is a candidate for diagnostics) next unless [?_, ?:].include? contents[:designator].first # these terms have already been resolved/coerced p = contents[:term1] o = contents[:term2] || (callback ? callback.call(subject) : subject) else s, p = (contents[:term2] ? contents.values_at(:term1, :term2) : [subject, contents[:term1]]).map do |t| # XXX DO WE NEED THIS ANYMORE?? t = resolve_term t callback ? callback.call(t) : t end end # the operation depends on whether the `-` modifier is present op = contents[:modifier][?-] ? :delete : :insert # if we're deleting triples and the values contain an empty # string then we're deleting a wildcard, same if we `=` overwrite if !reverse and op == :delete && values.include?('') || contents[:modifier][?=] # create a random variable name so we don't pass in a nil var = RDF::Query::Variable.new random_uuid_ncname # i can't remember why we don't do this in reverse, probably # because it is too easy to shoot yourself in the foot patch.delete RDF::Statement(s, p, var, graph_name: g) # nuke these since it will be pointless to evaluate further values.clear if op == :delete end # otherwise the code is basically the same values.each do |x| # get what should be guaranteed to be an RDF term or nil x = coerce_term(x, *contents[:designator]) or next # now we assign the appropriate direction reverse ? s = x : o = x # this will be either insert or delete patch.send op, RDF::Statement(s, p, o, graph_name: g) end end end patch end |