oj-introspect 0.3.0 → 0.5.0

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: dba2633765040e6c57bc0efb529d6a28d955d4b58ec2643ac5957b4677602692
4
- data.tar.gz: 208ae9e552fbce05eec0769634f7c45d463c202f621d8b10182afa17e481a021
3
+ metadata.gz: 0a72b92485dbfef2a4b2fe110e3209d277c1cb98a356648d5c37d65015906b1b
4
+ data.tar.gz: 9d8047afdd2b9434fd257f05eb3bafef180c57a3b7c8e5a873bdf954dfd2dfab
5
5
  SHA512:
6
- metadata.gz: b41e516970c5dd6f15ad478e4fd0d179e40bbd361f1577354c8ff3066e06cc8d06e1414561d048257a2b6c3a48b65037573227079691b00bed5bf1f265b31a25
7
- data.tar.gz: 2ded4748797fb9f87fec3fa9c7fed0a2b4b2ea38539aee5d085a15fea2631bc3f33a69e21f10950dc7233f631c106172a29eb961f03111221b501776ac44d8b6
6
+ metadata.gz: 42c8c6afb2256ae41a156892379fa8535f3944f457105db6d6f6b1581008dccc2ba76e413eef725428ea70d384b69ae3d6a8657d745a3eedda7997d1da13910a
7
+ data.tar.gz: 12446b7a5f18442a2dd7695823b08ebe331a71d707583342f8b9d7034a0acef529df8368cf490b2928da6ae4d31f673783075b3a24d3f302b6dbe8aab34a8db9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oj-introspect (0.3.0)
4
+ oj-introspect (0.5.0)
5
5
  oj (>= 3.13.22)
6
6
 
7
7
  GEM
data/bin/benchmark CHANGED
@@ -5,16 +5,21 @@ require "oj/introspect"
5
5
  require "json"
6
6
  require "benchmark/ips"
7
7
 
8
- TEST_JSON = '{ "foo": "bar" }'
8
+ TEST_JSON = File.read("./spec/fixtures/vulnerabilities.json")
9
9
 
10
10
  INTROSPECT_PARSER = Oj::Parser.introspect
11
+ FILTERED_INTROSPECT_PARSER = Oj::Introspect.new(filter: "remediations")
11
12
  USUAL_PARSER = Oj::Parser.usual
12
13
 
13
14
  Benchmark.ips do |b|
14
- b.report("Introspected") do
15
+ b.report("Introspect") do
15
16
  INTROSPECT_PARSER.parse(TEST_JSON)
16
17
  end
17
18
 
19
+ b.report("Filtered introspect") do
20
+ FILTERED_INTROSPECT_PARSER.parse(TEST_JSON)
21
+ end
22
+
18
23
  b.report("Oj usual") do
19
24
  USUAL_PARSER.parse(TEST_JSON)
20
25
  end
@@ -9,4 +9,4 @@ OJ_HEADERS = oj_version_file_path.join('..', '..', '..', 'ext', 'oj').to_s
9
9
 
10
10
  dir_config('oj', [OJ_HEADERS], [])
11
11
 
12
- create_makefile("oj-introspect/introspect_ext")
12
+ create_makefile("oj/introspect/introspect_ext")
@@ -16,16 +16,22 @@ typedef struct _introspect_S {
16
16
  struct _usual usual; // inherit all the attributes from `_usual` struct
17
17
  struct _byte_offsets byte_offsets; // I think it's better to encapsulate common fields under a namespace
18
18
 
19
+ char *filter;
20
+ bool introspect;
21
+
19
22
  void (*delegated_start_func)(struct _ojParser *p);
20
23
  void (*delegated_free_func)(struct _ojParser *p);
24
+ VALUE (*delegated_option_func)(struct _ojParser *p, const char *key, VALUE value);
21
25
  void (*delegated_open_object_func)(struct _ojParser *p);
22
26
  void (*delegated_open_object_key_func)(struct _ojParser *p);
27
+ void (*delegated_open_array_key_func)(struct _ojParser *p);
23
28
  void (*delegated_close_object_func)(struct _ojParser *p);
24
- } *IntrospectDelegate;
29
+ } * IntrospectDelegate;
25
30
 
26
31
  static void dfree(ojParser p) {
27
32
  IntrospectDelegate d = (IntrospectDelegate)p->ctx;
28
33
 
34
+ if(d->filter != NULL) xfree(d->filter);
29
35
  xfree(d->byte_offsets.stack);
30
36
  d->delegated_free_func(p);
31
37
  }
