Class: FtrRuby::Output

Inherits:
Object
  • Object
show all
Includes:
RDF, TripleEasy
Defined in:
lib/output.rb

Overview

Represents the output/result of executing a FAIR test against a specific resource.

This class generates a provenance-rich RDF graph describing a single test execution, including the result score, log messages, summary, and optional guidance for improvement.

The output follows the FAIR Test Registry (FTR) vocabulary and uses PROV for tracing the execution activity and the tested entity.

Examples:

output = FtrRuby::Output.new(
  testedGUID: "https://doi.org/10.5281/zenodo.1234567",
  meta: test_meta_hash
)
output.score = "pass"
output.comments << "Resource has a resolvable persistent identifier."
jsonld = output.createEvaluationResponse

Constant Summary collapse

OPUTPUT_VERSION =
"1.1.1"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(testedGUID:, meta:) ⇒ Output

Creates a new test output instance.

Parameters:

  • testedGUID (String)

    The identifier (usually URI) of the resource being tested

  • meta (Hash)

    Metadata about the test (same structure used by DCAT_Record)



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/output.rb', line 36

def initialize(testedGUID:, meta:)
  @score = "indeterminate"
  @testedGUID = testedGUID
  @uniqueid = "urn:fairtestoutput:" + SecureRandom.uuid
  @name = meta[:testname]
  @description = meta[:description]
  @license = meta[:license] || "https://creativecommons.org/licenses/by/4.0/"
  @dt = Time.now.iso8601
  @metric = meta[:metric]
  @version = meta[:testversion]
  @summary = meta[:summary] || "Summary:"
  @completeness = "100"
  @comments = []
  @guidance = meta.fetch(:guidance, [])
  @creator = meta[:creator]
  @protocol = meta[:protocol].gsub(%r{[:/]}, "")
  @host = meta[:host].gsub(%r{[:/]}, "")
  @basePath = meta[:basePath].gsub(%r{[:/]}, "")
  @softwareid = "#{@protocol}://#{@host}/#{@basePath}/#{meta[:testid]}"
  @api = "#{@softwareid}/api"
end

Class Attribute Details

.commentsObject (readonly)

Returns the value of attribute comments.



165
166
167
# File 'lib/output.rb', line 165

def comments
  @comments
end

Instance Attribute Details

#apiObject

Returns the value of attribute api.



25
26
27
# File 'lib/output.rb', line 25

def api
  @api
end

#basePathObject

Returns the value of attribute basePath.



25
26
27
# File 'lib/output.rb', line 25

def basePath
  @basePath
end

#commentsObject

Returns the value of attribute comments.



25
26
27
# File 'lib/output.rb', line 25

def comments
  @comments
end

#completenessObject

Returns the value of attribute completeness.



25
26
27
# File 'lib/output.rb', line 25

def completeness
  @completeness
end

#creatorObject

Returns the value of attribute creator.



25
26
27
# File 'lib/output.rb', line 25

def creator
  @creator
end

#descriptionObject

Returns the value of attribute description.



25
26
27
# File 'lib/output.rb', line 25

def description
  @description
end

#dtObject

Returns the value of attribute dt.



25
26
27
# File 'lib/output.rb', line 25

def dt
  @dt
end

#guidanceObject

Returns the value of attribute guidance.



25
26
27
# File 'lib/output.rb', line 25

def guidance
  @guidance
end

#hostObject

Returns the value of attribute host.



25
26
27
# File 'lib/output.rb', line 25

def host
  @host
end

#licenseObject

Returns the value of attribute license.



25
26
27
# File 'lib/output.rb', line 25

def license
  @license
end

#metricObject

Returns the value of attribute metric.



25
26
27
# File 'lib/output.rb', line 25

def metric
  @metric
end

#nameObject

Returns the value of attribute name.



25
26
27
# File 'lib/output.rb', line 25

def name
  @name
end

#protocolObject

Returns the value of attribute protocol.



25
26
27
# File 'lib/output.rb', line 25

def protocol
  @protocol
end

#scoreObject

Returns the value of attribute score.



25
26
27
# File 'lib/output.rb', line 25

def score
  @score
end

#softwareidObject

Returns the value of attribute softwareid.



25
26
27
# File 'lib/output.rb', line 25

def softwareid
  @softwareid
end

#summaryObject

Returns the value of attribute summary.



25
26
27
# File 'lib/output.rb', line 25

def summary
  @summary
end

#testedGUIDObject

Returns the value of attribute testedGUID.



25
26
27
# File 'lib/output.rb', line 25

def testedGUID
  @testedGUID
end

#testidObject

Returns the value of attribute testid.



25
26
27
# File 'lib/output.rb', line 25

def testid
  @testid
end

#uniqueidObject

Returns the value of attribute uniqueid.



25
26
27
# File 'lib/output.rb', line 25

def uniqueid
  @uniqueid
end

#versionObject

Returns the value of attribute version.



25
26
27
# File 'lib/output.rb', line 25

def version
  @version
end

Class Method Details

.clear_commentsObject



168
169
170
# File 'lib/output.rb', line 168

def self.clear_comments
  @comments = []
end

Instance Method Details

#add_newline_to_commentsObject



172
173
174
175
176
177
178
179
# File 'lib/output.rb', line 172

def add_newline_to_comments
  cleancomments = []
  @comments.each do |c|
    c += "\n" unless c =~ /\n$/
    cleancomments << c
  end
  @comments = cleancomments
