case_model 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7975b117f28b3b97b7280d00cfa2ed0ed2ed5f88
|
4
|
+
data.tar.gz: e6afbc109997f137b98fa31d54041a1f51bd0b97
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: db40192af1d3e44978dce73891cca821f5a00cff05b1d6b42a029afb2e3c4d7728f14920ca68f767e1111742faa99826ff7100a6b7fbbc171f4c785a636bde61
|
7
|
+
data.tar.gz: 04bbf2ca4ba64e812318d6b1b20a79210baf416ce8d3872d27eb8107af0f6e72498274dc40af6d46e6cace603901ad22a792eb38ea85bdc5802383579e82bc71
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# gem "rubidium", path: "~/Dropbox/PhD/project/code/rubidium"
|
4
|
+
# gem "rubidium-dir", path: "~/Dropbox/PhD/project/code/rubidium-dir"
|
5
|
+
|
6
|
+
gem 'rdf-n3', '1.99.0'
|
7
|
+
gem 'rdf-vocab', '0.8.7.1'
|
8
|
+
gem 'webmock', '1.22.3'
|
9
|
+
gem 'rest-client', '1.8.0'
|
10
|
+
gem 'rake', '10.5.0'
|
11
|
+
gem 'rspec', '3.4.0'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.4.0)
|
5
|
+
crack (0.4.3)
|
6
|
+
safe_yaml (~> 1.0.0)
|
7
|
+
diff-lcs (1.2.5)
|
8
|
+
domain_name (0.5.25)
|
9
|
+
unf (>= 0.0.5, < 1.0.0)
|
10
|
+
hashdiff (0.2.3)
|
11
|
+
http-cookie (1.0.2)
|
12
|
+
domain_name (~> 0.5)
|
13
|
+
link_header (0.0.8)
|
14
|
+
mime-types (2.99)
|
15
|
+
netrc (0.11.0)
|
16
|
+
rake (10.5.0)
|
17
|
+
rdf (1.99.1)
|
18
|
+
link_header (~> 0.0, >= 0.0.8)
|
19
|
+
rdf-n3 (1.99.0)
|
20
|
+
rdf (~> 1.99)
|
21
|
+
rdf-vocab (0.8.7.1)
|
22
|
+
rdf (~> 1.1, >= 1.1.10)
|
23
|
+
rest-client (1.8.0)
|
24
|
+
http-cookie (>= 1.0.2, < 2.0)
|
25
|
+
mime-types (>= 1.16, < 3.0)
|
26
|
+
netrc (~> 0.7)
|
27
|
+
rspec (3.4.0)
|
28
|
+
rspec-core (~> 3.4.0)
|
29
|
+
rspec-expectations (~> 3.4.0)
|
30
|
+
rspec-mocks (~> 3.4.0)
|
31
|
+
rspec-core (3.4.1)
|
32
|
+
rspec-support (~> 3.4.0)
|
33
|
+
rspec-expectations (3.4.0)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.4.0)
|
36
|
+
rspec-mocks (3.4.0)
|
37
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
+
rspec-support (~> 3.4.0)
|
39
|
+
rspec-support (3.4.1)
|
40
|
+
safe_yaml (1.0.4)
|
41
|
+
unf (0.1.4)
|
42
|
+
unf_ext
|
43
|
+
unf_ext (0.0.7.1)
|
44
|
+
webmock (1.22.3)
|
45
|
+
addressable (>= 2.3.6)
|
46
|
+
crack (>= 0.3.2)
|
47
|
+
hashdiff
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
rake (= 10.5.0)
|
54
|
+
rdf-n3 (= 1.99.0)
|
55
|
+
rdf-vocab (= 0.8.7.1)
|
56
|
+
rest-client (= 1.8.0)
|
57
|
+
rspec (= 3.4.0)
|
58
|
+
webmock (= 1.22.3)
|
59
|
+
|
60
|
+
BUNDLED WITH
|
61
|
+
1.11.2
|
data/README.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
CASE (Context-aware Software Ecosystem)
|
2
|
+
=======================================
|
3
|
+
|
4
|
+
Evaluation of application models
|
5
|
+
--------------------------------
|
6
|
+
|
7
|
+
Supplementary evaluation for the paper **Semantic Model of Variability and Capabilities of IoT Applications for Embedded Software Ecosystems**.
|
8
|
+
|
9
|
+
# Browsing the sample scenarios
|
10
|
+
|
11
|
+
To investigate the tested application models and scenarios, see the folder
|
12
|
+
[spec/use_cases](spec/use_cases).
|
13
|
+
|
14
|
+
# Installation
|
15
|
+
|
16
|
+
1. Install the Eye reasoner
|
17
|
+
- ([Windows](http://eulersharp.sourceforge.net/README.Windows), [OS X](http://eulersharp.sourceforge.net/README.MacOSX), [Linux](http://eulersharp.sourceforge.net/README.Linux))
|
18
|
+
- requires the SWI Prolog
|
19
|
+
- `brew tap homebrew/x11`
|
20
|
+
- `brew install swi-prolog`
|
21
|
+
2. Install [Ruby](https://www.ruby-lang.org/en/) version 2.x.x
|
22
|
+
3. Run in inside a folder for this repository: `gem install bundler`
|
23
|
+
4. Run in inside a folder for this repository: `bundle install`
|
24
|
+
|
25
|
+
# Running the specs
|
26
|
+
|
27
|
+
To run the tests, simply execute `rspec` in the folder of this repository.
|
data/Rakefile
ADDED
data/case_model.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'case_model'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.date = '2016-01-28'
|
5
|
+
s.summary = 'Resolver for the CASE ecosystem application models'
|
6
|
+
s.description = 'Built for the Context-Aware Software Ecosystem. Resolves application model requirements using semantic reasoning.'
|
7
|
+
s.authors = ['Matus Tomlein']
|
8
|
+
s.email = 'matus@cs.au.dk'
|
9
|
+
|
10
|
+
s.files = `git ls-files -z`.split("\x0")
|
11
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
12
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
|
15
|
+
s.homepage = 'https://github.com/case-iot/app_model'
|
16
|
+
s.license = 'MIT'
|
17
|
+
end
|
data/lib/case_model.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
@prefix e: <http://eulersharp.sourceforge.net/2003/03swap/log-rules#>.
|
2
|
+
@prefix st: <http://purl.org/restdesc/states#>.
|
3
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
|
4
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
|
5
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
|
6
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#>.
|
7
|
+
|
8
|
+
st:State a rdfs:Class;
|
9
|
+
rdfs:label "A consistent state of (parts of) the world at a certain point in time."@en.
|
10
|
+
|
11
|
+
st:StateChange a rdfs:Class;
|
12
|
+
rdfs:label "A transition from one state to another."@en.
|
13
|
+
|
14
|
+
st:added a rdf:Property, owl:FunctionalProperty;
|
15
|
+
rdfs:label "added triples"@en;
|
16
|
+
rdfs:domain st:StateChange;
|
17
|
+
rdfs:range log:Formula.
|
18
|
+
|
19
|
+
st:removed a rdf:Property, owl:FunctionalProperty;
|
20
|
+
rdfs:label "removed triples"@en;
|
21
|
+
rdfs:domain st:StateChange;
|
22
|
+
rdfs:range log:Formula.
|
23
|
+
|
24
|
+
st:parent a rdf:Property, owl:FunctionalProperty;
|
25
|
+
rdfs:label "is based upon"@en;
|
26
|
+
rdfs:domain st:StateChange;
|
27
|
+
rdfs:range st:State.
|
28
|
+
|
29
|
+
st:derivedFrom a rdf:Property, owl:FunctionalProperty;
|
30
|
+
rdfs:label "is derived from"@en;
|
31
|
+
rdfs:domain st:State;
|
32
|
+
rdfs:range st:StateChange.
|
33
|
+
|
34
|
+
# Derive the complete state from a state change
|
35
|
+
{
|
36
|
+
?change st:added ?added;
|
37
|
+
st:removed ?removed;
|
38
|
+
st:parent ?parent.
|
39
|
+
|
40
|
+
(?parent ?removed) e:graphDifference ?inherited.
|
41
|
+
(?inherited ?added) log:conjunction ?newState.
|
42
|
+
}
|
43
|
+
=>
|
44
|
+
{
|
45
|
+
?newState a st:State;
|
46
|
+
st:derivedFrom ?change.
|
47
|
+
}.
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative '../services/question_references'
|
2
|
+
|
3
|
+
class Action
|
4
|
+
attr_reader :query
|
5
|
+
|
6
|
+
include QuestionReferences
|
7
|
+
|
8
|
+
def initialize(node, repository)
|
9
|
+
@query = NodeQuery.new(node, repository)
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
query.value(LV.description)
|
14
|
+
end
|
15
|
+
|
16
|
+
def requirements
|
17
|
+
list = RDF::List.new(query.value(LV.requirement), query.repository)
|
18
|
+
list.map { |node| Requirement.new(node, query.repository) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def failed_requirements
|
22
|
+
requirements.select {|r| not r.satisfied? }
|
23
|
+
end
|
24
|
+
|
25
|
+
def compatible?
|
26
|
+
not failed_requirements.any?
|
27
|
+
end
|
28
|
+
|
29
|
+
def questions
|
30
|
+
q = []
|
31
|
+
q << question if has_question?
|
32
|
+
|
33
|
+
with_question = requirements.select { |r| r.has_question? }
|
34
|
+
q + with_question.map { |r| r.question }
|
35
|
+
end
|
36
|
+
|
37
|
+
def open_questions
|
38
|
+
questions.select { |q| not q.has_answer? }
|
39
|
+
end
|
40
|
+
|
41
|
+
def execution
|
42
|
+
ActionExecution.new(query.value(LV.executes), query.repository)
|
43
|
+
end
|
44
|
+
|
45
|
+
def effect
|
46
|
+
StateChange.new(query.value(LV.effect), query.repository)
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Answer
|
2
|
+
def self.create(reply_type, node, repository)
|
3
|
+
case reply_type
|
4
|
+
when :location
|
5
|
+
Location.new(node, repository)
|
6
|
+
when :temperature
|
7
|
+
Temperature.new(node, repository)
|
8
|
+
when :select
|
9
|
+
Selection.new(node, repository)
|
10
|
+
else
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def reply_type
|
16
|
+
question.reply_type
|
17
|
+
end
|
18
|
+
|
19
|
+
def question
|
20
|
+
node = query.value(QV.answers)
|
21
|
+
return nil if node.nil?
|
22
|
+
|
23
|
+
Question.new(node, query.repository)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Application
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
def initialize(node, repository)
|
5
|
+
@query = NodeQuery.new(node, repository)
|
6
|
+
end
|
7
|
+
|
8
|
+
def name
|
9
|
+
if query.value_exists?(RDF::Vocab::FOAF.name)
|
10
|
+
query.value(RDF::Vocab::FOAF.name)
|
11
|
+
else
|
12
|
+
query.value(LV.name)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def description
|
17
|
+
query.value(LV.description)
|
18
|
+
end
|
19
|
+
|
20
|
+
def questions
|
21
|
+
list = repo.query([nil, RDF.type, QV.Question]).map { |s| s.subject }
|
22
|
+
list.map { |node| Question.new(node, repo) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def open_questions
|
26
|
+
questions.select { |q| not q.has_answer? }
|
27
|
+
end
|
28
|
+
|
29
|
+
def question_with_text(text)
|
30
|
+
questions.find { |q| q.text == text }
|
31
|
+
end
|
32
|
+
|
33
|
+
def requirements
|
34
|
+
list = repo.query([nil, RDF.type, QV.Requirement]).map { |s| s.subject }
|
35
|
+
list.map { |node| Requirement.new(node, repo) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def requirement_with_description(description)
|
39
|
+
requirements.find { |r| r.description == description }
|
40
|
+
end
|
41
|
+
|
42
|
+
def deployment_plans
|
43
|
+
query.values(LV.hasDeploymentPlan).map do |node|
|
44
|
+
DeploymentPlan.new(node, repo)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def deployment_plan_with_description(description)
|
49
|
+
deployment_plans.find { |a| a.description == description }
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def repo
|
55
|
+
query.repository
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Capability
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
def initialize(node, repository)
|
5
|
+
@query = NodeQuery.new(node, repository)
|
6
|
+
end
|
7
|
+
|
8
|
+
def description
|
9
|
+
query.value(LV.description)
|
10
|
+
end
|
11
|
+
|
12
|
+
def actuators
|
13
|
+
query.values(LV.actuator).map do |node|
|
14
|
+
Device.new node, query.repository
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def sensors
|
19
|
+
query.values(LV.sensor).map do |node|
|
20
|
+
Device.new node, query.repository
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative '../services/question_references'
|
2
|
+
|
3
|
+
class DeploymentPlan
|
4
|
+
attr_reader :query
|
5
|
+
|
6
|
+
include QuestionReferences
|
7
|
+
|
8
|
+
def initialize(node, repository)
|
9
|
+
@query = NodeQuery.new(node, repository)
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
query.value(LV.description)
|
14
|
+
end
|
15
|
+
|
16
|
+
def host
|
17
|
+
nil unless query.value_exists?(LV.host)
|
18
|
+
EcosystemHost.new(query.value(LV.host), query.repository)
|
19
|
+
end
|
20
|
+
|
21
|
+
def arguments
|
22
|
+
node = query.value(LV.arguments)
|
23
|
+
arg_query = NodeQuery.new(node, query.repository)
|
24
|
+
|
25
|
+
if arg_query.value_exists?(RDFV.first)
|
26
|
+
RDF::List.new(node, query.repository)
|
27
|
+
else
|
28
|
+
arg_query.predicates_and_objects
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def deployment_plans
|
33
|
+
query.values(LV.hasDeploymentPlan).map do |node|
|
34
|
+
DeploymentPlan.new(node, query.repository)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def capabilities
|
39
|
+
list = RDF::List.new(query.value(LV.capabilities), query.repository)
|
40
|
+
list.map do |node|
|
41
|
+
Capability.new(node, query.repository)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Device
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
def initialize(node, repository)
|
5
|
+
@query = NodeQuery.new(node, repository)
|
6
|
+
end
|
7
|
+
|
8
|
+
def manufacturer_name
|
9
|
+
query.value(LV.manufacturerName)
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
query.value(LV.description)
|
14
|
+
end
|
15
|
+
|
16
|
+
def location
|
17
|
+
node = query.value(LV.locatedAt)
|
18
|
+
return nil if node.nil?
|
19
|
+
|
20
|
+
Location.new(node, query.repository)
|
21
|
+
end
|
22
|
+
|
23
|
+
def node
|
24
|
+
query.node
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
|
3
|
+
class HttpRequest
|
4
|
+
attr_reader :query
|
5
|
+
|
6
|
+
def initialize(node, repository)
|
7
|
+
@query = NodeQuery.new(node, repository)
|
8
|
+
end
|
9
|
+
|
10
|
+
def uri
|
11
|
+
query.value(HttpVocabulary.request_uri)
|
12
|
+
end
|
13
|
+
|
14
|
+
def body
|
15
|
+
query.value(HttpVocabulary.body)
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_name
|
19
|
+
query.value(HttpVocabulary.method_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute
|
23
|
+
raise "Unsupported method #{method_name}" unless method_name == 'POST'
|
24
|
+
RestClient.post(uri.to_s, body.to_s)
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Location
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
include Answer
|
5
|
+
|
6
|
+
def initialize(node, repository)
|
7
|
+
@query = NodeQuery.new(node, repository)
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
query.value(LV.locationName)
|
12
|
+
end
|
13
|
+
|
14
|
+
def name=(value)
|
15
|
+
query.set_value(LV.locationName, value)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rdf'
|
2
|
+
require 'rdf/vocab'
|
3
|
+
|
4
|
+
require_relative '../services/repository_proxy'
|
5
|
+
|
6
|
+
class Ontology
|
7
|
+
attr_reader :repository
|
8
|
+
|
9
|
+
include RepositoryProxy
|
10
|
+
|
11
|
+
def self.from_n3(n3_input)
|
12
|
+
Ontology.new(RDF::Repository.new, n3_input)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(repository, n3_input = nil)
|
16
|
+
@repository = repository
|
17
|
+
load_and_process_n3 n3_input if n3_input
|
18
|
+
# initialize_state
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_and_process_n3(n3_input)
|
22
|
+
(@n3_inputs ||= []) << n3_input
|
23
|
+
refresh
|
24
|
+
end
|
25
|
+
|
26
|
+
def applications
|
27
|
+
query([nil, RDF.type, LV.Application]).map do |statement|
|
28
|
+
Application.new(statement.subject, self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def devices
|
33
|
+
query([nil, RDF.type, LV.Device]).map do |statement|
|
34
|
+
Device.new(statement.subject, self)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def device_with_description(description)
|
39
|
+
devices.find { |d| d.description == description }
|
40
|
+
end
|
41
|
+
|
42
|
+
def refresh
|
43
|
+
@n3_inputs.each { |input| Reasoner.new(self).load_and_process_n3(input) }
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
## load an empty State formula in case there are some StateChange statements
|
49
|
+
def initialize_state
|
50
|
+
load_and_process_n3 '{ <http://example.com/x> <http://example.com/y> <http://example.com/z>.} a <http://purl.org/restdesc/states#State>.'
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Question
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
def initialize(node, repository)
|
5
|
+
@query = NodeQuery.new(node, repository)
|
6
|
+
end
|
7
|
+
|
8
|
+
def text
|
9
|
+
query.value(QV.text).to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def reply_type
|
13
|
+
QuestionReplyType.to_sym(query)
|
14
|
+
end
|
15
|
+
|
16
|
+
def has_answer?
|
17
|
+
query.value_exists?(QV.has_answer)
|
18
|
+
end
|
19
|
+
|
20
|
+
# returns an existing one or nil if there is no
|
21
|
+
def answer
|
22
|
+
node = query.value(QV.has_answer)
|
23
|
+
return nil if node.nil?
|
24
|
+
|
25
|
+
Answer.create(reply_type, node, query.repository)
|
26
|
+
end
|
27
|
+
|
28
|
+
# creates a new answer or returns an existing one
|
29
|
+
def answer!
|
30
|
+
answer || create_answer
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def repository; query.repository; end
|
36
|
+
|
37
|
+
def create_answer
|
38
|
+
node = generate_answer_node
|
39
|
+
repository << [ node, RDF.type, QV.answer_type ]
|
40
|
+
answer_query = NodeQuery.new(node, repository)
|
41
|
+
answer_query.set_value(QV.answers, query.node)
|
42
|
+
query.set_value(QV.has_answer, node)
|
43
|
+
|
44
|
+
answer
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_answer_node
|
48
|
+
question_uri_hash = query.node.to_s.hash.to_s
|
49
|
+
('answer' + question_uri_hash).to_sym
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative '../services/question_references'
|
2
|
+
|
3
|
+
class Requirement
|
4
|
+
attr_reader :query
|
5
|
+
|
6
|
+
def initialize(node, repository)
|
7
|
+
@query = NodeQuery.new(node, repository)
|
8
|
+
end
|
9
|
+
|
10
|
+
def description
|
11
|
+
query.value(LV.description)
|
12
|
+
end
|
13
|
+
|
14
|
+
def satisfied?
|
15
|
+
query.value(LV.satisfied) == true
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Selection
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
include Answer
|
5
|
+
|
6
|
+
def initialize(node, repository)
|
7
|
+
@query = NodeQuery.new(node, repository)
|
8
|
+
end
|
9
|
+
|
10
|
+
def options
|
11
|
+
if question.query.value_exists?(QV.options)
|
12
|
+
RDF::List.new(question.query.value(QV.options), query.repository)
|
13
|
+
elsif question.query.value_exists?(QV.option)
|
14
|
+
question.query.values(QV.option)
|
15
|
+
else
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def selected
|
21
|
+
query.value(LV.selected)
|
22
|
+
end
|
23
|
+
|
24
|
+
def selected=(value)
|
25
|
+
# in case it is an array, store all the answers
|
26
|
+
if value.is_a? Array
|
27
|
+
value.each { |v| query.set_value(LV.selected, v, false) }
|
28
|
+
else
|
29
|
+
query.set_value(LV.selected, value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class StateChange
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
def initialize(node, repository)
|
5
|
+
@query = NodeQuery.new(node, repository)
|
6
|
+
end
|
7
|
+
|
8
|
+
def apply
|
9
|
+
new_repo = query.repository.clone
|
10
|
+
new_repo.load_and_process_n3(state_rules)
|
11
|
+
new_repo
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def state_rules
|
17
|
+
File.read(File.dirname(__FILE__) + '/../descriptions/states.n3')
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Temperature
|
2
|
+
attr_reader :query
|
3
|
+
|
4
|
+
include Answer
|
5
|
+
|
6
|
+
def initialize(node, repository)
|
7
|
+
@query = NodeQuery.new(node, repository)
|
8
|
+
end
|
9
|
+
|
10
|
+
def in_celsius
|
11
|
+
query.value(LV.in_celsius)
|
12
|
+
end
|
13
|
+
|
14
|
+
def in_celsius=(value)
|
15
|
+
query.set_value(LV.in_celsius, value)
|
16
|
+
end
|
17
|
+
end
|