diff --git a/.travis.yml b/.travis.yml
index 3e17ac6..3a1eb50 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,17 @@
language: ruby
bundler_args: --without debug
script: "bundle exec rspec spec"
-before_install: "gem update --system"
+before_install:
+ - 'gem update --system --conservative || (gem i "rubygems-update:~>2.7" --no-document && update_rubygems)'
+ - 'gem update bundler --conservative'
env:
- CI=true
rvm:
- - 2.2
+ - 2.2.2
- 2.3
- 2.4
- 2.5
+ - 2.6
- jruby-9
- rbx-3
cache: bundler
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e462370..a12efba 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -6,7 +6,7 @@ Community contributions are essential for keeping Ruby RDF great. We want to kee
This repository uses [Git Flow](https://github.com/nvie/gitflow) to manage development and release activity. All submissions _must_ be on a feature branch based on the _develop_ branch to ease staging and integration.
-* create or respond to an issue on the [Github Repository](http://github.com/ruby-rdf/rdf-reasoner/issues)
+* create or respond to an issue on the [Github Repository](https://githubhub.com/ruby-rdf/rdf-reasoner/issues)
* Fork and clone the repo:
`git clone git@github.com:your-username/rdf-reasoner.git`
* Install bundle:
@@ -30,7 +30,7 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to manage devel
of thumb, additions larger than about 15 lines of code), we need an
explicit [public domain dedication][PDD] on record from you.
-[YARD]: http://yardoc.org/
-[YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
-[PDD]: http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
+[YARD]: https://yardoc.org/
+[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
+[PDD]: https://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
[pr]: https://github.com/ruby-rdf/rdf-reasoner/compare/
diff --git a/Gemfile b/Gemfile
index d103a0c..cb88497 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,4 +1,4 @@
-source "http://rubygems.org"
+source "https://rubygems.org"
gemspec
@@ -23,8 +23,3 @@ group :debug do
gem "redcarpet", platforms: :ruby
gem "byebug", platforms: :mri
end
-
-platforms :rbx do
- gem 'rubysl', '~> 2.0'
- gem 'rubinius', '~> 2.0'
-end
diff --git a/README.md b/README.md
index 095c246..89e704a 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ Reasons over RDFS/OWL vocabularies and schema.org to generate statements which a
* Entail `rdfs:subPropertyOf` generating an array of terms which are ancestors of the subject.
* Entail `rdfs:domain` and `rdfs:range` adding `rdf:type` assertions on the subject or object.
* Inverse `rdfs:subClassOf` entailment, to find descendant classes of the subject term.
+* Inverse `rdfs:subPropertyOf` entailment, to find descendant properties of the subject term.
* Entail `owl:equivalentClass` generating an array of terms equivalent to the subject.
* Entail `owl:equivalentProperty` generating an array of terms equivalent to the subject.
* `domainCompatible?` determines if a particular resource is compatible with the domain definition of a given predicate, based on the intersection of entailed subclasses with the property domain.
@@ -51,7 +52,7 @@ Domain and Range entailment include specific rules for schema.org vocabularies.
RDF::Reasoner.apply(:rdfs)
graph = RDF::Graph.load("etc/doap.ttl")
- subj = RDF::URI("http://rubygems.org/gems/rdf-reasoner")
+ subj = RDF::URI("https://rubygems.org/gems/rdf-reasoner")
RDF::Vocab::DOAP.name.domain_compatible?(subj, graph) # => true
### Determine if a resource is compatible with the ranges of a property
@@ -103,16 +104,16 @@ The `rdf` command-line interface is extended with `entail` and `lint` commands.
## Dependencies
-* [Ruby](http://ruby-lang.org/) (>= 2.2.2)
-* [RDF.rb](http://rubygems.org/gems/rdf) (~> 3.0)
+* [Ruby](https://ruby-lang.org/) (>= 2.2.2)
+* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.0)
## Mailing List
-*
+*
## Authors
-* [Gregg Kellogg](http://github.com/gkellogg) -
+* [Gregg Kellogg](https://githubhub.com/gkellogg) -
## Contributing
@@ -132,17 +133,17 @@ The `rdf` command-line interface is extended with `entail` and `lint` commands.
## License
This is free and unencumbered public domain software. For more information,
-see or the accompanying {file:UNLICENSE} file.
-
-[Ruby]: http://ruby-lang.org/
-[RDF]: http://www.w3.org/RDF/
-[YARD]: http://yardoc.org/
-[YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
-[PDD]: http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
-[SPARQL]: http://en.wikipedia.org/wiki/SPARQL
-[SPARQL Query]: http://www.w3.org/TR/2013/REC-sparql11-query-20130321/
-[SPARQL Entailment]:http://www.w3.org/TR/sparql11-entailment/
-[RDF 1.1]: http://www.w3.org/TR/rdf11-concepts
-[RDF.rb]: http://www.rubydoc.info/github/ruby-rdf/rdf/
-[RDF Schema]: http://www.w3.org/TR/rdf-schema/
+see or the accompanying {file:UNLICENSE} file.
+
+[Ruby]: https://ruby-lang.org/
+[RDF]: https://www.w3.org/RDF/
+[YARD]: https://yardoc.org/
+[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
+[PDD]: https://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
+[SPARQL]: https://en.wikipedia.org/wiki/SPARQL
+[SPARQL Query]: https://www.w3.org/TR/2013/REC-sparql11-query-20130321/
+[SPARQL Entailment]:https://www.w3.org/TR/sparql11-entailment/
+[RDF 1.1]: https://www.w3.org/TR/rdf11-concepts
+[RDF.rb]: https://www.rubydoc.info/github/ruby-rdf/rdf/
+[RDF Schema]: https://www.w3.org/TR/rdf-schema/
[Rack]: https://rack.github.io/
diff --git a/UNLICENSE b/UNLICENSE
index 68a49da..efb9808 100644
--- a/UNLICENSE
+++ b/UNLICENSE
@@ -21,4 +21,4 @@ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
-For more information, please refer to
+For more information, please refer to
diff --git a/VERSION b/VERSION
index 4b9fcbe..cb0c939 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.5.1
+0.5.2
diff --git a/etc/doap.ttl b/etc/doap.ttl
index 6faf513..549beb4 100644
--- a/etc/doap.ttl
+++ b/etc/doap.ttl
@@ -7,9 +7,9 @@
@prefix ex: .
@prefix xsd: .
- a doap:Project, earl:TestSubject, earl:Software ;
+ a doap:Project, earl:TestSubject, earl:Software ;
doap:name "RDF::Reasoner" ;
- doap:homepage ;
+ doap:homepage ;
doap:license ;
doap:shortdesc "RDFS/OWL/Schema.org Reasoner for RDF.rb."@en ;
doap:description """
@@ -25,14 +25,14 @@
;
doap:category ,
;
- doap:download-page ;
+ doap:download-page ;
doap:mailing-list ;
- doap:bug-database ;
- doap:blog ;
- doap:developer ;
- doap:maintainer ;
- doap:documenter ;
- foaf:maker ;
+ doap:bug-database ;
+ doap:blog ;
+ doap:developer ;
+ doap:maintainer ;
+ doap:documenter ;
+ foaf:maker ;
dc:title "RDF::Reasoner" ;
dc:description """
Reasons over RDFS/OWL vocabularies to generate statements which are
@@ -42,8 +42,8 @@
SPARQL Entailment Regimes.
"""@en ;
dc:date "2014-06-01"^^xsd:date ;
- dc:creator ;
- dc:isPartOf .
+ dc:creator ;
+ dc:isPartOf .
- a foaf:Person, foaf:Agent, dc:Agent;
+ a foaf:Person, foaf:Agent, dc:Agent;
foaf:name "Gregg Kellogg".
\ No newline at end of file
diff --git a/lib/rdf/reasoner.rb b/lib/rdf/reasoner.rb
index 68dc02d..bfac0d8 100644
--- a/lib/rdf/reasoner.rb
+++ b/lib/rdf/reasoner.rb
@@ -7,7 +7,7 @@ module RDF
# RDFS/OWL reasonsing for RDF.rb.
#
# @see http://www.w3.org/TR/2013/REC-sparql11-entailment-20130321/
- # @author [Gregg Kellogg](http://greggkellogg.net/)
+ # @author [Gregg Kellogg](https://greggkellogg.net/)
module Reasoner
require 'rdf/reasoner/format'
autoload :OWL, 'rdf/reasoner/owl'
diff --git a/lib/rdf/reasoner/format.rb b/lib/rdf/reasoner/format.rb
index 06973e2..9dd59c6 100644
--- a/lib/rdf/reasoner/format.rb
+++ b/lib/rdf/reasoner/format.rb
@@ -5,7 +5,7 @@ module RDF::Reasoner
# @example Obtaining an LD Patch format class
# RDF::Format.for(:reasoner) #=> RDF::Reasoner::Format
#
- # @see http://www.w3.org/TR/ldpatch/
+ # @see https://www.w3.org/TR/ldpatch/
class Format < RDF::Format
##
diff --git a/lib/rdf/reasoner/rdfs.rb b/lib/rdf/reasoner/rdfs.rb
index a94468e..359ac1f 100644
--- a/lib/rdf/reasoner/rdfs.rb
+++ b/lib/rdf/reasoner/rdfs.rb
@@ -34,6 +34,20 @@ def subPropertyOf_cache
@@subPropertyOf_cache ||= RDF::Util::Cache.new(-1)
end
+ ##
+ # @return [RDF::Util::Cache]
+ # @private
+ def subProperty_cache
+ @@subProperty_cache ||= RDF::Util::Cache.new(-1)
+ end
+
+ ##
+ # @return [RDF::Util::Cache]
+ # @private
+ def descendant_property_cache
+ @@descendant_property_cache ||= RDF::Util::Cache.new(-1)
+ end
+
##
# For a Term: yield or return inferred subClassOf relationships by recursively applying to named super classes to get a complete set of classes in the ancestor chain of this class
# For a Statement: if predicate is `rdf:types`, yield or return inferred statements having a subClassOf relationship to the type of this statement
@@ -139,6 +153,50 @@ def _entail_subPropertyOf
end
end
+ ##
+ # For a Term: yield or return inferred subProperty relationships
+ # by recursively applying to named subproperties to get a complete
+ # set of properties in the descendant chain of this property
+ #
+ # For a Statement: this is a no-op, as it's not useful in this context
+ # @private
+
+ def _entail_subProperty
+ case self
+ when RDF::URI, RDF::Node
+ unless property?
+ yield self if block_given?
+ return Array(self)
+ end
+
+ terms = descendant_property_cache[self] ||= (
+ Array(self.subProperty).map do |c|
+ c._entail_subProperty rescue c
+ end.flatten + Array(self)).compact
+
+ terms.each {|t| yield t } if block_given?
+ terms
+ else []
+ end
+ end
+
+ ##
+ # Get the immediate subproperties of this property.
+ #
+ # This iterates over terms defined in the vocabulary of this term,
+ # as well as the vocabularies imported by this vocabulary.
+ # @return [Array]
+ def subProperty
+ raise RDF::Reasoner::Error,
+ "#{self} Can't entail subProperty" unless property?
+ vocabs = [self.vocab] + self.vocab.imported_from
+ subProperty_cache[self] ||= vocabs.map do |v|
+ Array(v.properties).select do |p|
+ p.property? && Array(p.subPropertyOf).include?(self)
+ end
+ end.flatten.compact
+ end
+
##
# For a Statement: yield or return inferred statements having an rdf:type of the domain of the statement predicate
# @todo Should be able to entail owl:unionOf, which is a BNode. This should be allowed, and also add BNode values of that node, recursively, similar to SPARQL concise_bounded_description.uu
@@ -303,6 +361,7 @@ def self.included(mod)
mod.add_entailment :subClassOf, :_entail_subClassOf
mod.add_entailment :subClass, :_entail_subClass
mod.add_entailment :subPropertyOf, :_entail_subPropertyOf
+ mod.add_entailment :subProperty, :_entail_subProperty
mod.add_entailment :domain, :_entail_domain
mod.add_entailment :range, :_entail_range
end
@@ -319,4 +378,4 @@ def self.included(mod)
# Extend Mutable with these methods
::RDF::Mutable.send(:include, RDFS)
-end
\ No newline at end of file
+end
diff --git a/rdf-reasoner.gemspec b/rdf-reasoner.gemspec
index 68886de..ea5a1fc 100755
--- a/rdf-reasoner.gemspec
+++ b/rdf-reasoner.gemspec
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
gem.date = File.mtime('VERSION').strftime('%Y-%m-%d')
gem.name = "rdf-reasoner"
- gem.homepage = "http://github.com/gkellogg/rdf-reasoner"
+ gem.homepage = "https://githubhub.com/gkellogg/rdf-reasoner"
gem.license = 'Unlicense'
gem.summary = "RDFS/OWL Reasoner for RDF.rb"
@@ -16,7 +16,6 @@ Gem::Specification.new do |gem|
gem.platform = Gem::Platform::RUBY
gem.files = %w(AUTHORS README.md UNLICENSE VERSION) + Dir.glob('lib/**/*.rb')
gem.require_paths = %w(lib)
- gem.has_rdoc = false
gem.description = %(Reasons over RDFS/OWL vocabularies to generate statements
which are entailed based on base RDFS/OWL rules along with
vocabulary information. It can also be used to ask specific
@@ -32,10 +31,9 @@ Gem::Specification.new do |gem|
gem.add_development_dependency 'rdf-spec', '~> 3.0'
gem.add_development_dependency 'rdf-turtle', '~> 3.0'
- #gem.add_development_dependency 'json-ld', '~> 3.0'
- gem.add_development_dependency 'json-ld', '>= 2.2', '< 4.0'
+ gem.add_development_dependency 'json-ld', '~> 3.0'
gem.add_development_dependency 'equivalent-xml', '~> 0.6'
- gem.add_development_dependency 'rspec', '~> 3.7'
- gem.add_development_dependency 'yard' , '~> 0.9.12'
+ gem.add_development_dependency 'rspec', '~> 3.8'
+ gem.add_development_dependency 'yard' , '~> 0.9.19'
gem.post_install_message = nil
end
diff --git a/spec/rdfs_spec.rb b/spec/rdfs_spec.rb
index af8f092..9b3a8b2 100644
--- a/spec/rdfs_spec.rb
+++ b/spec/rdfs_spec.rb
@@ -137,6 +137,61 @@
end
end
+ # XXX this is cribbed from :subClass
+ describe :subProperty do
+ {
+ RDF::Vocab::DC.relation => %w(conformsTo hasFormat hasPart hasVersion
+ isFormatOf isPartOf isReferencedBy isReplacedBy isRequiredBy
+ isVersionOf references relation replaces requires source).map {
+ |t| RDF::Vocab::DC[t] } + %w(derived_from djmix_of mashup_of medley_of
+ remaster_of remix_of sampled_version_of).map {|t| RDF::Vocab::MO[t] },
+ RDF::Vocab::SIOC.space_of => %w(host_of).map {|t| RDF::Vocab::SIOC[t] },
+ }.each do |prop, entails|
+ context prop.pname do
+ describe RDF::Vocabulary::Term do
+ specify {
+ expect(prop.entail(:subProperty).map(&:pname)).to include(
+ *entails.map(&:pname))}
+ specify {
+ expect {|b| prop.entail(:subProperty, &b)
+ }.to yield_control.at_least(entails.length)}
+ end
+
+ # XXX all of these can probably be rolled up too
+
+ stmt = RDF::Statement(RDF::URI('a'), prop, RDF::Literal(true))
+
+ describe RDF::Statement do
+ subject {stmt}
+ let(:results) {entails.map {|r|
+ RDF::Statement(RDF::URI("a"), r, RDF::Literal(true))}}
+ specify {expect(subject.entail(:subProperty)).to be_empty}
+ specify {expect(subject.entail(:subProperty)).to all(be_inferred)}
+ specify {expect {|b|
+ subject.entail(:subProperty, &b)}.not_to yield_control}
+ end
+
+ describe RDF::Enumerable do
+ subject {[stmt].extend(RDF::Enumerable)}
+ specify {
+ expect(subject.entail(:subProperty)).to be_a(RDF::Enumerable)}
+ specify {expect(subject.entail(:subProperty).to_a).to be_empty}
+ specify {
+ expect {|b| subject.entail(:subProperty, &b)}.not_to yield_control}
+ end
+
+ describe RDF::Mutable do
+ subject {RDF::Graph.new << stmt}
+ let(:results) {subject.dup}
+ specify {expect(subject.entail(:subProperty)).to be_a(RDF::Graph)}
+ specify {expect(
+ subject.entail(:subProperty)).to be_equivalent_graph(results)}
+ specify {expect(subject.entail!(:subProperty)).to equal subject}
+ end
+ end
+ end
+ end unless ENV['CI']
+
describe :domain do
{
RDF::Vocab::FOAF.account => [RDF::Vocab::FOAF.Agent],
diff --git a/spec/readme_spec.rb b/spec/readme_spec.rb
index 1bd8a85..dddc447 100644
--- a/spec/readme_spec.rb
+++ b/spec/readme_spec.rb
@@ -25,7 +25,7 @@
it "Determine if a resource is compatible with the domains of a property" do
RDF::Reasoner.apply(:rdfs)
graph = RDF::Graph.load("etc/doap.ttl")
- subj = RDF::URI("http://rubygems.org/gems/rdf-reasoner")
+ subj = RDF::URI("https://rubygems.org/gems/rdf-reasoner")
expect(RDF::Vocab::DOAP.name).to be_domain_compatible(subj, graph)
end
@@ -40,7 +40,7 @@
RDF::Reasoner.apply(:owl)
graph = RDF::Graph.load("etc/doap.ttl")
graph.entail!(:equivalentClass)
- expect(graph).to have_statement(RDF::Statement(RDF::URI("http://greggkellogg.net/foaf#me"), RDF.type, RDF::Vocab::DC.Agent))
+ expect(graph).to have_statement(RDF::Statement(RDF::URI("https://greggkellogg.net/foaf#me"), RDF.type, RDF::Vocab::DC.Agent))
end
it "Yield all entailed statements for all entailment methods" do
diff --git a/spec/suite_helper.rb b/spec/suite_helper.rb
index 40dc0a5..7429116 100644
--- a/spec/suite_helper.rb
+++ b/spec/suite_helper.rb
@@ -6,7 +6,7 @@
# For now, override RDF::Utils::File.open_file to look for the file locally before attempting to retrieve it
module RDF::Util
module File
- REMOTE_PATH = "http://www.w3.org/2013/rdf-mt-tests/"
+ REMOTE_PATH = "https://www.w3.org/2013/rdf-mt-tests/"
LOCAL_PATH = ::File.expand_path("../w3c-rdf/rdf-mt", __FILE__) + '/'
class << self
diff --git a/spec/suite_spec.rb b/spec/suite_spec.rb
index ecca64f..7acca16 100644
--- a/spec/suite_spec.rb
+++ b/spec/suite_spec.rb
@@ -41,6 +41,8 @@
case result_graph
when RDF::Enumerable
# Add source triples to result to use equivalence
+ # FIXME: entailment test should be subgraph, considering BNode equivalence.
+ # Could be implemented in N3 as {G2 . {G1} => log:Success} or {G2} log:includes {G1}
action_graph.each {|s| result_graph << s}
expect(action_graph).to be_equivalent_graph(result_graph, t)
when false