rdf-borsh 1.0.0 → 1.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d3f80cf1f9a45652da775024fabd5c00d460f3d02c3ee34ed7ec355829a50f4
4
- data.tar.gz: c631076d5c4d8a9c57e2add7c937feb492699c3a5187ea735c06200713e9a03b
3
+ metadata.gz: 12224960d664fe3f0b70581cb3c1a0bce77e7425cd0cc9a83b4e6df9fe8d71f7
4
+ data.tar.gz: d83f64ba1f5e33243dd091b0a04e6c7c39a401bb057703ae03b1373278196204
5
5
  SHA512:
6
- metadata.gz: 1c45cf0db32119a5532825e288630b50d08634f72f8ef2e3c9d49719ca03aeaa2c3b52d03af4639163555ac90a17ff2f123eaaa01b1362fd28877b9c0a2dc13a
7
- data.tar.gz: ffc8a1a577fb3f8b0f0253de890dbb93366e7af112aab10af327ff27ce38e683462b2678027d6044c5fbb7106ceffc47768f7268bb71ef863e8108a807330b6d
6
+ metadata.gz: cea629b36b4aaea1e18c292210f9942e6ac2ee26659164daffa0540ddbe82fbb8bd54f57c55a726268ce4a985f611ee870fcb6feb31c3fb8b9f92dd914927ed4
7
+ data.tar.gz: 960ba17587d985344357d9c8c1b12e63827e070cb66ea1f0479727df8578519269d8bbfc24ad6a6925c261037db958b1cd897c64e403813b82f74a7e6350b9d5
data/CHANGES.md CHANGED
@@ -5,4 +5,8 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 1.0.2 - 2025-01-11
9
+
10
+ ## 1.0.1 - 2025-01-07
11
+
8
12
  ## 1.0.0 - 2025-01-07
