require 'rdf/format' module ShEx ## # ShEx format specification. Note that this format does not define any readers or writers. # # @example Obtaining an LD Patch format class # RDF::Format.for(:shex) #=> LD::Patch::Format # RDF::Format.for("etc/foaf.shex") # RDF::Format.for(file_name: "etc/foaf.shex") # RDF::Format.for(file_extension: "shex") # RDF::Format.for(content_type: "application/shex") # # @see http://www.w3.org/TR/ldpatch/ class Format < RDF::Format content_type 'application/shex', extension: :shex content_encoding 'utf-8' ## # Hash of CLI commands appropriate for this format # @return [Hash{Symbol => Lambda(Array, Hash)}] def self.cli_commands { shex: { description: "Validate repository given shape", help: "shex [--shape Resource] [--focus Resource] [--schema-input STRING] [--schema STRING] file", parse: true, lambda: -> (argv, **options) do options[:schema_input] ||= case options[:schema] when IO, StringIO then options[:schema] else RDF::Util::File.open_file(options[:schema]) {|f| f.read} end raise ArgumentError, "Shape matching requires a schema or reference to schema resource" unless options[:schema_input] raise ArgumentError, "Shape matching requires a focus node" unless options[:focus] format = options[:schema].to_s.end_with?('json') ? 'shexj' : 'shexc' shex = ShEx.parse(options[:schema_input], format: format, **options) if options[:to_sxp] || options[:to_json] options[:messages][:shex] = {} options[:messages][:shex].merge!({"S-Expression": [SXP::Generator.string(shex.to_sxp_bin)]}) if options[:to_sxp] options[:messages][:shex].merge!({ShExJ: [shex.to_json(JSON::LD::JSON_STATE)]}) if options[:to_json] else focus = options.delete(:focus) shape = options.delete(:shape) map = shape ? {focus => shape} : {} begin res = shex.execute(RDF::CLI.repository, map, focus: focus, **options) options[:messages][:shex] = { result: ["Satisfied shape."], detail: [SXP::Generator.string(res.to_sxp_bin)] } rescue ShEx::NotSatisfied => e options[:logger].error e.to_s options[:messages][:shex] = { result: ["Did not satisfied shape."], detail: [SXP::Generator.stringe.expression] } raise end end end, options: [ RDF::CLI::Option.new( symbol: :focus, datatype: String, control: :text, use: :required, on: ["--focus Resource"], description: "Focus node within repository" ) {|v| RDF::URI(v)}, RDF::CLI::Option.new( symbol: :shape, datatype: String, control: :text, use: :optional, on: ["--shape URI"], description: "Shape identifier within ShEx schema" ) {|v| RDF::URI(v)}, RDF::CLI::Option.new( symbol: :schema_input, datatype: String, control: :none, on: ["--schema-input STRING"], description: "ShEx schema in URI encoded format" ) {|v| URI.decode(v)}, RDF::CLI::Option.new( symbol: :schema, datatype: String, control: :url2, on: ["--schema URI"], description: "ShEx schema location" ) {|v| RDF::URI(v)}, RDF::CLI::Option.new( symbol: :to_json, datatype: String, control: :checkbox, on: ["--to-json"], description: "Display parsed schema as ShExJ" ), RDF::CLI::Option.new( symbol: :to_sxp, datatype: String, control: :checkbox, on: ["--to-sxp"], description: "Display parsed schema as an S-Expression" ), ] } } end end end