Module: JQ
- Defined in:
- lib/jq.rb,
ext/jq/jq_ext.c
Overview
JQ provides Ruby bindings for the jq JSON processor.
This gem wraps the jq C library, allowing you to apply jq filters to JSON strings directly from Ruby. It supports all standard jq operations and provides a clean Ruby API with proper error handling.
Thread Safety
This gem requires jq 1.7+ for safe multi-threaded operation. Each method call creates an isolated jq_state, and jq 1.7+ includes critical thread safety fixes (PR #2546). Safe to use from multiple threads in MRI Ruby.
Basic Usage
require 'jq'
# Simple filtering
JQ.filter('{"name":"Alice"}', '.name')
# => "\"Alice\""
# With options
JQ.filter('{"name":"Alice"}', '.name', raw_output: true)
# => "Alice"
# Multiple outputs
JQ.filter('[1,2,3]', '.[]', multiple_outputs: true)
# => ["1", "2", "3"]
Error Handling
All jq-related errors inherit from JQ::Error:
begin
JQ.filter('invalid', '.')
rescue JQ::ParseError => e
puts "Invalid JSON: #{e.message}"
end
Defined Under Namespace
Classes: CompileError, Error, ParseError, RuntimeError
Constant Summary collapse
- VERSION =
The gem version number
"1.0.0"
Class Method Summary collapse
-
.filter(json, filter, **options) ⇒ String+
Apply a jq filter to JSON input and return the result.
-
.validate_filter!(filter) ⇒ true
Validate a jq filter expression without executing it.
Class Method Details
.filter(json, filter, **options) ⇒ String+
Apply a jq filter to JSON input and return the result.
This is the primary method for using jq from Ruby. It parses the JSON input, compiles the filter expression, executes it, and returns the result as a JSON string (or array of strings with multiple_outputs: true).
Parameters
- json (String)
-
Valid JSON input string
- filter (String)
-
jq filter expression (e.g., “.name”, “.[] | select(.age > 18)”)
Options
- :raw_output (Boolean)
-
Return raw strings without JSON encoding (equivalent to jq -r). Default: false
- :compact_output (Boolean)
-
Output compact JSON on a single line. Default: true (set to false for pretty output)
- :sort_keys (Boolean)
-
Sort object keys alphabetically (equivalent to jq -S). Default: false
- :multiple_outputs (Boolean)
-
Return array of all results instead of just the first. Default: false
Returns
- String
-
JSON-encoded result (default), or raw string if raw_output: true
- Array<String>
-
Array of results if multiple_outputs: true
Raises
- JQ::ParseError
-
If the JSON input is invalid
- JQ::CompileError
-
If the jq filter expression is invalid
- JQ::RuntimeError
-
If the filter execution fails
- TypeError
-
If arguments are not strings
Examples
# Basic filtering
JQ.filter('{"name":"Alice","age":30}', '.name')
# => "\"Alice\""
# Raw output (no JSON encoding)
JQ.filter('{"name":"Alice"}', '.name', raw_output: true)
# => "Alice"
# Pretty output
JQ.filter('{"a":1,"b":2}', '.', compact_output: false)
# => "{\n \"a\": 1,\n \"b\": 2\n}"
# Multiple outputs
JQ.filter('[1,2,3]', '.[]', multiple_outputs: true)
# => ["1", "2", "3"]
# Sort keys
JQ.filter('{"z":1,"a":2}', '.', sort_keys: true)
# => "{\"a\":2,\"z\":1}"
# Complex transformation
json = '[{"name":"Alice","age":30},{"name":"Bob","age":25}]'
JQ.filter(json, '[.[] | select(.age > 26) | .name]')
# => "[\"Alice\"]"
Thread Safety
This method is thread-safe with jq 1.7+ (required by this gem). Each call creates an isolated jq_state, so concurrent calls do not interfere with each other.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'ext/jq/jq_ext.c', line 252 VALUE rb_jq_filter(int argc, VALUE *argv, VALUE self) { VALUE json_str, filter_str, opts; rb_scan_args(argc, argv, "2:", &json_str, &filter_str, &opts); Check_Type(json_str, T_STRING); Check_Type(filter_str, T_STRING); const char *json_cstr = StringValueCStr(json_str); const char *filter_cstr = StringValueCStr(filter_str); // Parse (default to compact output) int raw_output = 0, compact_output = 1; int sort_keys = 0, multiple_outputs = 0; if (!NIL_P(opts)) { Check_Type(opts, T_HASH); VALUE opt; opt = rb_hash_aref(opts, ID2SYM(rb_intern("raw_output"))); if (RTEST(opt)) raw_output = 1; opt = rb_hash_aref(opts, ID2SYM(rb_intern("compact_output"))); if (!NIL_P(opt)) compact_output = RTEST(opt) ? 1 : 0; opt = rb_hash_aref(opts, ID2SYM(rb_intern("sort_keys"))); if (RTEST(opt)) sort_keys = 1; opt = rb_hash_aref(opts, ID2SYM(rb_intern("multiple_outputs"))); if (RTEST(opt)) multiple_outputs = 1; } return rb_jq_filter_impl(json_cstr, filter_cstr, raw_output, compact_output, sort_keys, multiple_outputs); } |
.validate_filter!(filter) ⇒ true
Validate a jq filter expression without executing it.
This method compiles the filter to check for syntax errors without requiring any JSON input. Use this to validate user-provided filters before attempting to apply them to data.
Parameters
- filter (String)
-
jq filter expression to validate
Returns
- true
-
Always returns true if the filter is valid
Raises
- JQ::CompileError
-
If the filter expression is invalid
- TypeError
-
If filter is not a string
Examples
# Valid filters return true
JQ.validate_filter!('.name')
# => true
JQ.validate_filter!('.[] | select(.age > 18)')
# => true
# Invalid filters raise CompileError
JQ.validate_filter!('. @@@ .')
# raises JQ::CompileError: Syntax error in jq filter
# Validate user input before use
user_filter = params[:filter]
begin
JQ.validate_filter!(user_filter)
result = JQ.filter(json, user_filter)
rescue JQ::CompileError => e
puts "Invalid filter: #{e.message}"
end
Thread Safety
This method is thread-safe with jq 1.7+ (required by this gem).
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'ext/jq/jq_ext.c', line 338 VALUE rb_jq_validate_filter(VALUE self, VALUE filter) { Check_Type(filter, T_STRING); const char *filter_cstr = StringValueCStr(filter); jq_state *jq = jq_init(); if (!jq) { rb_raise(rb_eJQError, "Failed to initialize jq"); } if (!jq_compile(jq, filter_cstr)) { jv error = (jq); if (jv_is_valid(error) && jv_get_kind(error) == JV_KIND_STRING) { const char *error_msg = jv_string_value(error); VALUE rb_error_msg = rb_str_new_cstr(error_msg); jv_free(error); // Store C string before cleanup (StringValueCStr can raise) const char *error_cstr = StringValueCStr(rb_error_msg); jq_teardown(&jq); rb_raise(rb_eJQCompileError, "%s", error_cstr); } jv_free(error); jq_teardown(&jq); rb_raise(rb_eJQCompileError, "Syntax error in jq filter"); } jq_teardown(&jq); return Qtrue; } |