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
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
|