end

#createEvaluationResponseString

Generates the full evaluation response as JSON-LD.

Builds an RDF graph containing:

  • A ‘ftr:TestExecutionActivity`

  • A ‘ftr:TestResult` with score, summary, log, and guidance

  • Links to the tested entity and the test software

  • Provenance information

Returns:

  • (String)

    JSON-LD representation of the test result graph



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/output.rb', line 69

def createEvaluationResponse
  g = RDF::Graph.new
  schema = RDF::Vocab::SCHEMA
  xsd = RDF::Vocab::XSD
  dct = RDF::Vocab::DC
  prov = RDF::Vocab::PROV
  dcat = RDF::Vocab::DCAT
  dqv = RDF::Vocabulary.new("https://www.w3.org/TR/vocab-dqv/")
  ftr = RDF::Vocabulary.new("https://w3id.org/ftr#")
  sio = RDF::Vocabulary.new("http://semanticscience.org/resource/")
  cwmo = RDF::Vocabulary.new("http://purl.org/cwmo/#")

  add_newline_to_comments

  if summary =~ /^Summary$/
    summary = "Summary of test results: #{comments[-1]}"
    summary ||= "Summary of test results: #{comments[-2]}"
  end

  executionid = "urn:ostrails:testexecutionactivity:" + SecureRandom.uuid

  # tid = 'urn:ostrails:fairtestentity:' + SecureRandom.uuid
  # The entity is no longer an anonymous node, it is the GUID Of the tested input

  triplify(executionid, RDF.type, ftr.TestExecutionActivity, g)
  triplify(executionid, prov.wasAssociatedWith, softwareid, g)
  triplify(uniqueid, prov.wasGeneratedBy, executionid, g)

  triplify(uniqueid, RDF.type, ftr.TestResult, g)
  triplify(uniqueid, dct.identifier, uniqueid.to_s, g, datatype: xsd.string)
  triplify(uniqueid, dct.title, "#{name} OUTPUT", g)
  triplify(uniqueid, dct.description, "OUTPUT OF #{description}", g)
  triplify(uniqueid, dct.license, license, g)
  triplify(uniqueid, prov.value, score, g)
  triplify(uniqueid, ftr.summary, summary, g)
  triplify(uniqueid, RDF::Vocab::PROV.generatedAtTime, dt, g)
  triplify(uniqueid, ftr.log, comments.join, g)
  triplify(uniqueid, ftr.completion, completeness, g)

  triplify(uniqueid, ftr.outputFromTest, softwareid, g)
  triplify(softwareid, RDF.type, ftr.Test, g)
  triplify(softwareid, RDF.type, schema.SoftwareApplication, g)
  triplify(softwareid, RDF.type, dcat.DataService, g)
  triplify(softwareid, dct.identifier, softwareid.to_s, g, datatype: xsd.string)
  triplify(softwareid, dct.title, "#{name}", g)
  triplify(softwareid, dct.description, description, g)
  triplify(softwareid, dcat.endpointDescription, api, g) # returns yaml
  triplify(softwareid, dcat.endpointURL, softwareid, g) # POST to execute
  triplify(softwareid, "http://www.w3.org/ns/dcat#version", "#{version} OutputVersion:#{OPUTPUT_VERSION}", g) # dcat namespace in library has no version - dcat 2 not 3
  triplify(softwareid, dct.license, "https://github.com/wilkinsonlab/FAIR-Core-Tests/blob/main/LICENSE", g)
  triplify(softwareid, sio["SIO_000233"], metric, g) # implementation of

  # deprecated after release 1.0
  # triplify(uniqueid, prov.wasDerivedFrom, tid, g)
  # triplify(executionid, prov.used, tid, g)
  # triplify(tid, RDF.type, prov.Entity, g)
  # triplify(tid, schema.identifier, testedGUID, g, xsd.string)
  # triplify(tid, schema.url, testedGUID, g) if testedGUID =~ %r{^https?://}
  testedguidnode = "urn:ostrails:testedidentifiernode:" + SecureRandom.uuid

  begin
    triplify(uniqueid, ftr.assessmentTarget, testedguidnode, g)
    triplify(executionid, prov.used, testedguidnode, g)
    triplify(testedguidnode, RDF.type, prov.Entity, g)
    triplify(testedguidnode, dct.identifier, testedGUID, g, datatype: xsd.string)
  rescue StandardError
    triplify(uniqueid, ftr.assessmentTarget, "not a URI", g)
    triplify(executionid, prov.used, "not a URI", g)
    score = "fail"
  end

  unless score == "pass"
    guidance.each do |advice, label|
      adviceid = "urn:ostrails:testexecutionactivity:advice:" + SecureRandom.uuid
      triplify(uniqueid, ftr.suggestion, adviceid, g)
      triplify(adviceid, RDF.type, ftr.GuidanceContext, g)
      triplify(adviceid, RDFS.label, label, g)
      triplify(adviceid, dct.description, label, g)
      triplify(adviceid, sio["SIO_000339"], RDF::URI.new(advice), g)
    end
  end

  #      g.dump(:jsonld)
  w = RDF::Writer.for(:jsonld)
  w.dump(g, nil, prefixes: {
           xsd: RDF::Vocab::XSD,
           prov: RDF::Vocab::PROV,
           dct: RDF::Vocab::DC,
           dcat: RDF::Vocab::DCAT,
           ftr: ftr,
           sio: sio,
           schema: schema
         })
end