lib/rdf/json/reader.rb in rdf-json-0.0.2 vs lib/rdf/json/reader.rb in rdf-json-0.1.0

- old
+ new

@@ -2,32 +2,128 @@ ## # RDF/JSON parser. # # @example Obtaining an RDF/JSON reader class # RDF::Reader.for(:json) #=> RDF::JSON::Reader - # RDF::Reader.for("spec/data/test.json") - # RDF::Reader.for(:file_name => "spec/data/test.json") + # RDF::Reader.for("etc/doap.json") + # RDF::Reader.for(:file_name => "etc/doap.json") # RDF::Reader.for(:file_extension => "json") # RDF::Reader.for(:content_type => "application/json") # # @example Parsing RDF statements from an RDF/JSON file - # RDF::JSON::Reader.open("spec/data/test.json") do |reader| + # RDF::JSON::Reader.open("etc/doap.json") do |reader| # reader.each_statement do |statement| # puts statement.inspect # end # end # # @example Parsing RDF statements from an RDF/JSON string - # data = StringIO.new(File.read("spec/data/test.json")) + # data = StringIO.new(File.read("etc/doap.json")) # RDF::JSON::Reader.new(data) do |reader| # reader.each_statement do |statement| # puts statement.inspect # end # end # # @see http://n2.talis.com/wiki/RDF_JSON_Specification class Reader < RDF::Reader format RDF::JSON::Format - # TODO + ## + # @return [RDF::Graph] + attr_reader :graph + + ## + # Initializes the RDF/JSON reader instance. + # + # @param [IO, File, String] input + # @param [Hash{Symbol => Object}] options + # @yield [reader] + # @yieldparam [Reader] reader + def initialize(input = $stdin, options = {}, &block) + super do + @graph = RDF::Graph.new + + JSON.parse(@input.read).each do |subject, predicates| + subject = parse_subject(subject) + predicates.each do |predicate, objects| + predicate = parse_predicate(predicate) + objects.each do |object| + object = parse_object(object) + @graph << [subject, predicate, object] + end + end + end + + block.call(self) if block_given? + end + end + + ## + # Parses an RDF/JSON subject string into a URI reference or blank node. + # + # @param [String] subject + # @return [RDF::Resource] + def parse_subject(subject) + case subject + when /^_:/ then RDF::Node.new(subject[2..-1]) + else RDF::URI.new(subject) + end + end + + ## + # Parses an RDF/JSON predicate string into a URI reference. + # + # @param [String] predicate + # @return [RDF::URI] + def parse_predicate(predicate) + # TODO: support for CURIE predicates (issue #1 on GitHub). + parse_subject(predicate) + end + + ## + # Parses an RDF/JSON object string into an RDF value. + # + # @param [Hash{String => Object}] object + # @return [RDF::Value] + def parse_object(object) + raise RDF::ReaderError.new, "missing 'type' key in #{object.inspect}" unless object.has_key?('type') + raise RDF::ReaderError.new, "missing 'value' key in #{object.inspect}" unless object.has_key?('value') + + case type = object['type'] + when 'bnode' + RDF::Node.new(object['value'][2..-1]) + when 'uri' + RDF::URI.new(object['value']) + when 'literal' + RDF::Literal.new(object['value'], { + :language => object['lang'], + :datatype => object['datatype'], + }) + else + raise RDF::ReaderError, "expected 'type' to be 'bnode', 'uri', or 'literal', but got #{type.inspect}" + end + end + + ## + # Iterates the given block for each RDF statement in the input. + # + # @yield [statement] + # @yieldparam [RDF::Statement] statement + # @return [void] + def each_statement(&block) + @graph.each_statement(&block) + end + + ## + # Iterates the given block for each RDF triple in the input. + # + # @yield [subject, predicate, object] + # @yieldparam [RDF::Resource] subject + # @yieldparam [RDF::URI] predicate + # @yieldparam [RDF::Value] object + # @return [void] + def each_triple(&block) + @graph.each_triple(&block) + end end # class Reader end # module RDF::JSON