json-ld 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/README.md +9 -8
- data/VERSION +1 -1
- data/bin/jsonld +2 -1
- data/lib/json/ld.rb +43 -42
- data/lib/json/ld/api.rb +184 -39
- data/lib/json/ld/compact.rb +1 -1
- data/lib/json/ld/context.rb +88 -58
- data/lib/json/ld/expand.rb +27 -25
- data/lib/json/ld/extensions.rb +0 -23
- data/lib/json/ld/flatten.rb +1 -1
- data/lib/json/ld/reader.rb +2 -2
- data/lib/json/ld/resource.rb +1 -1
- data/spec/api_spec.rb +3 -1
- data/spec/compact_spec.rb +6 -4
- data/spec/context_spec.rb +20 -35
- data/spec/expand_spec.rb +42 -22
- data/spec/frame_spec.rb +1 -1
- data/spec/from_rdf_spec.rb +4 -22
- data/spec/suite_compact_spec.rb +2 -19
- data/spec/suite_error_spec.rb +17 -0
- data/spec/suite_expand_spec.rb +2 -16
- data/spec/suite_flatten_spec.rb +2 -16
- data/spec/suite_frame_spec.rb +2 -16
- data/spec/suite_from_rdf_spec.rb +2 -18
- data/spec/suite_helper.rb +218 -60
- data/spec/suite_remote_doc_spec.rb +17 -0
- data/spec/suite_to_rdf_spec.rb +2 -19
- data/spec/to_rdf_spec.rb +5 -5
- data/spec/writer_spec.rb +3 -3
- metadata +8 -6
- data/spec/suite_error_expand_spec.rb +0 -23
    
        checksums.yaml
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            !binary "U0hBMQ==":
         | 
| 3 3 | 
             
              metadata.gz: !binary |-
         | 
| 4 | 
            -
                 | 
| 4 | 
            +
                ZTJhN2RiZDA5MjA5ZTUxZGJhZTZhMTI5NGNkOTM3YjA0ZjkxYzlkYQ==
         | 
| 5 5 | 
             
              data.tar.gz: !binary |-
         | 
| 6 | 
            -
                 | 
| 6 | 
            +
                ZTRlZDUwNDA0Nzc5MWIyMDg5YmQ2MTQzY2JlYzU2YWYxMzAyNDBjMQ==
         | 
| 7 7 | 
             
            !binary "U0hBNTEy":
         | 
| 8 8 | 
             
              metadata.gz: !binary |-
         | 
| 9 | 
            -
                 | 
| 10 | 
            -
                 | 
| 11 | 
            -
                 | 
| 9 | 
            +
                YmY4M2Q3NjEyYmNkOTBlYjdiYzAzOWI1ZThhMDQ2ZjA3MWQ0ZTFiZDFkOGMx
         | 
| 10 | 
            +
                NzAyYzRhYjgwNGMyMjMxNTNjZjQ2N2I2NzQyZTRlMGQzMThjZmY1Mjc3ZTk4
         | 
| 11 | 
            +
                OTYyNDYzMmY1Yzc5ODFlNGY3MDY1OGQxOTY5NGRhZTdmY2FiOGQ=
         | 
| 12 12 | 
             
              data.tar.gz: !binary |-
         | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
                 | 
| 13 | 
            +
                ZjBlNTM5YTJkY2YxY2UyOGMxMmRlMjRiODk5Yjk0M2EyM2NiNzlkODBjNWY2
         | 
| 14 | 
            +
                ODg1MzAwOTUxODc0OTI3NDI3NzA0ZDk0ZGEzNTE3YjVmZWNhMzk2ZWY1MDAw
         | 
| 15 | 
            +
                M2M5NmFjM2M0OGUzMjA1Zjk2Zjg4ZDhiOTY0YWM2OTJlNWNiZjg=
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # JSON-LD reader/writer
         | 
| 2 2 |  | 
| 3 | 
            -
            [JSON-LD][] reader/writer for [RDF.rb][RDF.rb] and fully conforming [JSON-LD][] processor.
         | 
| 3 | 
            +
            [JSON-LD][] reader/writer for [RDF.rb][RDF.rb] and fully conforming [JSON-LD API][] processor. Additionally this gem implements [JSON-LD Framing][].
         | 
