rdf-borsh 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8d3f80cf1f9a45652da775024fabd5c00d460f3d02c3ee34ed7ec355829a50f4
4
+ data.tar.gz: c631076d5c4d8a9c57e2add7c937feb492699c3a5187ea735c06200713e9a03b
5
+ SHA512:
6
+ metadata.gz: 1c45cf0db32119a5532825e288630b50d08634f72f8ef2e3c9d49719ca03aeaa2c3b52d03af4639163555ac90a17ff2f123eaaa01b1362fd28877b9c0a2dc13a
7
+ data.tar.gz: ffc8a1a577fb3f8b0f0253de890dbb93366e7af112aab10af327ff27ce38e683462b2678027d6044c5fbb7106ceffc47768f7268bb71ef863e8108a807330b6d
data/AUTHORS ADDED
@@ -0,0 +1 @@
1
+ * Arto Bendiken <arto@bendiken.net>
data/CHANGES.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## 1.0.0 - 2025-01-07
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # RDF/Borsh for Ruby
2
+
3
+ [![License](https://img.shields.io/badge/license-Public%20Domain-blue.svg)](https://unlicense.org)
4
+ [![Compatibility](https://img.shields.io/badge/ruby-3.0%2B-blue)](https://rubygems.org/gems/rdf-borsh)
5
+ [![Package](https://img.shields.io/gem/v/rdf-borsh)](https://rubygems.org/gems/rdf-borsh)
6
+
7
+ A Ruby library for encoding and decoding RDF data using the [Borsh]
8
+ binary serialization format.
9
+
10
+ [Borsh]: https://borsh.io
11
+
12
+ ## 🛠️ Prerequisites
13
+
14
+ - [Ruby](https://ruby-lang.org) 3.0+
15
+
16
+ ## ⬇️ Installation
17
+
18
+ ### Installation via RubyGems
19
+
20
+ ```bash
21
+ gem install rdf-borsh
22
+ ```
23
+
24
+ ## 👉 Examples
25
+
26
+ ### Importing the library
27
+
28
+ ```ruby
29
+ require 'rdf/borsh'
30
+ ```
31
+
32
+ ## 👨‍💻 Development
33
+
34
+ ```bash
35
+ git clone https://github.com/ruby-rdf/rdf-borsh.git
36
+ ```
37
+
38
+ - - -
39
+
40
+ [![Share on Twitter](https://img.shields.io/badge/share%20on-twitter-03A9F4?logo=twitter)](https://twitter.com/share?url=https://github.com/ruby-rdf/rdf-borsh&text=RDF%2FBorsh+for+Ruby)
41
+ [![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
+ [![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
+ [![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)
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org/>
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,21 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require 'rdf/format'
4
+
5
+ module RDF::Borsh
6
+ class Format < RDF::Format
7
+ content_type 'application/x-rdf+borsh', extension: :borsh
8
+ reader { RDF::Borsh::Reader }
9
+ writer { RDF::Borsh::Writer }
10
+
11
+ MAGIC = 'RDFB'.freeze
12
+ VERSION = '1'.ord
13
+ FLAGS = 0b00000111
14
+
15
+ def self.name; "RDF/Borsh"; end
16
+
17
+ def self.detect(sample)
18
+ sample[0..4] == [MAGIC, VERSION].pack('a4C')
19
+ end
20
+ end # Format
21
+ end # RDF::Borsh
@@ -0,0 +1,90 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require 'extlz4'
4
+ require 'rdf'
5
+ require 'stringio'
6
+
7
+ module RDF::Borsh
8
+ class Reader < RDF::Reader
9
+ format RDF::Borsh::Format
10
+
11
+ MAGIC = RDF::Borsh::Format::MAGIC
12
+ VERSION = RDF::Borsh::Format::VERSION
13
+ FLAGS = RDF::Borsh::Format::FLAGS
14
+
15
+ def initialize(input = $stdin, **options, &block)
16
+ super(input, **options) do
17
+ input = @input
18
+ @version, @flags, @quad_count = self.read_header
19
+
20
+ input_size = input.read(4).unpack('V').first
21
+ @input = StringIO.new(self.decompress(input.read(input_size)), 'rb')
22
+ @terms = [nil] + self.read_terms
23
+
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
+
28
+ if block_given?
29
+ case block.arity
30
+ when 0 then self.instance_eval(&block)
31
+ else block.call(self)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def read_statement
38
+ quad_data = @input.read(8) or raise EOFError
39
+ g, s, p, o = quad_data.unpack('v4').map! { |term_id| @terms[term_id] }
40
+ RDF::Statement.new(s, p, o, graph_name: g)
41
+ end
42
+
43
+ def read_quad; self.read_statement.to_quad; end
44
+ def read_triple; self.read_statement.to_triple; end
45
+
46
+ ##
47
+ # Reads the compressed terms dictionary.
48
+ def read_terms
49
+ term_count = @input.read(4).unpack('V').first
50
+ term_count.times.map do
51
+ term_kind, term_string_size = @input.read(5).unpack('CV')
52
+ term_string = @input.read(term_string_size)
53
+
54
+ case term_kind
55
+ when 1 then RDF::URI(term_string)
56
+ when 2 then RDF::Node(term_string)
57
+ when 3 then RDF::Literal(term_string)
58
+ when 4
59
+ term_datatype_size = @input.read(4).unpack('V')
60
+ RDF::Literal(term_string, datatype: @input.read(term_datatype_size))
61
+ when 5
62
+ term_language_size = @input.read(4).unpack('V')
63
+ RDF::Literal(term_string, language: @input.read(term_language_size))
64
+ else
65
+ raise RDF::ReaderError, "unknown RDF/Borsh term type: #{term_kind}"
66
+ end
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Reads the uncompressed header.
72
+ def read_header
73
+ magic = @input.read(4).unpack('a4').first
74
+ raise RDF::ReaderError, "invalid RDF/Borsh header: #{magic.inspect}" if magic != MAGIC
75
+
76
+ version = @input.read(1).unpack('C').first
77
+ raise RDF::ReaderError, "invalid RDF/Borsh version: #{version}" if version != VERSION
78
+
79
+ flags = @input.read(1).unpack('C').first
80
+ raise RDF::ReaderError, "invalid RDF/Borsh flags: #{flags}" if flags != FLAGS
81
+
82
+ quad_count = @input.read(4).unpack('V').first
83
+ [version, flags, quad_count]
84
+ end
85
+
86
+ def decompress(data)
87
+ LZ4::BlockDecoder.new.decode(data)
88
+ end
89
+ end # Reader
90
+ end # RDF::Borsh
@@ -0,0 +1 @@
1
+ # This is free and unencumbered software released into the public domain.
@@ -0,0 +1,123 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ require 'extlz4'
4
+ require 'rdf'
5
+ require 'sorted_set'
6
+ require 'stringio'
7
+
8
+ module RDF::Borsh
9
+ class Writer < RDF::Writer
10
+ format RDF::Borsh::Format
11
+
12
+ MAGIC = RDF::Borsh::Format::MAGIC
13
+ VERSION = RDF::Borsh::Format::VERSION
14
+ FLAGS = RDF::Borsh::Format::FLAGS
15
+ LZ4HC_CLEVEL_MAX = 12
16
+
17
+ def initialize(output = $stdout, **options, &block)
18
+ @terms_dict, @terms_map = [], {}
19
+ @quads_set = SortedSet.new
20
+
21
+ super(output, **options) do
22
+ if block_given?
23
+ case block.arity
24
+ when 0 then self.instance_eval(&block)
25
+ else block.call(self)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def write_triple(subject, predicate, object)
32
+ self.write_quad(subject, predicate, object, nil)
33
+ end
34
+
35
+ def write_quad(subject, predicate, object, context)
36
+ s = self.intern_term(subject)
37
+ p = self.intern_term(predicate)
38
+ o = self.intern_term(object)
39
+ g = self.intern_term(context)
40
+ @quads_set << [g, s, p, o]
41
+ end
42
+
43
+ def flush
44
+ self.finish
45
+ super
46
+ end
47
+
48
+ def finish
49
+ self.write_header
50
+ self.write_terms
51
+ self.write_quads
52
+ end
53
+
54
+ # Writes the uncompressed header.
55
+ def write_header
56
+ @output.write([MAGIC, VERSION, FLAGS].pack('a4CC'))
57
+ @output.write([@quads_set.size].pack('V'))
58
+ end
59
+
60
+ # Writes the compressed terms dictionary.
61
+ def write_terms
62
+ buffer = StringIO.open do |output|
63
+ output.binmode
64
+ output.write([@terms_dict.size].pack('V'))
65
+ @terms_dict.each do |term|
66
+ output.write(case
67
+ when term.iri?
68
+ string = term.to_s
69
+ [1, string.bytesize, string].pack('CVa*')
70
+ when term.node?
71
+ string = term.id.to_s
72
+ [2, string.bytesize, string].pack('CVa*')
73
+ when term.literal? && term.plain?
74
+ string = term.value.to_s
75
+ [3, string.bytesize, string].pack('CVa*')
76
+ when term.literal? && term.datatype?
77
+ string = term.value.to_s
78
+ datatype = term.datatype.to_s
79
+ [4, string.bytesize, string, datatype.bytesize, datatype].pack('CVa*Va*')
80
+ when term.literal? && term.language?
81
+ string = term.value.to_s
82
+ language = term.language.to_s
83
+ [5, string.bytesize, string, datatype.language, language].pack('CVa*Va*')
84
+ else
85
+ raise RDF::WriterError, "unsupported RDF/Borsh term type: #{term.inspect}"
86
+ end)
87
+ end
88
+ self.compress(output.string)
89
+ end
90
+ @output.write([buffer.size].pack('V'))
91
+ @output.write(buffer)
92
+ end
93
+
94
+ def write_quads
95
+ buffer = StringIO.open do |output|
96
+ output.binmode
97
+ output.write([@quads_set.size].pack('V'))
98
+ @quads_set.each do |quad|
99
+ output.write(quad.pack('v4'))
100
+ end
101
+ self.compress(output.string)
102
+ end
103
+ @output.write([buffer.size].pack('V'))
104
+ @output.write(buffer)
105
+ end
106
+
107
+ # @return [Integer]
108
+ def intern_term(term)
109
+ return 0 if term.nil? # for the default graph
110
+ term_id = @terms_map[term]
111
+ if !term_id
112
+ term_id = @terms_dict.size + 1
113
+ @terms_dict << term
114
+ @terms_map[term] = term_id
115
+ end
116
+ term_id
117
+ end
118
+
119
+ def compress(data)
120
+ LZ4::BlockEncoder.new(LZ4HC_CLEVEL_MAX).encode(data)
121
+ end
122
+ end # Writer
123
+ end # RDF::Borsh
data/lib/rdf/borsh.rb ADDED
@@ -0,0 +1,13 @@
1
+ # This is free and unencumbered software released into the public domain.
2
+
3
+ module RDF
4
+ ##
5
+ # RDF/Borsh.
6
+ module Borsh
7
+ autoload :Format, 'rdf/borsh/format'
8
+ autoload :Reader, 'rdf/borsh/reader'
9
+ autoload :Writer, 'rdf/borsh/writer'
10
+ end
11
+ end
12
+
13
+ require 'rdf/borsh/version'
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdf-borsh
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Arto Bendiken
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-01-07 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: extlz4
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.3'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.3'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rdf
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.3'
40
+ - !ruby/object:Gem::Dependency
41
+ name: sorted_set
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rdf-spec
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.3'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.3'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rspec
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.12'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.12'
82
+ - !ruby/object:Gem::Dependency
83
+ name: yard
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.9'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.9'
96
+ description: A Ruby library for encoding and decoding RDF data using the Borsh binary
97
+ serialization format.
98
+ email: public-rdf-ruby@w3.org
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - AUTHORS
104
+ - CHANGES.md
105
+ - README.md
106
+ - UNLICENSE
107
+ - VERSION
108
+ - lib/rdf/borsh.rb
109
+ - lib/rdf/borsh/format.rb
110
+ - lib/rdf/borsh/reader.rb
111
+ - lib/rdf/borsh/version.rb
112
+ - lib/rdf/borsh/writer.rb
113
+ homepage: https://github.com/ruby-rdf/rdf-borsh
114
+ licenses:
115
+ - Unlicense
116
+ metadata:
117
+ bug_tracker_uri: https://github.com/ruby-rdf/rdf-borsh/issues
118
+ 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
120
+ homepage_uri: https://github.com/ruby-rdf/rdf-borsh
121
+ source_code_uri: https://github.com/ruby-rdf/rdf-borsh
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '3.0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubygems_version: 3.6.2
137
+ specification_version: 4
138
+ summary: RDF/Borsh for Ruby
139
+ test_files: []