case_model 0.0.1
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 +7 -0
- data/.travis.yml +4 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +61 -0
- data/README.md +27 -0
- data/Rakefile +9 -0
- data/case_model.gemspec +17 -0
- data/lib/case_model.rb +3 -0
- data/lib/descriptions/states.n3 +47 -0
- data/lib/models/action.rb +48 -0
- data/lib/models/answer.rb +25 -0
- data/lib/models/application.rb +57 -0
- data/lib/models/capability.rb +23 -0
- data/lib/models/deployment_plan.rb +44 -0
- data/lib/models/device.rb +26 -0
- data/lib/models/ecosystem_host.rb +5 -0
- data/lib/models/http_request.rb +27 -0
- data/lib/models/location.rb +17 -0
- data/lib/models/ontology.rb +52 -0
- data/lib/models/question.rb +51 -0
- data/lib/models/question_reply_type.rb +14 -0
- data/lib/models/requirement.rb +17 -0
- data/lib/models/selection.rb +32 -0
- data/lib/models/state_change.rb +19 -0
- data/lib/models/temperature.rb +17 -0
- data/lib/ontology/http_vocabulary.rb +17 -0
- data/lib/ontology/local_vocabulary.rb +26 -0
- data/lib/ontology/math_vocabulary.rb +15 -0
- data/lib/ontology/rdf_vocabulary.rb +11 -0
- data/lib/ontology/state_vocabulary.rb +9 -0
- data/lib/services/application_by_capability_finder.rb +37 -0
- data/lib/services/eye_serializer.rb +19 -0
- data/lib/services/node_builder.rb +34 -0
- data/lib/services/node_query.rb +55 -0
- data/lib/services/question_references.rb +19 -0
- data/lib/services/reasoner.rb +77 -0
- data/lib/services/repository_proxy.rb +26 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/models/answer_spec.rb +43 -0
- data/spec/unit/models/application_spec.rb +43 -0
- data/spec/unit/models/deployment_plan_spec.rb +28 -0
- data/spec/unit/models/http_request_spec.rb +42 -0
- data/spec/unit/models/location_spec.rb +36 -0
- data/spec/unit/models/question_spec.rb +89 -0
- data/spec/unit/models/requirement_spec.rb +29 -0
- data/spec/unit/models/selection_spec.rb +48 -0
- data/spec/unit/models/state_change_spec.rb +33 -0
- data/spec/unit/ontology/local_vocabulary_spec.rb +9 -0
- data/spec/unit/ontology/ontology_spec.rb +62 -0
- data/spec/unit/services/application_by_capability_finder_spec.rb +81 -0
- data/spec/unit/services/eye_serializer_spec.rb +34 -0
- data/spec/unit/services/node_builder_spec.rb +56 -0
- data/spec/unit/services/node_query_spec.rb +74 -0
- data/spec/unit/services/reasoner_spec.rb +76 -0
- data/spec/unit/spec_helper.rb +1 -0
- metadata +117 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
class HttpVocabulary
|
2
|
+
def self.method_missing(name, *arguments, &block)
|
3
|
+
uri_for(name)
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.method_name
|
7
|
+
uri_for('methodName')
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.request_uri
|
11
|
+
uri_for('requestURI')
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.uri_for(name)
|
15
|
+
RDF::URI("http://www.w3.org/2011/http##{name}")
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
|
3
|
+
class LocalVocabulary
|
4
|
+
def self.method_missing(name, *arguments, &block)
|
5
|
+
uri_for(name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.name
|
9
|
+
uri_for('name')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.question_type
|
13
|
+
uri_for('question')
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.answer_type
|
17
|
+
uri_for('answer')
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.uri_for(name)
|
21
|
+
RDF::URI("http://matus.tomlein.org/case/#{name}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
LV = LocalVocabulary
|
26
|
+
QV = LocalVocabulary
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class MathVocabulary
|
2
|
+
def self.method_missing(name, *arguments, &block)
|
3
|
+
uri_for(name)
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.less_than
|
7
|
+
uri_for('lessThan')
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.uri_for(name)
|
11
|
+
RDF::URI("http://www.w3.org/2000/10/swap/math##{name}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
MV = MathVocabulary
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class ApplicationByCapabilityFinder
|
2
|
+
def initialize(ontology)
|
3
|
+
@ontology = ontology
|
4
|
+
end
|
5
|
+
|
6
|
+
def find(options)
|
7
|
+
solutions = RDF::Query.execute(@ontology, {
|
8
|
+
application: {
|
9
|
+
LV.hasDeploymentPlan => {
|
10
|
+
LV.capability => options
|
11
|
+
}
|
12
|
+
}
|
13
|
+
})
|
14
|
+
|
15
|
+
solutions.map do |solution|
|
16
|
+
solution[:application]
|
17
|
+
end.uniq.map do |node|
|
18
|
+
Application.new(node, @ontology)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_by_type(type)
|
23
|
+
find({ RDF.type => type })
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_by_description(description)
|
27
|
+
find({ LV.description => description })
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_by_actuator(actuator)
|
31
|
+
find({ LV.actuator => actuator })
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_by_sensor(sensor)
|
35
|
+
find({ LV.sensor => sensor })
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class EyeSerializer
|
2
|
+
def self.serialize_implication(facts, precondition, postcondition)
|
3
|
+
pre = serialize_graph(precondition)
|
4
|
+
post = serialize_graph(postcondition)
|
5
|
+
"#{facts.dump(:ntriples)}{#{pre}} => {#{post}}.\n"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.serialize_graph(graph)
|
9
|
+
statements = []
|
10
|
+
graph.each_statement do |statement|
|
11
|
+
statements << RDF::Statement.new({
|
12
|
+
subject: statement.subject,
|
13
|
+
predicate: statement.predicate,
|
14
|
+
object: statement.object
|
15
|
+
}).to_s + "\n"
|
16
|
+
end
|
17
|
+
statements.join
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
class NodeBuilder
|
4
|
+
def self.create(properties, repository)
|
5
|
+
node = generate_node
|
6
|
+
query = NodeQuery.new node, repository
|
7
|
+
|
8
|
+
properties.each do |key, v|
|
9
|
+
values = if v.is_a?(Array)
|
10
|
+
v
|
11
|
+
else
|
12
|
+
[ v ]
|
13
|
+
end
|
14
|
+
|
15
|
+
values.each do |value|
|
16
|
+
query.set_value(key,
|
17
|
+
if value.is_a?(Hash)
|
18
|
+
create(value, repository)
|
19
|
+
else
|
20
|
+
value
|
21
|
+
end, false)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
node
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def self.generate_node
|
31
|
+
id = SecureRandom.hex
|
32
|
+
RDF::URI("http://example.org/#{id}")
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class NodeQuery
|
2
|
+
attr_reader :node, :repository
|
3
|
+
|
4
|
+
def initialize(node, repository)
|
5
|
+
@node = node
|
6
|
+
@repository = repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def value(predicate)
|
10
|
+
values(predicate).first
|
11
|
+
end
|
12
|
+
|
13
|
+
def values(predicate)
|
14
|
+
results = repository.query([ node, predicate, nil ])
|
15
|
+
results.map {|s| s.object }
|
16
|
+
end
|
17
|
+
|
18
|
+
def value_exists?(predicate)
|
19
|
+
values(predicate).any?
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_value(predicate, object, replace = true)
|
23
|
+
delete_value(predicate) if replace
|
24
|
+
@repository << [ node, predicate, object ]
|
25
|
+
end
|
26
|
+
|
27
|
+
def predicates_and_objects
|
28
|
+
values = {}
|
29
|
+
repository.query([ node, nil, nil ]).each do |s|
|
30
|
+
if values.has_key? s.predicate
|
31
|
+
if values[s.predicate].is_a? Array
|
32
|
+
values[s.predicate] << s.object
|
33
|
+
else
|
34
|
+
values[s.predicate] = [
|
35
|
+
values[s.predicate], s.object
|
36
|
+
]
|
37
|
+
end
|
38
|
+
else
|
39
|
+
values[s.predicate] = s.object
|
40
|
+
end
|
41
|
+
end
|
42
|
+
values
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def delete_value(predicate)
|
48
|
+
# makes sure not to delete any values in subgraphs
|
49
|
+
repository.query([ node, predicate, nil ]).select do |s|
|
50
|
+
s.graph_name.nil?
|
51
|
+
end.each do |s|
|
52
|
+
repository.delete(s)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module QuestionReferences
|
2
|
+
def has_question?
|
3
|
+
query.value_exists?(LV.requires_answering)
|
4
|
+
end
|
5
|
+
|
6
|
+
def has_condition?
|
7
|
+
query.value_exists?(LV.condition)
|
8
|
+
end
|
9
|
+
|
10
|
+
def question
|
11
|
+
node = query.value(LV.requires_answering)
|
12
|
+
return nil if node.nil?
|
13
|
+
Question.new(node, query.repository)
|
14
|
+
end
|
15
|
+
|
16
|
+
def question_answered?
|
17
|
+
question.has_answer?
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'rdf/n3'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
class Reasoner
|
5
|
+
attr_reader :repository
|
6
|
+
|
7
|
+
def initialize(repository)
|
8
|
+
@repository = repository
|
9
|
+
end
|
10
|
+
|
11
|
+
# implication doesn't work well when a blank node is used in the
|
12
|
+
# condition, e.g.:
|
13
|
+
# {?device1 <http://...#type> _:vehicle .} => {...}
|
14
|
+
# will always result in the postcondition, because of _:vehicle
|
15
|
+
def imply(precondition, postcondition)
|
16
|
+
eye_input = EyeSerializer.serialize_implication(
|
17
|
+
repository.facts_only,
|
18
|
+
repository.graph(precondition),
|
19
|
+
repository.graph(postcondition)
|
20
|
+
)
|
21
|
+
|
22
|
+
eye_output = run_eye eye_input
|
23
|
+
parse_eye_output eye_output
|
24
|
+
end
|
25
|
+
|
26
|
+
# makes sure that the graph with name condition is valid
|
27
|
+
# to do that, it creates a temporary graph (:helper_graph) and tries to imply
|
28
|
+
# condition => helper_graph
|
29
|
+
# it creates a new temp_reasoner object so as not to modify the current repository
|
30
|
+
# with the helper_graph
|
31
|
+
def check_condition(condition)
|
32
|
+
temp_repository = @repository.clone
|
33
|
+
temp_repository << [ LV.condition, LV.was, LV.true, :helper_graph ]
|
34
|
+
|
35
|
+
temp_reasoner = Reasoner.new temp_repository
|
36
|
+
result = temp_reasoner.imply(condition, :helper_graph)
|
37
|
+
|
38
|
+
result.query([ LV.condition, LV.was, LV.true ]).any?
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_and_process_n3(n3_input)
|
42
|
+
input = [
|
43
|
+
n3_input,
|
44
|
+
EyeSerializer.serialize_graph(repository.facts_only)
|
45
|
+
].join
|
46
|
+
|
47
|
+
eye_output = run_eye input
|
48
|
+
parse_eye_output eye_output, @repository
|
49
|
+
@repository
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def run_eye(input)
|
55
|
+
data = Tempfile.new('data')
|
56
|
+
data.write(input)
|
57
|
+
data.close
|
58
|
+
output = `eye --nope --pass #{data.path} 2> /dev/null`
|
59
|
+
data.unlink
|
60
|
+
|
61
|
+
output
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_eye_output(output, repo = nil)
|
65
|
+
output = remove_incompatible_prefix_from_eye_output output
|
66
|
+
repo = RDF::Repository.new if repo.nil?
|
67
|
+
reader = RDF::Reader.for(:n3).new(output)
|
68
|
+
reader.each_statement { |statement| repo << statement }
|
69
|
+
repo
|
70
|
+
end
|
71
|
+
|
72
|
+
def remove_incompatible_prefix_from_eye_output(output)
|
73
|
+
output.gsub(/PREFIX .+\n/) do |match|
|
74
|
+
match.sub('PREFIX ', '@prefix ') + '.'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RepositoryProxy
|
2
|
+
def graph(name)
|
3
|
+
graph_name = if name.is_a? Symbol; "_:#{name.to_s}"; else; name.to_s; end
|
4
|
+
g = RDF::Graph.new
|
5
|
+
repository.statements.each do |statement|
|
6
|
+
next if statement.graph_name.nil?
|
7
|
+
next unless statement.graph_name.to_s.include? graph_name
|
8
|
+
|
9
|
+
g << [ statement.subject, statement.predicate, statement.object ]
|
10
|
+
end
|
11
|
+
g
|
12
|
+
end
|
13
|
+
|
14
|
+
def facts_only
|
15
|
+
RDF::Graph.new do |g|
|
16
|
+
repository.statements.each do |statement|
|
17
|
+
g << statement if statement.graph_name.nil?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# proxy everything to the repository
|
23
|
+
def method_missing(method, *args, &block)
|
24
|
+
repository.send(method, *args, &block)
|
25
|
+
end
|
26
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Answer do
|
4
|
+
let(:repo) do
|
5
|
+
RDF::Repository.new do |r|
|
6
|
+
# DEVICE
|
7
|
+
r << [:dev, RDF.type, LV.Device]
|
8
|
+
r << [:dev, LV.manufacturerName, 'Grundfos']
|
9
|
+
r << [:dev, LV.locatedAt, :device_location]
|
10
|
+
# QUESTION
|
11
|
+
r << [:device_location, RDF.type, QV.question_type]
|
12
|
+
r << [:device_location, QV.replyType, QV.Location]
|
13
|
+
r << [:device_location, QV.location_of, :dev]
|
14
|
+
r << [:device_location, QV.text, 'Where is the thing?']
|
15
|
+
# ANSWER
|
16
|
+
r << [:device_location, QV.has_answer, :answer]
|
17
|
+
r << [:answer, RDF.type, QV.answer_type]
|
18
|
+
r << [:answer, QV.answers, :device_location]
|
19
|
+
r << [:answer, RDF.type, QV.Location]
|
20
|
+
r << [:answer, LV.locationName, 'Living Room']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:ontology) { Ontology.new(repo) }
|
25
|
+
let(:question) { Question.new(:device_location, ontology) }
|
26
|
+
let(:answer) { question.answer }
|
27
|
+
|
28
|
+
context '#question.text' do
|
29
|
+
subject { answer.question.text }
|
30
|
+
it { is_expected.not_to eq(nil) }
|
31
|
+
it { is_expected.to eq('Where is the thing?') }
|
32
|
+
end
|
33
|
+
|
34
|
+
context '#reply_type' do
|
35
|
+
subject { answer.reply_type }
|
36
|
+
it { is_expected.to eq(:location) }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'should have type Location' do
|
40
|
+
subject { answer }
|
41
|
+
it { is_expected.to be_kind_of Location }
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
def create_repo
|
4
|
+
RDF::Repository.new do |r|
|
5
|
+
r << [:a, RDF.type, LV.Application]
|
6
|
+
r << [:a, RDF::Vocab::FOAF.name, 'Some App']
|
7
|
+
r << [:a, LV.description, 'Description of the app.']
|
8
|
+
|
9
|
+
r << [:a, LV.hasDeploymentPlan, :deployment_plan1]
|
10
|
+
r << [:a, LV.hasDeploymentPlan, :deployment_plan2]
|
11
|
+
r << [:deployment_plan1, LV.description, 'This needs to be so and so.']
|
12
|
+
r << [:deployment_plan2, LV.description, 'This needs to be so and so.']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe Application do
|
17
|
+
let(:repo) { create_repo }
|
18
|
+
let(:ontology) { Ontology.new(repo) }
|
19
|
+
let(:app) { Application.new(:a, repo) }
|
20
|
+
|
21
|
+
context '#name' do
|
22
|
+
subject { app.name }
|
23
|
+
it { is_expected.to eq('Some App') }
|
24
|
+
end
|
25
|
+
|
26
|
+
context '#description' do
|
27
|
+
subject { app.description }
|
28
|
+
it { is_expected.to eq('Description of the app.') }
|
29
|
+
end
|
30
|
+
|
31
|
+
context '#deployment_plans' do
|
32
|
+
subject { app.deployment_plans.size }
|
33
|
+
it { is_expected.to eq 2 }
|
34
|
+
|
35
|
+
describe 'should not have doubles' do
|
36
|
+
before do
|
37
|
+
repo << [ :a, LV.hasDeploymentPlan, :deployment_plan2 ]
|
38
|
+
end
|
39
|
+
|
40
|
+
it { is_expected.to eq 2 }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe DeploymentPlan do
|
4
|
+
let(:repo) { RDF::Repository.new }
|
5
|
+
let(:ontology) { Ontology.new(repo) }
|
6
|
+
let(:deployment_plan) { DeploymentPlan.new(:a, repo) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
repo << [:deployment_plan, LV.description, 'Install the app']
|
10
|
+
end
|
11
|
+
|
12
|
+
context '#description' do
|
13
|
+
subject { deployment_plan.description }
|
14
|
+
it { is_expected.to eq('Install the app') }
|
15
|
+
end
|
16
|
+
|
17
|
+
context '#arguments' do
|
18
|
+
before do
|
19
|
+
arguments = RDF::List[ 'arg1', 'arg2' ]
|
20
|
+
repo << arguments
|
21
|
+
repo << [ :deployment_plan, LV.arguments, arguments ]
|
22
|
+
end
|
23
|
+
let(:arguments) { deployment_plan.arguments }
|
24
|
+
|
25
|
+
subject { arguments.to_a }
|
26
|
+
it { is_expected.to eq [ 'arg1', 'arg2' ] }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe HttpRequest do
|
4
|
+
let(:repo) { RDF::Repository.new }
|
5
|
+
let(:ontology) { Ontology.new(repo) }
|
6
|
+
let(:request) { HttpRequest.new(:r, repo) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
repo << [ :r, HttpVocabulary.method_name, 'POST' ]
|
10
|
+
repo << [ :r, HttpVocabulary.body, 'the body' ]
|
11
|
+
end
|
12
|
+
|
13
|
+
context '#uri' do
|
14
|
+
subject { request.uri }
|
15
|
+
|
16
|
+
describe 'as literal' do
|
17
|
+
before { repo << [ :r, HttpVocabulary.request_uri, 'http://example.com' ] }
|
18
|
+
|
19
|
+
it { is_expected.to eq 'http://example.com' }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'as URI' do
|
23
|
+
before { repo << [ :r, HttpVocabulary.request_uri, RDF::URI('http://example.eu') ] }
|
24
|
+
|
25
|
+
it { is_expected.to eq 'http://example.eu' }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#execute' do
|
30
|
+
before do
|
31
|
+
repo << [ :r, HttpVocabulary.request_uri, 'http://example.com' ]
|
32
|
+
stub_request(:post, 'example.com')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'makes the request' do
|
36
|
+
expect(request.execute).to eq true
|
37
|
+
|
38
|
+
expect(WebMock).to have_requested(:post, 'example.com').
|
39
|
+
with(:body => 'the body')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Location do
|
4
|
+
let(:repo) do
|
5
|
+
RDF::Repository.new do |r|
|
6
|
+
# ANSWER
|
7
|
+
r << [:location, RDF.type, QV.answer_type]
|
8
|
+
r << [:location, RDF.type, QV.location]
|
9
|
+
r << [:location, LV.locationName, 'Living Room']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:ontology) { Ontology.new(repo) }
|
14
|
+
let(:location) { Location.new(:location, repo) }
|
15
|
+
|
16
|
+
context '#name' do
|
17
|
+
subject { location.name }
|
18
|
+
it { is_expected.to eq('Living Room') }
|
19
|
+
end
|
20
|
+
|
21
|
+
context '#name=' do
|
22
|
+
before :each do
|
23
|
+
location.name = 'Kitchen'
|
24
|
+
end
|
25
|
+
|
26
|
+
subject { location.name }
|
27
|
+
it { is_expected.to eq('Kitchen') }
|
28
|
+
|
29
|
+
describe 'new instances should have the changed value' do
|
30
|
+
let(:new_answer) { Location.new(:location, repo) }
|
31
|
+
|
32
|
+
subject { new_answer.name }
|
33
|
+
it { is_expected.to eq('Kitchen') }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Question do
|
4
|
+
let(:repo) do
|
5
|
+
RDF::Repository.new do |r|
|
6
|
+
r << [:a, RDF.type, LV.Application]
|
7
|
+
r << [:device_location, RDF.type, QV.question_type]
|
8
|
+
r << [:device_location, QV.text, 'Where is the thing?']
|
9
|
+
r << [:device_location, QV.replyType, QV.Location]
|
10
|
+
r << [:device_location, QV.location_of, :device]
|
11
|
+
r << [:dev, RDF.type, LV.Device]
|
12
|
+
r << [:dev, LV.manufacturerName, 'Apple']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:ontology) { Ontology.new(repo) }
|
17
|
+
let(:question) { Question.new(:device_location, repo) }
|
18
|
+
|
19
|
+
context '#text' do
|
20
|
+
subject { question.text }
|
21
|
+
it { is_expected.to eq('Where is the thing?') }
|
22
|
+
end
|
23
|
+
|
24
|
+
context '#reply_type' do
|
25
|
+
subject { question.reply_type }
|
26
|
+
it { is_expected.to eq(:location) }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'without answer' do
|
30
|
+
context '#has_answer?' do
|
31
|
+
subject { question.has_answer? }
|
32
|
+
it { is_expected.to eq(false) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context '#answer' do
|
36
|
+
subject { question.answer }
|
37
|
+
it { is_expected.to eq(nil) }
|
38
|
+
end
|
39
|
+
|
40
|
+
context '#answer!' do
|
41
|
+
let(:answer) { question.answer! }
|
42
|
+
|
43
|
+
subject { answer }
|
44
|
+
it { is_expected.not_to eq(nil) }
|
45
|
+
|
46
|
+
describe 'location answer properties' do
|
47
|
+
before :each do
|
48
|
+
answer.name = 'Balcony'
|
49
|
+
end
|
50
|
+
|
51
|
+
subject { answer.name }
|
52
|
+
it { is_expected.to eq('Balcony') }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'with answer' do
|
58
|
+
before :each do
|
59
|
+
repo << [:answer, RDF.type, QV.answer_type]
|
60
|
+
repo << [:answer, QV.answers, :device_location]
|
61
|
+
repo << [:device_location, QV.has_answer, :answer]
|
62
|
+
end
|
63
|
+
|
64
|
+
context '#has_answer?' do
|
65
|
+
subject { question.has_answer? }
|
66
|
+
it { is_expected.to eq(true) }
|
67
|
+
end
|
68
|
+
|
69
|
+
context '#answer' do
|
70
|
+
let(:answer) { question.answer }
|
71
|
+
subject { answer }
|
72
|
+
|
73
|
+
it { is_expected.not_to eq(nil) }
|
74
|
+
|
75
|
+
context '#question.text' do
|
76
|
+
subject { answer.question.text }
|
77
|
+
it { is_expected.to eq(question.text) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context '#answer!' do
|
82
|
+
it 'should have the same value as calling answer' do
|
83
|
+
with_bang = question.answer!.name
|
84
|
+
without_bang = question.answer.name
|
85
|
+
expect(with_bang).to eq(without_bang)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Ontology do
|
4
|
+
let(:repo) { RDF::Repository.new }
|
5
|
+
let(:ontology) { Ontology.new(repo) }
|
6
|
+
let(:requirement) { Requirement.new(:req, repo) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
repo << [ :req, LV.description, 'This needs to be so and so.' ]
|
10
|
+
end
|
11
|
+
|
12
|
+
context '#description' do
|
13
|
+
subject { requirement.description }
|
14
|
+
it { is_expected.to eq('This needs to be so and so.') }
|
15
|
+
end
|
16
|
+
|
17
|
+
context '#satisfied?' do
|
18
|
+
describe 'satisfied requirement' do
|
19
|
+
before { repo << [ :req, LV.satisfied, true ] }
|
20
|
+
subject { requirement.satisfied? }
|
21
|
+
it { is_expected.to eq true }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'not satisfied requirement' do
|
25
|
+
subject { requirement.satisfied? }
|
26
|
+
it { is_expected.to eq false }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|