Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
name: CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
ruby-version: ['3.3']
ruby-version: ['3.3', '3.4']
os: [ubuntu-latest, macos-latest]

steps:
- uses: actions/checkout@v4
Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# sqlite_extensions-uuid

* Source code: https://github.com/jethrodaniel/sqlite_extensions-uuid
* Ruby gem: https://rubygems.org/gems/sqlite_extensions-uuid

## [Unreleased]

## v1.0.2 - 2025-07-03

* Update `SqliteExtensions::UUID.to_path` to include the library's file extension.

When loading an extension without a filename (at least on MacOS and Linux),
SQLite looks for a file ending in `.dylib` and `.so`, respectively.

As a result, if your extension is a `.bundle` file (on MacOS), then you
need to pass the full path.

Passing the full path shouldn't be an issue on any platform anyway.

NOTE: we determine the extension using `RbConfig::CONFIG["DLEXT"]`, and we
don't check if the file actually exists, we just construct the path.

* Internal cleanup: add a changelog, add MacOS to CI, update gemspec


## v1.0.1 - 2025-03-20

* Add `SqliteExtensions::UUID::VERSION`, use RSpec for internal tests.

## v1.0.0 - 2024-12-07

* Require `sqlite3-ruby` 2.4+ so we can use `sqlite3-ruby`'s extension
loading support.

Now that sqlite3-ruby natively supports loading extensions, we can load
extensions in Rails apps without having to monkey-patch anything, like so:

```ruby
gem "sqlite_extensions-uuid"
```

```yaml
development:
adapter: sqlite3
extensions:
- <%= SqliteExtensions::UUID.to_path %>
```
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,55 @@ It then exposes a method, `SqliteExtensions::UUID.to_path`, which returns the lo

This can be passed to [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) in `Database.new(extensions: [])` or `Database#load_extension`.

## Issues

### Missing `.load` command

The default `sqlite3` on MacOS doesn't allow loading runtime extensions, so you'll need to use a version that does, e.g, from `brew` (`brew install sqlite3`).

```console
% /usr/bin/sqlite3
SQLite version 3.43.2 2023-10-10 13:08:14
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .load
Error: unknown command or invalid arguments: "load". Enter ".help" for help
```

If using `brew`, you'll want to follow the suggestions from `brew info sqlite3`:

```console
% brew info sqlite3
...
==> Caveats
sqlite is keg-only, which means it was not symlinked into /opt/homebrew,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have sqlite first in your PATH, run:
echo 'export PATH="/opt/homebrew/opt/sqlite/bin:$PATH"' >> ~/.zshrc

For compilers to find sqlite you may need to set:
export LDFLAGS="-L/opt/homebrew/opt/sqlite/lib"
export CPPFLAGS="-I/opt/homebrew/opt/sqlite/include"

For pkg-config to find sqlite you may need to set:
export PKG_CONFIG_PATH="/opt/homebrew/opt/sqlite/lib/pkgconfig"
```

Afterwards, check that `.load` support works:

```console
% sqlite3
SQLite version 3.50.1 2025-06-06 14:52:32
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
(ins)sqlite> .load
Usage: .load FILE ?ENTRYPOINT?
```

## Development

```shell
Expand Down
5 changes: 4 additions & 1 deletion lib/sqlite_extensions/uuid.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# frozen_string_literal: true

require "rbconfig"

module SqliteExtensions
module UUID
def self.to_path
spec = Gem.loaded_specs["sqlite_extensions-uuid"]
File.join(spec.require_path, "sqlite_extensions/uuid/uuid")
path = File.join(spec.require_path, "sqlite_extensions/uuid/uuid")
path + "." + RbConfig::CONFIG.fetch("DLEXT")
end
end
end
2 changes: 1 addition & 1 deletion lib/sqlite_extensions/uuid/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module SqliteExtensions
module UUID
VERSION = "1.0.1"
VERSION = "1.0.2"
end
end
43 changes: 34 additions & 9 deletions spec/sqlite_extensions/uuid_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,49 @@

RSpec.describe SqliteExtensions::UUID do
it "has a version" do
expect(described_class::VERSION).to eq "1.0.1"
expect(described_class::VERSION).to eq "1.0.2"
end

describe "#to_path" do
subject { described_class.to_path }

before do
gemspec = instance_double(Gem::Specification, require_path: "foo")
allow(Gem).to receive(:loaded_specs).and_return("sqlite_extensions-uuid" => gemspec)
end

it "returns the path to the compiled extension" do
path = described_class.to_path
context "when linux" do
before do
allow(RbConfig::CONFIG).to receive(:fetch).with("DLEXT").and_return("so")
end

it { is_expected.to eq "foo/sqlite_extensions/uuid/uuid.so" }
end

context "when mac with .dylib extension" do
before do
allow(RbConfig::CONFIG).to receive(:fetch).with("DLEXT").and_return("dylib")
end

it { is_expected.to eq "foo/sqlite_extensions/uuid/uuid.dylib" }
end

context "when mac with .bundle extension" do
before do
allow(RbConfig::CONFIG).to receive(:fetch).with("DLEXT").and_return("bundle")
end

expect(path).to eq "foo/sqlite_extensions/uuid/uuid"
it { is_expected.to eq "foo/sqlite_extensions/uuid/uuid.bundle" }
end
end

it "has the correct gemspec info" do
it "has the correct gemspec info" do # rubocop:disable RSpec/ExampleLength
path = File.expand_path("../../sqlite_extensions-uuid.gemspec", __dir__)
gemspec = Gem::Specification.load path

expect(gemspec).to have_attributes(
name: "sqlite_extensions-uuid",
version: Gem::Version.new("1.0.1"),
version: Gem::Version.new("1.0.2"),
files: %w[
ext/sqlite_extensions/uuid/extconf.rb
ext/sqlite_extensions/uuid/sqlite3.h
Expand All @@ -35,13 +55,18 @@
lib/sqlite_extensions/uuid/version.rb
],
licenses: ["MIT"],
metadata: {},
metadata: {
"allowed_push_host" => "https://rubygems.org",
"changelog_uri" => "https://github.com/jethrodaniel/sqlite_extensions-uuid/blob/main/CHANGELOG.md",
"homepage_uri" => "https://github.com/jethrodaniel/sqlite_extensions-uuid",
"source_code_uri" => "https://github.com/jethrodaniel/sqlite_extensions-uuid"
},
required_ruby_version: Gem::Requirement.new([">= 3.0.0"]),
summary: "SQLite's UUID v4 extension, packaged as a gem"
summary: "SQLite's UUID v4 extension, packaged as a gem."
)
require_paths = gemspec.require_paths
expect(require_paths.size).to eq 2
expect(require_paths.first).to end_with "sqlite_extensions-uuid-1.0.1"
expect(require_paths.first).to end_with "sqlite_extensions-uuid-1.0.2"
expect(require_paths.last).to eq "lib"
end
end
6 changes: 5 additions & 1 deletion sqlite_extensions-uuid.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ Gem::Specification.new do |spec|
spec.authors = ["Mark Delk"]
spec.email = ["[email protected]"]

spec.summary = "SQLite's UUID v4 extension, packaged as a gem"
spec.summary = "SQLite's UUID v4 extension, packaged as a gem."
spec.homepage = "https://github.com/jethrodaniel/sqlite_extensions-uuid"
spec.license = "MIT"
spec.required_ruby_version = ">= 3.0.0"
spec.metadata["allowed_push_host"] = "https://rubygems.org"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"

spec.files = Dir.glob("lib/**/*.rb") + Dir.glob("ext/**/*.{c,h}")
spec.require_paths = ["lib"]
Expand Down