automerge-rb 0.1.1-x86_64-linux
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 +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +175 -0
- data/lib/automerge/3.0/automerge_ext.so +0 -0
- data/lib/automerge/3.1/automerge_ext.so +0 -0
- data/lib/automerge/3.2/automerge_ext.so +0 -0
- data/lib/automerge/3.3/automerge_ext.so +0 -0
- data/lib/automerge/3.4/automerge_ext.so +0 -0
- data/lib/automerge/version.rb +6 -0
- data/lib/automerge.rb +110 -0
- data/rust-toolchain.toml +4 -0
- metadata +103 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8a0b190bc2d03786af7b242b20f2efe2dc9056e7ff8fd30ed25267885e0deee8
|
|
4
|
+
data.tar.gz: 8ba9b83bc8590d5f530ad50107a3b53234ef1529d1ae7dd9f9925b8b947177ed
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f70478ec216bb954f9ecd103ce2cf379967f1111bd38c2b1c15aa543af24edfe9ba9b1eb08b41e63e1ffff155ac35e37509fc7f5f4b725ee009533f7162c7c98
|
|
7
|
+
data.tar.gz: 07cb3f7d6321edaaa4156a3a8f92c0522546078155b4b6ab0282070a8300b52a8e42b1eb92715fd4f21dffded1bfd0dedc7ed85ced8df1ec2cbf46632869fb90
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Automerge Ruby contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# automerge-rb
|
|
2
|
+
|
|
3
|
+
Ruby bindings for the upstream Automerge Rust core.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
gem install automerge-rb
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Precompiled native gems are published for the following platforms, so end users
|
|
12
|
+
do **not** need Rust or a C toolchain installed:
|
|
13
|
+
|
|
14
|
+
- `arm64-darwin` (Apple Silicon macOS)
|
|
15
|
+
- `x86_64-darwin` (Intel macOS)
|
|
16
|
+
- `x86_64-linux` (glibc)
|
|
17
|
+
- `aarch64-linux` (glibc)
|
|
18
|
+
- `x64-mingw-ucrt` (Windows)
|
|
19
|
+
|
|
20
|
+
Each native gem ships a fat binary covering Ruby 3.0–3.4. RubyGems auto-selects
|
|
21
|
+
the matching artifact for the host's platform and Ruby ABI at install time.
|
|
22
|
+
|
|
23
|
+
On any other platform `gem install automerge-rb` falls back to building from
|
|
24
|
+
source, which requires Rust (1.89+) and a C compiler. The source build also
|
|
25
|
+
runs whenever you set `--platform=ruby` explicitly.
|
|
26
|
+
|
|
27
|
+
## Build from source
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
bundle exec rake compile
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The Automerge checkout currently requires Rust 1.89 or newer. If your default
|
|
34
|
+
toolchain is older, install one with:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
rustup toolchain install 1.89.0
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The extension builds the Rust core in release mode by default. Use
|
|
41
|
+
`AUTOMERGE_RB_DEBUG=1 bundle exec rake compile` for a faster local debug build.
|
|
42
|
+
|
|
43
|
+
By default `extconf.rb` skips the Rust step if a prebuilt
|
|
44
|
+
`lib/automerge/<ruby-abi>/automerge_ext.<dlext>` already exists (i.e. inside a
|
|
45
|
+
native gem); set `AUTOMERGE_SOURCE_DIR` to point at a different Automerge Rust
|
|
46
|
+
workspace if you want to recompile from a custom checkout.
|
|
47
|
+
|
|
48
|
+
## Cross-compiling native gems
|
|
49
|
+
|
|
50
|
+
Maintainers can build the published binary set with rake-compiler-dock:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
bundle exec rake gem:native
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This invokes the same docker-backed cross toolchain that the release workflow
|
|
57
|
+
uses, producing `pkg/automerge-rb-<version>-<platform>.gem` for every supported
|
|
58
|
+
platform.
|
|
59
|
+
|
|
60
|
+
## Test alignment
|
|
61
|
+
|
|
62
|
+
The default test suite includes Ruby ports of upstream Automerge C/Rust
|
|
63
|
+
conformance cases and binary fixture checks:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
bundle exec rake test
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
To also run the vendored upstream Rust core test suite, use:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
bundle exec rake test:upstream_core
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
To run the upstream C API suite, install CMake and cmocka, then use:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
bundle exec rake test:upstream_c
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For a full local gate, run all three:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
bundle exec rake conformance
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If multiple Rust toolchains are installed, the Rake tasks prefer
|
|
88
|
+
`AUTOMERGE_RB_RUST_TOOLCHAIN` and otherwise use `1.89.0` when present so `cargo`
|
|
89
|
+
and `rustc` stay on the same toolchain.
|
|
90
|
+
|
|
91
|
+
## Usage
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
require "automerge"
|
|
95
|
+
|
|
96
|
+
doc = Automerge.from("cards" => [])
|
|
97
|
+
doc.insert(["cards"], 0, "title" => "Rewrite everything in Ruby", "done" => false)
|
|
98
|
+
doc.change(message: "Add card")
|
|
99
|
+
|
|
100
|
+
bytes = doc.save
|
|
101
|
+
loaded = Automerge.load(bytes)
|
|
102
|
+
loaded.to_h
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The Ruby API is path-oriented. A path is an array of map keys and list indexes:
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
doc.put(["cards", 0, "done"], true)
|
|
109
|
+
doc.get(["cards", 0, "done"]) #=> true
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Supported Automerge-specific scalar wrappers:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
Automerge::Counter.new(1)
|
|
116
|
+
Automerge::Timestamp.new(1_735_689_600_000)
|
|
117
|
+
Automerge::Bytes.new("\x00\x01".b)
|
|
118
|
+
Automerge::Text.new("mutable text")
|
|
119
|
+
Automerge::Uint.new(42)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Implemented document operations include:
|
|
123
|
+
|
|
124
|
+
- map/list/text reads and writes through path arrays
|
|
125
|
+
- commits, empty changes, rollback, actor IDs, heads, and forks
|
|
126
|
+
- save/load, incremental save/load, change lookup, missing deps, and applying changes
|
|
127
|
+
- merge conflict reads with `get_all`
|
|
128
|
+
- the stateful sync protocol with `SyncState`
|
|
129
|
+
- text cursors and text marks
|
|
130
|
+
|
|
131
|
+
## Historical reads
|
|
132
|
+
|
|
133
|
+
Every read accepts an optional `heads:` keyword argument naming a vector of
|
|
134
|
+
change hashes (typically returned by `Document#heads`). When supplied, the read
|
|
135
|
+
resolves against that historical snapshot instead of the current HEAD:
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
doc = Automerge.init
|
|
139
|
+
doc.put(["k"], "v1"); doc.commit
|
|
140
|
+
h1 = doc.heads
|
|
141
|
+
doc.put(["k"], "v2"); doc.commit
|
|
142
|
+
|
|
143
|
+
doc.get(["k"]) #=> "v2"
|
|
144
|
+
doc.get(["k"], heads: h1) #=> "v1"
|
|
145
|
+
doc.keys([], heads: h1) #=> ["k"]
|
|
146
|
+
doc.length(["list"], heads: h1)
|
|
147
|
+
doc.cursor_position(["text"], cursor, heads: h1)
|
|
148
|
+
doc.marks(["text"], heads: h1)
|
|
149
|
+
doc.get_all(["k"], heads: h1)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Change metadata
|
|
153
|
+
|
|
154
|
+
`Automerge.decode_change(bytes)` unpacks a change-bytes blob (from
|
|
155
|
+
`Document#change_by_hash` or `Document#get_changes`) into a hash describing the
|
|
156
|
+
change. Useful for audit logs and replication tooling:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
hash = doc.commit(message: "Add card", timestamp: Time.now.to_i)
|
|
160
|
+
meta = Automerge.decode_change(doc.change_by_hash(hash))
|
|
161
|
+
meta[:message] # => "Add card"
|
|
162
|
+
meta[:actor_id] # => "deadbeef"
|
|
163
|
+
meta[:timestamp] # => 1735689600
|
|
164
|
+
meta[:seq] # => 4
|
|
165
|
+
meta[:deps] # => [<change hash>, ...]
|
|
166
|
+
meta[:empty] # => false
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Thread safety
|
|
170
|
+
|
|
171
|
+
`Automerge::Document` instances are not thread-safe. Two threads sharing the
|
|
172
|
+
same `Document` must coordinate externally; concurrent mutations or even
|
|
173
|
+
concurrent reads against an in-progress writer will trigger undefined behavior
|
|
174
|
+
in the underlying Rust core. Sharing across threads is safe only after a
|
|
175
|
+
`save`/`load` round-trip or `fork` produces independent documents.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/automerge.rb
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "automerge/version"
|
|
4
|
+
|
|
5
|
+
module Automerge
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
class Scalar
|
|
9
|
+
attr_reader :value
|
|
10
|
+
|
|
11
|
+
def initialize(value)
|
|
12
|
+
@value = value
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
other.class == self.class && other.value == value
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Counter < Scalar; end
|
|
21
|
+
class Timestamp < Scalar; end
|
|
22
|
+
class Uint < Scalar; end
|
|
23
|
+
|
|
24
|
+
class Bytes < Scalar
|
|
25
|
+
def initialize(value)
|
|
26
|
+
@value = String(value).b
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Text < Scalar
|
|
31
|
+
def initialize(value = "")
|
|
32
|
+
@value = String(value)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
begin
|
|
38
|
+
RUBY_VERSION =~ /(\d+\.\d+)/
|
|
39
|
+
require_relative "automerge/#{Regexp.last_match(1)}/automerge_ext"
|
|
40
|
+
rescue LoadError
|
|
41
|
+
require_relative "automerge/automerge_ext"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
module Automerge
|
|
45
|
+
class Document
|
|
46
|
+
def self.from(value = nil, **opts)
|
|
47
|
+
actor_id = opts.delete(:actor_id)
|
|
48
|
+
value = opts if value.nil? && !opts.empty?
|
|
49
|
+
doc = new(actor_id: actor_id)
|
|
50
|
+
unless value.is_a?(Hash)
|
|
51
|
+
raise ArgumentError, "Automerge document root must be a Hash"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
value.each do |key, child|
|
|
55
|
+
doc.put([key], child)
|
|
56
|
+
end
|
|
57
|
+
doc.commit
|
|
58
|
+
doc
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def [](path)
|
|
62
|
+
get(path)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def []=(path, value)
|
|
66
|
+
put(path, value)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def change(message: nil, timestamp: nil)
|
|
70
|
+
if block_given?
|
|
71
|
+
begin
|
|
72
|
+
yield self
|
|
73
|
+
commit(message, timestamp)
|
|
74
|
+
rescue Exception
|
|
75
|
+
rollback
|
|
76
|
+
raise
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
commit(message, timestamp)
|
|
80
|
+
end
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def to_h
|
|
85
|
+
get([])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
alias to_hash to_h
|
|
89
|
+
|
|
90
|
+
def sync_state
|
|
91
|
+
SyncState.new
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.init(actor_id: nil)
|
|
96
|
+
Document.new(actor_id: actor_id)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.from(value = nil, **opts)
|
|
100
|
+
Document.from(value, **opts)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.load(bytes)
|
|
104
|
+
Document.load(bytes)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.decode_change(bytes)
|
|
108
|
+
Document.decode_change(bytes)
|
|
109
|
+
end
|
|
110
|
+
end
|
data/rust-toolchain.toml
ADDED
metadata
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: automerge-rb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: x86_64-linux
|
|
6
|
+
authors:
|
|
7
|
+
- Automerge Ruby contributors
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-05-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '13.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '13.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: minitest
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '5.16'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '5.16'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake-compiler
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.2'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.2'
|
|
55
|
+
description: A production-oriented Ruby SDK for Automerge backed by the upstream Rust/C
|
|
56
|
+
core.
|
|
57
|
+
email:
|
|
58
|
+
- maintainers@example.com
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- LICENSE.txt
|
|
64
|
+
- README.md
|
|
65
|
+
- lib/automerge.rb
|
|
66
|
+
- lib/automerge/3.0/automerge_ext.so
|
|
67
|
+
- lib/automerge/3.1/automerge_ext.so
|
|
68
|
+
- lib/automerge/3.2/automerge_ext.so
|
|
69
|
+
- lib/automerge/3.3/automerge_ext.so
|
|
70
|
+
- lib/automerge/3.4/automerge_ext.so
|
|
71
|
+
- lib/automerge/version.rb
|
|
72
|
+
- rust-toolchain.toml
|
|
73
|
+
homepage: https://github.com/automerge/automerge
|
|
74
|
+
licenses:
|
|
75
|
+
- MIT
|
|
76
|
+
metadata:
|
|
77
|
+
allowed_push_host: https://rubygems.org
|
|
78
|
+
source_code_uri: https://github.com/automerge/automerge
|
|
79
|
+
changelog_uri: https://github.com/automerge/automerge/blob/main/rust/CHANGELOG.md
|
|
80
|
+
rubygems_mfa_required: 'true'
|
|
81
|
+
post_install_message:
|
|
82
|
+
rdoc_options: []
|
|
83
|
+
require_paths:
|
|
84
|
+
- lib
|
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.0'
|
|
90
|
+
- - "<"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: 3.5.dev
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: 3.3.22
|
|
98
|
+
requirements: []
|
|
99
|
+
rubygems_version: 3.5.23
|
|
100
|
+
signing_key:
|
|
101
|
+
specification_version: 4
|
|
102
|
+
summary: Ruby bindings for the Automerge CRDT core
|
|
103
|
+
test_files: []
|