mongory 0.7.8-x64-mingw-ucrt → 0.8.0-x64-mingw-ucrt

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be58a265ee32174ecb4d519e38b47527684cd6c1e23a8d01d0b0d2f88c6d4570
4
- data.tar.gz: 65f05b2caec29a64b738483e3e007b63124efe9c61e45c6de21364c3f9122c66
3
+ metadata.gz: 0560f881e0b3bfe0389307652ae0a1afa3c7da61082caf2d9864479ce8f70e5f
4
+ data.tar.gz: 71610667bc9533393331354d1cb931c5c764ddf9ea08dd67eddc64eae7819ad9
5
5
  SHA512:
6
- metadata.gz: 93229abe702b61ab7a9e4b246d054806415e9f51bddfd6be8f57acc34623c7e7e340b36b0e51f513508e16927813e6b525fbbb90e8390bff84b8048454cb25d9
7
- data.tar.gz: c35113a4740b182c2c611434d0cdd760a54a07c72e213368bf8eea8ce65b89d3cd574c6ff3716ab4d2548e483bf34dd9dabd65927675035ab621d08fe1b87f37
6
+ metadata.gz: 4b1dc0fb39f810d07ff6152ae8091595508653fa111863eb1adc39853718e41b1a103ee44c41de7d309b0262aa5b5fb713d4d96d9de316de920e0a762b9e0582
7
+ data.tar.gz: a2fba2d4f184f6e1c3412583774f00abd872a6ee549a7b9536894ea67f38180245f95a33b559becbef570155b279a366724cba07629b5561bae663e3459277f9
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
- # Mongory-rb
1
+ # Mongory
2
+ ### Let you query everywhere !
2
3
 
3
- A Mongo-like in-memory query DSL for Ruby.
4
+ This is a Mongo-like in-memory query DSL for Ruby.
4
5
 
5
6
  Mongory lets you filter and query in-memory collections using syntax and semantics similar to MongoDB. It is designed for expressive chaining, symbolic operators, and composable matchers.
6
7
 
@@ -53,7 +54,18 @@ gem 'mongory'
53
54
 
54
55
  #### Before installing: install build tools
55
56
 
56
- Mongory ships with an optional native extension. Before installing the gem, make sure your system has a C build toolchain (gcc/clang and make). Install the toolchain with the following commands for your platform:
57
+ Mongory ships with an optional native C extension.
58
+ Before installing Mongory, make sure these following precompiled package support your platform:
59
+ - x86_64-linux-musl (Linux)
60
+ - aarch64-linux-musl (Linux)
61
+ - x86_64-linux (Linux)
62
+ - aarch64-linux (Linux)
63
+ - x86_64-darwin (MacOS Intel)
64
+ - arm64-darwin (MacOS Apple Silicon)
65
+ - x64-mingw32 (Windows)
66
+ - x64-mingw-ucrt (Windows)
67
+
68
+ If your platform excludes, make sure your system has a C build toolchain (gcc/clang and make). Install the toolchain with the following commands for your platform:
57
69
 
58
70
  - Debian/Ubuntu (including ruby:*-slim base images)
59
71
  ```bash
@@ -85,19 +97,6 @@ yum groupinstall -y "Development Tools"
85
97
  xcode-select --install
86
98
  ```
87
99
 
88
- #### Rails Generator
89
-
90
- You can install a starter configuration with:
91
-
92
- ```bash
93
- rails g mongory:install
94
- ```
95
-
96
- This will generate `config/initializers/mongory.rb` and set up:
97
- - Optional symbol operator snippets (e.g. `:age.gt => 18`)
98
- - Class registration (e.g. `Array`, `ActiveRecord::Relation`, etc.)
99
- - Custom value/key converters for your ORM
100
-
101
100
  ### Basic Usage
102
101
  ```ruby
103
102
  records = [
@@ -119,29 +118,18 @@ limited = records.mongory
119
118
  .where(:age.gte => 18) # Conditions apply to limited set
120
119
  ```
121
120
 
