From 8a3da7f6f19012efc4c70fdb57f44d8910d3514c Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Fri, 22 May 2020 12:09:05 -0700 Subject: [PATCH 01/22] Update URLs to use HTTPS, where possible. --- AUTHORS | 2 +- README.md | 36 +++++++++++++++---------------- UNLICENSE | 2 +- etc/doap.ttl | 40 ++++++++++++++--------------------- lib/sxp.rb | 14 ------------ lib/sxp/pair.rb | 4 ++-- lib/sxp/reader/common_lisp.rb | 6 +++--- lib/sxp/reader/scheme.rb | 6 +++--- lib/sxp/reader/sparql.rb | 12 +++++------ sxp.gemspec | 2 +- 10 files changed, 51 insertions(+), 73 deletions(-) diff --git a/AUTHORS b/AUTHORS index e3f9a56..3350b98 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,2 @@ * Arto Bendiken -* Gregg Kellogg +* Gregg Kellogg diff --git a/README.md b/README.md index aac470d..5d711f2 100755 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ This is a Ruby implementation of a universal [S-expression][] parser. -[![Gem Version](https://badge.fury.io/rb/sxp.png)](http://badge.fury.io/rb/sxp) -[![Build Status](https://travis-ci.org/dryruby/sxp.rb.png?branch=master)](http://travis-ci.org/dryruby/sxp.rb) +[![Gem Version](https://badge.fury.io/rb/sxp.png)](https:/badge.fury.io/rb/sxp) +[![Build Status](https://travis-ci.org/dryruby/sxp.rb.png?branch=master)](https:/travis-ci.org/dryruby/sxp.rb) ## Features @@ -44,7 +44,7 @@ This is a Ruby implementation of a universal [S-expression][] parser. require 'rdf' - SXP::Reader::SPARQL.read %q((base )) #=> [:base, RDF::URI('http://ar.to/')] + SXP::Reader::SPARQL.read %q((base )) #=> [:base, RDF::URI('https://ar.to/')] ### Writing an SXP with formatting @@ -52,7 +52,7 @@ This is a Ruby implementation of a universal [S-expression][] parser. ## Documentation -* Full documentation available on [RubyDoc](http://rubydoc.info/gems/sxp/file/README.md) +* Full documentation available on [RubyDoc](https:/rubydoc.info/gems/sxp/file/README.md) * {SXP} @@ -74,14 +74,14 @@ This is a Ruby implementation of a universal [S-expression][] parser. Dependencies ------------ -* [Ruby](http://ruby-lang.org/) (>= 2.4) -* [RDF.rb](http://rubygems.org/gems/rdf) (~> 3.1), only needed for SPARQL +* [Ruby](https:/ruby-lang.org/) (>= 2.4) +* [RDF.rb](https:/rubygems.org/gems/rdf) (~> 3.1), only needed for SPARQL S-expressions Installation ------------ -The recommended installation method is via [RubyGems](http://rubygems.org/). +The recommended installation method is via [RubyGems](https:/rubygems.org/). To install the latest official release of the SXP.rb gem, do: % [sudo] gem install sxp @@ -96,33 +96,33 @@ To get a local working copy of the development repository, do: Alternatively, you can download the latest development version as a tarball as follows: - % wget http://github.com/dryruby/sxp.rb/tarball/master + % wget https:/github.com/dryruby/sxp.rb/tarball/master Resources --------- -* -* -* +* +* +* Authors ------- -* [Arto Bendiken](https://github.com/bendiken) - -* [Gregg Kellogg](http://github.com/gkellogg) - +* [Arto Bendiken](https://github.com/artob) - +* [Gregg Kellogg](https://github.com/gkellogg) - Contributors ------------ -* [Ben Lavender](https://github.com/bhuga) - +* [Ben Lavender](https://github.com/bhuga) - License ------- SXP.rb is free and unencumbered public domain software. For more -information, see or the accompanying UNLICENSE file. +information, see or the accompanying UNLICENSE file. -[S-expression]: http://en.wikipedia.org/wiki/S-expression -[Scheme]: http://scheme.info/ -[Common Lisp]: http://en.wikipedia.org/wiki/Common_Lisp +[S-expression]: https://en.wikipedia.org/wiki/S-expression +[Scheme]: https://scheme.info/ +[Common Lisp]: https://en.wikipedia.org/wiki/Common_Lisp [SPARQL]: https://jena.apache.org/documentation/notes/sse.html diff --git a/UNLICENSE b/UNLICENSE index 68a49da..ea7eb6d 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/etc/doap.ttl b/etc/doap.ttl index ff387f7..e941738 100644 --- a/etc/doap.ttl +++ b/etc/doap.ttl @@ -1,8 +1,8 @@ -@base . -@prefix dc: . +@base . +@prefix dc: . @prefix doap: . @prefix foaf: . -@prefix rdf: . +@prefix rdf: . @prefix rdfs: . @prefix xsd: . @@ -17,31 +17,23 @@ subset of the IEEE Scheme and DSSSL standards. """@en; doap:implements ; - doap:developer , ; - doap:maintainer , ; - doap:documenter , ; - dc:creator ; - foaf:maker ; - doap:bug-database ; - doap:category , - , - , - , - , - ; + doap:developer , ; + doap:maintainer ; + doap:documenter , ; + dc:creator ; + foaf:maker ; + doap:bug-database ; doap:created "2007-02-26"^^xsd:date; - doap:homepage ; - doap:license ; - doap:platform "Ruby" . + doap:homepage ; + doap:license ; + doap:programming-language "Ruby" . - a foaf:Person; - foaf:homepage ; + a foaf:Person; + foaf:homepage ; foaf:mbox ; foaf:name "Gregg Kellogg" . - a foaf:Person; - rdfs:isDefinedBy ; - foaf:homepage ; + a foaf:Person; + foaf:homepage ; foaf:mbox ; - rdfs:seeAlso ; foaf:name "Arto Bendiken" . diff --git a/lib/sxp.rb b/lib/sxp.rb index 74b4017..bf675bb 100644 --- a/lib/sxp.rb +++ b/lib/sxp.rb @@ -1,20 +1,6 @@ require 'rational' require 'stringio' -if RUBY_VERSION < '1.8.7' - # @see http://rubygems.org/gems/backports - begin - require 'backports/1.8.7' - rescue LoadError - begin - require 'rubygems' - require 'backports/1.8.7' - rescue LoadError - abort "SXP.rb requires Ruby 1.8.7 or the Backports gem (hint: `gem install backports')." - end - end -end - require 'sxp/version' require 'sxp/extensions' require 'sxp/writer' diff --git a/lib/sxp/pair.rb b/lib/sxp/pair.rb index b40a6c0..afd44b1 100644 --- a/lib/sxp/pair.rb +++ b/lib/sxp/pair.rb @@ -27,7 +27,7 @@ def empty? # Returns `true` if the tail of this pair is not `nil` or another pair. # # @return [Boolean] - # @see http://srfi.schemers.org/srfi-1/srfi-1.html#ImproperLists + # @see https:/srfi.schemers.org/srfi-1/srfi-1.html#ImproperLists def dotted? !proper? end @@ -36,7 +36,7 @@ def dotted? # Returns `true` if the tail of this pair is `nil` or another pair. # # @return [Boolean] - # @see http://srfi.schemers.org/srfi-1/srfi-1.html#ImproperLists + # @see https:/srfi.schemers.org/srfi-1/srfi-1.html#ImproperLists def proper? tail.nil? || tail.is_a?(Pair) end diff --git a/lib/sxp/reader/common_lisp.rb b/lib/sxp/reader/common_lisp.rb index d1a2b1d..9b683fb 100644 --- a/lib/sxp/reader/common_lisp.rb +++ b/lib/sxp/reader/common_lisp.rb @@ -3,7 +3,7 @@ module SXP; class Reader ## # A Common Lisp S-expressions parser. # - # @see http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node14.html + # @see https:/www.cs.cmu.edu/Groups/AI/html/cltl/clm/node14.html class CommonLisp < Basic OPTIONS = {nil: nil, t: true, quote: :quote, function: :function} @@ -16,7 +16,7 @@ class CommonLisp < Basic # Escape characters, used in the form `#\Backspace`. Case is treated # insensitively - # @see http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node22.html + # @see https:/www.cs.cmu.edu/Groups/AI/html/cltl/clm/node22.html CHARACTERS = { 'newline' => "\n", 'space' => " ", @@ -114,7 +114,7 @@ def read_function # eroneously read characters back in the input stream # # @return [String] - # @see http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node22.html + # @see https:/www.cs.cmu.edu/Groups/AI/html/cltl/clm/node22.html def read_character lit = read_literal diff --git a/lib/sxp/reader/scheme.rb b/lib/sxp/reader/scheme.rb index f741068..34223a7 100644 --- a/lib/sxp/reader/scheme.rb +++ b/lib/sxp/reader/scheme.rb @@ -3,7 +3,7 @@ module SXP; class Reader ## # A Scheme R4RS S-expressions parser. # - # @see http://people.csail.mit.edu/jaffer/r4rs_9.html#SEC65 + # @see https:/people.csail.mit.edu/jaffer/r4rs_9.html#SEC65 class Scheme < Extended DECIMAL = /^[+-]?(\d*)?\.\d*$/ INTEGER_BASE_2 = /^[+-]?[01]+$/ @@ -14,7 +14,7 @@ class Scheme < Extended # Escape characters, used in the form `#\newline`. Case is treated # insensitively - # @see http://people.csail.mit.edu/jaffer/r4rs_9.html#SEC65 + # @see https:/people.csail.mit.edu/jaffer/r4rs_9.html#SEC65 CHARACTERS = { 'newline' => "\n", 'space' => " ", @@ -76,7 +76,7 @@ def read_sharp # eroneously read characters back in the input stream # # @return [String] - # @see http://people.csail.mit.edu/jaffer/r4rs_9.html#SEC65 + # @see https:/people.csail.mit.edu/jaffer/r4rs_9.html#SEC65 def read_character lit = read_literal diff --git a/lib/sxp/reader/sparql.rb b/lib/sxp/reader/sparql.rb index 41f015a..2e6a54b 100644 --- a/lib/sxp/reader/sparql.rb +++ b/lib/sxp/reader/sparql.rb @@ -1,13 +1,13 @@ # -*- encoding: utf-8 -*- -require 'rdf' # @see http://rubygems.org/gems/rdf +require 'rdf' # @see https:/rubygems.org/gems/rdf module SXP; class Reader ## # A SPARQL Syntax Expressions (SSE) parser. # - # Requires [RDF.rb](http://rdf.rubyforge.org/). + # Requires [RDF.rb](https:/rubygems.org/gems/rdf/). # - # @see http://openjena.org/wiki/SSE + # @see https:/openjena.org/wiki/SSE class SPARQL < Extended # Alias for rdf:type A = /^a$/ @@ -83,12 +83,12 @@ def initialize(input, **options, &block) end ## - # Reads SSE Tokens, including {RDF::Literal}, {RDF::URI} and RDF::Node. + # Reads SSE Tokens, including `RDF::Literal`, `RDF::URI` and `RDF::Node`. # # Performs forward reference for prefix and base URI representations and saves in # {#base_uri} and {#prefixes} accessors. # - # Transforms tokens matching a {PNAME} pattern into {RDF::URI} instances if a match is + # Transforms tokens matching a {PNAME} pattern into `RDF::URI` instances if a match is # found with a previously identified {PREFIX}. # @return [Object] def read_token @@ -211,7 +211,7 @@ def read_rdf_uri # # Atoms parsed including `base`, `prefix`, `true`, `false`, numeric, BNodes and variables. # - # Creates {RDF::Literal}, RDF::Node, or {RDF::Query::Variable} instances where appropriate. + # Creates `RDF::Literal`, `RDF::Node`, or `RDF::Query::Variable` instances where appropriate. # # @return [Object] def read_atom diff --git a/sxp.gemspec b/sxp.gemspec index 9e4547e..f5143ff 100755 --- a/sxp.gemspec +++ b/sxp.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |gem| gem.date = File.mtime('VERSION').strftime('%Y-%m-%d') gem.name = 'sxp' - gem.homepage = 'http://sxp.rubyforge.org/' + gem.homepage = 'https://github.com/dryruby/sxp/' gem.license = 'Unlicense' gem.summary = 'A pure-Ruby implementation of a universal S-expression parser.' gem.description = 'Universal S-expression parser with specific support for Common Lisp, Scheme, and RDF/SPARQL' From 5c259d9af334b95e0e9e621254e65f1bdcbf6768 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Fri, 22 May 2020 12:35:36 -0700 Subject: [PATCH 02/22] Use http://unlicense.org/ for doap:license, in the absense of anything more specific. --- etc/doap.ttl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/doap.ttl b/etc/doap.ttl index e941738..3e9c288 100644 --- a/etc/doap.ttl +++ b/etc/doap.ttl @@ -25,7 +25,7 @@ doap:bug-database ; doap:created "2007-02-26"^^xsd:date; doap:homepage ; - doap:license ; + doap:license ; doap:programming-language "Ruby" . a foaf:Person; From 25f5d813233a106404604fd392dae90524740a27 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sat, 30 May 2020 13:15:25 -0700 Subject: [PATCH 03/22] Update doap:license (again) to https://unlicense.org/1.0/. --- etc/doap.ttl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/doap.ttl b/etc/doap.ttl index 3e9c288..46bd10c 100644 --- a/etc/doap.ttl +++ b/etc/doap.ttl @@ -25,7 +25,7 @@ doap:bug-database ; doap:created "2007-02-26"^^xsd:date; doap:homepage ; - doap:license ; + doap:license ; doap:programming-language "Ruby" . a foaf:Person; From 4ac9545fbcdfab410ad35a8a4d1143ea48e90909 Mon Sep 17 00:00:00 2001 From: Arto Bendiken Date: Sat, 12 Sep 2020 11:29:16 +0300 Subject: [PATCH 04/22] Configured Gitstamp for GitHub Actions. --- .github/workflows/gitstamp.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/gitstamp.yaml diff --git a/.github/workflows/gitstamp.yaml b/.github/workflows/gitstamp.yaml new file mode 100644 index 0000000..20b034a --- /dev/null +++ b/.github/workflows/gitstamp.yaml @@ -0,0 +1,19 @@ +# See: https://github.com/artob/gitstamp-action +--- +name: Gitstamp +on: + push: + branches: + - develop +jobs: + gitstamp: + runs-on: ubuntu-latest + name: Timestamp commit with Gitstamp + steps: + - name: Clone repository + uses: actions/checkout@v2 + - name: Submit Gitstamp transaction + uses: artob/gitstamp-action@v1 + with: + wallet-key: ${{ secrets.GITSTAMP_KEYFILE }} + commit-link: true From cb672f2f1901308ed942da1c4352d3a615b69002 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 25 Oct 2020 16:50:59 -0700 Subject: [PATCH 05/22] Update PDD info in the README.Update PDD info in the README. --- Gemfile | 1 + README.md | 40 ++++++++++++++++++++++++++-------------- bin/sxp2json | 4 ++-- bin/sxp2rdf | 4 ++-- bin/sxp2xml | 4 ++-- bin/sxp2yaml | 4 ++-- 6 files changed, 35 insertions(+), 22 deletions(-) diff --git a/Gemfile b/Gemfile index a5236da..85e716a 100644 --- a/Gemfile +++ b/Gemfile @@ -6,4 +6,5 @@ gem "rdf", git: "git://github.com/ruby-rdf/rdf.git", branch: "develop" group :debug do gem "byebug", platform: :mri + gem 'awesome_print', github: 'MatthiasWinkelmann/awesome_print' end diff --git a/README.md b/README.md index 5d711f2..34b6594 100755 --- a/README.md +++ b/README.md @@ -71,23 +71,20 @@ This is a Ruby implementation of a universal [S-expression][] parser. ### Generating SXP * {SXP::Generator} -Dependencies ------------- +# Dependencies * [Ruby](https:/ruby-lang.org/) (>= 2.4) * [RDF.rb](https:/rubygems.org/gems/rdf) (~> 3.1), only needed for SPARQL S-expressions -Installation ------------- +# Installation The recommended installation method is via [RubyGems](https:/rubygems.org/). To install the latest official release of the SXP.rb gem, do: % [sudo] gem install sxp -Download --------- +## Download To get a local working copy of the development repository, do: @@ -98,26 +95,38 @@ as follows: % wget https:/github.com/dryruby/sxp.rb/tarball/master -Resources ---------- +## Resources * * * -Authors -------- +## Authors * [Arto Bendiken](https://github.com/artob) - * [Gregg Kellogg](https://github.com/gkellogg) - -Contributors ------------- +## Contributors * [Ben Lavender](https://github.com/bhuga) - -License -------- +## Contributing +This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange development and release activity. All submissions _must_ be on a feature branch based on the _develop_ branch to ease staging and integration. + +* Do your best to adhere to the existing coding conventions and idioms. +* Don't use hard tabs, and don't leave trailing whitespace on any line. +* Do document every method you add using [YARD][] annotations. Read the + [tutorial][YARD-GS] or just look at the existing code for examples. +* Don't touch the `.gemspec`, `VERSION` or `AUTHORS` files. If you need to + change them, do so on your private branch only. +* Do feel free to add yourself to the `CREDITS` file and the corresponding + list in the the `README`. Alphabetical order applies. +* Do note that in order for us to merge any non-trivial changes (as a rule + of thumb, additions larger than about 15 lines of code), we need an + explicit [public domain dedication][PDD] on record from you, + which you will be asked to agree to on the first commit to a repo within the organization. + +## License SXP.rb is free and unencumbered public domain software. For more information, see or the accompanying UNLICENSE file. @@ -126,3 +135,6 @@ information, see or the accompanying UNLICENSE file. [Scheme]: https://scheme.info/ [Common Lisp]: https://en.wikipedia.org/wiki/Common_Lisp [SPARQL]: https://jena.apache.org/documentation/notes/sse.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 diff --git a/bin/sxp2json b/bin/sxp2json index 17c8aed..1c6b6a5 100755 --- a/bin/sxp2json +++ b/bin/sxp2json @@ -1,5 +1,5 @@ -#!/usr/bin/env ruby -rubygems -$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))) +#!/usr/bin/env ruby +$::unshift(File.expand_path("../../lib", __FILE__)) require 'sxp' abort "Usage: #{File.basename($0)} input.sxp > output.json" if ARGV.empty? diff --git a/bin/sxp2rdf b/bin/sxp2rdf index 01e5d91..a3cb32c 100755 --- a/bin/sxp2rdf +++ b/bin/sxp2rdf @@ -1,5 +1,5 @@ -#!/usr/bin/env ruby -rubygems -$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))) +#!/usr/bin/env ruby +$::unshift(File.expand_path("../../lib", __FILE__)) require 'sxp' abort "Usage: #{File.basename($0)} input.sxp > output.rdf" if ARGV.empty? diff --git a/bin/sxp2xml b/bin/sxp2xml index 29b72f2..74830b6 100755 --- a/bin/sxp2xml +++ b/bin/sxp2xml @@ -1,5 +1,5 @@ -#!/usr/bin/env ruby -rubygems -$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))) +#!/usr/bin/env ruby +$::unshift(File.expand_path("../../lib", __FILE__)) require 'sxp' abort "Usage: #{File.basename($0)} input.sxp > output.xml" if ARGV.empty? diff --git a/bin/sxp2yaml b/bin/sxp2yaml index 8b7fa83..1b082e4 100755 --- a/bin/sxp2yaml +++ b/bin/sxp2yaml @@ -1,5 +1,5 @@ -#!/usr/bin/env ruby -rubygems -$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))) +#!/usr/bin/env ruby +$::unshift(File.expand_path("../../lib", __FILE__)) require 'sxp' abort "Usage: #{File.basename($0)} input.sxp > output.yaml" if ARGV.empty? From b75b537906f07d9f68b5645f74b34ad45328196a Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 8 Nov 2020 13:34:43 -0800 Subject: [PATCH 06/22] Update PDD info in the README.Update PDD info in the README.Update version of awesome_print. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 85e716a..1c2e5d5 100644 --- a/Gemfile +++ b/Gemfile @@ -6,5 +6,5 @@ gem "rdf", git: "git://github.com/ruby-rdf/rdf.git", branch: "develop" group :debug do gem "byebug", platform: :mri - gem 'awesome_print', github: 'MatthiasWinkelmann/awesome_print' + gem 'awesome_print', github: 'akshaymohite/awesome_print' end From a9334a3ad7c867bde72cd6fcce646a187882a1ce Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sat, 21 Nov 2020 13:04:34 -0800 Subject: [PATCH 07/22] Run CI on ruby-head. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4ed71ed..98e5c0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,14 @@ rvm: - 2.5 - 2.6 - 2.7 + - ruby-head - jruby - rbx cache: bundler sudo: false matrix: allow_failures: + - rvm: ruby-head - rvm: jruby - rvm: rbx dist: trusty From ad1dc2f59bf8d9196fd822c90fd6753f4c3ed001 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Tue, 22 Dec 2020 11:57:42 -0800 Subject: [PATCH 08/22] Run CI on GitHub. --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++++++++++ README.md | 2 +- sxp.gemspec | 4 ++-- 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8d5176a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +# This workflow runs continuous CI across different versions of ruby on all branches and pull requests to develop. + +name: CI +on: + push: + branches: [ '**' ] + pull_request: + branches: [ develop ] + workflow_dispatch: + +jobs: + tests: + name: Ruby ${{ matrix.ruby }} + if: "contains(github.event.commits[0].message, '[ci skip]') == false" + runs-on: ubuntu-latest + env: + CI: true + strategy: + fail-fast: false + matrix: + ruby: + - 2.4 + - 2.5 + - 2.6 + - 2.7 + - ruby-head + - jruby + steps: + - name: Clone repository + uses: actions/checkout@v2 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + - name: Install dependencies + run: bundle install --jobs 4 --retry 3 + - name: Run tests + run: bundle exec rspec spec + diff --git a/README.md b/README.md index 34b6594..5cb2507 100755 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This is a Ruby implementation of a universal [S-expression][] parser. [![Gem Version](https://badge.fury.io/rb/sxp.png)](https:/badge.fury.io/rb/sxp) -[![Build Status](https://travis-ci.org/dryruby/sxp.rb.png?branch=master)](https:/travis-ci.org/dryruby/sxp.rb) +[![Build Status](https://github.com/dryruby/sxp.rb/workflows/CI/badge.svg?branch=develop)](https://github.com/dryruby/sxp.rb/actions?query=workflow%3ACI) ## Features diff --git a/sxp.gemspec b/sxp.gemspec index f5143ff..2052bde 100755 --- a/sxp.gemspec +++ b/sxp.gemspec @@ -22,8 +22,8 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 2.4' gem.requirements = [] - gem.add_development_dependency 'rspec', '~> 3.9' - gem.add_development_dependency 'yard' , '~> 0.9.20' + gem.add_development_dependency 'rspec', '~> 3.10' + gem.add_development_dependency 'yard' , '~> 0.9' gem.add_runtime_dependency 'rdf', '~> 3.1' gem.post_install_message = nil From 3ed4391fdac1b8f634fed576f5aa962f8d96c128 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Tue, 22 Dec 2020 12:04:54 -0800 Subject: [PATCH 09/22] Configure coveralls. --- .coveralls.yml | 1 + .gitignore | 1 + Gemfile | 5 +++++ README.md | 1 + spec/spec_helper.rb | 15 +++++++++++++++ 5 files changed, 23 insertions(+) create mode 100644 .coveralls.yml diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..956c866 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1 @@ +repo_token: 6TBOCfVJmaf2hdCQLUaO6aFptRqL2sfcK diff --git a/.gitignore b/.gitignore index e462acd..5c00ba9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ tmp Gemfile.lock /.rbx/ /.bundle +coverage diff --git a/Gemfile b/Gemfile index 1c2e5d5..b5c5325 100644 --- a/Gemfile +++ b/Gemfile @@ -8,3 +8,8 @@ group :debug do gem "byebug", platform: :mri gem 'awesome_print', github: 'akshaymohite/awesome_print' end + +group :development, :test do + gem 'simplecov', platforms: :mri + gem 'coveralls', '~> 0.8', platforms: :mri +end diff --git a/README.md b/README.md index 5cb2507..b288e7c 100755 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ This is a Ruby implementation of a universal [S-expression][] parser. [![Gem Version](https://badge.fury.io/rb/sxp.png)](https:/badge.fury.io/rb/sxp) [![Build Status](https://github.com/dryruby/sxp.rb/workflows/CI/badge.svg?branch=develop)](https://github.com/dryruby/sxp.rb/actions?query=workflow%3ACI) +[![Coverage Status](https://coveralls.io/repos/dryruby/sxp.rb/badge.svg)](https://coveralls.io/r/dryruby/sxp.rb) ## Features diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cb0e3e4..ea687eb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,21 @@ require "bundler/setup" require 'rspec' + +begin + require 'simplecov' + require 'coveralls' + SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ + SimpleCov::Formatter::HTMLFormatter, + Coveralls::SimpleCov::Formatter + ]) + SimpleCov.start do + add_filter "/spec/" + end +rescue LoadError => e + STDERR.puts "Coverage Skipped: #{e.message}" +end + require 'sxp' include SXP From 86e8f8e76d0cde4ff0f6aeba28f7cdfcac5684cc Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 11 Aug 2021 14:34:44 -0700 Subject: [PATCH 10/22] Update CI for coveralls. Remove awesome_print dependency (could have replaced with amazing_print). --- .github/workflows/ci.yml | 10 +++++++--- .travis.yml | 20 -------------------- Gemfile | 5 ++--- README.md | 2 +- spec/spec_helper.rb | 11 +++++++++-- 5 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d5176a..a725c23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,11 +15,11 @@ jobs: runs-on: ubuntu-latest env: CI: true + ALLOW_FAILURES: ${{ endsWith(matrix.ruby, 'head') }} strategy: fail-fast: false matrix: ruby: - - 2.4 - 2.5 - 2.6 - 2.7 @@ -35,5 +35,9 @@ jobs: - name: Install dependencies run: bundle install --jobs 4 --retry 3 - name: Run tests - run: bundle exec rspec spec - + run: bundle exec rspec spec || $ALLOW_FAILURES + - name: Coveralls GitHub Action + uses: coverallsapp/github-action@v1.1.2 + if: "matrix.ruby == '3.0'" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 98e5c0c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: ruby -script: "bundle exec rspec spec" -env: - - CI=true -rvm: - - 2.4 - - 2.5 - - 2.6 - - 2.7 - - ruby-head - - jruby - - rbx -cache: bundler -sudo: false -matrix: - allow_failures: - - rvm: ruby-head - - rvm: jruby - - rvm: rbx -dist: trusty diff --git a/Gemfile b/Gemfile index b5c5325..06eb956 100644 --- a/Gemfile +++ b/Gemfile @@ -6,10 +6,9 @@ gem "rdf", git: "git://github.com/ruby-rdf/rdf.git", branch: "develop" group :debug do gem "byebug", platform: :mri - gem 'awesome_print', github: 'akshaymohite/awesome_print' end group :development, :test do - gem 'simplecov', platforms: :mri - gem 'coveralls', '~> 0.8', platforms: :mri + gem 'simplecov', '~> 0.21', platforms: :mri + gem 'simplecov-lcov', '~> 0.8', platforms: :mri end diff --git a/README.md b/README.md index b288e7c..e2e6a24 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This is a Ruby implementation of a universal [S-expression][] parser. [![Gem Version](https://badge.fury.io/rb/sxp.png)](https:/badge.fury.io/rb/sxp) [![Build Status](https://github.com/dryruby/sxp.rb/workflows/CI/badge.svg?branch=develop)](https://github.com/dryruby/sxp.rb/actions?query=workflow%3ACI) -[![Coverage Status](https://coveralls.io/repos/dryruby/sxp.rb/badge.svg)](https://coveralls.io/r/dryruby/sxp.rb) +[![Coverage Status](https://coveralls.io/repos/dryruby/sxp.rb/badge.svg?branch=develop)](https://coveralls.io/r/dryruby/sxp.rb?branch=develop) ## Features diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ea687eb..4e3c6aa 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,10 +6,17 @@ begin require 'simplecov' - require 'coveralls' + require 'simplecov-lcov' + + SimpleCov::Formatter::LcovFormatter.config do |config| + #Coveralls is coverage by default/lcov. Send info results + config.report_with_single_file = true + config.single_report_path = 'coverage/lcov.info' + end + SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ SimpleCov::Formatter::HTMLFormatter, - Coveralls::SimpleCov::Formatter + SimpleCov::Formatter::LcovFormatter ]) SimpleCov.start do add_filter "/spec/" From 10fffbcef27d63a7a038c0699fc4b555c2a298e2 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Tue, 26 Oct 2021 12:16:55 -0700 Subject: [PATCH 11/22] Update CI. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a725c23..5f45ff1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,7 @@ jobs: - 2.5 - 2.6 - 2.7 + - 3.0 - ruby-head - jruby steps: @@ -35,7 +36,7 @@ jobs: - name: Install dependencies run: bundle install --jobs 4 --retry 3 - name: Run tests - run: bundle exec rspec spec || $ALLOW_FAILURES + run: ruby --version; bundle exec rspec spec || $ALLOW_FAILURES - name: Coveralls GitHub Action uses: coverallsapp/github-action@v1.1.2 if: "matrix.ruby == '3.0'" From 9928a59f9b69122a1dcbf8963babf1b5cf8d2931 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 8 Dec 2021 11:06:33 -0800 Subject: [PATCH 12/22] Update documentation, dependencies, and version sync for 1.2. --- .github/workflows/ci.yml | 1 - README.md | 6 +++--- VERSION | 2 +- sxp.gemspec | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f45ff1..970180d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,6 @@ jobs: fail-fast: false matrix: ruby: - - 2.5 - 2.6 - 2.7 - 3.0 diff --git a/README.md b/README.md index e2e6a24..d140db0 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This is a Ruby implementation of a universal [S-expression][] parser. * Parses S-expressions in universal, [Scheme][], [Common Lisp][], or [SPARQL][] syntax. * Adds a `#to_sxp` method to Ruby objects. -* Compatible with Ruby >= 2.4, Rubinius >= 3.0, and JRuby 9+. +* Compatible with Ruby >= 2.6, Rubinius >= 3.0, and JRuby 9+. ## Examples @@ -74,8 +74,8 @@ This is a Ruby implementation of a universal [S-expression][] parser. # Dependencies -* [Ruby](https:/ruby-lang.org/) (>= 2.4) -* [RDF.rb](https:/rubygems.org/gems/rdf) (~> 3.1), only needed for SPARQL +* [Ruby](https:/ruby-lang.org/) (>= 2.6) +* [RDF.rb](https:/rubygems.org/gems/rdf) (~> 3.2), only needed for SPARQL S-expressions # Installation diff --git a/VERSION b/VERSION index 9084fa2..26aaba0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.0 +1.2.0 diff --git a/sxp.gemspec b/sxp.gemspec index 2052bde..cb691e2 100755 --- a/sxp.gemspec +++ b/sxp.gemspec @@ -20,7 +20,7 @@ Gem::Specification.new do |gem| gem.executables = %w(sxp2rdf sxp2json sxp2xml sxp2yaml) gem.require_paths = %w(lib) - gem.required_ruby_version = '>= 2.4' + gem.required_ruby_version = '>= 2.6' gem.requirements = [] gem.add_development_dependency 'rspec', '~> 3.10' gem.add_development_dependency 'yard' , '~> 0.9' From 9b4ef53e866636dad848e9b97cb964e5d9eb2d56 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Mon, 13 Dec 2021 14:44:07 -0800 Subject: [PATCH 13/22] Sync more gem versions. --- sxp.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sxp.gemspec b/sxp.gemspec index cb691e2..10a83d0 100755 --- a/sxp.gemspec +++ b/sxp.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |gem| gem.requirements = [] gem.add_development_dependency 'rspec', '~> 3.10' gem.add_development_dependency 'yard' , '~> 0.9' - gem.add_runtime_dependency 'rdf', '~> 3.1' + gem.add_runtime_dependency 'rdf', '~> 3.2' gem.post_install_message = nil end From 93df8087d93ddc9d24eac7ad1523ea761314111e Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 15 Dec 2021 17:04:36 -0800 Subject: [PATCH 14/22] Improve documentation on dialects. --- README.md | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/README.md b/README.md index d140db0..487053f 100755 --- a/README.md +++ b/README.md @@ -13,6 +13,156 @@ This is a Ruby implementation of a universal [S-expression][] parser. * Adds a `#to_sxp` method to Ruby objects. * Compatible with Ruby >= 2.6, Rubinius >= 3.0, and JRuby 9+. +## Basic syntax + +S-Expressions derive from LISP, and include some basic datatypes common to all variants: + +
+
Pairs
+
Of the form (2 . 3)
+
Lists
+
Of the form (1 (2 3))
+
Symbols
+
Of the form with-hyphen ?@!$ a\ symbol\ with\ spaces
+
Strings
+
Of the form "Hello, world!"
+ Strings may include the following special characters: +
    +
  • \b — Backspace
  • +
  • \f — Form Feed
  • +
  • \n — New Line
  • +
  • \r — Carriage Return
  • +
  • \t — Horizontal Tab
  • +
  • \uxxxx — 2-byte Unicode character escape
  • +
  • \Uxxxxxxxx — 4-byte Unicode character escape
  • +
  • \" — Double-quote character
  • +
  • \\ — Backspace
  • +
+ Additionally, any other character may follow \, representing the character itself. +
+
Characters
+
Of the form ...
+
Integers
+
Of the form -9876543210
+
Floating-point numbers
+
Of the form -0.0 6.28318 6.022e23
+
Rationals
+
Of the form 1/3
+
+ +Additionally, variation-specific formats support additional datatypes: + +### Scheme + +In addition to the standard datatypes, the Scheme dialect supports the following: + +
+
Lists
+
In addition to ( ... ), a square bracket pair may be used for reading lists of the form [ ... ]. +
+
Comments
+
A comment starts with ; and continues to the end of the line. +
Sharp character sequences
+
Such as #t, #n, and #xXXX.
+
    +
  • #n — Null
  • +
  • #f — False
  • +
  • #t — True
  • +
  • #bBBB — Binary number
  • +
  • #oOOO — Octal number
  • +
  • #dDDD — Decimal number
  • +
  • #xXXX — Hexadecimal number
  • +
  • #\C — A single Unicode character
  • +
  • #\space — A space character
  • +
  • #\newline — A newline character
  • +
  • #; — Skipped character
  • +
  • #! — Skipped to end of line
  • +
+
+
+ +### Common Lisp + +In addition to the standard datatypes, the Common Lisp dialect supports the following: + +
+
Comments
+
A comment starts with ; and continues to the end of the line. +
Symbols
+
In addition to base symbols, any character sequence delimited by | is treated as a symbol.
+
Sharp character sequences
+
Such as #t, #n, and #xXXX.
+
    +
  • #bBBB — Binary number
  • +
  • #oOOO — Octal number
  • +
  • #xXXX — Hexadecimal number
  • +
  • #C — A single Unicode character
  • +
  • #\newline — A newline character
  • +
  • #\space — A space character
  • +
  • #\backspace — A backspace character
  • +
  • #\tab — A tab character
  • +
  • #\linefeed — A linefeed character
  • +
  • #\page — A page feed character
  • +
  • #\return — A carriage return character
  • +
  • #\rubout — A rubout character
  • +
  • #'function — A function definition
  • +
+
+
+ +### SPARQL/RDF + +In addition to the standard datatypes, the SPARQL dialect supports the following: + +
+
Lists
+
In addition to ( ... ), a square bracket pair may be used for reading lists of the form [ ... ]. +
+
Comments
+
A comment starts with # or ; and continues to the end of the line. +
Literals
+
Strings are interpreted as an RDF Literal with datatype xsd:string. It can be followed by @lang to create a language-tagged string, or ^^IRI to create a datatyped-literal. Examples: +
    +
  • "a plain literal"
  • +
  • "a literal with a language"@en
  • +
  • "a typed literal"^^<http://example/>
  • +
  • "a typed literal with a PNAME"^^xsd:string
  • +
+
+
IRIs
+
An IRI is formed as in SPARQL, either enclosed by <...>, or having the form of a PNAME. If a base iri is defined in a containing base expression, IRIs using the <...> are resolved against that base iri. If the PNAME form is used, the prefix must be defined in a containing prefix expression. Examples: +
    +
  • <http://example/foo>
  • +
  • (base <http://example.com> <foo>)
  • +
  • (prefix ((foo: <http://example.com/>)) foo:bar)
  • +
  • a # synonym for rdf:type
  • +
+
+
Blank Nodes
+
An blank node is formed as in SPARQL. Examples: +
    +
  • _:
  • +
  • _:id
  • +
+
+
Variables
+
A SPARQL variable is defined using either ? or $ prefixes, as in SPARQL. Examples: +
    +
  • ?var
  • +
  • $var
  • +
+
+
Numbers and booleans
+
As with SPARQL. Examples: +
    +
  • true, false
  • +
  • 123, -18
  • +
  • 123.0, 456.
  • +
  • 1.0e0, 1.0E+6
  • +
+
+
+ ## Examples require 'sxp' From 3e9a201a0ebc321a52c4da46dbf02263234fe3a1 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 15 Dec 2021 17:05:24 -0800 Subject: [PATCH 15/22] Some improvements for Scheme sharp sequences. --- lib/sxp/reader/scheme.rb | 4 +- spec/scheme_spec.rb | 98 ++++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 41 deletions(-) diff --git a/lib/sxp/reader/scheme.rb b/lib/sxp/reader/scheme.rb index 34223a7..31884fd 100644 --- a/lib/sxp/reader/scheme.rb +++ b/lib/sxp/reader/scheme.rb @@ -64,8 +64,8 @@ def read_sharp when ?d, ?D then read_integer(10) when ?x, ?X then read_integer(16) when ?\\ then read_character - when ?; then skip; read - when ?! then skip_line; read # shebang + when ?; then skip # comment character + when ?! then skip_line; skip # shebang else raise Error, "invalid sharp-sign read syntax: ##{char.chr}" end end diff --git a/spec/scheme_spec.rb b/spec/scheme_spec.rb index 5fbdf4e..453d02b 100644 --- a/spec/scheme_spec.rb +++ b/spec/scheme_spec.rb @@ -33,62 +33,82 @@ end end - context "when reading characters" do - { - %q(#\a) => "a", - %q(#\A) => "A", - %q(#\C) => "C", - %q(#\ ) => " ", - %q(#\space) => " ", - %q(#\newline) => "\n", - }.each do |input, output| - it "reads '#{input}' as a character" do - expect(read(input)).to eq output + context "sharp sequences" do + context "when reading characters" do + { + %q(#\a) => "a", + %q(#\A) => "A", + %q(#\C) => "C", + %q(#\ ) => " ", + %q(#\space) => " ", + %q(#\newline) => "\n", + }.each do |input, output| + it "reads '#{input}' as a character" do + expect(read(input)).to eq output + end end end - end - context "when reading integers in decimal form" do - it "reads '123' as an integer" do - expect(read(%q(123))).to eq 123 - end + context "when reading integers in decimal form" do + it "reads '123' as an integer" do + expect(read(%q(123))).to eq 123 + end - it "reads '#d123' as an integer" do - expect(read(%q(#d123))).to eq 123 - end + it "reads '#d123' as an integer" do + expect(read(%q(#d123))).to eq 123 + end - it "reads '#D123' as an integer" do - expect(read(%q(#D123))).to eq 123 + it "reads '#D123' as an integer" do + expect(read(%q(#D123))).to eq 123 + end end - end - context "when reading integers in binary form" do - it "reads '#b1010' as an integer" do - expect(read(%q(#b1010))).to eq 0b1010 + context "when reading integers in binary form" do + it "reads '#b1010' as an integer" do + expect(read(%q(#b1010))).to eq 0b1010 + end + + it "reads '#B1010' as an integer" do + expect(read(%q(#B1010))).to eq 0b1010 + end end - it "reads '#B1010' as an integer" do - expect(read(%q(#B1010))).to eq 0b1010 + context "when reading integers in octal form" do + it "reads '#o755' as an integer" do + expect(read(%q(#o755))).to eq 0755 + end + + it "reads '#O755' as an integer" do + expect(read(%q(#O755))).to eq 0755 + end end - end - context "when reading integers in octal form" do - it "reads '#o755' as an integer" do - expect(read(%q(#o755))).to eq 0755 + context "when reading integers in hexadecimal form" do + it "reads '#xFF' as an integer" do + expect(read(%q(#xFF))).to eq 0xFF + end + + it "reads '#XFF' as an integer" do + expect(read(%q(#XFF))).to eq 0xFF + end end - it "reads '#O755' as an integer" do - expect(read(%q(#O755))).to eq 0755 + context "when reading #n" do + it "reads '#n' as NULL" do + expect(read(%q(#n))).to be_nil + end end - end - context "when reading integers in hexadecimal form" do - it "reads '#xFF' as an integer" do - expect(read(%q(#xFF))).to eq 0xFF + context "when reading #;" do + it "reads '#;' as an empty string" do + expect(read(%q(#;[]))).to eq [] + end end - it "reads '#XFF' as an integer" do - expect(read(%q(#XFF))).to eq 0xFF + context "when reading #!" do + it "reads '#!/usr/bin/env sxp2json\nfoo' as an empty string" do + expect(read(%(#!/usr/bin/env sxp2json\n[]))).to eq [] + end end end From f9b73b6817472dc59b5d87ff9ef03ed37d957387 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 15 Dec 2021 17:09:25 -0800 Subject: [PATCH 16/22] Re-do support for proper IRI serialization by reading prefixes and base expressions and propgating to lower elements to create PNames when serializing only if appropriate. Consolodates the contents of writer.rb into extensions.rb. For #20. --- .gitignore | 1 + lib/sxp.rb | 1 - lib/sxp/extensions.rb | 300 ++++++++++++++++++++++++++++++++++++++- lib/sxp/generator.rb | 39 +++-- lib/sxp/reader/sparql.rb | 6 +- lib/sxp/writer.rb | 216 ---------------------------- spec/extensions_spec.rb | 52 +++++++ spec/generator_spec.rb | 64 +++++++-- spec/sparql_spec.rb | 4 - spec/spec_helper.rb | 1 + sxp.gemspec | 4 +- 11 files changed, 439 insertions(+), 249 deletions(-) delete mode 100644 lib/sxp/writer.rb diff --git a/.gitignore b/.gitignore index 5c00ba9..6ee93ef 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ Gemfile.lock /.rbx/ /.bundle coverage +/.byebug_history diff --git a/lib/sxp.rb b/lib/sxp.rb index bf675bb..67414c4 100644 --- a/lib/sxp.rb +++ b/lib/sxp.rb @@ -3,7 +3,6 @@ require 'sxp/version' require 'sxp/extensions' -require 'sxp/writer' module SXP autoload :Pair, 'sxp/pair' diff --git a/lib/sxp/extensions.rb b/lib/sxp/extensions.rb index 224934a..2d13a54 100644 --- a/lib/sxp/extensions.rb +++ b/lib/sxp/extensions.rb @@ -1,6 +1,90 @@ +# -*- encoding: utf-8 -*- +require 'bigdecimal' +require 'time' + +## +# Extensions for Ruby's `Object` class. +class Object + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + to_s.to_json + end +end + +## +# Extensions for Ruby's `NilClass` class. +class NilClass + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + '#n' + end +end + +## +# Extensions for Ruby's `FalseClass` class. +class FalseClass + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + '#f' + end +end + +## +# Extensions for Ruby's `TrueClass` class. +class TrueClass + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + '#t' + end +end + +## +# Extensions for Ruby's `String` class. +class String + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + inspect + end +end + ## # Extensions for Ruby's `Symbol` class. class Symbol + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + to_s + end + ## # Returns `true` if this is a keyword symbol. # @@ -10,17 +94,225 @@ def keyword? end end -# Update RDF::URI if RDF is loaded +## +# Extensions for Ruby's `Integer` class. +class Integer + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + to_s + end +end + +## +# Extensions for Ruby's `BigDecimal` class. +class BigDecimal + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + to_f.to_s + end +end + +## +# Extensions for Ruby's `Float` class. +class Float + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + case + when nan? then 'nan.0' + when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0') + else to_s + end + end +end + +## +# Extensions for Ruby's `Array` class. +class Array + ## + # Returns the SXP representation of this object. + # + # If array is of the form `[:base, uri, ..]`, the base_uri is taken from the second value + # + # If array is of the form `[:prefix, [..], ..]`, prefixes are taken from the second value + # + # Prefixes always are terminated by a ':' + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + '(' << map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri) }.join(' ') << ')' + end +end + +## +# Extensions for Ruby's `Time` class. +class Time + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + '#@' << (respond_to?(:xmlschema) ? xmlschema : to_i).to_s + end +end + +## +# Extensions for Ruby's `Regexp` class. +class Regexp + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + '#' << inspect + end +end + begin - require 'rdf' + require 'rdf' # For SPARQL/RDF ## - # Extensions for RDF::URI + # Extensions for Ruby's `Array` class. + # These extensions depend on RDF being loaded + class Array + ## + # Returns the SXP representation of this object. + # + # If array is of the form `[:base, uri, ..]`, the base_uri is taken from the second value + # + # If array is of the form `[:prefix, [..], ..]`, prefixes are taken from the second value + # + # Prefixes always are terminated by a ':' + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + if self.first == :base && self.length == 3 && self[1].is_a?(RDF::URI) + base_uri = self[1] + '(' << (self[0,2].map(&:to_sxp) << self.last.to_sxp(prefixes: prefixes, base_uri: base_uri)).join(' ') << ')' + elsif self.first == :prefix && self.length == 3 && self[1].is_a?(Array) + prefixes = prefixes ? prefixes.dup : {} + self[1].each do |defn| + prefixes[defn.first.to_s.chomp(':').to_sym] = RDF::URI(defn.last) if defn.is_a?(Array) && defn.length == 2 + end + pfx_sxp = self[1].map {|(p,s)|["#{p.to_s.chomp(':')}:".to_sym, RDF::URI(s)]}.to_sxp + '(' << [:prefix, pfx_sxp, self.last.to_sxp(prefixes: prefixes, base_uri: base_uri)].join(' ') << ')' + else + '(' << map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri) }.join(' ') << ')' + end + end + end + class RDF::URI + ## + # Returns the SXP representation of this a URI. Uses Lexical representation, if set, otherwise, any PName match, otherwise, the relativized version of the URI if a base_uri is given, otherwise just the URI. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + return lexical if lexical + pn = pname(prefixes: prefixes || {}) + return pn unless to_s == pn + md = self == base_uri ? '' : self.relativize(base_uri) + "<#{md}>" + end + # Original lexical value of this URI to allow for round-trip serialization. def lexical=(value); @lexical = value; end def lexical; @lexical; end end + + class RDF::Node + ## + # Returns the SXP representation of this object. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + to_s + end + end + + class RDF::Literal + ## + # Returns the SXP representation of a Literal. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + case datatype + when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.time + # Retain stated lexical form if possible + valid? ? to_s : object.to_sxp + else + text = value.dump + text << "@#{language}" if self.has_language? + text << "^^#{datatype.to_sxp(prefixes: prefixes, base_uri: base_uri)}" if self.has_datatype? + text + end + end + end + + class RDF::Query + # Transform Query into an Array form of an SXP + # + # If Query is named, it's treated as a GroupGraphPattern, otherwise, a BGP + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [Array] + def to_sxp(prefixes: nil, base_uri: nil) + res = [:bgp] + patterns + (named? ? [:graph, graph_name, res] : res).to_sxp(prefixes: prefixes, base_uri: base_uri) + end + end + + class RDF::Query::Pattern + # Transform Query Pattern into an SXP + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + [:triple, subject, predicate, object].to_sxp(prefixes: prefixes, base_uri: base_uri) + end + end + + class RDF::Query::Variable + ## + # Transform Query variable into an SXP. + # + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + to_s + end + end rescue LoadError - # Ignore + # Ignore if RDF not loaded end diff --git a/lib/sxp/generator.rb b/lib/sxp/generator.rb index af09946..2ba4a5e 100644 --- a/lib/sxp/generator.rb +++ b/lib/sxp/generator.rb @@ -16,18 +16,41 @@ class Block ## # @param [Object] obj - def initialize(obj, indent) + # @param [Integer] indent + # @param [Hash] prefixes(nil) + # @param [String] base_uri(nil) + def initialize(obj, indent, prefixes: nil, base_uri: nil) @indent = indent @elements = [] + @prefixes = prefixes + @base_uri = base_uri if obj.is_a?(Array) - obj.compact.each {|o| @elements << Block.new(o, indent + 1)} + # If this is a base or prefix element, update our representations + if obj.first == :base && obj.length == 3 && obj[1].is_a?(RDF::URI) + base_uri = obj[1] + @elements << Block.new(:base, indent + 1) + @elements << Block.new(obj[1], indent + 1) + @elements << Block.new(obj.last, indent + 1, prefixes: prefixes, base_uri: base_uri) + elsif obj.first == :prefix && obj.length == 3 && obj[1].is_a?(Array) + prefixes = prefixes ? prefixes.dup : {} + obj[1].each do |defn| + prefixes[defn.first.to_s.chomp(':').to_sym] = RDF::URI(defn.last) if defn.is_a?(Array) && defn.length == 2 + end + @elements << Block.new(:prefix, indent + 1) + @elements << Block.new(obj[1], indent + 1) + @elements << Block.new(obj.last, indent + 1, prefixes: prefixes, base_uri: base_uri) + else + obj.compact.each do |o| + @elements << Block.new(o, indent + 1, prefixes: prefixes, base_uri: base_uri) + end + end else @elements = obj end end ## - # Agregate length over each element accounting for spaces + # Aggregate length over each element accounting for spaces # # @return [Integer] # If indent is not not nil, returns zero @@ -35,7 +58,7 @@ def length if @elements.is_a?(Array) @elements.map(&:length).inject(:+).to_i + @elements.length - 1 else - @elements.to_sxp.length + @elements.to_sxp(prefixes: @prefixes, base_uri: @base_uri).length end end @@ -44,8 +67,8 @@ def length # This should only be called on a block when # no indentation is to be applied # @return [String] - def to_sxp - @elements.to_sxp + def to_sxp(prefixes: nil, base_uri: nil) + @elements.to_sxp(prefixes: prefixes || @prefixes, base_uri: base_uri || @base_uri) end ## @@ -67,7 +90,7 @@ def formatted first, *elems = @elements unless first.sxp? # It's atomic, write out after paren - buffer += first.to_sxp + "\n" + buffer += first.to_sxp(prefixes: @prefixes, base_uri: @base_uri) + "\n" else buffer += "\n" elems.unshift(first) @@ -77,7 +100,7 @@ def formatted end buffer += do_indent + ")\n" else - buffer += do_indent + @elements.to_sxp + "\n" + buffer += do_indent + @elements.to_sxp(prefixes: @prefixes, base_uri: @base_uri) + "\n" end buffer end diff --git a/lib/sxp/reader/sparql.rb b/lib/sxp/reader/sparql.rb index 2e6a54b..bf95ae1 100644 --- a/lib/sxp/reader/sparql.rb +++ b/lib/sxp/reader/sparql.rb @@ -129,8 +129,6 @@ def read_token uri = RDF::URI(base.to_s + suffix) #STDERR.puts "read_tok lexical uri: #{uri.inspect}" - # Cause URI to be serialized as a lexical - uri.lexical = value [:atom, uri] else tok @@ -184,9 +182,7 @@ def read_rdf_uri # If we have a base URI, use that when constructing a new URI uri = if self.base_uri && RDF::URI(buffer).relative? - u = self.base_uri.join(buffer) - u.lexical = "<#{buffer}>" unless u.to_s == buffer # So that it can be re-serialized properly - u + self.base_uri.join(buffer) else RDF::URI(buffer) end diff --git a/lib/sxp/writer.rb b/lib/sxp/writer.rb deleted file mode 100644 index d4618a1..0000000 --- a/lib/sxp/writer.rb +++ /dev/null @@ -1,216 +0,0 @@ -# -*- encoding: utf-8 -*- -require 'bigdecimal' -require 'time' - -## -# Extensions for Ruby's `Object` class. -class Object - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - to_s.to_json - end -end - -## -# Extensions for Ruby's `NilClass` class. -class NilClass - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - '#n' - end -end - -## -# Extensions for Ruby's `FalseClass` class. -class FalseClass - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - '#f' - end -end - -## -# Extensions for Ruby's `TrueClass` class. -class TrueClass - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - '#t' - end -end - -## -# Extensions for Ruby's `String` class. -class String - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - inspect - end -end - -## -# Extensions for Ruby's `Symbol` class. -class Symbol - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - to_s - end -end - -## -# Extensions for Ruby's `Integer` class. -class Integer - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - to_s - end -end - -## -# Extensions for Ruby's `BigDecimal` class. -class BigDecimal - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - to_f.to_s - end -end - -## -# Extensions for Ruby's `Float` class. -class Float - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - case - when nan? then 'nan.0' - when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0') - else to_s - end - end -end - -## -# Extensions for Ruby's `Array` class. -class Array - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - '(' << map { |x| x.to_sxp }.join(' ') << ')' - end -end - -## -# Extensions for Ruby's `Time` class. -class Time - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - '#@' << (respond_to?(:xmlschema) ? xmlschema : to_i).to_s - end -end - -## -# Extensions for Ruby's `Regexp` class. -class Regexp - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp - '#' << inspect - end -end - -begin - require 'rdf' # For SPARQL - - class RDF::URI - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp; lexical || "<#{self}>"; end - end - - class RDF::Node - ## - # Returns the SXP representation of this object. - # - # @return [String] - def to_sxp; to_s; end - end - - class RDF::Literal - ## - # Returns the SXP representation of a Literal. - # - # @return [String] - def to_sxp - case datatype - when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.time - # Retain stated lexical form if possible - valid? ? to_s : object.to_sxp - else - text = value.dump - text << "@#{language}" if self.has_language? - text << "^^#{datatype.to_sxp}" if self.has_datatype? - text - end - end - end - - class RDF::Query - # Transform Query into an Array form of an SXP - # - # If Query is named, it's treated as a GroupGraphPattern, otherwise, a BGP - # - # @return [Array] - def to_sxp - res = [:bgp] + patterns - (named? ? [:graph, graph_name, res] : res).to_sxp - end - end - - class RDF::Query::Pattern - # Transform Query Pattern into an SXP - # @return [String] - def to_sxp - [:triple, subject, predicate, object].to_sxp - end - end - - class RDF::Query::Variable - def to_sxp; to_s; end - end -rescue LoadError => e - # Ignore if RDF not loaded -end \ No newline at end of file diff --git a/spec/extensions_spec.rb b/spec/extensions_spec.rb index c51bfe1..2417fb2 100644 --- a/spec/extensions_spec.rb +++ b/spec/extensions_spec.rb @@ -36,6 +36,10 @@ specify { expect(RDF::Literal.new("2013-11-21", datatype: RDF::XSD.date).to_sxp).to eq %q("2013-11-21"^^)} end +describe "RDF::Literal#to_sxp with prefix" do + specify { expect(RDF::Literal.new("2013-11-21", datatype: RDF::XSD.date).to_sxp(prefixes: {xsd: RDF::XSD.to_uri})).to eq %q("2013-11-21"^^xsd:date)} +end + describe "RDF::URI#to_sxp" do specify { expect(RDF::URI("http://example.com").to_sxp).to eq %q()} @@ -44,6 +48,16 @@ u.lexical = "foo:a" expect(u.to_sxp).to eq %q(foo:a) end + + it "uses prefix if defined" do + u = RDF::URI("http://example.com/a") + expect(u.to_sxp(prefixes: {foo: 'http://example.com/'})).to eq %q(foo:a) + end + + it "uses base if defined" do + u = RDF::URI("http://example.com/a") + expect(u.to_sxp(base_uri: 'http://example.com/')).to eq %q() + end end describe "RDF::Query::Variable#to_sxp" do @@ -86,4 +100,42 @@ expect(st.to_sxp).to eq sxp end end + + context "prefix array with content" do + let(:prefix) { + [:prefix, [ + [:"foo:", RDF::URI("http://example.com/foo/")], + [:"bar:", RDF::URI("http://example.com/bar#")], + [:":", RDF::URI("http://empty/")] + ]] + } + { + ( + [RDF::URI("http://example.com/foo/a")] + ) => %q(foo:a), + ( + [RDF::Literal.new("2013-11-21", datatype: RDF::URI("http://example.com/foo/date"))] + ) => %q("2013-11-21"^^foo:date), + }.each_pair do |st, sxp| + it "generates #{sxp} given #{st.inspect}" do + expect((prefix + st).to_sxp).to eq "(prefix ((foo: ) (bar: ) (: )) #{sxp})" + end + end + end + + context "base array with content" do + let(:base) {[:base, RDF::URI("http://example.com/foo/")]} + { + ( + [RDF::URI("http://example.com/foo/a")] + ) => %q(), + ( + [RDF::Literal.new("2013-11-21", datatype: RDF::URI("http://example.com/foo/date"))] + ) => %q("2013-11-21"^^), + }.each_pair do |st, sxp| + it "generates #{sxp} given #{st.inspect}" do + expect((base + st).to_sxp).to eq "(base #{sxp})" + end + end + end end \ No newline at end of file diff --git a/spec/generator_spec.rb b/spec/generator_spec.rb index f471d35..61789e3 100644 --- a/spec/generator_spec.rb +++ b/spec/generator_spec.rb @@ -3,11 +3,11 @@ describe SXP::Generator do context ".string" do { - "short sxp" => [ + "short sxp":[ [:bgp, [:triple, :s, :p, :o]], %{(bgp (triple s p o))\n} ], - "long component" => [ + "long component":[ [:thing, [:string, "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"]], %{(thing (string @@ -15,15 +15,15 @@ )) }.gsub(/^ /, '') ], - "SPARQL" => [ + "SPARQL":[ [:prefix, - [[:":", :""]], + [[:":", RDF::URI("http://example/")]], [:dataset, - [:"", - [:named, :""], - [:named, :""], - [:named, :""], - [:named, :""]], + [RDF::URI("data-g1.ttl"), + [:named, RDF::URI("data-g1.ttl")], + [:named, RDF::URI("data-g2.ttl")], + [:named, RDF::URI("data-g3.ttl")], + [:named, RDF::URI("data-g4.ttl")]], [:union, [:bgp,[:triple, :"?s", :"?p", :"?o"]], [:graph, :"?g", [:bgp, [:triple, :"?s", :"?p", :"?o"]]]]]], @@ -38,7 +38,7 @@ (union (bgp (triple ?s ?p ?o)) (graph ?g (bgp (triple ?s ?p ?o))))) ) }.gsub(/^ /, '') ], - "EBNF" => [ + "EBNF":[ [[:rule, :empty, "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"], [:rule, :ebnf, "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"]], %q{( @@ -49,6 +49,50 @@ "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" )) }.gsub(/^ /, '') + ], + "SPARQL Terms": [ + [:bgp, + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal("")], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal("hello")], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal("hello", language: :en)], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal(true)], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal(false)], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal(123)], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal(-18)], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal::Decimal.new(123.0)], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal::Double.new(1.0e0)], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Literal("lex", datatype: 'http://example.org/thing')], + [:triple, RDF::URI(:a), RDF::URI(:b), RDF::Query::Variable.new(:x)], + ], + %q{(bgp + (triple "") + (triple "hello") + (triple "hello"@en) + (triple true) + (triple false) + (triple 123) + (triple -18) + (triple 123.0) + (triple 1.0) + (triple "lex"^^) + (triple ?x)) + }.gsub(/^ /, '') + ], + "issue 20": [ + [:prefix, + [[:"wdt:", RDF::URI("http://www.wikidata.org/prop/direct/")], + [:"wd:", RDF::URI("http://www.wikidata.org/entity/")]], + [:bgp, + [:triple, + RDF::Query::Variable.new(:person), + RDF::URI("http://www.wikidata.org/prop/direct/P31"), + RDF::URI("http://www.wikidata.org/entity/Q5")]]], + %q{(prefix + ( + (wdt: ) + (wd: )) + (bgp (triple ?person wdt:P31 wd:Q5))) + }.gsub(/^ /, '') ] }.each do |title, (input, expected)| it title do diff --git a/spec/sparql_spec.rb b/spec/sparql_spec.rb index 5ed11d3..1a3f1f4 100644 --- a/spec/sparql_spec.rb +++ b/spec/sparql_spec.rb @@ -155,10 +155,6 @@ [[:"ex:", RDF::URI("foo#")], [:":", RDF::URI("bar#")]], RDF::URI("foo#bar"), RDF::URI("bar#baz")] end - - it "reads adds lexical to URI" do - expect(read('(prefix ex: ex:bar)').last.lexical).to eq "ex:bar" - end end context "when reading symbols" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4e3c6aa..c188be2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,7 @@ require "bundler/setup" require 'rspec' +require 'amazing_print' begin require 'simplecov' diff --git a/sxp.gemspec b/sxp.gemspec index 10a83d0..51377a8 100755 --- a/sxp.gemspec +++ b/sxp.gemspec @@ -22,9 +22,11 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 2.6' gem.requirements = [] + gem.add_runtime_dependency 'rdf', '~> 3.2' + + gem.add_development_dependency 'amazing_print', '~> 1.4' gem.add_development_dependency 'rspec', '~> 3.10' gem.add_development_dependency 'yard' , '~> 0.9' - gem.add_runtime_dependency 'rdf', '~> 3.2' gem.post_install_message = nil end From 57861f54962bc00b0978c1ae1cbc258a11018400 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Thu, 16 Dec 2021 14:29:52 -0800 Subject: [PATCH 17/22] Add to_sxp extensions from SPARQL. --- lib/sxp/extensions.rb | 111 +++++++++++++++++++++++++-------------- lib/sxp/generator.rb | 4 +- spec/common_lisp_spec.rb | 24 +++++---- spec/extensions_spec.rb | 18 +++++-- spec/generator_spec.rb | 7 ++- spec/scheme_spec.rb | 58 ++++++-------------- 6 files changed, 124 insertions(+), 98 deletions(-) diff --git a/lib/sxp/extensions.rb b/lib/sxp/extensions.rb index 2d13a54..3c96aea 100644 --- a/lib/sxp/extensions.rb +++ b/lib/sxp/extensions.rb @@ -8,8 +8,8 @@ class Object ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) to_s.to_json @@ -22,8 +22,8 @@ class NilClass ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) '#n' @@ -36,8 +36,8 @@ class FalseClass ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) '#f' @@ -50,8 +50,8 @@ class TrueClass ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) '#t' @@ -64,8 +64,8 @@ class String ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) inspect @@ -78,8 +78,8 @@ class Symbol ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) to_s @@ -100,8 +100,8 @@ class Integer ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) to_s @@ -114,8 +114,8 @@ class BigDecimal ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) to_f.to_s @@ -128,8 +128,8 @@ class Float ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) case @@ -152,22 +152,36 @@ class Array # # Prefixes always are terminated by a ':' # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) '(' << map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri) }.join(' ') << ')' end end +## +# Extensions for Ruby's `Hash` class. +class Hash + ## + # Returns the SXP representation of this object. + # + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + to_a.to_sxp(prefixes: prefixes, base_uri: base_uri) + end +end + ## # Extensions for Ruby's `Time` class. class Time ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) '#@' << (respond_to?(:xmlschema) ? xmlschema : to_i).to_s @@ -180,8 +194,8 @@ class Regexp ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) '#' << inspect @@ -204,8 +218,8 @@ class Array # # Prefixes always are terminated by a ':' # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) if self.first == :base && self.length == 3 && self[1].is_a?(RDF::URI) @@ -228,8 +242,8 @@ class RDF::URI ## # Returns the SXP representation of this a URI. Uses Lexical representation, if set, otherwise, any PName match, otherwise, the relativized version of the URI if a base_uri is given, otherwise just the URI. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) return lexical if lexical @@ -248,8 +262,8 @@ class RDF::Node ## # Returns the SXP representation of this object. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) to_s @@ -260,14 +274,14 @@ class RDF::Literal ## # Returns the SXP representation of a Literal. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) case datatype when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.time # Retain stated lexical form if possible - valid? ? to_s : object.to_sxp + valid? ? to_s : object.to_sxp(prefixes: nil, base_uri: nil) else text = value.dump text << "@#{language}" if self.has_language? @@ -275,6 +289,22 @@ def to_sxp(prefixes: nil, base_uri: nil) text end end + + class Double + ## + # Returns the SXP representation of this object. + # + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + case + when nan? then 'nan.0' + when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0') + else canonicalize.to_s.downcase + end + end + end end class RDF::Query @@ -282,8 +312,8 @@ class RDF::Query # # If Query is named, it's treated as a GroupGraphPattern, otherwise, a BGP # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [Array] def to_sxp(prefixes: nil, base_uri: nil) res = [:bgp] + patterns @@ -294,8 +324,8 @@ def to_sxp(prefixes: nil, base_uri: nil) class RDF::Query::Pattern # Transform Query Pattern into an SXP # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) [:triple, subject, predicate, object].to_sxp(prefixes: prefixes, base_uri: base_uri) @@ -306,11 +336,12 @@ class RDF::Query::Variable ## # Transform Query variable into an SXP. # - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) # @return [String] def to_sxp(prefixes: nil, base_uri: nil) - to_s + prefix = distinguished? ? (existential? ? '$' : '?') : (existential? ? '$$' : '??') + unbound? ? "#{prefix}#{name}".to_sym.to_sxp : ["#{prefix}#{name}".to_sym, value].to_sxp end end rescue LoadError diff --git a/lib/sxp/generator.rb b/lib/sxp/generator.rb index 2ba4a5e..d59964e 100644 --- a/lib/sxp/generator.rb +++ b/lib/sxp/generator.rb @@ -17,8 +17,8 @@ class Block ## # @param [Object] obj # @param [Integer] indent - # @param [Hash] prefixes(nil) - # @param [String] base_uri(nil) + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil)l) def initialize(obj, indent, prefixes: nil, base_uri: nil) @indent = indent @elements = [] diff --git a/spec/common_lisp_spec.rb b/spec/common_lisp_spec.rb index ce9521f..3d317ea 100644 --- a/spec/common_lisp_spec.rb +++ b/spec/common_lisp_spec.rb @@ -58,16 +58,20 @@ # TODO end - context "when reading integers in decimal form" do - it "reads `123` as an integer" do - expect(read(%q(123))).to eq 123 - end - end - - context "when reading integers in hexadecimal form" do - %w(#xFF #XFF #xff #XFF).each do |input| - it "reads `#{input}` as an integer" do - expect(read(input)).to eq 0xFF + context "when reading integers" do + { + '#b1010' => 0b1010, + '#B1010' => 0b1010, + '#o755' => 0755, + '#O755' => 0755, + '123' => 123, + '#xFF' => 0xFF, + '#XFF' => 0xFF, + '#xff' => 0xFF, + '#Xff' => 0xFF, + }.each_pair do |input, output| + it "reads #{input} as an integer" do + expect(read(input)).to eq output end end end diff --git a/spec/extensions_spec.rb b/spec/extensions_spec.rb index 2417fb2..5e2512a 100644 --- a/spec/extensions_spec.rb +++ b/spec/extensions_spec.rb @@ -18,6 +18,7 @@ [['a', 2], '("a" 2)'], [Time.parse("2011-03-13T11:22:33Z"), '#@2011-03-13T11:22:33Z'], [/foo/, '#/foo/'], + [{a: 'b'}, %q(((a "b")))], ].each do |(value, result)| it "returns #{result.inspect} for #{value.inspect}" do expect(value.to_sxp).to eq result @@ -30,10 +31,19 @@ end describe "RDF::Literal#to_sxp" do - specify { expect(RDF::Literal.new("a").to_sxp).to eq %q("a")} - specify { expect(RDF::Literal.new("a", language: "en-us").to_sxp).to eq %q("a"@en-us)} - specify { expect(RDF::Literal.new("a", datatype: RDF::XSD.string).to_sxp).to eq %q("a")} - specify { expect(RDF::Literal.new("2013-11-21", datatype: RDF::XSD.date).to_sxp).to eq %q("2013-11-21"^^)} + { + RDF::Literal.new("a") => %q("a"), + RDF::Literal.new("a", language: "en-us") => %q("a"@en-us), + RDF::Literal.new("2013-11-21", datatype: RDF::XSD.date) => %q("2013-11-21"^^), + RDF::Literal(1) => %q(1), + RDF::Literal::Decimal.new(1.0) => '1.0', + RDF::Literal(1.0e1) => '1.0e1', + RDF::Literal(Float::INFINITY) => "+inf.0", + RDF::Literal(-Float::INFINITY) => "-inf.0", + RDF::Literal(Float::NAN) => "nan.0", + }.each_pair do |l, sxp| + specify {expect(l.to_sxp).to eq sxp} + end end describe "RDF::Literal#to_sxp with prefix" do diff --git a/spec/generator_spec.rb b/spec/generator_spec.rb index 61789e3..db22795 100644 --- a/spec/generator_spec.rb +++ b/spec/generator_spec.rb @@ -73,11 +73,16 @@ (triple 123) (triple -18) (triple 123.0) - (triple 1.0) + (triple 1.0e0) (triple "lex"^^) (triple ?x)) }.gsub(/^ /, '') ], + "SPARQL base": [ + [:base, RDF::URI("http://example.com/"), RDF::URI("http://example.com/a")], + %q{(base ) + }.gsub(/^ /, '') + ], "issue 20": [ [:prefix, [[:"wdt:", RDF::URI("http://www.wikidata.org/prop/direct/")], diff --git a/spec/scheme_spec.rb b/spec/scheme_spec.rb index 453d02b..00376cb 100644 --- a/spec/scheme_spec.rb +++ b/spec/scheme_spec.rb @@ -49,47 +49,23 @@ end end - context "when reading integers in decimal form" do - it "reads '123' as an integer" do - expect(read(%q(123))).to eq 123 - end - - it "reads '#d123' as an integer" do - expect(read(%q(#d123))).to eq 123 - end - - it "reads '#D123' as an integer" do - expect(read(%q(#D123))).to eq 123 - end - end - - context "when reading integers in binary form" do - it "reads '#b1010' as an integer" do - expect(read(%q(#b1010))).to eq 0b1010 - end - - it "reads '#B1010' as an integer" do - expect(read(%q(#B1010))).to eq 0b1010 - end - end - - context "when reading integers in octal form" do - it "reads '#o755' as an integer" do - expect(read(%q(#o755))).to eq 0755 - end - - it "reads '#O755' as an integer" do - expect(read(%q(#O755))).to eq 0755 - end - end - - context "when reading integers in hexadecimal form" do - it "reads '#xFF' as an integer" do - expect(read(%q(#xFF))).to eq 0xFF - end - - it "reads '#XFF' as an integer" do - expect(read(%q(#XFF))).to eq 0xFF + context "when reading integers" do + { + '#b1010' => 0b1010, + '#B1010' => 0b1010, + '#o755' => 0755, + '#O755' => 0755, + '123' => 123, + '#d123' => 123, + '#D123' => 123, + '#xFF' => 0xFF, + '#XFF' => 0xFF, + '#xff' => 0xFF, + '#Xff' => 0xFF, + }.each do |input, output| + it "reads #{input} as an integer" do + expect(read(input)).to eq output + end end end From adfe08560d981d7326a208a86308d783db3119bc Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Thu, 16 Dec 2021 16:20:23 -0800 Subject: [PATCH 18/22] Support Common Lisp vectors (`#(foo)`) using the Ruby Vector class. For #16. --- lib/sxp/extensions.rb | 21 +++++++++++++++------ lib/sxp/reader/common_lisp.rb | 5 ++++- spec/common_lisp_spec.rb | 10 +++++++--- spec/extensions_spec.rb | 12 ++++++++++++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/lib/sxp/extensions.rb b/lib/sxp/extensions.rb index 3c96aea..d88e330 100644 --- a/lib/sxp/extensions.rb +++ b/lib/sxp/extensions.rb @@ -1,5 +1,6 @@ # -*- encoding: utf-8 -*- require 'bigdecimal' +require 'matrix' require 'time' ## @@ -146,12 +147,6 @@ class Array ## # Returns the SXP representation of this object. # - # If array is of the form `[:base, uri, ..]`, the base_uri is taken from the second value - # - # If array is of the form `[:prefix, [..], ..]`, prefixes are taken from the second value - # - # Prefixes always are terminated by a ':' - # # @param [Hash{Symbol => RDF::URI}] prefixes(nil) # @param [RDF::URI] base_uri(nil) # @return [String] @@ -160,6 +155,20 @@ def to_sxp(prefixes: nil, base_uri: nil) end end +## +# Extensions for Ruby's `Vector` class. +class Vector + ## + # Returns the SXP representation of this object. + # + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil) + '#(' << to_a.map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri) }.join(' ') << ')' + end +end + ## # Extensions for Ruby's `Hash` class. class Hash diff --git a/lib/sxp/reader/common_lisp.rb b/lib/sxp/reader/common_lisp.rb index 9b683fb..42e3619 100644 --- a/lib/sxp/reader/common_lisp.rb +++ b/lib/sxp/reader/common_lisp.rb @@ -1,4 +1,6 @@ # -*- encoding: utf-8 -*- +require 'matrix' + module SXP; class Reader ## # A Common Lisp S-expressions parser. @@ -88,7 +90,8 @@ def read_symbol(delimiter = nil) # # @return [Array] def read_vector - raise NotImplementedError, "#{self.class}#read_vector" # TODO + list = read_list(')') + Vector.[](*list) end ## diff --git a/spec/common_lisp_spec.rb b/spec/common_lisp_spec.rb index 3d317ea..b9526c1 100644 --- a/spec/common_lisp_spec.rb +++ b/spec/common_lisp_spec.rb @@ -86,13 +86,17 @@ end end - context "when reading vectors", pending: "Support for vectors" do + context "when reading vectors" do it "reads `#()` as an empty vector" do - expect(read(%q(#()))).to eq [] + expect(read(%q(#()))).to eq Vector[] end it "reads `#(1 2 3)` as a vector" do - expect(read(%q(#(1 2 3)))).to eq [1, 2, 3] + expect(read(%q(#(1 2 3)))).to eq Vector[1, 2, 3] + end + + it "reads `#(hello \"world\")` as a vector" do + expect(read(%q(#(hello "world")))).to eq Vector[:hello, "world"] end end diff --git a/spec/extensions_spec.rb b/spec/extensions_spec.rb index 5e2512a..901b1c8 100644 --- a/spec/extensions_spec.rb +++ b/spec/extensions_spec.rb @@ -26,6 +26,18 @@ end end +describe "Vector" do + { + Vector[] => %q(#()), + Vector[1, 2, 3] => %q(#(1 2 3)), + Vector[:hello, "world"] => %q(#(hello "world")) + }.each do |value, result| + it "returns #{result.inspect} for #{value.inspect}" do + expect(value.to_sxp).to eq result + end + end +end + describe "RDF::Node#to_sxp" do specify { expect(RDF::Node.new("a").to_sxp).to eq %q(_:a)} end From 5c35c162d3d6f715777d8b3add057dd4e236415d Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 19 Dec 2021 12:41:38 -0800 Subject: [PATCH 19/22] Use generic **options instead of explicit keyword arguments for most to_sxp methods. --- lib/sxp/extensions.rb | 114 +++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 73 deletions(-) diff --git a/lib/sxp/extensions.rb b/lib/sxp/extensions.rb index d88e330..6258dba 100644 --- a/lib/sxp/extensions.rb +++ b/lib/sxp/extensions.rb @@ -9,10 +9,8 @@ class Object ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) to_s.to_json end end @@ -23,10 +21,8 @@ class NilClass ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) '#n' end end @@ -37,10 +33,8 @@ class FalseClass ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) '#f' end end @@ -51,10 +45,8 @@ class TrueClass ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) '#t' end end @@ -65,10 +57,8 @@ class String ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) inspect end end @@ -79,10 +69,8 @@ class Symbol ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) to_s end @@ -101,10 +89,8 @@ class Integer ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) to_s end end @@ -115,10 +101,8 @@ class BigDecimal ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) to_f.to_s end end @@ -129,10 +113,8 @@ class Float ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) case when nan? then 'nan.0' when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0') @@ -147,11 +129,9 @@ class Array ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) - '(' << map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri) }.join(' ') << ')' + def to_sxp() + '(' << map { |x| x.to_sxp(**options) }.join(' ') << ')' end end @@ -161,11 +141,9 @@ class Vector ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) - '#(' << to_a.map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri) }.join(' ') << ')' + def to_sxp(**options) + '#(' << to_a.map { |x| x.to_sxp(**options) }.join(' ') << ')' end end @@ -175,11 +153,9 @@ class Hash ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) - to_a.to_sxp(prefixes: prefixes, base_uri: base_uri) + def to_sxp(**options) + to_a.to_sxp(**options) end end @@ -189,10 +165,8 @@ class Time ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) '#@' << (respond_to?(:xmlschema) ? xmlschema : to_i).to_s end end @@ -203,10 +177,8 @@ class Regexp ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) '#' << inspect end end @@ -230,19 +202,27 @@ class Array # @param [Hash{Symbol => RDF::URI}] prefixes(nil) # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(prefixes: nil, base_uri: nil, **options) if self.first == :base && self.length == 3 && self[1].is_a?(RDF::URI) base_uri = self[1] - '(' << (self[0,2].map(&:to_sxp) << self.last.to_sxp(prefixes: prefixes, base_uri: base_uri)).join(' ') << ')' + '(' << ( + self[0,2].map(&:to_sxp) << + self.last.to_sxp(prefixes: prefixes, base_uri: base_uri, **options) + ).join(' ') << ')' elsif self.first == :prefix && self.length == 3 && self[1].is_a?(Array) prefixes = prefixes ? prefixes.dup : {} self[1].each do |defn| - prefixes[defn.first.to_s.chomp(':').to_sym] = RDF::URI(defn.last) if defn.is_a?(Array) && defn.length == 2 + prefixes[defn.first.to_s.chomp(':').to_sym] = RDF::URI(defn.last) if + defn.is_a?(Array) && defn.length == 2 end pfx_sxp = self[1].map {|(p,s)|["#{p.to_s.chomp(':')}:".to_sym, RDF::URI(s)]}.to_sxp - '(' << [:prefix, pfx_sxp, self.last.to_sxp(prefixes: prefixes, base_uri: base_uri)].join(' ') << ')' + '(' << [ + :prefix, + pfx_sxp, + self.last.to_sxp(prefixes: prefixes, base_uri: base_uri, **options) + ].join(' ') << ')' else - '(' << map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri) }.join(' ') << ')' + '(' << map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri, **options) }.join(' ') << ')' end end end @@ -254,7 +234,7 @@ class RDF::URI # @param [Hash{Symbol => RDF::URI}] prefixes(nil) # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(prefixes: nil, base_uri: nil, **options) return lexical if lexical pn = pname(prefixes: prefixes || {}) return pn unless to_s == pn @@ -271,10 +251,8 @@ class RDF::Node ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) to_s end end @@ -283,18 +261,16 @@ class RDF::Literal ## # Returns the SXP representation of a Literal. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) case datatype when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.time # Retain stated lexical form if possible - valid? ? to_s : object.to_sxp(prefixes: nil, base_uri: nil) + valid? ? to_s : object.to_sxp(**options) else text = value.dump text << "@#{language}" if self.has_language? - text << "^^#{datatype.to_sxp(prefixes: prefixes, base_uri: base_uri)}" if self.has_datatype? + text << "^^#{datatype.to_sxp(**options)}" if self.has_datatype? text end end @@ -303,10 +279,8 @@ class Double ## # Returns the SXP representation of this object. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) case when nan? then 'nan.0' when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0') @@ -321,23 +295,19 @@ class RDF::Query # # If Query is named, it's treated as a GroupGraphPattern, otherwise, a BGP # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [Array] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) res = [:bgp] + patterns - (named? ? [:graph, graph_name, res] : res).to_sxp(prefixes: prefixes, base_uri: base_uri) + (named? ? [:graph, graph_name, res] : res).to_sxp(**options) end end class RDF::Query::Pattern # Transform Query Pattern into an SXP # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) - [:triple, subject, predicate, object].to_sxp(prefixes: prefixes, base_uri: base_uri) + def to_sxp(**options) + [:triple, subject, predicate, object].to_sxp(**options) end end @@ -345,10 +315,8 @@ class RDF::Query::Variable ## # Transform Query variable into an SXP. # - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil) # @return [String] - def to_sxp(prefixes: nil, base_uri: nil) + def to_sxp(**options) prefix = distinguished? ? (existential? ? '$' : '?') : (existential? ? '$$' : '??') unbound? ? "#{prefix}#{name}".to_sym.to_sxp : ["#{prefix}#{name}".to_sym, value].to_sxp end From 3f610363c39232aa32f38ffa03edd0fa33015217 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 19 Dec 2021 13:15:34 -0800 Subject: [PATCH 20/22] Explicitly add matrix gem, as it's no longer part of standard library in 3.1. --- sxp.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/sxp.gemspec b/sxp.gemspec index 51377a8..b806450 100755 --- a/sxp.gemspec +++ b/sxp.gemspec @@ -23,6 +23,7 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 2.6' gem.requirements = [] gem.add_runtime_dependency 'rdf', '~> 3.2' + gem.add_runtime_dependency 'matrix' gem.add_development_dependency 'amazing_print', '~> 1.4' gem.add_development_dependency 'rspec', '~> 3.10' From c12178afd00f0250dad908d0ca51ed1a84c7818a Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 26 Dec 2021 22:45:24 -0800 Subject: [PATCH 21/22] CI on Ruby 3.1. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 970180d..0aaedb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,7 @@ jobs: - 2.6 - 2.7 - 3.0 + - 3.1 - ruby-head - jruby steps: From 2b496f0cf4e287ec5e2c87407a6be8ae04e57466 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 29 Dec 2021 09:51:27 -0800 Subject: [PATCH 22/22] Improve yard tags. --- lib/sxp/generator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sxp/generator.rb b/lib/sxp/generator.rb index d59964e..0eb806b 100644 --- a/lib/sxp/generator.rb +++ b/lib/sxp/generator.rb @@ -17,8 +17,8 @@ class Block ## # @param [Object] obj # @param [Integer] indent - # @param [Hash{Symbol => RDF::URI}] prefixes(nil) - # @param [RDF::URI] base_uri(nil)l) + # @param [Hash{Symbol => RDF::URI}] prefixes (nil) + # @param [RDF::URI] base_uri (nil) def initialize(obj, indent, prefixes: nil, base_uri: nil) @indent = indent @elements = []