data/README.md CHANGED
@@ -3,15 +3,25 @@
3
3
  [![License](https://img.shields.io/badge/license-Public%20Domain-blue.svg)](https://unlicense.org)
4
4
  [![Compatibility](https://img.shields.io/badge/ruby-3.0%2B-blue)](https://rubygems.org/gems/rdf-borsh)
5
5
  [![Package](https://img.shields.io/gem/v/rdf-borsh)](https://rubygems.org/gems/rdf-borsh)
6
+ [![Documentation](https://img.shields.io/badge/rubydoc-latest-blue)](https://rubydoc.info/gems/rdf-borsh)
6
7
 
7
- A Ruby library for encoding and decoding RDF data using the [Borsh]
8
- binary serialization format.
8
+ **RDF/Borsh** is a [Ruby] library and [RDF.rb] extension for encoding
9
+ and decoding [RDF] knowledge graphs in the [Borsh] binary serialization
10
+ format. (See the [specification].)
9
11
 
10
- [Borsh]: https://borsh.io
12
+ ## ✨ Features
13
+
14
+ - Serializes RDF datasets into compact and efficient binary files.
15
+ - Implements the `application/x-rdf+borsh` MIME type with a `.rdfb` extension.
16
+ - Employes LZ4 compression for both the term dictionary and quad data.
17
+ - Designed for blockchain and distributed ledger applications.
18
+ - Supports reading from and writing to files or I/O streams.
19
+ - Plays nice with others: entirely contained in the `RDF::Borsh` module.
20
+ - 100% free and unencumbered public domain software.
11
21
 
12
22
  ## 🛠️ Prerequisites
13
23
 
14
- - [Ruby](https://ruby-lang.org) 3.0+
24
+ - [Ruby] 3.0+
15
25
 
16
26
  ## ⬇️ Installation
17
27
 
@@ -27,8 +37,35 @@ gem install rdf-borsh
27
37
 
28
38
  ```ruby
29
39
  require 'rdf/borsh'
40
+
41
+ include RDF
42
+ ```
43
+
44
+ ### Serializing an RDF graph into an RDF/Borsh file
45
+
46
+ ```ruby
47
+ RDF::Borsh::Writer.open("mygraph.rdfb") do |writer|
48
+ writer << [RDF::URI("https://rubygems.org/gems/rdf-borsh"), RDFS.label, "RDF/Borsh for Ruby"]
49
+ end
30
50
  ```
31
51
 
52
+ ### Parsing an RDF graph from an RDF/Borsh file
53
+
54
+ ```ruby
55
+ graph = RDF::Graph.load("mygraph.rdfb")
56
+ graph.to_a
57
+ ```
58
+
59
+ ### Parsing an RDF/Borsh dataset from standard input
60
+
61
+ ```ruby
62
+ RDF::Borsh::Reader.new($stdin).to_a
63
+ ```
64
+
65
+ ## 📚 Reference
66
+
67
+ https://rubydoc.info/gems/rdf-borsh
68
+
32
69
  ## 👨‍💻 Development
33
70
 
34
71
  ```bash
@@ -41,3 +78,9 @@ git clone https://github.com/ruby-rdf/rdf-borsh.git
41
78
  [![Share on Reddit](https://img.shields.io/badge/share%20on-reddit-red?logo=reddit)](https://reddit.com/submit?url=https://github.com/ruby-rdf/rdf-borsh&title=RDF%2FBorsh+for+Ruby)
42
79
  [![Share on Hacker News](https://img.shields.io/badge/share%20on-hacker%20news-orange?logo=ycombinator)](https://news.ycombinator.com/submitlink?u=https://github.com/ruby-rdf/rdf-borsh&t=RDF%2FBorsh+for+Ruby)
43
80
  [![Share on Facebook](https://img.shields.io/badge/share%20on-facebook-1976D2?logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/ruby-rdf/rdf-borsh)
81
+
82
+ [Borsh]: https://borsh.io
83
+ [RDF]: https://www.w3.org/TR/rdf12-concepts/
84
+ [RDF.rb]: https://github.com/ruby-rdf/rdf
85
+ [Ruby]: https://ruby-lang.org
86
+ [specification]: https://github.com/ruby-rdf/rdf-borsh/blob/master/doc/spec.md
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.0.2
@@ -4,7 +4,7 @@ require 'rdf/format'
4
4
 
5
5
  module RDF::Borsh
6
6
  class Format < RDF::Format
7
- content_type 'application/x-rdf+borsh', extension: :borsh
7
+ content_type 'application/x-rdf+borsh', extension: :rdfb
8
8
  reader { RDF::Borsh::Reader }
9
9
  writer { RDF::Borsh::Writer }
10
10
 
@@ -1,5 +1,6 @@
1
1
  # This is free and unencumbered software released into the public domain.
2
2
 
3
+ require 'borsh'
3
4
  require 'extlz4'
4
5
  require 'rdf'
5
6
  require 'stringio'
@@ -15,15 +16,17 @@ module RDF::Borsh
15
16
  def initialize(input = $stdin, **options, &block)
16
17
  super(input, **options) do
17
18
  input = @input
19
+
20
+ @input.extend(Borsh::Readable)
18
21
  @version, @flags, @quad_count = self.read_header
19
22
 
20
- input_size = input.read(4).unpack('V').first
21
- @input = StringIO.new(self.decompress(input.read(input_size)), 'rb')
23
+ input_size = input.read_u32
24
+ @input = Borsh::Buffer.new(self.decompress(input.read(input_size)))
22
25
  @terms = [nil] + self.read_terms
23
26
 
24
- input_size = input.read(4).unpack('V').first
25
- @input = StringIO.new(self.decompress(input.read(input_size)), 'rb')
26
- _ = @input.read(4).unpack('V').first
27
+ input_size = input.read_u32
28
+ @input = Borsh::Buffer.new(self.decompress(input.read(input_size)))
29
+ _ = @input.read_u32
27
30
 
28
31
  if block_given?
29
32
  case block.arity
@@ -46,9 +49,9 @@ module RDF::Borsh
46
49
  ##
47
50
  # Reads the compressed terms dictionary.
48
51
  def read_terms
49
- term_count = @input.read(4).unpack('V').first
52
+ term_count = @input.read_u32
50
53
  term_count.times.map do
51
- term_kind, term_string_size = @input.read(5).unpack('CV')
54
+ term_kind, term_string_size = @input.read_u8, @input.read_u32
52
55
  term_string = @input.read(term_string_size)
53
56
 
54
57
  case term_kind
@@ -56,10 +59,10 @@ module RDF::Borsh
56
59
  when 2 then RDF::Node(term_string)
57
60
  when 3 then RDF::Literal(term_string)
58
61
  when 4
59
- term_datatype_size = @input.read(4).unpack('V')
62
+ term_datatype_size = @input.read_u32
60
63
  RDF::Literal(term_string, datatype: @input.read(term_datatype_size))
61
64
  when 5
62
- term_language_size = @input.read(4).unpack('V')
65
+ term_language_size = @input.read_u32
63
66
  RDF::Literal(term_string, language: @input.read(term_language_size))
64
67
  else
65
68
  raise RDF::ReaderError, "unknown RDF/Borsh term type: #{term_kind}"
@@ -73,13 +76,13 @@ module RDF::Borsh
73
76
  magic = @input.read(4).unpack('a4').first
74
77
  raise RDF::ReaderError, "invalid RDF/Borsh header: #{magic.inspect}" if magic != MAGIC
75
78
 
76
- version = @input.read(1).unpack('C').first
79
+ version = @input.read_u8
77
80
  raise RDF::ReaderError, "invalid RDF/Borsh version: #{version}" if version != VERSION
78
81
 
79
- flags = @input.read(1).unpack('C').first
82
+ flags = @input.read_u8
80
83
  raise RDF::ReaderError, "invalid RDF/Borsh flags: #{flags}" if flags != FLAGS
81
84
 
82
- quad_count = @input.read(4).unpack('V').first
85
+ quad_count = @input.read_u32
83
86
  [version, flags, quad_count]
84
87
  end
85
88
 
@@ -1,9 +1,9 @@
1
1
  # This is free and unencumbered software released into the public domain.
2
2
 
3
+ require 'borsh'
3
4
  require 'extlz4'
4
5
  require 'rdf'
5
6
  require 'sorted_set'
6
- require 'stringio'
7
7
 
8
8
  module RDF::Borsh
9
9
  class Writer < RDF::Writer
@@ -14,7 +14,19 @@ module RDF::Borsh
14
14
  FLAGS = RDF::Borsh::Format::FLAGS
15
15
  LZ4HC_CLEVEL_MAX = 12
16
16
 
17
+ ##
18
+ # Initializes the RDF/Borsh writer.
19
+ #
20
+ # @param [IO, StringIO] output
21
+ # @param [Hash{Symbol => Object}] options
22
+ # @yield [writer]
23
+ # @yieldparam [RDF::Borsh::Writer] writer
24
+ # @yieldreturn [void]
25
+ # @return [void]
17
26
  def initialize(output = $stdout, **options, &block)
27
+ output.extend(Borsh::Writable)
28
+ output.binmode if output.respond_to?(:binmode)
29
+
18
30
  @terms_dict, @terms_map = [], {}
19
31
  @quads_set = SortedSet.new
20
32
 
@@ -24,14 +36,30 @@ module RDF::Borsh
24
36
  when 0 then self.instance_eval(&block)
25
37
  else block.call(self)
26
38
  end
39
+ self.finish
27
40
  end
28
41
  end
29
42
  end
30
43
 
44
+ ##
45
+ # Writes an RDF triple.
46
+ #
47
+ # @param [RDF::Resource] subject
48
+ # @param [RDF::URI] predicate
49
+ # @param [RDF::Term] object
50
+ # @return [void]
31
51
  def write_triple(subject, predicate, object)
32
52
  self.write_quad(subject, predicate, object, nil)
33
53
  end
34
54
 
55
+ ##
56
+ # Writes an RDF quad.
57
+ #
58
+ # @param [RDF::Resource] subject
59
+ # @param [RDF::URI] predicate
60
+ # @param [RDF::Term] object
61
+ # @param [RDF::Resource] context
62
+ # @return [void]
35
63
  def write_quad(subject, predicate, object, context)
36
64
  s = self.intern_term(subject)
37
65
  p = self.intern_term(predicate)
@@ -40,28 +68,42 @@ module RDF::Borsh
40
68
  @quads_set << [g, s, p, o]
41
69
  end
42
70
 
71
+ ##
72
+ # Flushes the output.
73
+ #
74
+ # @return [void]
43
75
  def flush
44
76
  self.finish
45
77
  super
46
78
  end
47
79
 
80
+ ##
81
+ # Finishes writing the output.
82
+ #
83
+ # @return [void]
48
84
  def finish
49
85
  self.write_header
50
86
  self.write_terms
51
87
  self.write_quads
52
88
  end
53
89
 
90
+ ##
54
91
  # Writes the uncompressed header.
92
+ #
93
+ # @return [void]
55
94
  def write_header
95
+ @output.binmode
56
96
  @output.write([MAGIC, VERSION, FLAGS].pack('a4CC'))
57
- @output.write([@quads_set.size].pack('V'))
97
+ @output.write_u32(@quads_set.size)
58
98
  end
59
99
 
100
+ ##
60
101
  # Writes the compressed terms dictionary.
102
+ #
103
+ # @return [void]
61
104
  def write_terms
62
- buffer = StringIO.open do |output|
63
- output.binmode
64
- output.write([@terms_dict.size].pack('V'))
105
+ buffer = self.compress do |output|
106
+ output.write_u32(@terms_dict.size)
65
107
  @terms_dict.each do |term|
66
108
  output.write(case
67
109
  when term.iri?
@@ -85,25 +127,30 @@ module RDF::Borsh
85
127
  raise RDF::WriterError, "unsupported RDF/Borsh term type: #{term.inspect}"
86
128
  end)
87
129
  end
88
- self.compress(output.string)
89
130
  end
90
- @output.write([buffer.size].pack('V'))
131
+ @output.write_u32(buffer.size)
91
132
  @output.write(buffer)
92
133
  end
93
134
 
135
+ ##
136
+ # Writes the compressed quads set.
137
+ #
138
+ # @return [void]
94
139
  def write_quads
95
- buffer = StringIO.open do |output|
96
- output.binmode
97
- output.write([@quads_set.size].pack('V'))
140
+ buffer = self.compress do |output|
141
+ output.write_u32(@quads_set.size)
98
142
  @quads_set.each do |quad|
99
- output.write(quad.pack('v4'))
143
+ quad.each { |tid| output.write_u16(tid) }
100
144
  end
101
- self.compress(output.string)
102
145
  end
103
- @output.write([buffer.size].pack('V'))
146
+ @output.write_u32(buffer.size)
104
147
  @output.write(buffer)
105
148
  end
106
149
 
150
+ ##
151
+ # Interns the given RDF term.
152
+ #
153
+ # @param [RDF::Term] term
107
154
  # @return [Integer]
108
155
  def intern_term(term)
109
156
  return 0 if term.nil? # for the default graph
@@ -116,8 +163,12 @@ module RDF::Borsh
116
163
  term_id
117
164
  end
118
165
 
119
- def compress(data)
120
- LZ4::BlockEncoder.new(LZ4HC_CLEVEL_MAX).encode(data)
166
+ ##
167
+ # @yield [Borsh::Buffer]
168
+ # @return [String]
169
+ def compress(&block)
170
+ uncompressed = Borsh::Buffer.open(&block)
171
+ LZ4::BlockEncoder.new(LZ4HC_CLEVEL_MAX).encode(uncompressed)
121
172
  end
122
173
  end # Writer
123
174
  end # RDF::Borsh
data/lib/rdf/borsh.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # This is free and unencumbered software released into the public domain.
2
2
 
3
+ require 'rdf'
4
+
3
5
  module RDF
4
6
  ##
5
- # RDF/Borsh.
7
+ # RDF/Borsh extension for RDF.rb.
6
8
  module Borsh
7
9
  autoload :Format, 'rdf/borsh/format'
8
10
  autoload :Reader, 'rdf/borsh/reader'
@@ -10,4 +12,4 @@ module RDF
10
12
  end
11
13
  end
12
14
 
13
- require 'rdf/borsh/version'
15
+ require_relative 'borsh/version'
metadata CHANGED
@@ -1,14 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdf-borsh
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arto Bendiken
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-07 00:00:00.000000000 Z
10
+ date: 2025-01-11 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: borsh
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.1'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: extlz4
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -93,8 +107,8 @@ dependencies:
93
107
  - - "~>"
94
108
  - !ruby/object:Gem::Version
95
109
  version: '0.9'
96
- description: A Ruby library for encoding and decoding RDF data using the Borsh binary
97
- serialization format.
110
+ description: An RDF.rb extension for encoding and decoding RDF knowledge graphs in
111
+ the Borsh binary serialization format.
98
112
  email: public-rdf-ruby@w3.org
99
113
  executables: []
100
114
  extensions: []
@@ -116,7 +130,7 @@ licenses:
116
130
  metadata:
117
131
  bug_tracker_uri: https://github.com/ruby-rdf/rdf-borsh/issues
118
132
  changelog_uri: https://github.com/ruby-rdf/rdf-borsh/blob/master/CHANGES.md
119
- documentation_uri: https://github.com/ruby-rdf/rdf-borsh/blob/master/README.md
133
+ documentation_uri: https://rubydoc.info/gems/rdf-borsh
120
134
  homepage_uri: https://github.com/ruby-rdf/rdf-borsh
121
135
  source_code_uri: https://github.com/ruby-rdf/rdf-borsh
122
136
  rdoc_options: []