122
- ### C Extension (Optional but Recommended)
123
-
124
- Mongory-rb includes an optional high-performance C extension powered by [mongory-core](https://github.com/mongoryhq/mongory-core):
121
+ #### Rails Generator
125
122
 
126
- **System Dependencies:**
127
- - C99-compatible compiler (gcc/clang)
128
- - CMake >= 3.12 (optional; only needed if you want to build `mongory-core` standalone or run its native tests)
123
+ You can install a starter configuration with:
129
124
 
130
- **Installation:**
131
125
  ```bash
132
- # macOS
133
- brew install cmake
134
-
135
- # Ubuntu/Debian
136
- sudo apt install cmake build-essential
137
-
138
- # CentOS/RHEL
139
- sudo yum install cmake gcc make
126
+ rails g mongory:install
140
127
  ```
141
128
 
142
- The C extension provides significant performance improvements for large datasets. If not available, Mongory-rb automatically falls back to pure Ruby implementation.
143
-
144
- Note: The Ruby C extension is built via Ruby's `mkmf` (see `ext/mongory_ext/extconf.rb`) and compiles `mongory-core` sources directly. You do not need CMake for normal gem installation.
129
+ This will generate `config/initializers/mongory.rb` and set up:
130
+ - Optional symbol operator snippets (e.g. `:age.gt => 18`)
131
+ - Class registration (e.g. `Array`, `ActiveRecord::Relation`, etc.)
132
+ - Custom value/key converters for your ORM
145
133
 
146
134
  ## Positioning
147
135
 
@@ -201,8 +189,8 @@ This will:
201
189
 
202
190
  The generated matcher will:
203
191
  - Be named `ClassInMatcher`
204
- - Register the operator as `$classIn`
205
- - Be available as `:class_in` in queries
192
+ - Register the operator as `$classIn` makes it available in queries
193
+ - Enable `:field.class_in` query snippet (If symbol snippet enabled)
206
194
 
207
195
  Example usage of the generated matcher:
208
196
  ```ruby
@@ -248,8 +236,7 @@ User.where(status: 'active').mongory.where(:age.gte => 18, :name.regex => "^S.+"
248
236
  ```
249
237
 
250
238
  This injects a `.mongory` method via an internal extension module.
251
-
252
- Internally, the query is compiled into a matcher tree using the `QueryMatcher` and `ConditionConverter`.
239
+ Internally, the query is compiled into a matcher tree.
253
240
 
254
241
  | Method | Description | Example |
255
242
  |--------|-------------|---------|
@@ -311,19 +298,13 @@ And: {"age"=>{"$gte"=>18}, "$or"=>[{"status"=>"active"}, {"name"=>{"$regex"=>/^J
311
298
 
312
299
  This helps you understand how your query is being processed and can be useful for debugging complex conditions.
313
300
 
314
- Or use the debugger for detailed matching process:
301
+ Or use trace for detailed matching process:
315
302
  ```ruby
316
- # Enable debugging
317
- Mongory.debugger.enable
318
-
319
303
  # Execute your query
320
304
  query = Mongory.build_query(users).where(age: { :$gt => 18 })
321
- query.each do |user|
305
+ query.trace do |user|
322
306
  puts user
323
307
  end
324
-
325
- # Display the debug trace
326
- Mongory.debugger.display
327
308
  ```
328
309
 
329
310
  The debug output will show detailed matching process with full class names:
@@ -351,6 +332,7 @@ The debug output includes:
351
332
  | Pattern | `$regex` |
352
333
  | Presence | `$exists`, `$present` |
353
334
  | Nested Match | `$elemMatch`, `$every` |
335
+ | Other | `$size` |
354
336
 
355
337
  Note: Some operators are Mongory-specific and not available in MongoDB:
356
338
  - `$present`: Checks if a field is considered "present" (not nil, not empty, not KEY_NOT_FOUND)
@@ -399,10 +381,11 @@ end
399
381
 
400
382
  1. **Debugging Queries**
401
383
  ```ruby
402
- Mongory.debugger.enable
403
- records.mongory.where(:age => 18).to_a
404
- Mongory.debugger.display
405
- Mongory.debugger.disable
384
+ records.mongory.where(:age => 18).trace.to_a
385
+ ```
386
+ If using C extension:
387
+ ```ruby
388
+ records.mongory.c.where(:age => 18).trace.to_a
406
389
  ```
407
390
 
408
391
  2. **Common Issues**
data/docs/clang_bridge.md CHANGED
@@ -1,3 +1,27 @@
1
+ ### C Extension (Optional but Recommended)
2
+
3
+ Mongory-rb includes an optional high-performance C extension powered by [mongory-core](https://github.com/mongoryhq/mongory-core):
4
+
5
+ **System Dependencies:**
6
+ - C99-compatible compiler (gcc/clang)
7
+ - CMake >= 3.12 (optional; only needed if you want to build `mongory-core` standalone or run its native tests)
8
+
9
+ **Installation:**
10
+ ```bash
11
+ # macOS
12
+ brew install cmake
13
+
14
+ # Ubuntu/Debian
15
+ sudo apt install cmake build-essential
16
+
17
+ # CentOS/RHEL
18
+ sudo yum install cmake gcc make
19
+ ```
20
+
21
+ The C extension provides significant performance improvements for large datasets. If not available, Mongory-rb automatically falls back to pure Ruby implementation.
22
+
23
+ Note: The Ruby C extension is built via Ruby's `mkmf` (see `ext/mongory_ext/extconf.rb`) and compiles `mongory-core` sources directly. You do not need CMake for normal gem installation.
24
+
1
25
  # Clang Bridge (C Extension)
2
26
 
3
27
  The Clang bridge connects the Ruby DSL to the `mongory-core` engine via a compact C layer. It exposes two key entry points:
@@ -49,7 +49,7 @@ end
49
49
  # Simple query (Mongory) test
50
50
  puts "\nSimple query (Mongory) (#{size} records):"
51
51
  gc_handler do
52
- builder = records.mongory.where(:age.gte => 18)
52
+ builder = records.mongory.where({:age.gte => 18})
53
53
  5.times do
54
54
  result = Benchmark.measure do
55
55
  builder.to_a
@@ -62,7 +62,7 @@ end
62
62
  # Simple query (Mongory::CMatcher) test
63
63
  puts "\nSimple query (Mongory::CMatcher) (#{size} records):"
64
64
  gc_handler do
65
- matcher = Mongory::CMatcher.new(:age.gte => 18)
65
+ matcher = Mongory::CMatcher.new({:age.gte => 18})
66
66
  5.times do
67
67
  result = Benchmark.measure do
68
68
  records.select { |r| matcher.match?(r) }
@@ -75,7 +75,7 @@ end
75
75
  # Simple query (Mongory::CQueryBuilder) test
76
76
  puts "\nSimple query (Mongory::CQueryBuilder) (#{size} records):"
77
77
  gc_handler do
78
- builder = Mongory::CQueryBuilder.new(records).where(:age.gte => 18)
78
+ builder = Mongory::CQueryBuilder.new(records).where({:age.gte => 18})
79
79
  5.times do
80
80
  result = Benchmark.measure do
81
81
  builder.to_a
@@ -138,12 +138,12 @@ end
138
138
 
139
139
  puts "\nComplex query (Mongory) use CMatcher (#{size} records):"
140
140
  gc_handler do
141
- matcher = Mongory::CMatcher.new(
141
+ matcher = Mongory::CMatcher.new({
142
142
  '$or' => [
143
143
  { :age.gte => 18 },
144
144
  { status: 'active' }
145
145
  ]
146
- )
146
+ })
147
147
  5.times do
148
148
  result = Benchmark.measure do
149
149
  records.select { |r| matcher.match?(r) }
@@ -167,18 +167,4 @@ end
167
167
  end
168
168
  raise "count mismatch" if builder.count != count_of_complex_query
169
169
  end
170
-
171
- puts "\nTest Mongory::CMatcher#trace"
172
- matcher = Mongory::CMatcher.new(
173
- '$or' => [
174
- { :age.gte => 18 },
175
- { status: 'active' }
176
- ]
177
- )
178
- # matcher.enable_trace
179
- records.sample(30).each do |r|
180
- matcher.trace(r)
181
- end
182
- # matcher.print_trace
183
- # matcher.disable_trace
184
170
  end
@@ -26,34 +26,34 @@ static VALUE inMongoryDataConverter;
26
26
  static VALUE inMongoryConditionConverter;
27
27
 
28
28
  // Matcher wrapper structure
29
- typedef struct ruby_mongory_matcher_t {
29
+ typedef struct rb_mongory_matcher_t {
30
30
  mongory_matcher *matcher;
31
31
  mongory_value *condition;
32
32
  mongory_memory_pool *pool;
33
33
  mongory_memory_pool *scratch_pool;
34
+ mongory_memory_pool *trace_pool;
34
35
  mongory_table *string_map;
35
36
  mongory_table *symbol_map;
36
37
  mongory_array *mark_list;
37
- bool trace_enabled;
38
38
  VALUE ctx;
39
- } ruby_mongory_matcher_t;
39
+ } rb_mongory_matcher_t;
40
40
 
41
- typedef struct ruby_mongory_memory_pool_t {
41
+ typedef struct rb_mongory_memory_pool_t {
42
42
  mongory_memory_pool base;
43
- ruby_mongory_matcher_t *owner;
44
- } ruby_mongory_memory_pool_t;
43
+ rb_mongory_matcher_t *owner;
44
+ } rb_mongory_memory_pool_t;
45
45
 
46
- typedef struct ruby_mongory_table_t {
46
+ typedef struct rb_mongory_table_t {
47
47
  mongory_table base;
48
48
  VALUE rb_hash;
49
- ruby_mongory_matcher_t *owner;
50
- } ruby_mongory_table_t;
49
+ rb_mongory_matcher_t *owner;
50
+ } rb_mongory_table_t;
51
51
 
52
- typedef struct ruby_mongory_array_t {
52
+ typedef struct rb_mongory_array_t {
53
53
  mongory_array base;
54
54
  VALUE rb_array;
55
- ruby_mongory_matcher_t *owner;
56
- } ruby_mongory_array_t;
55
+ rb_mongory_matcher_t *owner;
56
+ } rb_mongory_array_t;
57
57
 
58
58
  typedef struct {
59
59
  mongory_table *table;
@@ -61,23 +61,23 @@ typedef struct {
61
61
  } hash_conv_ctx;
62
62
 
63
63
  // Forward declarations
64
- static void ruby_mongory_matcher_mark(void *ptr);
65
- static void ruby_mongory_matcher_free(void *ptr);
66
- mongory_value *ruby_to_mongory_value_deep(mongory_memory_pool *pool, VALUE rb_value);
67
- mongory_value *ruby_to_mongory_value_shallow(mongory_memory_pool *pool, VALUE rb_value);
68
- mongory_value *ruby_mongory_table_wrap(mongory_memory_pool *pool, VALUE rb_hash);
69
- mongory_value *ruby_mongory_array_wrap(mongory_memory_pool *pool, VALUE rb_array);
70
- static VALUE cache_fetch_string(ruby_mongory_matcher_t *owner, const char *key);
71
- static VALUE cache_fetch_symbol(ruby_mongory_matcher_t *owner, const char *key);
72
- static ruby_mongory_memory_pool_t *ruby_mongory_memory_pool_new();
73
- static void rb_mongory_matcher_parse_argv(ruby_mongory_matcher_t *wrapper, int argc, VALUE *argv);
74
- static bool mongory_error_handling(mongory_memory_pool *pool, char *error_message);
75
-
76
- static const rb_data_type_t ruby_mongory_matcher_type = {
64
+ static void rb_mongory_matcher_mark(void *ptr);
65
+ static void rb_mongory_matcher_free(void *ptr);
66
+ mongory_value *rb_to_mongory_value_deep(mongory_memory_pool *pool, VALUE rb_value);
67
+ mongory_value *rb_to_mongory_value_shallow(mongory_memory_pool *pool, VALUE rb_value);
68
+ mongory_value *rb_mongory_table_wrap(mongory_memory_pool *pool, VALUE rb_hash);
69
+ mongory_value *rb_mongory_array_wrap(mongory_memory_pool *pool, VALUE rb_array);
70
+ static VALUE cache_fetch_string(rb_mongory_matcher_t *owner, const char *key);
71
+ static VALUE cache_fetch_symbol(rb_mongory_matcher_t *owner, const char *key);
72
+ static rb_mongory_memory_pool_t *rb_mongory_memory_pool_new();
73
+ static void rb_mongory_matcher_parse_argv(rb_mongory_matcher_t *wrapper, int argc, VALUE *argv);
74
+ static bool rb_mongory_error_handling(mongory_memory_pool *pool, char *error_message);
75
+
76
+ static const rb_data_type_t rb_mongory_matcher_type = {
77
77
  .wrap_struct_name = "mongory_matcher",
78
78
  .function = {
79
- .dmark = ruby_mongory_matcher_mark,
80
- .dfree = ruby_mongory_matcher_free,
79
+ .dmark = rb_mongory_matcher_mark,
80
+ .dfree = rb_mongory_matcher_free,
81
81
  .dsize = NULL,
82
82
  },
83
83
  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
@@ -88,30 +88,38 @@ static const rb_data_type_t ruby_mongory_matcher_type = {
88
88
  */
89
89
 
90
90
  // Mongory::CMatcher.new(condition)
91
- static VALUE ruby_mongory_matcher_new(int argc, VALUE *argv, VALUE class) {
92
- ruby_mongory_memory_pool_t *matcher_pool = ruby_mongory_memory_pool_new();
93
- ruby_mongory_memory_pool_t *scratch_pool = ruby_mongory_memory_pool_new();
94
- ruby_mongory_matcher_t *wrapper = ALLOC(ruby_mongory_matcher_t);
95
- wrapper->pool = &matcher_pool->base;
96
- wrapper->scratch_pool = &scratch_pool->base;
97
- wrapper->string_map = mongory_table_new(wrapper->pool);
98
- wrapper->symbol_map = mongory_table_new(wrapper->pool);
99
- wrapper->mark_list = mongory_array_new(wrapper->pool);
100
- wrapper->trace_enabled = false;
91
+ static VALUE rb_mongory_matcher_new(int argc, VALUE *argv, VALUE class) {
92
+ rb_mongory_memory_pool_t *matcher_pool = rb_mongory_memory_pool_new();
93
+ mongory_memory_pool *matcher_pool_base = &matcher_pool->base;
94
+ rb_mongory_memory_pool_t *scratch_pool = rb_mongory_memory_pool_new();
95
+ mongory_memory_pool *scratch_pool_base = &scratch_pool->base;
96
+ rb_mongory_matcher_t *wrapper = ALLOC(rb_mongory_matcher_t);
97
+ wrapper->pool = matcher_pool_base;
98
+ wrapper->scratch_pool = scratch_pool_base;
99
+ wrapper->trace_pool = NULL;
100
+ wrapper->ctx = NULL;
101
+ wrapper->string_map = mongory_table_new(matcher_pool_base);
102
+ wrapper->symbol_map = mongory_table_new(matcher_pool_base);
103
+ wrapper->mark_list = mongory_array_new(matcher_pool_base);
104
+ wrapper->condition = NULL;
105
+ wrapper->matcher = NULL;
101
106
  matcher_pool->owner = wrapper;
102
107
  scratch_pool->owner = wrapper;
103
108
  rb_mongory_matcher_parse_argv(wrapper, argc, argv);
104
109
 
105
- mongory_matcher *matcher = mongory_matcher_new(wrapper->pool, wrapper->condition, wrapper->ctx);
106
- if (mongory_error_handling(wrapper->pool, "Failed to create matcher")) {
110
+ mongory_matcher *matcher = mongory_matcher_new(matcher_pool_base, wrapper->condition, wrapper->ctx);
111
+ if (rb_mongory_error_handling(matcher_pool_base, "Failed to create matcher")) {
112
+ matcher_pool_base->free(matcher_pool_base);
113
+ scratch_pool_base->free(scratch_pool_base);
114
+ xfree(wrapper);
107
115
  return Qnil;
108
116
  }
109
117
 
110
118
  wrapper->matcher = matcher;
111
- return TypedData_Wrap_Struct(class, &ruby_mongory_matcher_type, wrapper);
119
+ return TypedData_Wrap_Struct(class, &rb_mongory_matcher_type, wrapper);
112
120
  }
113
121
 
114
- static void rb_mongory_matcher_parse_argv(ruby_mongory_matcher_t *wrapper, int argc, VALUE *argv) {
122
+ static void rb_mongory_matcher_parse_argv(rb_mongory_matcher_t *self, int argc, VALUE *argv) {
115
123
  VALUE condition, kw_hash;
116
124
  rb_scan_args(argc, argv, "1:", &condition, &kw_hash);
117
125
  const ID ctx_id[1] = { rb_intern("context") };
@@ -120,40 +128,50 @@ static void rb_mongory_matcher_parse_argv(ruby_mongory_matcher_t *wrapper, int a
120
128
  rb_get_kwargs(kw_hash, ctx_id, 1, 0, kw_vals);
121
129
  }
122
130
  if (kw_vals[0] != Qundef) {
123
- wrapper->ctx = kw_vals[0];
131
+ self->ctx = kw_vals[0];
124
132
  } else {
125
- wrapper->ctx = rb_funcall(cMongoryMatcherContext, rb_intern("new"), 0);
133
+ self->ctx = rb_funcall(cMongoryMatcherContext, rb_intern("new"), 0);
126
134
  }
127
135
  VALUE converted_condition = rb_funcall(inMongoryConditionConverter, rb_intern("convert"), 1, condition);
128
- wrapper->condition = ruby_to_mongory_value_deep(wrapper->pool, converted_condition);
129
- wrapper->mark_list->push(wrapper->mark_list, wrapper->condition);
130
- mongory_value *store_ctx = mongory_value_wrap_u(wrapper->pool, (void *)wrapper->ctx);
131
- store_ctx->origin = (void *)wrapper->ctx;
132
- wrapper->mark_list->push(wrapper->mark_list, store_ctx);
136
+ self->condition = rb_to_mongory_value_deep(self->pool, converted_condition);
137
+ self->mark_list->push(self->mark_list, self->condition);
138
+ mongory_value *store_ctx = mongory_value_wrap_u(self->pool, (void *)self->ctx);
139
+ store_ctx->origin = (void *)self->ctx;
140
+ self->mark_list->push(self->mark_list, store_ctx);
133
141
  }
134
142
 
135
143
  // Mongory::CMatcher#match(data)
136
- static VALUE ruby_mongory_matcher_match(VALUE self, VALUE data) {
137
- ruby_mongory_matcher_t *wrapper;
138
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
139
- mongory_value *data_value;
140
- data_value = ruby_to_mongory_value_shallow(wrapper->scratch_pool, data);
141
- if (mongory_error_handling(wrapper->scratch_pool, "Match failed")) {
144
+ static VALUE rb_mongory_matcher_match(VALUE self, VALUE data) {
145
+ rb_mongory_matcher_t *self_wrapper;
146
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, self_wrapper);
147
+ mongory_matcher *matcher = self_wrapper->matcher;
148
+ mongory_memory_pool *scratch_pool = self_wrapper->scratch_pool;
149
+ mongory_memory_pool *trace_pool = self_wrapper->trace_pool;
150
+ mongory_value *data_value = rb_to_mongory_value_shallow(scratch_pool, data);
151
+
152
+ if (rb_mongory_error_handling(scratch_pool, "Match failed")) {
142
153
  return Qnil;
143
154
  }
144
- bool result = mongory_matcher_match(wrapper->matcher, data_value);
145
- if (!wrapper->trace_enabled) {
146
- wrapper->scratch_pool->reset(wrapper->scratch_pool);
155
+
156
+ bool result = mongory_matcher_match(matcher, data_value);
157
+
158
+ if (trace_pool) {
159
+ mongory_matcher_print_trace(matcher);
160
+ trace_pool->reset(trace_pool);
161
+ mongory_matcher_enable_trace(matcher, trace_pool);
147
162
  }
163
+
164
+ scratch_pool->reset(scratch_pool);
165
+
148
166
  return result ? Qtrue : Qfalse;
149
167
  }
150
168
 
151
169
  // Mongory::CMatcher#explain
152
- static VALUE ruby_mongory_matcher_explain(VALUE self) {
153
- ruby_mongory_matcher_t *wrapper;
154
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
170
+ static VALUE rb_mongory_matcher_explain(VALUE self) {
171
+ rb_mongory_matcher_t *wrapper;
172
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, wrapper);
155
173
  mongory_matcher_explain(wrapper->matcher, wrapper->scratch_pool);
156
- if (mongory_error_handling(wrapper->scratch_pool, "Explain failed")) {
174
+ if (rb_mongory_error_handling(wrapper->scratch_pool, "Explain failed")) {
157
175
  return Qnil;
158
176
  }
159
177
  wrapper->scratch_pool->reset(wrapper->scratch_pool);
@@ -161,78 +179,91 @@ static VALUE ruby_mongory_matcher_explain(VALUE self) {
161
179
  }
162
180
 
163
181
  // Mongory::CMatcher#trace(data)
164
- static VALUE ruby_mongory_matcher_trace(VALUE self, VALUE data) {
165
- ruby_mongory_matcher_t *wrapper;
166
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
167
- mongory_value *data_value = ruby_to_mongory_value_shallow(wrapper->scratch_pool, data);
168
- if (mongory_error_handling(wrapper->scratch_pool, "Trace failed")) {
182
+ static VALUE rb_mongory_matcher_trace(VALUE self, VALUE data) {
183
+ rb_mongory_matcher_t *wrapper;
184
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, wrapper);
185
+ mongory_memory_pool *trace_pool = mongory_memory_pool_new();
186
+ mongory_value *data_value = rb_to_mongory_value_shallow(trace_pool, data);
187
+
188
+ if (rb_mongory_error_handling(trace_pool, "Trace failed")) {
189
+ trace_pool->free(trace_pool);
169
190
  return Qnil;
170
191
  }
192
+
171
193
  bool matched = mongory_matcher_trace(wrapper->matcher, data_value);
172
- wrapper->scratch_pool->reset(wrapper->scratch_pool);
194
+ trace_pool->free(trace_pool);
195
+
173
196
  return matched ? Qtrue : Qfalse;
174
197
  }
175
198
 
176
199
  // Mongory::CMatcher#enable_trace
177
- static VALUE ruby_mongory_matcher_enable_trace(VALUE self) {
178
- ruby_mongory_matcher_t *wrapper;
179
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
180
- mongory_matcher_enable_trace(wrapper->matcher, wrapper->scratch_pool);
181
- if (mongory_error_handling(wrapper->scratch_pool, "Enable trace failed")) {
200
+ static VALUE rb_mongory_matcher_enable_trace(VALUE self) {
201
+ rb_mongory_matcher_t *wrapper;
202
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, wrapper);
203
+ mongory_memory_pool *trace_pool = rb_mongory_memory_pool_new();
204
+ mongory_matcher_enable_trace(wrapper->matcher, trace_pool);
205
+
206
+ if (rb_mongory_error_handling(trace_pool, "Enable trace failed")) {
207
+ trace_pool->free(trace_pool);
182
208
  return Qnil;
183
209
  }
184
- wrapper->trace_enabled = true;
210
+ wrapper->trace_pool = trace_pool;
211
+
185
212
  return Qnil;
186
213
  }
187
214
 
188
215
  // Mongory::CMatcher#disable_trace
189
- static VALUE ruby_mongory_matcher_disable_trace(VALUE self) {
190
- ruby_mongory_matcher_t *wrapper;
191
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
216
+ static VALUE rb_mongory_matcher_disable_trace(VALUE self) {
217
+ rb_mongory_matcher_t *wrapper;
218
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, wrapper);
219
+ mongory_memory_pool *trace_pool = wrapper->trace_pool;
192
220
  mongory_matcher_disable_trace(wrapper->matcher);
193
- if (mongory_error_handling(wrapper->scratch_pool, "Disable trace failed")) {
194
- return Qnil;
195
- }
196
- wrapper->scratch_pool->reset(wrapper->scratch_pool);
197
- wrapper->trace_enabled = false;
221
+ rb_mongory_error_handling(trace_pool, "Disable trace failed");
222
+ trace_pool->free(trace_pool);
223
+ wrapper->trace_pool = NULL;
224
+
198
225
  return Qnil;
199
226
  }
200
227
 
201
228
  // Mongory::CMatcher#print_trace
202
- static VALUE ruby_mongory_matcher_print_trace(VALUE self) {
203
- ruby_mongory_matcher_t *wrapper;
204
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
229
+ static VALUE rb_mongory_matcher_print_trace(VALUE self) {
230
+ rb_mongory_matcher_t *wrapper;
231
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, wrapper);
205
232
  mongory_matcher_print_trace(wrapper->matcher);
206
- mongory_error_handling(wrapper->scratch_pool, "Print trace failed");
233
+ rb_mongory_error_handling(wrapper->trace_pool, "Print trace failed");
234
+
207
235
  return Qnil;
208
236
  }
209
237
 
210
238
  // Mongory::CMatcher#condition
211
- static VALUE ruby_mongory_matcher_condition(VALUE self) {
212
- ruby_mongory_matcher_t *wrapper;
213
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
239
+ static VALUE rb_mongory_matcher_condition(VALUE self) {
240
+ rb_mongory_matcher_t *wrapper;
241
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, wrapper);
242
+
214
243
  return (VALUE)wrapper->condition->origin;
215
244
  }
216
245
 
217
246
  // Mongory::CMatcher#context
218
- static VALUE ruby_mongory_matcher_context(VALUE self) {
219
- ruby_mongory_matcher_t *wrapper;
220
- TypedData_Get_Struct(self, ruby_mongory_matcher_t, &ruby_mongory_matcher_type, wrapper);
247
+ static VALUE rb_mongory_matcher_context(VALUE self) {
248
+ rb_mongory_matcher_t *wrapper;
249
+ TypedData_Get_Struct(self, rb_mongory_matcher_t, &rb_mongory_matcher_type, wrapper);
250
+
221
251
  return wrapper->ctx ? wrapper->ctx : Qnil;
222
252
  }
223
253
 
224
254
  // Mongory::CMatcher.trace_result_colorful=(colorful)
225
- static VALUE ruby_mongory_matcher_trace_result_colorful(VALUE self, VALUE colorful) {
255
+ static VALUE rb_mongory_matcher_trace_result_colorful(VALUE self, VALUE colorful) {
226
256
  (void)self;
227
257
  mongory_matcher_trace_result_colorful_set(RTEST(colorful));
258
+
228
259
  return Qnil;
229
260
  }
230
261
 
231
262
  /**
232
263
  * Create a new memory pool
233
264
  */
234
- static ruby_mongory_memory_pool_t *ruby_mongory_memory_pool_new() {
235
- ruby_mongory_memory_pool_t *pool = malloc(sizeof(ruby_mongory_memory_pool_t));
265
+ static rb_mongory_memory_pool_t *rb_mongory_memory_pool_new() {
266
+ rb_mongory_memory_pool_t *pool = malloc(sizeof(rb_mongory_memory_pool_t));
236
267
  mongory_memory_pool *base = mongory_memory_pool_new();
237
268
  memcpy(&pool->base, base, sizeof(mongory_memory_pool));
238
269
  free(base);
@@ -243,12 +274,16 @@ static ruby_mongory_memory_pool_t *ruby_mongory_memory_pool_new() {
243
274
  /**
244
275
  * Ruby GC management functions
245
276
  */
246
- static void ruby_mongory_matcher_free(void *ptr) {
247
- ruby_mongory_matcher_t *wrapper = (ruby_mongory_matcher_t *)ptr;
277
+ static void rb_mongory_matcher_free(void *ptr) {
278
+ rb_mongory_matcher_t *wrapper = (rb_mongory_matcher_t *)ptr;
248
279
  mongory_memory_pool *pool = wrapper->pool;
249
280
  mongory_memory_pool *scratch_pool = wrapper->scratch_pool;
281
+ mongory_memory_pool *trace_pool = wrapper->trace_pool;
250
282
  pool->free(pool);
251
283
  scratch_pool->free(scratch_pool);
284
+ if (trace_pool) {
285
+ trace_pool->free(trace_pool);
286
+ }
252
287
  xfree(wrapper);
253
288
  }
254
289
 
@@ -264,10 +299,10 @@ static bool gc_mark_array_cb(mongory_value *value, void *acc) {
264
299
  /**
265
300
  * GC marking callback for mongory_matcher
266
301
  */
267
- static void ruby_mongory_matcher_mark(void *ptr) {
268
- ruby_mongory_matcher_t *wrapper = (ruby_mongory_matcher_t *)ptr;
269
- if (!wrapper) return;
270
- wrapper->mark_list->each(wrapper->mark_list, NULL, gc_mark_array_cb);
302
+ static void rb_mongory_matcher_mark(void *ptr) {
303
+ rb_mongory_matcher_t *self = (rb_mongory_matcher_t *)ptr;
304
+ if (!self) return;
305
+ self->mark_list->each(self->mark_list, NULL, gc_mark_array_cb);
271
306
  }
272
307
 
273
308
  /**
@@ -275,7 +310,7 @@ static void ruby_mongory_matcher_mark(void *ptr) {
275
310
  */
276
311
 
277
312
  // Helper function to convert Ruby value to C string
278
- static char *ruby_mongory_value_to_cstr(mongory_value *value, mongory_memory_pool *pool) {
313
+ static char *rb_mongory_value_to_cstr(mongory_value *value, mongory_memory_pool *pool) {
279
314
  (void)pool;
280
315
  VALUE rb_value = (VALUE)value->origin;
281
316
  VALUE rb_str = rb_funcall(rb_value, rb_intern("inspect"), 0);
@@ -283,7 +318,7 @@ static char *ruby_mongory_value_to_cstr(mongory_value *value, mongory_memory_poo
283
318
  }
284
319
 
285
320
  // Helper function for primitive conversion of Ruby value to mongory_value
286
- static mongory_value *ruby_to_mongory_value_primitive(mongory_memory_pool *pool, VALUE rb_value) {
321
+ static mongory_value *rb_to_mongory_value_primitive(mongory_memory_pool *pool, VALUE rb_value) {
287
322
  mongory_value *mg_value = NULL;
288
323
  switch (TYPE(rb_value)) {
289
324
  case T_NIL:
@@ -325,8 +360,8 @@ static mongory_value *ruby_to_mongory_value_primitive(mongory_memory_pool *pool,
325
360
  return mg_value;
326
361
  }
327
362
  // Shallow conversion: Convert Ruby value to mongory_value (fully materialize arrays/tables)
328
- static mongory_value *ruby_to_mongory_value_shallow_rec(mongory_memory_pool *pool, VALUE rb_value, bool converted) {
329
- mongory_value *mg_value = ruby_to_mongory_value_primitive(pool, rb_value);
363
+ static mongory_value *rb_to_mongory_value_shallow_rec(mongory_memory_pool *pool, VALUE rb_value, bool converted) {
364
+ mongory_value *mg_value = rb_to_mongory_value_primitive(pool, rb_value);
330
365
  if (mg_value) {
331
366
  mg_value->origin = rb_value;
332
367
  return mg_value;
@@ -334,12 +369,12 @@ static mongory_value *ruby_to_mongory_value_shallow_rec(mongory_memory_pool *poo
334
369
 
335
370
  switch (TYPE(rb_value)) {
336
371
  case T_ARRAY: {
337
- mg_value = ruby_mongory_array_wrap(pool, rb_value);
372
+ mg_value = rb_mongory_array_wrap(pool, rb_value);
338
373
  break;
339
374
  }
340
375
 
341
376
  case T_HASH: {
342
- mg_value = ruby_mongory_table_wrap(pool, rb_value);
377
+ mg_value = rb_mongory_table_wrap(pool, rb_value);
343
378
  break;
344
379
  }
345
380
 
@@ -349,7 +384,7 @@ static mongory_value *ruby_to_mongory_value_shallow_rec(mongory_memory_pool *poo
349
384
  break;
350
385
  } else {
351
386
  VALUE converted_value = rb_funcall(inMongoryDataConverter, rb_intern("convert"), 1, rb_value);
352
- return ruby_to_mongory_value_shallow_rec(pool, converted_value, true);
387
+ return rb_to_mongory_value_shallow_rec(pool, converted_value, true);
353
388
  }
354
389
  }
355
390
  mg_value->origin = rb_value;
@@ -357,15 +392,15 @@ static mongory_value *ruby_to_mongory_value_shallow_rec(mongory_memory_pool *poo
357
392
  }
358
393
 
359
394
  // Shallow conversion: Convert Ruby value to mongory_value (fully materialize arrays/tables)
360
- mongory_value *ruby_to_mongory_value_shallow(mongory_memory_pool *pool, VALUE rb_value) {
361
- return ruby_to_mongory_value_shallow_rec(pool, rb_value, false);
395
+ mongory_value *rb_to_mongory_value_shallow(mongory_memory_pool *pool, VALUE rb_value) {
396
+ return rb_to_mongory_value_shallow_rec(pool, rb_value, false);
362
397
  }
363
398
 
364
399
  // Helper function for deep conversion of hash values
365
400
  static int hash_foreach_deep_convert_cb(VALUE key, VALUE val, VALUE ptr) {
366
401
  hash_conv_ctx *ctx = (hash_conv_ctx *)ptr;
367
- ruby_mongory_memory_pool_t *rb_pool = (ruby_mongory_memory_pool_t *)ctx->pool;
368
- ruby_mongory_matcher_t *owner = rb_pool->owner;
402
+ rb_mongory_memory_pool_t *rb_pool = (rb_mongory_memory_pool_t *)ctx->pool;
403
+ rb_mongory_matcher_t *owner = rb_pool->owner;
369
404
  mongory_table *store_map;
370
405
  char *key_str;
371
406
  if (SYMBOL_P(key)) {
@@ -378,14 +413,14 @@ static int hash_foreach_deep_convert_cb(VALUE key, VALUE val, VALUE ptr) {
378
413
  mongory_value *store = mongory_value_wrap_u(ctx->pool, NULL);
379
414
  store->origin = (void *)key;
380
415
  store_map->set(store_map, key_str, store);
381
- mongory_value *cval = ruby_to_mongory_value_deep(ctx->pool, val);
416
+ mongory_value *cval = rb_to_mongory_value_deep(ctx->pool, val);
382
417
  ctx->table->set(ctx->table, key_str, cval);
383
418
  return ST_CONTINUE;
384
419
  }
385
420
 
386
421
  // Deep conversion: Convert Ruby value to mongory_value (fully materialize arrays/tables)
387
- static mongory_value *ruby_to_mongory_value_deep_rec(mongory_memory_pool *pool, VALUE rb_value, bool converted) {
388
- mongory_value *mg_value = ruby_to_mongory_value_primitive(pool, rb_value);
422
+ static mongory_value *rb_to_mongory_value_deep_rec(mongory_memory_pool *pool, VALUE rb_value, bool converted) {
423
+ mongory_value *mg_value = rb_to_mongory_value_primitive(pool, rb_value);
389
424
  if (mg_value) {
390
425
  mg_value->origin = rb_value;
391
426
  return mg_value;
@@ -395,7 +430,7 @@ static mongory_value *ruby_to_mongory_value_deep_rec(mongory_memory_pool *pool,
395
430
  mongory_array *array = mongory_array_new(pool);
396
431
 
397
432
  for (long i = 0; i < RARRAY_LEN(rb_value); i++) {
398
- array->push(array, ruby_to_mongory_value_deep(pool, RARRAY_AREF(rb_value, i)));
433
+ array->push(array, rb_to_mongory_value_deep(pool, RARRAY_AREF(rb_value, i)));
399
434
  }
400
435
  mg_value = mongory_value_wrap_a(pool, array);
401
436
  break;
@@ -417,7 +452,7 @@ static mongory_value *ruby_to_mongory_value_deep_rec(mongory_memory_pool *pool,
417
452
  break;
418
453
  } else {
419
454
  VALUE converted_value = rb_funcall(inMongoryDataConverter, rb_intern("convert"), 1, rb_value);
420
- mg_value = ruby_to_mongory_value_deep_rec(pool, converted_value, true);
455
+ mg_value = rb_to_mongory_value_deep_rec(pool, converted_value, true);
421
456
  break;
422
457
  }
423
458
  }
@@ -426,13 +461,13 @@ static mongory_value *ruby_to_mongory_value_deep_rec(mongory_memory_pool *pool,
426
461
  }
427
462
 
428
463
  // Deep conversion: Convert Ruby value to mongory_value (fully materialize arrays/tables)
429
- mongory_value *ruby_to_mongory_value_deep(mongory_memory_pool *pool, VALUE rb_value) {
430
- return ruby_to_mongory_value_deep_rec(pool, rb_value, false);
464
+ mongory_value *rb_to_mongory_value_deep(mongory_memory_pool *pool, VALUE rb_value) {
465
+ return rb_to_mongory_value_deep_rec(pool, rb_value, false);
431
466
  }
432
467
 
433
468
  // Get value from Ruby hash via mongory_table
434
- mongory_value *ruby_mongory_table_get(mongory_table *self, char *key) {
435
- ruby_mongory_table_t *table = (ruby_mongory_table_t *)self;
469
+ mongory_value *rb_mongory_table_get(mongory_table *self, char *key) {
470
+ rb_mongory_table_t *table = (rb_mongory_table_t *)self;
436
471
  VALUE rb_hash = table->rb_hash;
437
472
  VALUE rb_value = Qundef;
438
473
 
@@ -449,47 +484,47 @@ mongory_value *ruby_mongory_table_get(mongory_table *self, char *key) {
449
484
  if (rb_value == Qundef) {
450
485
  return NULL;
451
486
  }
452
- return ruby_to_mongory_value_shallow(table->base.pool, rb_value);
487
+ return rb_to_mongory_value_shallow(table->base.pool, rb_value);
453
488
  }
454
489
 
455
490
  // Shallow conversion: Wrap Ruby hash as mongory_table
456
- mongory_value *ruby_mongory_table_wrap(mongory_memory_pool *pool, VALUE rb_hash) {
457
- ruby_mongory_table_t *table = MG_ALLOC_PTR(pool, ruby_mongory_table_t);
458
- ruby_mongory_memory_pool_t *rb_pool = (ruby_mongory_memory_pool_t *)pool;
491
+ mongory_value *rb_mongory_table_wrap(mongory_memory_pool *pool, VALUE rb_hash) {
492
+ rb_mongory_table_t *table = MG_ALLOC_PTR(pool, rb_mongory_table_t);
493
+ rb_mongory_memory_pool_t *rb_pool = (rb_mongory_memory_pool_t *)pool;
459
494
  table->base.pool = pool;
460
- table->base.get = ruby_mongory_table_get;
495
+ table->base.get = rb_mongory_table_get;
461
496
  table->rb_hash = rb_hash;
462
497
  table->base.count = RHASH_SIZE(rb_hash);
463
498
  table->owner = rb_pool->owner;
464
499
  mongory_value *mg_value = mongory_value_wrap_t(pool, &table->base);
465
500
  mg_value->origin = (void *)rb_hash;
466
- mg_value->to_str = ruby_mongory_value_to_cstr;
501
+ mg_value->to_str = rb_mongory_value_to_cstr;
467
502
  return mg_value;
468
503
  }
469
504
 
470
505
  // Get value from Ruby array via mongory_array
471
- static mongory_value *ruby_mongory_array_get(mongory_array *self, size_t index) {
472
- ruby_mongory_array_t *array = (ruby_mongory_array_t *)self;
506
+ static mongory_value *rb_mongory_array_get(mongory_array *self, size_t index) {
507
+ rb_mongory_array_t *array = (rb_mongory_array_t *)self;
473
508
  VALUE rb_array = array->rb_array;
474
509
  if (index >= (size_t)RARRAY_LEN(rb_array)) {
475
510
  return NULL;
476
511
  }
477
512
  VALUE rb_value = rb_ary_entry(rb_array, index);
478
- return ruby_to_mongory_value_shallow(self->pool, rb_value);
513
+ return rb_to_mongory_value_shallow(self->pool, rb_value);
479
514
  }
480
515
 
481
516
  // Shallow conversion: Wrap Ruby array as mongory_array
482
- mongory_value *ruby_mongory_array_wrap(mongory_memory_pool *pool, VALUE rb_array) {
483
- ruby_mongory_array_t *array = MG_ALLOC_PTR(pool, ruby_mongory_array_t);
484
- ruby_mongory_memory_pool_t *rb_pool = (ruby_mongory_memory_pool_t *)pool;
517
+ mongory_value *rb_mongory_array_wrap(mongory_memory_pool *pool, VALUE rb_array) {
518
+ rb_mongory_array_t *array = MG_ALLOC_PTR(pool, rb_mongory_array_t);
519
+ rb_mongory_memory_pool_t *rb_pool = (rb_mongory_memory_pool_t *)pool;
485
520
  array->base.pool = pool;
486
- array->base.get = ruby_mongory_array_get;
521
+ array->base.get = rb_mongory_array_get;
487
522
  array->rb_array = rb_array;
488
523
  array->base.count = RARRAY_LEN(rb_array);
489
524
  array->owner = rb_pool->owner;
490
525
  mongory_value *mg_value = mongory_value_wrap_a(pool, &array->base);
491
526
  mg_value->origin = (void *)rb_array;
492
- mg_value->to_str = ruby_mongory_value_to_cstr;
527
+ mg_value->to_str = rb_mongory_value_to_cstr;
493
528
  return mg_value;
494
529
  }
495
530
 
@@ -502,7 +537,7 @@ void *mongory_value_to_ruby(mongory_memory_pool *pool, mongory_value *value) {
502
537
  }
503
538
 
504
539
  // ===== Cache helper implementations =====
505
- static VALUE cache_fetch_string(ruby_mongory_matcher_t *owner, const char *key) {
540
+ static VALUE cache_fetch_string(rb_mongory_matcher_t *owner, const char *key) {
506
541
  if (!owner || !owner->string_map) return rb_utf8_str_new_cstr(key);
507
542
  mongory_value *v = owner->string_map->get(owner->string_map, (char *)key);
508
543
  if (v && v->origin) return (VALUE)v->origin;
@@ -522,7 +557,7 @@ static inline VALUE char_key_to_symbol(const char *key, rb_encoding *enc) {
522
557
  }
523
558
 
524
559
  // Cache helper for Ruby symbol keys
525
- static VALUE cache_fetch_symbol(ruby_mongory_matcher_t *owner, const char *key) {
560
+ static VALUE cache_fetch_symbol(rb_mongory_matcher_t *owner, const char *key) {
526
561
  rb_encoding *enc = rb_utf8_encoding();
527
562
  if (!owner || !owner->symbol_map) {
528
563
  return char_key_to_symbol(key, enc);
@@ -538,7 +573,7 @@ static VALUE cache_fetch_symbol(ruby_mongory_matcher_t *owner, const char *key)
538
573
  }
539
574
 
540
575
  // Regex adapter bridging to Ruby's Regexp
541
- static bool ruby_regex_match_adapter(mongory_memory_pool *pool, mongory_value *pattern, mongory_value *value) {
576
+ static bool rb_mongory_regex_match_adapter(mongory_memory_pool *pool, mongory_value *pattern, mongory_value *value) {
542
577
  if (!pattern || !value) {
543
578
  return false;
544
579
  }
@@ -565,7 +600,7 @@ static bool ruby_regex_match_adapter(mongory_memory_pool *pool, mongory_value *p
565
600
  }
566
601
 
567
602
  // Regex adapter bridging to Ruby's Regexp
568
- static char *ruby_regex_stringify_adapter(mongory_memory_pool *pool, mongory_value *pattern) {
603
+ static char *rb_mongory_regex_stringify_adapter(mongory_memory_pool *pool, mongory_value *pattern) {
569
604
  (void)pool;
570
605
  if (pattern->type != MONGORY_TYPE_REGEX) {
571
606
  return NULL;
@@ -576,10 +611,10 @@ static char *ruby_regex_stringify_adapter(mongory_memory_pool *pool, mongory_val
576
611
  }
577
612
 
578
613
  // Custom matcher adapter bridging to Ruby's custom matcher
579
- static mongory_matcher_custom_context *ruby_custom_matcher_build(char *key, mongory_value *condition, void *ctx) {
614
+ static mongory_matcher_custom_context *rb_mongory_custom_matcher_build(char *key, mongory_value *condition, void *ctx) {
580
615
  mongory_memory_pool *pool = condition->pool;
581
- ruby_mongory_memory_pool_t *rb_pool = (ruby_mongory_memory_pool_t *)pool;
582
- ruby_mongory_matcher_t *owner = rb_pool->owner;
616
+ rb_mongory_memory_pool_t *rb_pool = (rb_mongory_memory_pool_t *)pool;
617
+ rb_mongory_matcher_t *owner = rb_pool->owner;
583
618
  VALUE matcher_class = rb_funcall(mMongoryMatchers, rb_intern("lookup"), 1, cache_fetch_string(owner, key));
584
619
  if (matcher_class == Qnil) {
585
620
  return NULL;
@@ -611,24 +646,23 @@ static mongory_matcher_custom_context *ruby_custom_matcher_build(char *key, mong
611
646
  }
612
647
 
613
648
  // Custom matcher adapter bridging to Ruby's custom matcher
614
- static bool ruby_custom_matcher_match(void *ruby_matcher, mongory_value *value) {
649
+ static bool rb_mongory_custom_matcher_match(void *ruby_matcher, mongory_value *value) {
615
650
  VALUE matcher = (VALUE)ruby_matcher;
616
651
  VALUE match_result = rb_funcall(matcher, rb_intern("match?"), 1, value->origin);
617
652
  return RTEST(match_result);
618
653
  }
619
654
 
620
655
  // Custom matcher adapter bridging to Ruby's custom matcher
621
- static bool ruby_custom_matcher_lookup(char *key) {
656
+ static bool rb_mongory_custom_matcher_lookup(char *key) {
622
657
  VALUE matcher_class = rb_funcall(mMongoryMatchers, rb_intern("lookup"), 1, rb_str_new_cstr(key));
623
658
  return RTEST(matcher_class);
624
659
  }
625
660
 
626
661
  // Error handling for mongory_memory_pool
627
- static bool mongory_error_handling(mongory_memory_pool *pool, char *error_message) {
662
+ static bool rb_mongory_error_handling(mongory_memory_pool *pool, char *error_message) {
628
663
  if (pool->error) {
629
664
  rb_raise(eMongoryTypeError, "%s: %s", error_message, pool->error->message);
630
665
  pool->error = NULL;
631
- pool->reset(pool);
632
666
  return true;
633
667
  }
634
668
  return false;
@@ -656,28 +690,28 @@ void Init_mongory_ext(void) {
656
690
  eMongoryTypeError = rb_define_class_under(mMongory, "TypeError", eMongoryError);
657
691
 
658
692
  // Define Matcher methods
659
- rb_define_singleton_method(cMongoryMatcher, "new", ruby_mongory_matcher_new, -1);
660
- rb_define_singleton_method(cMongoryMatcher, "trace_result_colorful=", ruby_mongory_matcher_trace_result_colorful, 1);
661
- rb_define_method(cMongoryMatcher, "match?", ruby_mongory_matcher_match, 1);
662
- rb_define_method(cMongoryMatcher, "explain", ruby_mongory_matcher_explain, 0);
663
- rb_define_method(cMongoryMatcher, "condition", ruby_mongory_matcher_condition, 0);
664
- rb_define_method(cMongoryMatcher, "context", ruby_mongory_matcher_context, 0);
665
- rb_define_method(cMongoryMatcher, "trace", ruby_mongory_matcher_trace, 1);
666
- rb_define_method(cMongoryMatcher, "enable_trace", ruby_mongory_matcher_enable_trace, 0);
667
- rb_define_method(cMongoryMatcher, "disable_trace", ruby_mongory_matcher_disable_trace, 0);
668
- rb_define_method(cMongoryMatcher, "print_trace", ruby_mongory_matcher_print_trace, 0);
693
+ rb_define_singleton_method(cMongoryMatcher, "new", rb_mongory_matcher_new, -1);
694
+ rb_define_singleton_method(cMongoryMatcher, "trace_result_colorful=", rb_mongory_matcher_trace_result_colorful, 1);
695
+ rb_define_method(cMongoryMatcher, "match?", rb_mongory_matcher_match, 1);
696
+ rb_define_method(cMongoryMatcher, "explain", rb_mongory_matcher_explain, 0);
697
+ rb_define_method(cMongoryMatcher, "condition", rb_mongory_matcher_condition, 0);
698
+ rb_define_method(cMongoryMatcher, "context", rb_mongory_matcher_context, 0);
699
+ rb_define_method(cMongoryMatcher, "trace", rb_mongory_matcher_trace, 1);
700
+ rb_define_method(cMongoryMatcher, "enable_trace", rb_mongory_matcher_enable_trace, 0);
701
+ rb_define_method(cMongoryMatcher, "disable_trace", rb_mongory_matcher_disable_trace, 0);
702
+ rb_define_method(cMongoryMatcher, "print_trace", rb_mongory_matcher_print_trace, 0);
669
703
 
670
704
  // Set regex adapter to use Ruby's Regexp
671
- mongory_regex_func_set(ruby_regex_match_adapter);
672
- mongory_regex_stringify_func_set(ruby_regex_stringify_adapter);
705
+ mongory_regex_func_set(rb_mongory_regex_match_adapter);
706
+ mongory_regex_stringify_func_set(rb_mongory_regex_stringify_adapter);
673
707
 
674
708
  // Set value converter functions
675
- mongory_value_converter_deep_convert_set(ruby_to_mongory_value_deep);
676
- mongory_value_converter_shallow_convert_set(ruby_to_mongory_value_shallow);
709
+ mongory_value_converter_deep_convert_set(rb_to_mongory_value_deep);
710
+ mongory_value_converter_shallow_convert_set(rb_to_mongory_value_shallow);
677
711
  mongory_value_converter_recover_set(mongory_value_to_ruby);
678
712
 
679
713
  // Set custom matcher adapter
680
- mongory_custom_matcher_match_func_set(ruby_custom_matcher_match);
681
- mongory_custom_matcher_build_func_set(ruby_custom_matcher_build);
682
- mongory_custom_matcher_lookup_func_set(ruby_custom_matcher_lookup);
714
+ mongory_custom_matcher_match_func_set(rb_mongory_custom_matcher_match);
715
+ mongory_custom_matcher_build_func_set(rb_mongory_custom_matcher_build);
716
+ mongory_custom_matcher_lookup_func_set(rb_mongory_custom_matcher_lookup);
683
717
  }
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongory
4
+ # This class is the C extension of Mongory::QueryMatcher.
5
+ # It is used to match records using the C extension.
6
+ # @example
7
+ # matcher = Mongory::CMatcher.new(condition)
8
+ # matcher.match?(record) #=> true
9
+ # # or
10
+ # collection.mongory.c.where(condition).to_a
11
+ class CMatcher
12
+ # @!method self.new(condition)
13
+ # @param condition [Object] the condition
14
+ # @return [Mongory::CMatcher] a new matcher
15
+ # @note This method is implemented in the C extension
16
+ #
17
+ # @!method match?(record)
18
+ # @param record [Object] the record to match against
19
+ # @return [Boolean] true if the record matches the condition, false otherwise
20
+ # @note This method is implemented in the C extension
21
+ # @!method explain
22
+ # @return [void]
23
+ # @note This method will print metcher tree structure
24
+ # @note This method is implemented in the C extension
25
+ # @!method trace
26
+ # @return [Boolean] true if the record matches the condition, false otherwise
27
+ # @note This method will print matching process
28
+ # @note This method is implemented in the C extension
29
+ # @!method enable_trace
30
+ # @return [void]
31
+ # @note This method will enable trace
32
+ # @note This method is implemented in the C extension
33
+ # @!method disable_trace
34
+ # @return [void]
35
+ # @note This method will disable trace
36
+ # @note This method is implemented in the C extension
37
+ # @!method print_trace
38
+ # @return [void]
39
+ # @note This method will print trace result
40
+ # @note This method is implemented in the C extension
41
+ # @!method condition
42
+ # @return [Object] the condition
43
+ # @note This method is implemented in the C extension
44
+ # @!method context
45
+ # @return [Utils::Context] the context
46
+ # @note This method is implemented in the C extension
47
+ # @!method trace_result_colorful=
48
+ # @param colorful [Boolean] whether to enable colorful trace result
49
+ # @return [Boolean]
50
+ # @note This method is implemented in the C extension
51
+
52
+ # @return [Proc] a Proc that performs the matching operation
53
+ def to_proc
54
+ Proc.new { |record| match?(record) }
55
+ end
56
+ end
57
+ end
@@ -65,10 +65,27 @@ module Mongory
65
65
  @matcher.prepare_query
66
66
  matcher_block = @matcher.to_proc
67
67
  @records.each do |record|
68
+ @context.current_record = record
68
69
  yield record if matcher_block.call(record)
69
70
  end
70
71
  end
71
72
 
73
+ def trace
74
+ return to_enum(:trace) unless block_given?
75
+
76
+ Mongory.debugger.enable
77
+ @matcher.prepare_query
78
+ @records.each do |record|
79
+ @context.current_record = record
80
+ matched = @matcher.match?(record)
81
+ Mongory.debugger.display
82
+ yield record if matched
83
+ Mongory.debugger.clear
84
+ end
85
+ ensure
86
+ Mongory.debugger.disable
87
+ end
88
+
72
89
  # Adds a condition to filter records using the given condition.
73
90
  # This is an alias for `and`.
74
91
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mongory
4
- VERSION = '0.7.8'
4
+ VERSION = '0.8.0'
5
5
  end
data/lib/mongory.rb CHANGED
@@ -120,6 +120,7 @@ begin
120
120
  abi = RUBY_VERSION.split('.').first(2).join('.')
121
121
  require "core/#{abi}/mongory_ext"
122
122
  require_relative 'mongory/c_query_builder'
123
+ require_relative 'mongory/c_matcher'
123
124
  rescue LoadError => e
124
125
  warn("Mongory C extension is disabled because mongory_ext is not loaded: #{e.message}")
125
126
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.8
4
+ version: 0.8.0
5
5
  platform: x64-mingw-ucrt
6
6
  authors:
7
7
  - koten0224
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-08-27 00:00:00.000000000 Z
11
+ date: 2025-08-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Mongo-like in-memory query DSL for Ruby
14
14
  email:
@@ -88,6 +88,7 @@ files:
88
88
  - lib/generators/mongory/matcher/templates/matcher.rb.erb
89
89
  - lib/generators/mongory/matcher/templates/matcher_spec.rb.erb
90
90
  - lib/mongory.rb
91
+ - lib/mongory/c_matcher.rb
91
92
  - lib/mongory/c_query_builder.rb
92
93
  - lib/mongory/converters.rb
93
94
  - lib/mongory/converters/abstract_converter.rb