@@ -36,6 +42,31 @@ static void start(ojParser p) {
36
42
  d->delegated_start_func(p);
37
43
  // Reset to zero so the parser and delegate can be reused.
38
44
  d->byte_offsets.current = 0;
45
+
46
+ /*
47
+ * If the `filter` is provided we will start introspecting later
48
+ * once we encounter with the key provided.
49
+ */
50
+ d->introspect = (d->filter == NULL);
51
+ }
52
+
53
+ static void copy_ruby_str(char **target, VALUE source) {
54
+ size_t len = RSTRING_LEN(source);
55
+ *target = ALLOC_N(char, len + 1);
56
+ memcpy(*target, RSTRING_PTR(source), len);
57
+ (*target)[len] = '\0'; // Parantheses are important as it means => (*target + sizeof(char) * len)
58
+ }
59
+
60
+ static VALUE option(ojParser p, const char *key, VALUE value) {
61
+ IntrospectDelegate d = (IntrospectDelegate)p->ctx;
62
+
63
+ if(strcmp(key, "filter=") == 0) {
64
+ copy_ruby_str(&d->filter, value); // We need to copy the value as GC can free it later.
65
+
66
+ return Qtrue;
67
+ }
68
+
69
+ return d->delegated_option_func(p, key, value);
39
70
  }
40
71
 
41
72
  static void ensure_byte_offsets_stack(IntrospectDelegate d) {
@@ -65,16 +96,56 @@ static void open_object_introspected(ojParser p) {
65
96
  d->delegated_open_object_func(p);
66
97
  }
67
98
 
99
+ static char * previously_inserted_key(IntrospectDelegate d) {
100
+ Key key = (d->usual.ktail - 1);
101
+
102
+ return ((size_t)key->len < sizeof(key->buf)) ? key->buf : key->key;
103
+ }
104
+
105
+ static bool should_switch_introspection(IntrospectDelegate d) {
106
+ return strcmp(d->filter, previously_inserted_key(d)) == 0;
107
+ }
108
+
109
+ /*
110
+ * WHEN there is a filter
111
+ * AND
112
+ * WHEN the introspection is disabled
113
+ * AND the last inserted key matches the filter
114
+ * THEN enable introspection
115
+ * OR
116
+ * WHEN the introspection is enabled
117
+ * AND the last inserted key matches the filter
118
+ * THEN disable introspection
119
+ */
120
+ static void switch_introspection(IntrospectDelegate d) {
121
+ if(d->filter == NULL) return;
122
+
123
+ d->introspect = should_switch_introspection(d) != d->introspect; // a XOR b
124
+ }
125
+
68
126
  static void open_object_key_introspected(ojParser p) {
69
127
  push(p);
70
128
 
71
129
  IntrospectDelegate d = (IntrospectDelegate)p->ctx;
72
130
  d->delegated_open_object_key_func(p);
131
+
132
+ if(!d->introspect) switch_introspection(d);
133
+ }
134
+
135
+ static void open_array_key_introspected(ojParser p) {
136
+ IntrospectDelegate d = (IntrospectDelegate)p->ctx;
137
+ d->delegated_open_array_key_func(p);
138
+
139
+ if(!d->introspect) switch_introspection(d);
73
140
  }
74
141
 
75
142
  static void set_introspection_values(ojParser p) {
76
143
  IntrospectDelegate d = (IntrospectDelegate)p->ctx;
77
144
 
145
+ if(!d->introspect) return;
146
+
147
+ switch_introspection(d);
148
+
78
149
  volatile VALUE obj = rb_hash_new();
79
150
  rb_hash_aset(obj, ID2SYM(rb_intern("start_byte")), INT2FIX(pop(p)));
80
151
  rb_hash_aset(obj, ID2SYM(rb_intern("end_byte")), INT2FIX(p->cur));
@@ -100,6 +171,9 @@ static void init_introspect_parser(ojParser p, VALUE ropts) {
100
171
  d->delegated_start_func = p->start;
101
172
  p->start = start;
102
173
 
174
+ d->delegated_option_func = p->option;
175
+ p->option = option;
176
+
103
177
  // We are cheating with the mark, free, and options functions. Since struct
104
178
  // _usual is the first member of struct _introspect the cast to Usual in the
105
179
  // usual.c mark() function should still work just fine.
@@ -117,7 +191,9 @@ static void init_introspect_parser(ojParser p, VALUE ropts) {
117
191
  f->close_object = close_object_introspected;
118
192
 
119
193
  f = &p->funcs[OBJECT_FUN];
194
+ d->delegated_open_array_key_func = f->open_array;
120
195
  d->delegated_open_object_key_func = f->open_object;
196
+ f->open_array = open_array_key_introspected;
121
197
  f->open_object = open_object_key_introspected;
122
198
  f->close_object = close_object_introspected;
123
199
 
@@ -126,6 +202,8 @@ static void init_introspect_parser(ojParser p, VALUE ropts) {
126
202
  d->byte_offsets.stack = ALLOC_N(long, BYTE_OFFSETS_STACK_INC_SIZE);
127
203
  d->byte_offsets.length = BYTE_OFFSETS_STACK_INC_SIZE;
128
204
 
205
+ d->filter = NULL;
206
+
129
207
  // Process options.
130
208
  oj_parser_set_option(p, ropts);
131
209
  }
@@ -1,5 +1,5 @@
1
1
  module Oj
2
2
  class Introspect
3
- VERSION = "0.3.0"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oj-introspect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mehmet Emin INAC
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-02 00:00:00.000000000 Z
11
+ date: 2022-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj