Skip to content
Open
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
98 changes: 98 additions & 0 deletions .github/workflows/cibuildgem.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: "Package and release gems with precompiled binaries"
on:
workflow_dispatch:
inputs:
release:
description: "If the whole build passes on all platforms, release the gems on RubyGems.org"
required: false
type: boolean
default: false
env:
CIBUILDGEM: 1
jobs:
compile:
timeout-minutes: 20
name: "Cross compile the gem on different ruby versions"
strategy:
matrix:
os: ["macos-latest", "ubuntu-22.04"]
runs-on: "${{ matrix.os }}"
steps:
- name: "Checkout code"
uses: "actions/checkout@v5"
- name: "Install autotools"
if: "${{ runner.os == 'macOS' }}"
run: brew install autoconf automake libtool
- name: "Setup Ruby"
uses: "ruby/setup-ruby@v1"
with:
ruby-version: "3.3.9"
bundler-cache: true
- name: "Run cibuildgem"
uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
with:
step: "compile"
test:
timeout-minutes: 20
name: "Run the test suite"
needs: compile
strategy:
matrix:
os: ["macos-latest", "ubuntu-22.04"]
rubies: ["4.0", "3.4", "3.3"]
type: ["cross", "native"]
runs-on: "${{ matrix.os }}"
steps:
- name: "Checkout code"
uses: "actions/checkout@v5"
- name: "Install autotools"
if: "${{ runner.os == 'macOS' && matrix.type == 'native' }}"
run: brew install autoconf automake libtool
- name: "Setup Ruby"
uses: "ruby/setup-ruby@v1"
with:
ruby-version: "${{ matrix.rubies }}"
bundler-cache: true
- name: "Run cibuildgem"
uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
with:
step: "test_${{ matrix.type }}"
install:
timeout-minutes: 15
name: "Verify the gem can be installed"
needs: test
strategy:
matrix:
os: ["macos-latest", "ubuntu-22.04"]
runs-on: "${{ matrix.os }}"
steps:
- name: "Install autotools"
if: "${{ runner.os == 'macOS' }}"
run: brew install autoconf automake libtool
- name: "Setup Ruby"
uses: "ruby/setup-ruby@v1"
with:
ruby-version: "4.0.0"
- name: "Run cibuildgem"
uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
with:
step: "install"
release:
environment: release
permissions:
id-token: write
contents: read
timeout-minutes: 5
if: ${{ inputs.release }}
name: "Release all gems with RubyGems"
needs: install
runs-on: "ubuntu-latest"
steps:
- name: "Setup Ruby"
uses: "ruby/setup-ruby@v1"
with:
ruby-version: "4.0.0"
- name: "Run cibuildgem"
uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
with:
step: "release"
4 changes: 2 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
AllCops:
Exclude:
- 'tmp/**/*'
TargetRubyVersion: 2.3
Metrics/LineLength:
TargetRubyVersion: 3.3
Layout/LineLength:
Enabled: false
Metrics/BlockLength:
Enabled: false
Expand Down
17 changes: 0 additions & 17 deletions .travis.yml

This file was deleted.

