diff --git a/.travis.yml b/.travis.yml index 9e1f468..3bda01c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,21 @@ language: ruby -bundler_args: --without debug script: "bundle exec rspec spec" env: - - CI=true + global: + - CI=true + - NOKOGIRI_USE_SYSTEM_LIBRARIES=true +gemfile: + - Gemfile + - Gemfile-pure rvm: - - 2.2 - - 2.3 - 2.4 - - jruby-9 - - rbx-3 + - 2.5 + - 2.6 + - 2.7 + - jruby cache: bundler sudo: false matrix: allow_failures: - - rvm: jruby-9 - - rvm: rbx-3 + - rvm: jruby dist: trusty diff --git a/Gemfile b/Gemfile index 9ae9858..ae363b3 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem 'rdf-rdfa', github: "ruby-rdf/rdf-rdfa", branch: "develop" gem "nokogiri" group :development do - gem 'ebnf', github: "gkellogg/ebnf", branch: "develop" + gem 'ebnf', github: "dryruby/ebnf", branch: "develop" gem 'json-ld', github: "ruby-rdf/json-ld", branch: "develop" gem 'rdf-aggregate-repo', github: "ruby-rdf/rdf-aggregate-repo", branch: "develop" gem 'rdf-isomorphic', github: "ruby-rdf/rdf-isomorphic", branch: "develop" @@ -24,9 +24,3 @@ group :debug do gem "ruby-debug", platforms: :jruby gem "byebug", platform: :mri end - -platforms :rbx do - gem 'rubysl', '~> 2.0' - gem 'rubinius', '~> 2.0' - gem 'json' -end diff --git a/Gemfile-pure b/Gemfile-pure index 91c89fb..c44310f 100644 --- a/Gemfile-pure +++ b/Gemfile-pure @@ -7,7 +7,7 @@ gem 'rdf', github: "ruby-rdf/rdf", branch: "develop" gem 'rdf-rdfa', github: "ruby-rdf/rdf-rdfa", branch: "develop" group :development do - gem 'ebnf', github: "gkellogg/ebnf", branch: "develop" + gem 'ebnf', github: "dryruby/ebnf", branch: "develop" gem 'json-ld', github: "ruby-rdf/json-ld", branch: "develop" gem 'rdf-aggregate-repo', github: "ruby-rdf/rdf-aggregate-repo", branch: "develop" gem 'rdf-isomorphic', github: "ruby-rdf/rdf-isomorphic", branch: "develop" @@ -24,9 +24,3 @@ group :debug do gem "ruby-debug", platforms: :jruby gem "byebug", platform: :mri end - -platforms :rbx do - gem 'rubysl', '~> 2.0' - gem 'rubinius', '~> 2.0' - gem 'json' -end diff --git a/README.md b/README.md index 0f46a9f..6f9a3c7 100755 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Install with `gem install rdf-rdfxml` * 100% free and unencumbered [public domain](http://unlicense.org/) software. * Implements a complete parser for [RDF/XML][]. -* Compatible with Ruby >= 2.2.2. +* Compatible with Ruby >= 2.4. ## Usage: Instantiate a parser and parse source, specifying type and base-URL @@ -40,8 +40,8 @@ Write a graph to a file: end ## Dependencies -* [RDF.rb](http://rubygems.org/gems/rdf) (>= 2.0) -* Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.6.0) +* [RDF.rb](http://rubygems.org/gems/rdf) (~> 3.1) +* Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.10) ## Documentation Full documentation available on [Rubydoc.info][RDF/XML doc]) diff --git a/VERSION b/VERSION index c043eea..fd2a018 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.1 +3.1.0 diff --git a/lib/rdf/rdfxml/reader.rb b/lib/rdf/rdfxml/reader.rb index 427f3a9..11e94a5 100644 --- a/lib/rdf/rdfxml/reader.rb +++ b/lib/rdf/rdfxml/reader.rb @@ -41,7 +41,7 @@ def initialize(base, element, graph, &cb) end # Clone existing evaluation context adding information from element - def clone(element, options = {}, &cb) + def clone(element, **options, &cb) new_ec = EvaluationContext.new(@base, nil, @graph) new_ec.uri_mappings = self.uri_mappings.clone new_ec.language = self.language @@ -136,7 +136,7 @@ def inspect # @yieldparam [RDF::Reader] reader # @yieldreturn [void] ignored # @raise [Error] Raises RDF::ReaderError if _validate_ - def initialize(input = $stdin, options = {}, &block) + def initialize(input = $stdin, **options, &block) super do @library = case options[:library] when nil @@ -156,7 +156,7 @@ def initialize(input = $stdin, options = {}, &block) self.extend(@implementation) input.rewind if input.respond_to?(:rewind) - initialize_xml(input, options) rescue log_fatal($!.message) + initialize_xml(input, **options) rescue log_fatal($!.message) log_error("Empty document") if root.nil? log_error("Synax errors") {doc_errors} if !doc_errors.empty? @@ -427,7 +427,7 @@ def nodeElement(el, ec) else literal_opts[:language] = child_ec.language end - literal = RDF::Literal.new(child.inner_text, literal_opts) + literal = RDF::Literal.new(child.inner_text, **literal_opts) add_triple(child, subject, predicate, literal) reify(id, child, subject, predicate, literal, ec) if id elsif parseType == "Resource" diff --git a/lib/rdf/rdfxml/reader/nokogiri.rb b/lib/rdf/rdfxml/reader/nokogiri.rb index b57f0d1..47f5453 100644 --- a/lib/rdf/rdfxml/reader/nokogiri.rb +++ b/lib/rdf/rdfxml/reader/nokogiri.rb @@ -227,7 +227,7 @@ def method_missing(method, *args) # # @param [Hash{Symbol => Object}] options # @return [void] - def initialize_xml(input, options = {}) + def initialize_xml(input, **options) require 'nokogiri' unless defined?(::Nokogiri) @doc = case input when ::Nokogiri::XML::Document diff --git a/lib/rdf/rdfxml/reader/rexml.rb b/lib/rdf/rdfxml/reader/rexml.rb index d8bdcf8..f7c2f54 100644 --- a/lib/rdf/rdfxml/reader/rexml.rb +++ b/lib/rdf/rdfxml/reader/rexml.rb @@ -245,7 +245,7 @@ def method_missing(method, *args) # # @param [Hash{Symbol => Object}] options # @return [void] - def initialize_xml(input, options = {}) + def initialize_xml(input, **options) require 'rexml/document' unless defined?(::REXML) @doc = case input when ::REXML::Document diff --git a/lib/rdf/rdfxml/writer.rb b/lib/rdf/rdfxml/writer.rb index c55b830..579886c 100644 --- a/lib/rdf/rdfxml/writer.rb +++ b/lib/rdf/rdfxml/writer.rb @@ -113,7 +113,7 @@ def self.options # URI to use as @href for output stylesheet processing instruction. # @yield [writer] # @yieldparam [RDF::Writer] writer - def initialize(output = $stdout, options = {}, &block) + def initialize(output = $stdout, **options, &block) super end @@ -170,7 +170,7 @@ def write_epilogue # @return String # The rendered document is returned as a string # Return Haml template for document from `haml_template[:subject]` - def render_subject(subject, predicates, options = {}, &block) + def render_subject(subject, predicates, **options, &block) # extract those properties that can be rendered as attributes attr_props = if [:untyped, :typed].include?(@attributes) options[:property_values].inject({}) do |memo, (prop, values)| @@ -189,7 +189,7 @@ def render_subject(subject, predicates, options = {}, &block) end predicates -= attr_props.keys.map {|k| expand_curie(k).to_s} - super(subject, predicates, options.merge(attr_props: attr_props), &block) + super(subject, predicates, **options.merge(attr_props: attr_props), &block) end # See if we can serialize as attribute. # * untyped attributes that aren't duplicated where xml:lang == @lang @@ -228,8 +228,8 @@ def predicate_as_attribute?(prop, object) # @yieldreturn [:ignored] # @return String # The rendered document is returned as a string - def render_document(subjects, options = {}, &block) - super(subjects, options.merge(stylesheet: @options[:stylesheet]), &block) + def render_document(subjects, **options, &block) + super(subjects, **options.merge(stylesheet: @options[:stylesheet]), &block) end # Render a single- or multi-valued predicate using `haml_template[:property_value]` or `haml_template[:property_values]`. Yields each object for optional rendering. The block should only render for recursive subject definitions (i.e., where the object is also a subject and is rendered underneath the first referencing subject). @@ -256,7 +256,7 @@ def render_document(subjects, options = {}, &block) # The block should only return a string for recursive object definitions. # @return String # The rendered document is returned as a string - def render_property(predicate, objects, options = {}, &block) + def render_property(predicate, objects, **options, &block) log_debug {"render_property(#{predicate}): #{objects.inspect}, #{options.inspect}"} # If there are multiple objects, and no :property_values is defined, call recursively with # each object @@ -280,7 +280,7 @@ def render_property(predicate, objects, options = {}, &block) log_debug {"list: #{list.inspect} #{list.to_a}"} log_depth do - render_collection(predicate, list, options) do |object| + render_collection(predicate, list, **options) do |object| yield(object, true) if block_given? end end @@ -290,7 +290,7 @@ def render_property(predicate, objects, options = {}, &block) if objects.length > 1 # Render each property using property_value template objects.map do |object| - log_depth {render_property(predicate, [object], options, &block)} + log_depth {render_property(predicate, [object], **options, &block)} end.join(" ") else log_fatal("Missing property template", exception: RDF::WriterError) if template.nil? @@ -301,7 +301,7 @@ def render_property(predicate, objects, options = {}, &block) property: get_qname(predicate), recurse: log_depth <= @max_depth }.merge(options) - hamlify(template, options, &block) + hamlify(template, **options, &block) end end @@ -319,7 +319,7 @@ def render_property(predicate, objects, options = {}, &block) # The block should only return a string for recursive object definitions. # @return String # The rendered collection is returned as a string - def render_collection(predicate, list, options = {}, &block) + def render_collection(predicate, list, **options, &block) template = options[:haml] || haml_template[:collection] options = { @@ -328,7 +328,7 @@ def render_collection(predicate, list, options = {}, &block) property: get_qname(predicate), recurse: log_depth <= @max_depth, }.merge(options) - hamlify(template, options) do |object| + hamlify(template, **options) do |object| yield object end end diff --git a/rdf-rdfxml.gemspec b/rdf-rdfxml.gemspec index b2db238..0a4a3c3 100755 --- a/rdf-rdfxml.gemspec +++ b/rdf-rdfxml.gemspec @@ -17,41 +17,26 @@ Gem::Specification.new do |gem| gem.platform = Gem::Platform::RUBY gem.files = %w(README.md History.md AUTHORS CONTRIBUTORS VERSION UNLICENSE) + Dir.glob('lib/**/*.rb') gem.require_paths = %w(lib) - gem.has_rdoc = false - gem.required_ruby_version = '>= 2.2.2' + gem.required_ruby_version = '>= 2.4' gem.requirements = [] - #gem.add_runtime_dependency 'rdf', '~> 3.0' - #gem.add_runtime_dependency 'rdf-rdfa', '~> 3.0' - #gem.add_runtime_dependency 'rdf-xsd', '~> 3.0' - gem.add_runtime_dependency 'rdf', '>= 2.2', '< 4.0' - gem.add_runtime_dependency 'rdf-rdfa', '>= 2.2', '< 4.0' - gem.add_runtime_dependency 'rdf-xsd', '>= 2.2', '< 4.0' + gem.add_runtime_dependency 'rdf', '~> 3.1' + gem.add_runtime_dependency 'rdf-xsd', '~> 3.1' + gem.add_runtime_dependency 'rdf-rdfa', '~> 3.1' gem.add_runtime_dependency 'htmlentities', '~> 4.3' - #gem.add_development_dependency 'nokogiri' , '>= 1.6.1' # conditionally done in Gemfile - #gem.add_development_dependency 'equivalent-xml' , '~> 0.2' # conditionally done in Gemfile + #gem.add_development_dependency 'nokogiri' , '~> 1.10' + #gem.add_development_dependency 'equivalent-xml' , '~> 0.6' # conditionally done in Gemfile gem.add_development_dependency 'open-uri-cached', '~> 0.0', '>= 0.0.5' - gem.add_development_dependency 'spira', '= 0.0.12' - #gem.add_development_dependency 'json-ld', '~> 3.0' - gem.add_development_dependency 'json-ld', '>= 2.1', '< 4.0' - gem.add_development_dependency 'rspec', '~> 3.4' - gem.add_development_dependency 'rspec-its', '~> 1.2' - #gem.add_development_dependency 'rdf-isomorphic', '~> 3.0' - #gem.add_development_dependency 'rdf-turtle', '~> 3.0' - #gem.add_development_dependency 'rdf-spec', '~> 3.0' - #gem.add_development_dependency 'rdf-vocab', '~> 3.0' - gem.add_development_dependency 'rdf-isomorphic', '>= 2.2', '< 4.0' - gem.add_development_dependency 'rdf-turtle', '>= 2.2', '< 4.0' - gem.add_development_dependency 'rdf-spec', '>= 2.2', '< 4.0' - gem.add_development_dependency 'rdf-vocab', '>= 2.2', '< 4.0' - gem.add_development_dependency 'yard' , '~> 0.8' - - # Rubinius has it's own dependencies - if RUBY_ENGINE == "rbx" && RUBY_VERSION >= "2.1.0" - gem.add_runtime_dependency "racc" - end + gem.add_development_dependency 'json-ld', '>= 3.1' + gem.add_development_dependency 'rspec', '~> 3.9' + gem.add_development_dependency 'rspec-its', '~> 1.3' + gem.add_development_dependency 'rdf-isomorphic', '~> 3.1' + gem.add_development_dependency 'rdf-turtle', '~> 3.1' + gem.add_development_dependency 'rdf-spec', '~> 3.1' + gem.add_development_dependency 'rdf-vocab', '~> 3.1' + gem.add_development_dependency 'yard' , '~> 0.9.20' gem.post_install_message = nil end diff --git a/script/parse b/script/parse index 4a33ad6..917fb84 100755 --- a/script/parse +++ b/script/parse @@ -9,7 +9,7 @@ require 'getoptlong' require 'logger' require 'open-uri' -def run(input, options) +def run(input, **options) reader_class = RDF::Reader.for(options[:input_format].to_sym) raise "Reader not found for #{$input_format}" unless reader_class @@ -17,7 +17,7 @@ def run(input, options) num = 0 if options[:output_format] == :ntriples || options[:quiet] - reader_class.new(input, options).each do |statement| + reader_class.new(input, **options).each do |statement| num += 1 if options[:quiet] #print "." @@ -26,12 +26,12 @@ def run(input, options) end end elsif options[:output_format] == :inspect - reader_class.new(input, options).each do |statement| + reader_class.new(input, **options).each do |statement| num += 1 options[:output].puts statement.inspect end else - r = reader_class.new(input, options) + r = reader_class.new(input, **options) g = RDF::Repository.new << r num = g.count STDERR.puts "graph: #{g.dump(:ttl)}" if options[:verbose] @@ -93,9 +93,9 @@ end if ARGV.empty? s = input ? input : $stdin.read - run(StringIO.new(s), options) + run(StringIO.new(s), **options) else ARGV.each do |test_file| - run(Kernel.open(test_file), options) + run(Kernel.open(test_file), **options) end end diff --git a/script/tc b/script/tc index 5e4ce20..840722d 100755 --- a/script/tc +++ b/script/tc @@ -30,7 +30,7 @@ def earl_preamble(options) ) end -def run_tc(tc, options) +def run_tc(tc, **options) STDERR.write "run #{tc.name}" if options[:verbose] diff --git a/spec/jruby_spec.rb b/spec/jruby_spec.rb index ef82f0e..7daa7c2 100644 --- a/spec/jruby_spec.rb +++ b/spec/jruby_spec.rb @@ -38,9 +38,9 @@ end # Serialize @graph to a string and compare against regexps - def serialize(options = {}) + def serialize(**options) @debug = [] - result = RDF::RDFXML::Writer.buffer({logger: false, standard_prefixes: true}.merge(options)) do |writer| + result = RDF::RDFXML::Writer.buffer(logger: false, standard_prefixes: true, **options) do |writer| writer << @graph end require 'cgi' diff --git a/spec/reader_spec.rb b/spec/reader_spec.rb index f897dce..eb90dd3 100644 --- a/spec/reader_spec.rb +++ b/spec/reader_spec.rb @@ -1126,8 +1126,8 @@ end end - def parse(input, options) - RDF::Repository.new << RDF::RDFXML::Reader.new(input, options.merge(logger: logger, library: @library)) + def parse(input, **options) + RDF::Repository.new << RDF::RDFXML::Reader.new(input, logger: logger, library: @library, **options) end end diff --git a/spec/suite_helper.rb b/spec/suite_helper.rb index 401a8c6..6fda920 100644 --- a/spec/suite_helper.rb +++ b/spec/suite_helper.rb @@ -9,6 +9,10 @@ module File REMOTE_PATH = "http://www.w3.org/2013/RDFXMLTests/" LOCAL_PATH = ::File.expand_path("../w3c-rdf/rdf-xml", __FILE__) + '/' + class << self + alias_method :original_open_file, :open_file + end + ## # Override to use Patron for http and https, Kernel.open otherwise. # @@ -18,43 +22,49 @@ module File # HTTP Request headers. # @return [IO] File stream # @yield [IO] File stream - def self.open_file(filename_or_url, options = {}, &block) - case filename_or_url.to_s - when /^file:/ + def self.open_file(filename_or_url, **options, &block) + case + when filename_or_url.to_s =~ /^file:/ path = filename_or_url[5..-1] - Kernel.open(path.to_s, &block) - when /^#{REMOTE_PATH}/ - begin - #puts "attempt to open #{filename_or_url} locally" - local_filename = filename_or_url.to_s.sub(REMOTE_PATH, LOCAL_PATH) - if ::File.exist?(local_filename) - response = ::File.open(local_filename) - #puts "use #{filename_or_url} locally" - case filename_or_url.to_s - when /\.rdf$/ - def response.content_type; 'application/rdf+xml'; end - when /\.nt$/ - def response.content_type; 'application/n-triples'; end - end + Kernel.open(path.to_s, options, &block) + when (filename_or_url.to_s =~ %r{^#{REMOTE_PATH}} && Dir.exist?(LOCAL_PATH)) + #puts "attempt to open #{filename_or_url} locally" + localpath = filename_or_url.to_s.sub(REMOTE_PATH, LOCAL_PATH) + response = begin + ::File.open(localpath) + rescue Errno::ENOENT => e + raise IOError, e.message + end + document_options = { + base_uri: RDF::URI(filename_or_url), + charset: Encoding::UTF_8, + code: 200, + headers: {} + } + #puts "use #{filename_or_url} locally" + document_options[:headers][:content_type] = case filename_or_url.to_s + when /\.html$/ then 'text/html' + when /\.xhtml$/ then 'application/xhtml+xml' + when /\.xml$/ then 'application/xml' + when /\.svg$/ then 'image/svg+xml' + when /\.ttl$/ then 'text/turtle' + when /\.ttl$/ then 'text/turtle' + when /\.jsonld$/ then 'application/ld+json' + else 'unknown' + end - if block_given? - begin - yield response - ensure - response.close - end - else - response - end - else - Kernel.open(filename_or_url.to_s, &block) - end - rescue Errno::ENOENT #, OpenURI::HTTPError - # Not there, don't run tests - StringIO.new("") + document_options[:headers][:content_type] = response.content_type if response.respond_to?(:content_type) + # For overriding content type from test data + document_options[:headers][:content_type] = options[:contentType] if options[:contentType] + + remote_document = RDF::Util::File::RemoteDocument.new(response.read, **document_options) + if block_given? + yield remote_document + else + remote_document end else - Kernel.open(filename_or_url.to_s, &block) + original_open_file(filename_or_url, **options, &block) end end end @@ -93,7 +103,7 @@ def self.open(file) g = RDF::Repository.load(file, format: :turtle) JSON::LD::API.fromRDF(g) do |expanded| JSON::LD::API.frame(expanded, FRAME) do |framed| - yield Manifest.new(framed['@graph'].first) + yield Manifest.new(framed) end end end diff --git a/spec/writer_spec.rb b/spec/writer_spec.rb index dd0c174..7bb6ec9 100644 --- a/spec/writer_spec.rb +++ b/spec/writer_spec.rb @@ -705,21 +705,22 @@ class FOO < RDF::Vocabulary("http://foo/"); end end end unless ENV['CI'] # Not for continuous integration - def parse(input, options = {}) + def parse(input, **options) reader_class = RDF::Reader.for(options.fetch(:format, :rdfxml)) - reader_class.new(input, options, &:each).to_a.extend(RDF::Enumerable) + reader_class.new(input, **options, &:each).to_a.extend(RDF::Enumerable) end # Serialize ntstr to a string and compare against regexps - def serialize(ntstr, options = {}) + def serialize(ntstr, **options) g = ntstr.is_a?(RDF::Enumerable) ? ntstr : parse(ntstr, format: :ntriples, validate: false, logger: []) logger.info "serialized: #{ntstr}" - result = RDF::RDFXML::Writer.buffer(options.merge( + result = RDF::RDFXML::Writer.buffer( logger: logger, standard_prefixes: true, - encoding: Encoding::UTF_8 - )) do |writer| + encoding: Encoding::UTF_8, + **options + ) do |writer| writer << g end require 'cgi'