| 4 4 |  | 
| 5 5 | 
             
            [](http://badge.fury.io/rb/json-ld)
         | 
| 6 6 | 
             
            [](http://travis-ci.org/ruby-rdf/json-ld)
         | 
| @@ -220,13 +220,12 @@ Install with `gem install json-ld` | |
| 220 220 | 
             
            Full documentation available on [RubyDoc](http://rubydoc.info/gems/json-ld/file/README.md)
         | 
| 221 221 |  | 
| 222 222 | 
             
            ## Differences from [JSON-LD API][]
         | 
| 223 | 
            -
            The specified JSON-LD API is based on a WebIDL definition intended for use within  | 
| 223 | 
            +
            The specified JSON-LD API is based on a WebIDL definition implementing [Promises][] intended for use within a browser.
         | 
| 224 224 | 
             
            This version implements a more Ruby-like variation of this API without the use
         | 
| 225 | 
            -
            of  | 
| 226 | 
            -
            execute synchronously, so that the return from a method can be used as well as a block.
         | 
| 225 | 
            +
            of promises or callback arguments, preferring Ruby blocks. All API methods
         | 
| 226 | 
            +
            execute synchronously, so that the return from a method can typically be used as well as a block.
         | 
| 227 227 |  | 
| 228 | 
            -
            Note, the API method signatures differed in versions before 1.0, in that they also had
         | 
| 229 | 
            -
            a callback parameter.
         | 
| 228 | 
            +
            Note, the API method signatures differed in versions before 1.0, in that they also had a callback parameter. And 1.0.6 has some other minor method signature differences than previous versions. This should be the only exception to the use of semantic versioning.
         | 
| 230 229 |  | 
| 231 230 | 
             
            ### Principal Classes
         | 
| 232 231 | 
             
            * {JSON::LD}
         | 
| @@ -288,5 +287,7 @@ see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file. | |
| 288 287 | 
             
            [PDD]:              http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
         | 
| 289 288 | 
             
            [RDF.rb]:           http://rubygems.org/gems/rdf
         | 
| 290 289 | 
             
            [Backports]:        http://rubygems.org/gems/backports
         | 
| 291 | 
            -
            [JSON-LD]:          http:// | 
| 292 | 
            -
            [JSON-LD API]:      http:// | 
| 290 | 
            +
            [JSON-LD]:          http://www.w3.org/TR/json-ld/ "JSON-LD 1.0"
         | 
| 291 | 
            +
            [JSON-LD API]:      http://www.w3.org/TR/json-ld-api/ "JSON-LD 1.0 Processing Algorithms and API"
         | 
| 292 | 
            +
            [JSON-LD Framing]:  http://json-ld.org/spec/latest/json-ld-framing/ "JSON-LD Framing 1.0"
         | 
| 293 | 
            +
            [Promises]:         http://dom.spec.whatwg.org/#promises
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            1.0. | 
| 1 | 
            +
            1.0.6
         | 
    
        data/bin/jsonld
    CHANGED
    
    | @@ -26,7 +26,8 @@ def run(input, options) | |
| 26 26 | 
             
              prefixes = {}
         | 
| 27 27 | 
             
              start = Time.new
         | 
| 28 28 | 
             
              if options[:expand]
         | 
| 29 | 
            -
                 | 
| 29 | 
            +
                options = options.merge(:expandContext => options.delete(:context)) if options.has_key?(:context)
         | 
| 30 | 
            +
                output = JSON::LD::API.expand(input, options)
         | 
| 30 31 | 
             
                secs = Time.new - start
         | 
| 31 32 | 
             
                options[:output].puts output.to_json(JSON::LD::JSON_STATE)
         | 
| 32 33 | 
             
                STDERR.puts "Expanded in #{secs} seconds." unless options[:quiet]
         | 
    
        data/lib/json/ld.rb
    CHANGED
    
    | @@ -88,48 +88,49 @@ module JSON | |
| 88 88 | 
             
                def self.debug?; @debug; end
         | 
| 89 89 | 
             
                def self.debug=(value); @debug = value; end
         | 
| 90 90 |  | 
| 91 | 
            -
                class  | 
| 92 | 
            -
                   | 
| 93 | 
            -
             | 
| 94 | 
            -
                   | 
| 95 | 
            -
                   | 
| 96 | 
            -
             | 
| 97 | 
            -
                   | 
| 98 | 
            -
             | 
| 99 | 
            -
                  class  | 
| 100 | 
            -
                  class  | 
| 101 | 
            -
                  class  | 
| 102 | 
            -
                  class  | 
| 103 | 
            -
                  class  | 
| 104 | 
            -
                  class  | 
| 105 | 
            -
                  class  | 
| 106 | 
            -
                  class  | 
| 107 | 
            -
                  class  | 
| 108 | 
            -
                  class  | 
| 109 | 
            -
                  class  | 
| 110 | 
            -
                  class  | 
| 111 | 
            -
                  class  | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
                  class  | 
| 116 | 
            -
                  class CyclicIRIMapping <  | 
| 117 | 
            -
                  class  | 
| 118 | 
            -
                  class  | 
| 119 | 
            -
                  class  | 
| 120 | 
            -
                  class  | 
| 121 | 
            -
                  class  | 
| 122 | 
            -
                  class  | 
| 123 | 
            -
                  class  | 
| 124 | 
            -
                  class  | 
| 125 | 
            -
                  class  | 
| 126 | 
            -
                  class  | 
| 127 | 
            -
                  class  | 
| 128 | 
            -
                  class  | 
| 129 | 
            -
                  class  | 
| 130 | 
            -
                  class  | 
| 131 | 
            -
                  class  | 
| 132 | 
            -
                  class  | 
| 91 | 
            +
                class JsonLdError < Exception
         | 
| 92 | 
            +
                  def to_s
         | 
| 93 | 
            +
                    "#{self.class.instance_variable_get :@code}: #{super}"
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
                  def code
         | 
| 96 | 
            +
                    self.class.instance_variable_get :@code
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  class LoadingDocumentFailed < JsonLdError; @code = "loading document failed"; end
         | 
| 100 | 
            +
                  class ListOfLists < JsonLdError; @code = "list of lists"; end
         | 
| 101 | 
            +
                  class InvalidIndexValue < JsonLdError; @code = "invalid @index value"; end
         | 
| 102 | 
            +
                  class ConflictingIndexes < JsonLdError; @code = "conflicting indexes"; end
         | 
| 103 | 
            +
                  class InvalidIdValue < JsonLdError; @code = "invalid @id value"; end
         | 
| 104 | 
            +
                  class InvalidLocalContext < JsonLdError; @code = "invalid local context"; end
         | 
| 105 | 
            +
                  class MultipleContextLinkHeaders < JsonLdError; @code = "multiple context link headers"; end
         | 
| 106 | 
            +
                  class LoadingRemoteContextFailed < JsonLdError; @code = "loading remote context failed"; end
         | 
| 107 | 
            +
                  class InvalidRemoteContext < JsonLdError; @code = "invalid remote context"; end
         | 
| 108 | 
            +
                  class RecursiveContextInclusion < JsonLdError; @code = "recursive context inclusion"; end
         | 
| 109 | 
            +
                  class InvalidBaseIRI < JsonLdError; @code = "invalid base IRI"; end
         | 
| 110 | 
            +
                  class InvalidVocabMapping < JsonLdError; @code = "invalid vocab mapping"; end
         | 
| 111 | 
            +
                  class InvalidDefaultLanguage < JsonLdError; @code = "invalid default language"; end
         | 
| 112 | 
            +
                  class KeywordRedefinition < JsonLdError; @code = "keyword redefinition"; end
         | 
| 113 | 
            +
                  class InvalidTermDefinition < JsonLdError; @code = "invalid term definition"; end
         | 
| 114 | 
            +
                  class InvalidReverseProperty < JsonLdError; @code = "invalid reverse property"; end
         | 
| 115 | 
            +
                  class InvalidIRIMapping < JsonLdError; @code = "invalid IRI mapping"; end
         | 
| 116 | 
            +
                  class CyclicIRIMapping < JsonLdError; @code = "cyclic IRI mapping"; end
         | 
| 117 | 
            +
                  class InvalidKeywordAlias < JsonLdError; @code = "invalid keyword alias"; end
         | 
| 118 | 
            +
                  class InvalidTypeMapping < JsonLdError; @code = "invalid type mapping"; end
         | 
| 119 | 
            +
                  class InvalidLanguageMapping < JsonLdError; @code = "invalid language mapping"; end
         | 
| 120 | 
            +
                  class CollidingKeywords < JsonLdError; @code = "colliding keywords"; end
         | 
| 121 | 
            +
                  class InvalidContainerMapping < JsonLdError; @code = "invalid container mapping"; end
         | 
| 122 | 
            +
                  class InvalidTypeValue < JsonLdError; @code = "invalid type value"; end
         | 
| 123 | 
            +
                  class InvalidValueObject < JsonLdError; @code = "invalid value object"; end
         | 
| 124 | 
            +
                  class InvalidValueObjectValue < JsonLdError; @code = "invalid value object value"; end
         | 
| 125 | 
            +
                  class InvalidLanguageTaggedString < JsonLdError; @code = "invalid language-tagged string"; end
         | 
| 126 | 
            +
                  class InvalidLanguageTaggedValue < JsonLdError; @code = "invalid language-tagged value"; end
         | 
| 127 | 
            +
                  class InvalidTypedValue < JsonLdError; @code = "invalid typed value"; end
         | 
| 128 | 
            +
                  class InvalidSetOrListObject < JsonLdError; @code = "invalid set or list object"; end
         | 
| 129 | 
            +
                  class InvalidLanguageMapValue < JsonLdError; @code = "invalid language map value"; end
         | 
| 130 | 
            +
                  class CompactionToListOfLists < JsonLdError; @code = "compaction to list of lists"; end
         | 
| 131 | 
            +
                  class InvalidReversePropertyMap < JsonLdError; @code = "invalid reverse property map"; end
         | 
| 132 | 
            +
                  class InvalidReverseValue < JsonLdError; @code = "invalid @reverse value"; end
         | 
| 133 | 
            +
                  class InvalidReversePropertyValue < JsonLdError; @code = "invalid reverse property value"; end
         | 
| 133 134 | 
             
                end
         | 
| 134 135 |  | 
| 135 136 | 
             
                class InvalidFrame < Exception
         | 
    
        data/lib/json/ld/api.rb
    CHANGED
    
    | @@ -48,39 +48,56 @@ module JSON::LD | |
| 48 48 | 
             
                # Initialize the API, reading in any document and setting global options
         | 
| 49 49 | 
             
                #
         | 
| 50 50 | 
             
                # @param [String, #read, Hash, Array] input
         | 
| 51 | 
            -
                # @param [String, #read | 
| 51 | 
            +
                # @param [String, #read, Hash, Array, JSON::LD::Context] context
         | 
| 52 52 | 
             
                #   An external context to use additionally to the context embedded in input when expanding the input.
         | 
| 53 53 | 
             
                # @param  [Hash{Symbol => Object}] options
         | 
| 54 | 
            -
                # @option options [ | 
| 54 | 
            +
                # @option options [String, #to_s] :base
         | 
| 55 55 | 
             
                #   The Base IRI to use when expanding the document. This overrides the value of `input` if it is a _IRI_. If not specified and `input` is not an _IRI_, the base IRI defaults to the current document IRI if in a browser context, or the empty string if there is no document context.
         | 
| 56 | 
            +
                #   If not specified, and a base IRI is found from `input`, options[:base] will be modified with this value.
         | 
| 56 57 | 
             
                # @option options [Boolean] :compactArrays (true)
         | 
| 57 58 | 
             
                #   If set to `true`, the JSON-LD processor replaces arrays with just one element with that element during compaction. If set to `false`, all arrays will remain arrays even if they have just one element.
         | 
| 59 | 
            +
                # @option options [Proc] :documentLoader
         | 
| 60 | 
            +
                #   The callback of the loader to be used to retrieve remote documents and contexts. If specified, it must be used to retrieve remote documents and contexts; otherwise, if not specified, the processor's built-in loader must be used. See {documentLoader} for the method signature.
         | 
| 61 | 
            +
                # @option options [String, #read, Hash, Array, JSON::LD::Context] :expandContext
         | 
| 62 | 
            +
                #   A context that is used to initialize the active context when expanding a document.
         | 
| 58 63 | 
             
                # @option options [Boolean, String, RDF::URI] :flatten
         | 
| 59 64 | 
             
                #   If set to a value that is not `false`, the JSON-LD processor must modify the output of the Compaction Algorithm or the Expansion Algorithm by coalescing all properties associated with each subject via the Flattening Algorithm. The value of `flatten must` be either an _IRI_ value representing the name of the graph to flatten, or `true`. If the value is `true`, then the first graph encountered in the input document is selected and flattened.
         | 
| 60 | 
            -
                # @option options [ | 
| 61 | 
            -
                #   If set to  | 
| 62 | 
            -
                # | 
| 65 | 
            +
                # @option options [String] :processingMode ("json-ld-1.0")
         | 
| 66 | 
            +
                #   If set to "json-ld-1.0", the JSON-LD processor must produce exactly the same results as the algorithms defined in this specification. If set to another value, the JSON-LD processor is allowed to extend or modify the algorithms defined in this specification to enable application-specific optimizations. The definition of such optimizations is beyond the scope of this specification and thus not defined. Consequently, different implementations may implement different optimizations. Developers must not define modes beginning with json-ld as they are reserved for future versions of this specification.
         | 
| 67 | 
            +
                # @option options [String] :produceGeneralizedRdf (false)
         | 
| 68 | 
            +
                #   Unless the produce generalized RDF flag is set to true, RDF triples containing a blank node predicate are excluded from output.
         | 
| 63 69 | 
             
                # @option options [Boolean] :useNativeTypes (true)
         | 
| 64 70 | 
             
                #   If set to `true`, the JSON-LD processor will use native datatypes for expression xsd:integer, xsd:boolean, and xsd:double values, otherwise, it will use the expanded form.
         | 
| 65 | 
            -
                # @option options [Boolean] :useRdfType (false)
         | 
| 66 | 
            -
                #   If set to `true`, the JSON-LD processor will try to convert datatyped literals to JSON native types instead of using the expanded object form when converting from RDF. `xsd:boolean` values will be converted to `true` or `false`. `xsd:integer` and `xsd:double` values will be converted to JSON numbers.
         | 
| 67 71 | 
             
                # @option options [Boolean] :rename_bnodes (true)
         | 
| 68 72 | 
             
                #   Rename bnodes as part of expansion, or keep them the same.
         | 
| 69 73 | 
             
                # @yield [api]
         | 
| 70 74 | 
             
                # @yieldparam [API]
         | 
| 71 75 | 
             
                def initialize(input, context, options = {}, &block)
         | 
| 72 76 | 
             
                  @options = {:compactArrays => true}.merge(options)
         | 
| 73 | 
            -
                  options =  | 
| 77 | 
            +
                  @options[:validate] = true if @options[:processingMode] == "json-ld-1.0"
         | 
| 78 | 
            +
                  @options[:documentLoader] ||= self.class.method(:documentLoader)
         | 
| 79 | 
            +
                  options[:rename_bnodes] ||= true
         | 
| 74 80 | 
             
                  @namer = options[:rename_bnodes] ? BlankNodeNamer.new("b") : BlankNodeMapper.new
         | 
| 81 | 
            +
                  content_type = nil
         | 
| 75 82 | 
             
                  @value = case input
         | 
| 76 83 | 
             
                  when Array, Hash then input.dup
         | 
| 77 | 
            -
                  when IO, StringIO | 
| 84 | 
            +
                  when IO, StringIO
         | 
| 85 | 
            +
                    @options = {:base => input.base_uri}.merge(@options) if input.respond_to?(:base_uri)
         | 
| 86 | 
            +
                    JSON.parse(input.read)
         | 
| 78 87 | 
             
                  when String
         | 
| 79 | 
            -
                     | 
| 80 | 
            -
             | 
| 81 | 
            -
                     | 
| 82 | 
            -
                     | 
| 88 | 
            +
                    remote_doc = @options[:documentLoader].call(input, @options)
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    @options = {:base => remote_doc.documentUrl}.merge(@options)
         | 
| 91 | 
            +
                    context = context ? [context, remote_doc.contextUrl].compact : remote_doc.contextUrl
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    case remote_doc.document
         | 
| 94 | 
            +
                    when String then JSON.parse(remote_doc.document)
         | 
| 95 | 
            +
                    else remote_doc.document
         | 
| 96 | 
            +
                    end
         | 
| 83 97 | 
             
                  end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  # Update calling context :base option, if not defined
         | 
| 100 | 
            +
                  options[:base] ||= @options[:base] if @options[:base]
         | 
| 84 101 | 
             
                  @context = Context.new(@options)
         | 
| 85 102 | 
             
                  @context = @context.parse(context) if context
         | 
| 86 103 |  | 
| @@ -100,20 +117,18 @@ module JSON::LD | |
| 100 117 | 
             
                #
         | 
| 101 118 | 
             
                # @param [String, #read, Hash, Array] input
         | 
| 102 119 | 
             
                #   The JSON-LD object to copy and perform the expansion upon.
         | 
| 103 | 
            -
                # @param [String, #read, Hash, Array, JSON::LD::Context] context
         | 
| 104 | 
            -
                #   An external context to use additionally to the context embedded in input when expanding the input.
         | 
| 105 120 | 
             
                # @param  [Hash{Symbol => Object}] options
         | 
| 106 121 | 
             
                #   See options in {JSON::LD::API#initialize}
         | 
| 107 | 
            -
                # @raise [ | 
| 122 | 
            +
                # @raise [JsonLdError]
         | 
| 108 123 | 
             
                # @yield jsonld
         | 
| 109 124 | 
             
                # @yieldparam [Array<Hash>] jsonld
         | 
| 110 125 | 
             
                #   The expanded JSON-LD document
         | 
| 111 126 | 
             
                # @return [Array<Hash>]
         | 
| 112 127 | 
             
                #   The expanded JSON-LD document
         | 
| 113 128 | 
             
                # @see http://json-ld.org/spec/latest/json-ld-api/#expansion-algorithm
         | 
| 114 | 
            -
                def self.expand(input,  | 
| 129 | 
            +
                def self.expand(input, options = {})
         | 
| 115 130 | 
             
                  result = nil
         | 
| 116 | 
            -
                  API.new(input,  | 
| 131 | 
            +
                  API.new(input, options[:expandContext], options) do |api|
         | 
| 117 132 | 
             
                    result = api.expand(api.value, nil, api.context)
         | 
| 118 133 | 
             
                  end
         | 
| 119 134 |  | 
| @@ -147,14 +162,14 @@ module JSON::LD | |
| 147 162 | 
             
                #   The compacted JSON-LD document
         | 
| 148 163 | 
             
                # @return [Hash]
         | 
| 149 164 | 
             
                #   The compacted JSON-LD document
         | 
| 150 | 
            -
                # @raise [ | 
| 165 | 
            +
                # @raise [JsonLdError]
         | 
| 151 166 | 
             
                # @see http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm
         | 
| 152 167 | 
             
                def self.compact(input, context, options = {})
         | 
| 153 168 | 
             
                  expanded = result = nil
         | 
| 154 169 |  | 
| 155 170 | 
             
                  # 1) Perform the Expansion Algorithm on the JSON-LD input.
         | 
| 156 171 | 
             
                  #    This removes any existing context to allow the given context to be cleanly applied.
         | 
| 157 | 
            -
                  expanded = API.expand(input,  | 
| 172 | 
            +
                  expanded = API.expand(input, options)
         | 
| 158 173 |  | 
| 159 174 | 
             
                  API.new(expanded, context, options) do
         | 
| 160 175 | 
             
                    debug(".compact") {"expanded input: #{expanded.to_json(JSON_STATE)}"}
         | 
| @@ -195,10 +210,10 @@ module JSON::LD | |
| 195 210 | 
             
                  flattened = []
         | 
| 196 211 |  | 
| 197 212 | 
             
                  # Expand input to simplify processing
         | 
| 198 | 
            -
                  expanded_input = API.expand(input,  | 
| 213 | 
            +
                  expanded_input = API.expand(input, options)
         | 
| 199 214 |  | 
| 200 215 | 
             
                  # Initialize input using frame as context
         | 
| 201 | 
            -
                  API.new(expanded_input,  | 
| 216 | 
            +
                  API.new(expanded_input, context, options) do
         | 
| 202 217 | 
             
                    debug(".flatten") {"expanded input: #{value.to_json(JSON_STATE)}"}
         | 
| 203 218 |  | 
| 204 219 | 
             
                    # Initialize node map to a JSON object consisting of a single member whose key is @default and whose value is an empty JSON object.
         | 
| @@ -221,7 +236,7 @@ module JSON::LD | |
| 221 236 |  | 
| 222 237 | 
             
                    if context && !flattened.empty?
         | 
| 223 238 | 
             
                      # Otherwise, return the result of compacting flattened according the Compaction algorithm passing context ensuring that the compaction result uses the @graph keyword (or its alias) at the top-level, even if the context is empty or if there is only one element to put in the @graph array. This ensures that the returned document has a deterministic structure.
         | 
| 224 | 
            -
                      compacted = compact(flattened, nil)
         | 
| 239 | 
            +
                      compacted = depth {compact(flattened, nil)}
         | 
| 225 240 | 
             
                      compacted = [compacted] unless compacted.is_a?(Array)
         | 
| 226 241 | 
             
                      kwgraph = self.context.compact_iri('@graph', :quiet => true)
         | 
| 227 242 | 
             
                      flattened = self.context.serialize.merge(kwgraph => compacted)
         | 
| @@ -274,22 +289,25 @@ module JSON::LD | |
| 274 289 | 
             
                  framing_state[:embed] = options[:embed] if options.has_key?(:embed)
         | 
| 275 290 | 
             
                  framing_state[:explicit] = options[:explicit] if options.has_key?(:explicit)
         | 
| 276 291 | 
             
                  framing_state[:omitDefault] = options[:omitDefault] if options.has_key?(:omitDefault)
         | 
| 292 | 
            +
                  options[:documentLoader] ||= method(:documentLoader)
         | 
| 277 293 |  | 
| 278 294 | 
             
                  # de-reference frame to create the framing object
         | 
| 279 295 | 
             
                  frame = case frame
         | 
| 280 296 | 
             
                  when Hash then frame.dup
         | 
| 281 297 | 
             
                  when IO, StringIO then JSON.parse(frame.read)
         | 
| 282 298 | 
             
                  when String
         | 
| 283 | 
            -
                     | 
| 284 | 
            -
                     | 
| 285 | 
            -
                     | 
| 299 | 
            +
                    remote_doc = options[:documentLoader].call(frame)
         | 
| 300 | 
            +
                    case remote_doc.document
         | 
| 301 | 
            +
                    when String then JSON.parse(remote_doc.document)
         | 
| 302 | 
            +
                    else remote_doc.document
         | 
| 303 | 
            +
                    end
         | 
| 286 304 | 
             
                  end
         | 
| 287 305 |  | 
| 288 | 
            -
                  # Expand frame to simplify processing
         | 
| 289 | 
            -
                  expanded_frame = API.expand(frame)
         | 
| 290 | 
            -
                  
         | 
| 291 306 | 
             
                  # Expand input to simplify processing
         | 
| 292 | 
            -
                  expanded_input = API.expand(input)
         | 
| 307 | 
            +
                  expanded_input = API.expand(input, options)
         | 
| 308 | 
            +
             | 
| 309 | 
            +
                  # Expand frame to simplify processing
         | 
| 310 | 
            +
                  expanded_frame = API.expand(frame, options)
         | 
| 293 311 |  | 
| 294 312 | 
             
                  # Initialize input using frame as context
         | 
| 295 313 | 
             
                  API.new(expanded_input, nil, options) do
         | 
| @@ -334,25 +352,23 @@ module JSON::LD | |
| 334 352 | 
             
                #
         | 
| 335 353 | 
             
                # @param [String, #read, Hash, Array] input
         | 
| 336 354 | 
             
                #   The JSON-LD object to process when outputting statements.
         | 
| 337 | 
            -
                # @param [String, #read, Hash, Array, JSON::LD::Context] context
         | 
| 338 | 
            -
                #   An external context to use additionally to the context embedded in input when expanding the input.
         | 
| 339 355 | 
             
                # @param [{Symbol,String => Object}] options
         | 
| 340 356 | 
             
                #   See options in {JSON::LD::API#initialize}
         | 
| 341 357 | 
             
                #   Options passed to {JSON::LD::API.expand}
         | 
| 342 | 
            -
                # @option options [Boolean] : | 
| 358 | 
            +
                # @option options [Boolean] :produceGeneralizedRdf (false)
         | 
| 343 359 | 
             
                #   If true, output will include statements having blank node predicates, otherwise they are dropped.
         | 
| 344 | 
            -
                # @raise [ | 
| 360 | 
            +
                # @raise [JsonLdError]
         | 
| 345 361 | 
             
                # @return [Array<RDF::Statement>] if no block given
         | 
| 346 362 | 
             
                # @yield statement
         | 
| 347 363 | 
             
                # @yieldparam [RDF::Statement] statement
         | 
| 348 | 
            -
                def self.toRDF(input,  | 
| 364 | 
            +
                def self.toRDF(input, options = {}, &block)
         | 
| 349 365 | 
             
                  results = []
         | 
| 350 366 | 
             
                  results.extend(RDF::Enumerable)
         | 
| 351 367 |  | 
| 352 368 | 
             
                  # Expand input to simplify processing
         | 
| 353 | 
            -
                  expanded_input = API.expand(input,  | 
| 369 | 
            +
                  expanded_input = API.expand(input, options)
         | 
| 354 370 |  | 
| 355 | 
            -
                  API.new(expanded_input,  | 
| 371 | 
            +
                  API.new(expanded_input, nil, options) do
         | 
| 356 372 | 
             
                    # 1) Perform the Expansion Algorithm on the JSON-LD input.
         | 
| 357 373 | 
             
                    #    This removes any existing context to allow the given context to be cleanly applied.
         | 
| 358 374 | 
             
                    debug(".toRDF") {"expanded input: #{expanded_input.to_json(JSON_STATE)}"}
         | 
| @@ -367,8 +383,29 @@ module JSON::LD | |
| 367 383 | 
             
                    node_map.each do |graph_name, graph|
         | 
| 368 384 | 
             
                      context = as_resource(graph_name) unless graph_name == '@default'
         | 
| 369 385 | 
             
                      debug(".toRDF") {"context: #{context ? context.to_ntriples : 'null'}"}
         | 
| 386 | 
            +
                      # Drop results for graphs which are named with relative IRIs
         | 
| 387 | 
            +
                      if graph_name.is_a?(RDF::URI) && !graph_name.absolute
         | 
| 388 | 
            +
                        debug(".toRDF") {"drop relative graph_name: #{statement.to_ntriples}"}
         | 
| 389 | 
            +
                        next
         | 
| 390 | 
            +
                      end
         | 
| 370 391 | 
             
                      graph_to_rdf(graph).each do |statement|
         | 
| 371 | 
            -
                        next if statement.predicate.node? && !options[: | 
| 392 | 
            +
                        next if statement.predicate.node? && !options[:produceGeneralizedRdf]
         | 
| 393 | 
            +
                        # Drop results with relative IRIs
         | 
| 394 | 
            +
                        relative = statement.to_a.any? do |r|
         | 
| 395 | 
            +
                          case r
         | 
| 396 | 
            +
                          when RDF::URI
         | 
| 397 | 
            +
                            r.relative?
         | 
| 398 | 
            +
                          when RDF::Literal
         | 
| 399 | 
            +
                            r.has_datatype? && r.datatype.relative?
         | 
| 400 | 
            +
                          else
         | 
| 401 | 
            +
                            false
         | 
| 402 | 
            +
                          end
         | 
| 403 | 
            +
                        end
         | 
| 404 | 
            +
                        if relative
         | 
| 405 | 
            +
                          debug(".toRDF") {"drop statement with relative IRIs: #{statement.to_ntriples}"}
         | 
| 406 | 
            +
                          next
         | 
| 407 | 
            +
                        end
         | 
| 408 | 
            +
             | 
| 372 409 | 
             
                        statement.context = context if context
         | 
| 373 410 | 
             
                        if block_given?
         | 
| 374 411 | 
             
                          yield statement
         | 
| @@ -395,7 +432,7 @@ module JSON::LD | |
| 395 432 | 
             
                # @return [Array<Hash>]
         | 
| 396 433 | 
             
                #   The JSON-LD document in expanded form
         | 
| 397 434 | 
             
                def self.fromRDF(input, options = {}, &block)
         | 
| 398 | 
            -
                  options = {:useNativeTypes =>  | 
| 435 | 
            +
                  options = {:useNativeTypes => false}.merge(options)
         | 
| 399 436 | 
             
                  result = nil
         | 
| 400 437 |  | 
| 401 438 | 
             
                  API.new(nil, nil, options) do |api|
         | 
| @@ -405,6 +442,114 @@ module JSON::LD | |
| 405 442 | 
             
                  yield result if block_given?
         | 
| 406 443 | 
             
                  result
         | 
| 407 444 | 
             
                end
         | 
| 445 | 
            +
             | 
| 446 | 
            +
                ##
         | 
| 447 | 
            +
                # Default document loader.
         | 
| 448 | 
            +
                # @param [RDF::URI, String] url
         | 
| 449 | 
            +
                # @param [Hash<Symbol => Object>] options
         | 
| 450 | 
            +
                # @option options [Boolean] :validate
         | 
| 451 | 
            +
                #   Allow only appropriate content types
         | 
| 452 | 
            +
                # @return [RemoteDocument] retrieved remote document and context information unless block given
         | 
| 453 | 
            +
                # @yield remote_document
         | 
| 454 | 
            +
                # @yieldparam [RemoteDocument] remote_document
         | 
| 455 | 
            +
                # @raise [JsonLdError]
         | 
| 456 | 
            +
                def self.documentLoader(url, options = {})
         | 
| 457 | 
            +
                  require 'net/http' unless defined?(Net::HTTP)
         | 
| 458 | 
            +
                  remote_document = nil
         | 
| 459 | 
            +
                  options[:headers] ||= OPEN_OPTS[:headers]
         | 
| 460 | 
            +
             | 
| 461 | 
            +
                  url = url.to_s[5..-1] if url.to_s.start_with?("file:")
         | 
| 462 | 
            +
                  case url.to_s
         | 
| 463 | 
            +
                  when /^http/
         | 
| 464 | 
            +
                    parsed_url = ::URI.parse(url.to_s)
         | 
| 465 | 
            +
                    until remote_document do
         | 
| 466 | 
            +
                      Net::HTTP::start(parsed_url.host, parsed_url.port) do |http|
         | 
| 467 | 
            +
                        request = Net::HTTP::Get.new(parsed_url.request_uri, options[:headers])
         | 
| 468 | 
            +
                        http.request(request) do |response|
         | 
| 469 | 
            +
                          case response
         | 
| 470 | 
            +
                          when Net::HTTPSuccess
         | 
| 471 | 
            +
                            # found object
         | 
| 472 | 
            +
                            content_type, ct_param = response.content_type.to_s.downcase.split(";")
         | 
| 473 | 
            +
             | 
| 474 | 
            +
                            # If the passed input is a DOMString representing the IRI of a remote document, dereference it. If the retrieved document's content type is neither application/json, nor application/ld+json, nor any other media type using a +json suffix as defined in [RFC6839], reject the promise passing an loading document failed error.
         | 
| 475 | 
            +
                            if content_type && options[:validate]
         | 
| 476 | 
            +
                              main, sub = content_type.split("/")
         | 
| 477 | 
            +
                              raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
         | 
| 478 | 
            +
                                main != 'application' ||
         | 
| 479 | 
            +
                                sub !~ /^(.*\+)?json$/
         | 
| 480 | 
            +
                            end
         | 
| 481 | 
            +
             | 
| 482 | 
            +
                            remote_document = RemoteDocument.new(parsed_url.to_s, response.body)
         | 
| 483 | 
            +
             | 
| 484 | 
            +
                            # If the input has been retrieved, the response has an HTTP Link Header [RFC5988] using the http://www.w3.org/ns/json-ld#context link relation and a content type of application/json or any media type with a +json suffix as defined in [RFC6839] except application/ld+json, update the active context using the Context Processing algorithm, passing the context referenced in the HTTP Link Header as local context. The HTTP Link Header is ignored for documents served as application/ld+json If multiple HTTP Link Headers using the http://www.w3.org/ns/json-ld#context link relation are found, the promise is rejected with a JsonLdError whose code is set to multiple context link headers and processing is terminated.
         | 
| 485 | 
            +
                            unless content_type.start_with?("application/ld+json")
         | 
| 486 | 
            +
                              links = response["link"].to_s.
         | 
| 487 | 
            +
                                split(",").
         | 
| 488 | 
            +
                                map(&:strip).
         | 
| 489 | 
            +
                                select {|h| h =~ %r{rel=\"http://www.w3.org/ns/json-ld#context\"}}
         | 
| 490 | 
            +
                              case links.length
         | 
| 491 | 
            +
                              when 0  then #nothing to do
         | 
| 492 | 
            +
                              when 1
         | 
| 493 | 
            +
                                remote_document.contextUrl = links.first.match(/<([^>]*)>/) && $1
         | 
| 494 | 
            +
                              else
         | 
| 495 | 
            +
                                raise JSON::LD::JsonLdError::MultipleContextLinkHeaders,
         | 
| 496 | 
            +
                                  "expected at most 1 Link header with rel=jsonld:context, got #{links.length}"
         | 
| 497 | 
            +
                              end
         | 
| 498 | 
            +
                            end
         | 
| 499 | 
            +
             | 
| 500 | 
            +
                            yield remote_document if block_given?
         | 
| 501 | 
            +
                          when Net::HTTPRedirection
         | 
| 502 | 
            +
                            # Follow redirection
         | 
| 503 | 
            +
                            parsed_url = ::URI.parse(response["Location"])
         | 
| 504 | 
            +
                          else
         | 
| 505 | 
            +
                            raise JSON::LD::JsonLdError::LoadingDocumentFailed, "<#{parsed_url}>: #{response.msg}(#{response.code})"
         | 
| 506 | 
            +
                          end
         | 
| 507 | 
            +
                        end
         | 
| 508 | 
            +
                      end
         | 
| 509 | 
            +
                    end
         | 
| 510 | 
            +
                  else
         | 
| 511 | 
            +
                    # Use regular open
         | 
| 512 | 
            +
                    RDF::Util::File.open_file(url, options) do |f|
         | 
| 513 | 
            +
                      remote_document = RemoteDocument.new(url, f.read)
         | 
| 514 | 
            +
                      content_type, ct_param = f.content_type.to_s.downcase.split(";") if f.respond_to?(:content_type)
         | 
| 515 | 
            +
                      if content_type && options[:validate]
         | 
| 516 | 
            +
                        main, sub = content_type.split("/")
         | 
| 517 | 
            +
                        raise JSON::LD::JsonLdError::LoadingDocumentFailed, "content_type: #{content_type}" if
         | 
| 518 | 
            +
                          main != 'application' ||
         | 
| 519 | 
            +
                          sub !~ /^(.*\+)?json$/
         | 
| 520 | 
            +
                      end
         | 
| 521 | 
            +
             | 
| 522 | 
            +
                      yield remote_document if block_given?
         | 
| 523 | 
            +
                    end
         | 
| 524 | 
            +
                  end
         | 
| 525 | 
            +
                  remote_document
         | 
| 526 | 
            +
                end
         | 
| 527 | 
            +
             | 
| 528 | 
            +
                ##
         | 
| 529 | 
            +
                # A {RemoteDocument} is returned from a {documentLoader}.
         | 
| 530 | 
            +
                class RemoteDocument
         | 
| 531 | 
            +
                  # @return [String] URL of the loaded document, after redirects
         | 
| 532 | 
            +
                  attr_reader :documentUrl
         | 
| 533 | 
            +
             | 
| 534 | 
            +
                  # @return [String, Array<Hash>, Hash]
         | 
| 535 | 
            +
                  #   The retrieved document, either as raw text or parsed JSON
         | 
| 536 | 
            +
                  attr_reader :document
         | 
| 537 | 
            +
             | 
| 538 | 
            +
                  # @return [String]
         | 
| 539 | 
            +
                  #   The URL of a remote context as specified by an HTTP Link header with rel=`http://www.w3.org/ns/json-ld#context`
         | 
| 540 | 
            +
                  attr_accessor :contextUrl
         | 
| 541 | 
            +
             | 
| 542 | 
            +
                  # @param [String] url URL of the loaded document, after redirects
         | 
| 543 | 
            +
                  # @param [String, Array<Hash>, Hash] document
         | 
| 544 | 
            +
                  #   The retrieved document, either as raw text or parsed JSON
         | 
| 545 | 
            +
                  # @param [String] context_url (nil)
         | 
| 546 | 
            +
                  #   The URL of a remote context as specified by an HTTP Link header with rel=`http://www.w3.org/ns/json-ld#context`
         | 
| 547 | 
            +
                  def initialize(url, document, context_url = nil)
         | 
| 548 | 
            +
                    @documentUrl = url
         | 
| 549 | 
            +
                    @document = document
         | 
| 550 | 
            +
                    @contextUrl = context_url
         | 
| 551 | 
            +
                  end
         | 
| 552 | 
            +
                end
         | 
| 408 553 | 
             
              end
         | 
| 409 554 | 
             
            end
         | 
| 410 555 |  |