17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@ Ruby bindings for jq.
see [http://stedolan.github.io/jq/](http://stedolan.github.io/jq/).

[![Gem Version](https://badge.fury.io/rb/ruby-jq.svg)](http://badge.fury.io/rb/ruby-jq)
[![Build Status](https://travis-ci.org/winebarrel/ruby-jq.svg?branch=master)](https://travis-ci.org/winebarrel/ruby-jq)

## Prerequisites
## Precompiled binaries

jq requires the Oniguruma library to provide regex support. To install Oniguruma
for your system, please follow the instructions in the [jq FAQ](https://github.com/stedolan/jq/wiki/FAQ#installation).
Precompiled platform gems are published for `x86_64-linux` and `arm64-darwin`
(one binary per supported minor Ruby version), so installing on those platforms
requires no compiler or build tools. They are built and released with
[cibuildgem](https://github.com/Shopify/cibuildgem) via the
`.github/workflows/cibuildgem.yaml` workflow.

On other platforms the source gem is installed instead: it downloads and
statically compiles [OpsLevel's fork of jq](https://github.com/OpsLevel/jq)
(jq 1.6 lineage where `env`/`$ENV` always return an empty object) along with
[Onigmo](https://github.com/k-takata/Onigmo) for regex support, so the built
extension is self-contained. Building from source requires autoconf, automake,
and libtool.

## Installation

Expand Down
5 changes: 5 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ RSpec::Core::RakeTask.new('spec')

Rake::ExtensionTask.new('jq_core') do |ext|
ext.ext_dir = 'ext'
ext.lib_dir = 'lib/jq'
ext.cross_compiling do |spec|
# Platform gems ship precompiled binaries and never build from source.
spec.dependencies.reject! { |dep| dep.name == 'mini_portile2' }
end
end

RuboCop::RakeTask.new do |task|
Expand Down
30 changes: 23 additions & 7 deletions ext/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,30 @@ def using_system_libraries?
end

unless using_system_libraries?
message "Buildling jq using packaged libraries.\n"
message "Building jq using packaged libraries.\n"

require 'rubygems'
require 'mini_portile2'

recipe = MiniPortile.new('jq', '1.6')
recipe.files = ['https://github.com/stedolan/jq/archive/jq-1.6.tar.gz']
onigmo = MiniPortile.new('onigmo', '6.2.0')
onigmo.files = ['https://github.com/k-takata/Onigmo/releases/download/Onigmo-6.2.0/onigmo-6.2.0.tar.gz']
onigmo.configure_options = [
'--disable-shared',
'--enable-static',
'--with-pic'
]
onigmo.cook

# OpsLevel fork of jq: `env`/`$ENV` always return an empty object.
recipe = MiniPortile.new('jq', '1.6.opslevel')
recipe.files = ['https://github.com/OpsLevel/jq/archive/845f4206dd8a82355325bafffbb54a5155cf67ec.tar.gz']
recipe.configure_options = [
'--enable-shared',
'--disable-maintainer-mode'
'--disable-maintainer-mode',
'--disable-docs',
'--disable-shared',
'--enable-static',
'--with-pic',
"--with-oniguruma=#{onigmo.path}"
]
class << recipe
def configure
Expand All @@ -26,10 +40,12 @@ def configure
end
recipe.cook
recipe.activate
$LIBPATH = ["#{recipe.path}/lib"] | $LIBPATH # rubocop:disable Style/GlobalVars
$LIBPATH = ["#{recipe.path}/lib", "#{onigmo.path}/lib"] | $LIBPATH # rubocop:disable Style/GlobalVars
$CPPFLAGS << " -I#{recipe.path}/include" # rubocop:disable Style/GlobalVars

abort 'libonigmo not found' unless have_library('onigmo')
end

abort 'libjq not found' unless have_library('jq')

create_makefile('jq_core')
create_makefile('jq/jq_core')
9 changes: 8 additions & 1 deletion lib/jq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
require 'tempfile'
require 'stringio'

require 'jq_core'
begin
# Load the precompiled binary matching the current Ruby, if this is a
# platform-specific gem packaged by cibuildgem.
require "jq/#{RUBY_VERSION[/\d+\.\d+/]}/jq_core"
rescue LoadError
# Fall back to the extension compiled from source at install time.
require 'jq/jq_core'
end
require 'jq/version'
require 'jq/parser'

Expand Down
2 changes: 1 addition & 1 deletion lib/jq/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module JQ
VERSION = '0.2.2'
VERSION = '0.3.0'
end
2 changes: 2 additions & 0 deletions ruby-jq.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
# spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ['lib']

spec.required_ruby_version = '>= 3.3'

spec.add_dependency 'multi_json'
spec.add_runtime_dependency 'mini_portile2', '>= 2.2.0'

Expand Down
12 changes: 11 additions & 1 deletion spec/jq_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@

specify 'read from file (> 4096)' do
Tempfile.open("ruby-jq.spec.#{$PROCESS_ID}") do |src|
src.puts('[' + (1..10).map { <<~JSON }.join(',') + ']')
src.puts("[#{(1..10).map { <<~JSON }.join(',')}]")
{
"glossary": {
"title": "example glossary",
Expand Down Expand Up @@ -260,6 +260,16 @@
expect(JQ(src).search('.menu.popup.menuitem[].value')).to eq(%w[New Open Close])
end

specify 'regex support (requires onigmo)' do
expect(JQ('["foo", "bar", "baz"]').search('.[] | select(test("^ba"))')).to eq(%w[bar baz])
expect(JQ('"foo123bar"').search('capture("(?<digits>[0-9]+)")')).to eq([{ 'digits' => '123' }])
end

specify 'env is always empty (OpsLevel jq fork)' do
expect(JQ('null').search('env')).to eq([{}])
expect(JQ('null').search('$ENV')).to eq([{}])
end

specify 'compile error' do
expect do
JQ('{}').search('...')
Expand Down
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

$LOAD_PATH << File.dirname(__FILE__) + '/../lib'
$LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
require 'tempfile'
require 'jq'
require 'jq/extend'