ree_lib 1.0.63 → 1.0.65
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/ree_lib/packages/ree_dao/package/ree_dao/association.rb +55 -32
- data/lib/ree_lib/packages/ree_dao/package/ree_dao/associations.rb +21 -13
- data/lib/ree_lib/packages/ree_dao/spec/ree_dao/functions/load_agg/load_agg_benchmark_spec.rb +2 -0
- data/lib/ree_lib/packages/ree_dao/spec/ree_dao/functions/load_agg/load_agg_spec.rb +89 -3
- data/lib/ree_lib/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6a080727db9b2998d5e983aa2e024fd73833e6b98deb2f75eb8ac8309af1c6b
|
4
|
+
data.tar.gz: b96cc24d1df8586e8159e96c7545017ecab7009a01bd5b9a2b9c759fb1beeddd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1a8e3c1d0471a58cb3dd4602a83a8da2f30498e4af39f9ade709a256592d8f3a6ef6c58a14a8fff1c3f865d9508c49e5673d4bbbe8d0ddbe95fa5dd37074695
|
7
|
+
data.tar.gz: 34e1a0221ad4040a469082111c63687903e6e5d6a89d25c8ada10f742efbd6774e0e8bc729c251670a5ef293b4917dfebe3c701be6155f84241a4a651d952b9c
|
data/Gemfile.lock
CHANGED
@@ -2,9 +2,10 @@ module ReeDao
|
|
2
2
|
class Association
|
3
3
|
include Ree::LinkDSL
|
4
4
|
|
5
|
+
link :demodulize, from: :ree_string
|
5
6
|
link :group_by, from: :ree_array
|
6
7
|
link :index_by, from: :ree_array
|
7
|
-
link :
|
8
|
+
link :underscore, from: :ree_string
|
8
9
|
|
9
10
|
attr_reader :parent, :parent_dao_name, :list, :global_opts
|
10
11
|
|
@@ -22,8 +23,8 @@ module ReeDao
|
|
22
23
|
Ksplat[RestKeys => Any],
|
23
24
|
Optblock => Array
|
24
25
|
)
|
25
|
-
def load(assoc_type, assoc_name, **
|
26
|
-
load_association(assoc_type, assoc_name, **
|
26
|
+
def load(assoc_type, assoc_name, **__opts, &block)
|
27
|
+
load_association(assoc_type, assoc_name, **__opts, &block)
|
27
28
|
end
|
28
29
|
|
29
30
|
def handle_field(field_proc)
|
@@ -36,19 +37,30 @@ module ReeDao
|
|
36
37
|
Ksplat[RestKeys => Any],
|
37
38
|
Optblock => Nilor[Array]
|
38
39
|
)
|
39
|
-
def load_association(assoc_type, assoc_name, **
|
40
|
-
|
40
|
+
def load_association(assoc_type, assoc_name, **__opts, &block)
|
41
|
+
__opts[:autoload_children] ||= false
|
41
42
|
|
42
43
|
assoc_index = load_association_by_type(
|
43
44
|
assoc_type,
|
44
45
|
assoc_name,
|
45
|
-
**
|
46
|
+
**__opts
|
46
47
|
)
|
47
48
|
|
48
|
-
dao = find_dao(assoc_name, parent,
|
49
|
-
dao_name = dao.first_source_table
|
49
|
+
dao = find_dao(assoc_name, parent, __opts[:scope])
|
50
50
|
|
51
|
-
|
51
|
+
dao_name = if dao
|
52
|
+
dao.first_source_table
|
53
|
+
elsif __opts[:scope].is_a?(Array)
|
54
|
+
name = underscore(demodulize(__opts[:scope].first.class.name))
|
55
|
+
|
56
|
+
if name.end_with?("s")
|
57
|
+
"#{name}es"
|
58
|
+
else
|
59
|
+
"#{name}s"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
process_block(assoc_index, __opts[:autoload_children], __opts[:to_dto], dao_name, &block) if block_given?
|
52
64
|
|
53
65
|
list
|
54
66
|
end
|
@@ -58,17 +70,17 @@ module ReeDao
|
|
58
70
|
Symbol,
|
59
71
|
Ksplat[RestKeys => Any] => Any
|
60
72
|
)
|
61
|
-
def load_association_by_type(type, assoc_name, **
|
73
|
+
def load_association_by_type(type, assoc_name, **__opts)
|
62
74
|
case type
|
63
75
|
when :belongs_to
|
64
76
|
one_to_one(
|
65
77
|
parent_dao_name,
|
66
78
|
assoc_name,
|
67
79
|
list,
|
68
|
-
scope:
|
69
|
-
primary_key:
|
70
|
-
foreign_key:
|
71
|
-
setter:
|
80
|
+
scope: __opts[:scope],
|
81
|
+
primary_key: __opts[:primary_key],
|
82
|
+
foreign_key: __opts[:foreign_key],
|
83
|
+
setter: __opts[:setter],
|
72
84
|
reverse: false
|
73
85
|
)
|
74
86
|
when :has_one
|
@@ -76,11 +88,11 @@ module ReeDao
|
|
76
88
|
parent_dao_name,
|
77
89
|
assoc_name,
|
78
90
|
list,
|
79
|
-
scope:
|
80
|
-
primary_key:
|
81
|
-
foreign_key:
|
82
|
-
to_dto:
|
83
|
-
setter:
|
91
|
+
scope: __opts[:scope],
|
92
|
+
primary_key: __opts[:primary_key],
|
93
|
+
foreign_key: __opts[:foreign_key],
|
94
|
+
to_dto: __opts[:to_dto],
|
95
|
+
setter: __opts[:setter],
|
84
96
|
reverse: true
|
85
97
|
)
|
86
98
|
when :has_many
|
@@ -88,11 +100,11 @@ module ReeDao
|
|
88
100
|
parent_dao_name,
|
89
101
|
assoc_name,
|
90
102
|
list,
|
91
|
-
scope:
|
92
|
-
primary_key:
|
93
|
-
foreign_key:
|
94
|
-
to_dto:
|
95
|
-
setter:
|
103
|
+
scope: __opts[:scope],
|
104
|
+
primary_key: __opts[:primary_key],
|
105
|
+
foreign_key: __opts[:foreign_key],
|
106
|
+
to_dto: __opts[:to_dto],
|
107
|
+
setter: __opts[:setter]
|
96
108
|
)
|
97
109
|
end
|
98
110
|
end
|
@@ -125,9 +137,9 @@ module ReeDao
|
|
125
137
|
autoload_children,
|
126
138
|
**global_opts
|
127
139
|
).instance_exec(assoc_list, &block)
|
128
|
-
threads[:association_threads].map do |association, assoc_type, assoc_name,
|
140
|
+
threads[:association_threads].map do |association, assoc_type, assoc_name, __opts, block|
|
129
141
|
Thread.new do
|
130
|
-
association.load(assoc_type, assoc_name, **
|
142
|
+
association.load(assoc_type, assoc_name, **__opts, &block)
|
131
143
|
end
|
132
144
|
end.map(&:join)
|
133
145
|
|
@@ -163,12 +175,14 @@ module ReeDao
|
|
163
175
|
assoc_dao = find_dao(assoc_name, parent, scope)
|
164
176
|
|
165
177
|
if reverse
|
178
|
+
# has_one
|
166
179
|
if !foreign_key
|
167
180
|
foreign_key = "#{parent_assoc_name.to_s.gsub(/s$/,'')}_id".to_sym
|
168
181
|
end
|
169
182
|
|
170
183
|
root_ids = list.map(&:id).uniq
|
171
184
|
else
|
185
|
+
# belongs_to
|
172
186
|
if !foreign_key
|
173
187
|
foreign_key = :"#{assoc_name}_id"
|
174
188
|
end
|
@@ -182,7 +196,6 @@ module ReeDao
|
|
182
196
|
items = add_scopes(scope, global_opts[assoc_name])
|
183
197
|
end
|
184
198
|
|
185
|
-
|
186
199
|
assoc = index_by(items) { _1.send(reverse ? foreign_key : :id) }
|
187
200
|
|
188
201
|
populate_association(
|
@@ -192,6 +205,7 @@ module ReeDao
|
|
192
205
|
setter: setter,
|
193
206
|
reverse: reverse,
|
194
207
|
primary_key: primary_key,
|
208
|
+
foreign_key: foreign_key,
|
195
209
|
to_dto: to_dto
|
196
210
|
)
|
197
211
|
|
@@ -243,6 +257,7 @@ module ReeDao
|
|
243
257
|
assoc_name,
|
244
258
|
setter: setter,
|
245
259
|
primary_key: primary_key,
|
260
|
+
foreign_key: foreign_key,
|
246
261
|
to_dto: to_dto,
|
247
262
|
multiple: true
|
248
263
|
)
|
@@ -256,13 +271,14 @@ module ReeDao
|
|
256
271
|
Symbol,
|
257
272
|
Kwargs[
|
258
273
|
primary_key: Nilor[Symbol],
|
274
|
+
foreign_key: Nilor[Symbol],
|
259
275
|
reverse: Nilor[Bool],
|
260
276
|
setter: Nilor[Or[Symbol, Proc]],
|
261
277
|
to_dto: Nilor[Proc],
|
262
278
|
multiple: Bool
|
263
279
|
] => Any
|
264
280
|
)
|
265
|
-
def populate_association(list, association_index, assoc_name, primary_key: nil, reverse: nil, setter: nil, to_dto: nil, multiple: false)
|
281
|
+
def populate_association(list, association_index, assoc_name, primary_key: nil, foreign_key: nil, reverse: nil, setter: nil, to_dto: nil, multiple: false)
|
266
282
|
assoc_setter = if setter
|
267
283
|
setter
|
268
284
|
else
|
@@ -272,11 +288,13 @@ module ReeDao
|
|
272
288
|
list.each do |item|
|
273
289
|
if setter && setter.is_a?(Proc)
|
274
290
|
if to_dto
|
275
|
-
assoc_index =
|
291
|
+
assoc_index = {}
|
292
|
+
|
293
|
+
association_index.each do |key, value|
|
276
294
|
if value.is_a?(Array)
|
277
|
-
value.map { to_dto.call(_1) }
|
295
|
+
assoc_index[key] = value.map { to_dto.call(_1) }
|
278
296
|
else
|
279
|
-
to_dto.call(value)
|
297
|
+
assoc_index[key] = to_dto.call(value)
|
280
298
|
end
|
281
299
|
end
|
282
300
|
|
@@ -288,7 +306,11 @@ module ReeDao
|
|
288
306
|
key = if reverse.nil?
|
289
307
|
primary_key
|
290
308
|
else
|
291
|
-
reverse
|
309
|
+
if reverse
|
310
|
+
primary_key
|
311
|
+
else
|
312
|
+
foreign_key ? foreign_key : "#{assoc_name}_id"
|
313
|
+
end
|
292
314
|
end
|
293
315
|
|
294
316
|
value = association_index[item.send(key)]
|
@@ -328,6 +350,7 @@ module ReeDao
|
|
328
350
|
return dao_from_name if dao_from_name
|
329
351
|
|
330
352
|
raise ArgumentError, "can't find DAO for :#{assoc_name}, provide correct scope or association name" if scope.nil?
|
353
|
+
return nil if scope.is_a?(Array)
|
331
354
|
|
332
355
|
table_name = scope.first_source_table
|
333
356
|
dao_from_scope = parent.instance_variable_get("@#{table_name}")
|
@@ -14,8 +14,13 @@ module ReeDao
|
|
14
14
|
@parent_dao_name = parent_dao_name
|
15
15
|
@autoload_children = autoload_children
|
16
16
|
|
17
|
-
|
17
|
+
if @only && @except
|
18
|
+
shared_keys = @only.intersection(@except)
|
18
19
|
|
20
|
+
if shared_keys.size > 0
|
21
|
+
raise ArgumentError.new("you can't use both :only and :except for #{shared_keys.map { "\"#{_1}\"" }.join(", ")} keys")
|
22
|
+
end
|
23
|
+
end
|
19
24
|
|
20
25
|
if !self.class.sync_mode?
|
21
26
|
@assoc_threads = []
|
@@ -40,8 +45,8 @@ module ReeDao
|
|
40
45
|
Nilor[Proc, Sequel::Dataset],
|
41
46
|
Optblock => Any
|
42
47
|
)
|
43
|
-
def belongs_to(assoc_name,
|
44
|
-
association(__method__, assoc_name,
|
48
|
+
def belongs_to(assoc_name, __opts = nil, &block)
|
49
|
+
association(__method__, assoc_name, __opts, &block)
|
45
50
|
end
|
46
51
|
|
47
52
|
contract(
|
@@ -49,8 +54,8 @@ module ReeDao
|
|
49
54
|
Nilor[Proc, Sequel::Dataset],
|
50
55
|
Optblock => Any
|
51
56
|
)
|
52
|
-
def has_one(assoc_name,
|
53
|
-
association(__method__, assoc_name,
|
57
|
+
def has_one(assoc_name, __opts = nil, &block)
|
58
|
+
association(__method__, assoc_name, __opts, &block)
|
54
59
|
end
|
55
60
|
|
56
61
|
contract(
|
@@ -58,8 +63,8 @@ module ReeDao
|
|
58
63
|
Nilor[Proc, Sequel::Dataset],
|
59
64
|
Optblock => Any
|
60
65
|
)
|
61
|
-
def has_many(assoc_name,
|
62
|
-
association(__method__, assoc_name,
|
66
|
+
def has_many(assoc_name, __opts = nil, &block)
|
67
|
+
association(__method__, assoc_name, __opts, &block)
|
63
68
|
end
|
64
69
|
|
65
70
|
contract(Symbol, Proc => Any)
|
@@ -80,16 +85,16 @@ module ReeDao
|
|
80
85
|
Nilor[Proc, Sequel::Dataset],
|
81
86
|
Optblock => Any
|
82
87
|
)
|
83
|
-
def association(assoc_type, assoc_name,
|
88
|
+
def association(assoc_type, assoc_name, __opts, &block)
|
84
89
|
if self.class.sync_mode?
|
85
90
|
return if association_is_not_included?(assoc_name) || list.empty?
|
86
91
|
|
87
92
|
association = Association.new(self, parent_dao_name, list, **global_opts)
|
88
93
|
|
89
94
|
if assoc_type == :field
|
90
|
-
association.handle_field(assoc_name,
|
95
|
+
association.handle_field(assoc_name, __opts)
|
91
96
|
else
|
92
|
-
association.load(assoc_type, assoc_name, **get_assoc_opts(
|
97
|
+
association.load(assoc_type, assoc_name, **get_assoc_opts(__opts), &block)
|
93
98
|
end
|
94
99
|
else
|
95
100
|
if association_is_not_included?(assoc_name) || list.empty?
|
@@ -99,7 +104,7 @@ module ReeDao
|
|
99
104
|
association = Association.new(self, parent_dao_name, list, **global_opts)
|
100
105
|
|
101
106
|
if assoc_type == :field
|
102
|
-
field_proc =
|
107
|
+
field_proc = __opts
|
103
108
|
{
|
104
109
|
association_threads: @assoc_threads,
|
105
110
|
field_threads: @field_threads << [
|
@@ -109,7 +114,7 @@ module ReeDao
|
|
109
114
|
else
|
110
115
|
{
|
111
116
|
association_threads: @assoc_threads << [
|
112
|
-
association, assoc_type, assoc_name, get_assoc_opts(
|
117
|
+
association, assoc_type, assoc_name, get_assoc_opts(__opts), block
|
113
118
|
],
|
114
119
|
field_threads: @field_threads
|
115
120
|
}
|
@@ -125,7 +130,10 @@ module ReeDao
|
|
125
130
|
return false if only && only.include?(assoc_name)
|
126
131
|
|
127
132
|
if only && !only.include?(assoc_name)
|
128
|
-
|
133
|
+
if autoload_children
|
134
|
+
return true if except && except.include?(assoc_name)
|
135
|
+
return false
|
136
|
+
end
|
129
137
|
return true
|
130
138
|
end
|
131
139
|
end
|
@@ -105,7 +105,7 @@ RSpec.describe :load_agg do
|
|
105
105
|
has_one :author
|
106
106
|
has_many :chapters
|
107
107
|
|
108
|
-
has_many :reviews do |reviews_list|
|
108
|
+
has_many :reviews, -> { reviews_opts } do |reviews_list|
|
109
109
|
has_one :review_author
|
110
110
|
|
111
111
|
field :review_calculatetable_field, -> { some_method(reviews_list) }
|
@@ -130,8 +130,8 @@ RSpec.describe :load_agg do
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def some_method(list)
|
133
|
-
puts list.map(&:id)
|
134
|
-
puts list.map { _1.class.name }
|
133
|
+
# puts list.map(&:id)
|
134
|
+
# puts list.map { _1.class.name }
|
135
135
|
end
|
136
136
|
|
137
137
|
def passport_opts
|
@@ -146,6 +146,10 @@ RSpec.describe :load_agg do
|
|
146
146
|
scope: books.where(title: "1984")
|
147
147
|
}
|
148
148
|
end
|
149
|
+
|
150
|
+
def reviews_opts
|
151
|
+
{ autoload_children: true }
|
152
|
+
end
|
149
153
|
end
|
150
154
|
|
151
155
|
class ReeDaoLoadAggTest::UsersAggWithDto
|
@@ -353,6 +357,24 @@ RSpec.describe :load_agg do
|
|
353
357
|
end
|
354
358
|
end
|
355
359
|
|
360
|
+
class ReeDaoLoadAggTest::UsersAggOnlyExceptKeys
|
361
|
+
include ReeDao::AggregateDSL
|
362
|
+
|
363
|
+
aggregate :users_agg_only_except_keys do
|
364
|
+
link :users, from: :ree_dao_load_agg_test
|
365
|
+
link :organizations, from: :ree_dao_load_agg_test
|
366
|
+
link :books, from: :ree_dao_load_agg_test
|
367
|
+
link :load_agg, from: :ree_dao
|
368
|
+
end
|
369
|
+
|
370
|
+
def call(ids_or_scope, **opts)
|
371
|
+
load_agg(users, ids_or_scope, **opts) do
|
372
|
+
belongs_to :organization
|
373
|
+
has_many :books
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
356
378
|
let(:users_agg) { ReeDaoLoadAggTest::UsersAgg.new }
|
357
379
|
let(:users_agg_block) { ReeDaoLoadAggTest::UsersAggBlockTest.new }
|
358
380
|
let(:users_agg_scope_method) { ReeDaoLoadAggTest::UsersAggScopeMethodTest.new }
|
@@ -361,6 +383,7 @@ RSpec.describe :load_agg do
|
|
361
383
|
let(:users_agg_without_dao) { ReeDaoLoadAggTest::UsersAggWithoutDao.new }
|
362
384
|
let(:users_agg_with_dto) { ReeDaoLoadAggTest::UsersAggWithDto.new }
|
363
385
|
let(:users_agg_only_dataset) { ReeDaoLoadAggTest::UsersAggOnlyDataset.new }
|
386
|
+
let(:user_agg_only_except_keys) { ReeDaoLoadAggTest::UsersAggOnlyExceptCase.new }
|
364
387
|
let(:organizations) { ReeDaoLoadAggTest::Organizations.new }
|
365
388
|
let(:users) { ReeDaoLoadAggTest::Users.new }
|
366
389
|
let(:user_passports) { ReeDaoLoadAggTest::UserPassports.new }
|
@@ -385,6 +408,69 @@ RSpec.describe :load_agg do
|
|
385
408
|
}.to raise_error(ArgumentError)
|
386
409
|
}
|
387
410
|
|
411
|
+
it {
|
412
|
+
organizations.delete_all
|
413
|
+
users.delete_all
|
414
|
+
user_passports.delete_all
|
415
|
+
books.delete_all
|
416
|
+
chapters.delete_all
|
417
|
+
|
418
|
+
organization = ReeDaoLoadAggTest::Organization.new(name: "Test Org")
|
419
|
+
organizations.put(organization)
|
420
|
+
|
421
|
+
user_1 = ReeDaoLoadAggTest::User.new(name: "John", age: 33, organization_id: organization.id)
|
422
|
+
user_2 = ReeDaoLoadAggTest::User.new(name: "Sam", age: 21, organization_id: organization.id)
|
423
|
+
users.put(user_1)
|
424
|
+
users.put(user_2)
|
425
|
+
|
426
|
+
passport_1 = ReeDaoLoadAggTest::UserPassport.new(user_id: user_1.id, info: "some info")
|
427
|
+
user_passports.put(passport_1)
|
428
|
+
user_passports.put(ReeDaoLoadAggTest::UserPassport.new(user_id: user_2.id, info: "another info"))
|
429
|
+
|
430
|
+
book_1 = ReeDaoLoadAggTest::Book.new(user_id: user_1.id, title: "1984")
|
431
|
+
book_2 = ReeDaoLoadAggTest::Book.new(user_id: user_1.id, title: "1408")
|
432
|
+
|
433
|
+
books.put(book_1)
|
434
|
+
books.put(book_2)
|
435
|
+
|
436
|
+
chapter = ReeDaoLoadAggTest::Chapter.new(book_id: book_1.id, title: "beginning")
|
437
|
+
chapters.put(chapter)
|
438
|
+
chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_1.id, title: "interlude"))
|
439
|
+
chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_1.id, title: "tragic ending"))
|
440
|
+
chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_2.id, title: "beginning"))
|
441
|
+
chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_2.id, title: "ending"))
|
442
|
+
|
443
|
+
|
444
|
+
authors.put(ReeDaoLoadAggTest::Author.new(book_id: book_1.id, name: "George Orwell"))
|
445
|
+
review = ReeDaoLoadAggTest::Review.new(book_id: book_1.id, rating: 10)
|
446
|
+
reviews.put(review)
|
447
|
+
reviews.put(ReeDaoLoadAggTest::Review.new(book_id: book_1.id, rating: 7))
|
448
|
+
review_authors.put(ReeDaoLoadAggTest::ReviewAuthor.new(review_id: review.id, name: "John Review"))
|
449
|
+
|
450
|
+
res = users_agg.call(
|
451
|
+
users.all,
|
452
|
+
only: [:books, :reviews],
|
453
|
+
except: [:review_author]
|
454
|
+
)
|
455
|
+
|
456
|
+
expect(res.first.books.first.reviews.first.review_author).to eq(nil)
|
457
|
+
}
|
458
|
+
|
459
|
+
it {
|
460
|
+
organizations.delete_all
|
461
|
+
users.delete_all
|
462
|
+
|
463
|
+
organization = ReeDaoLoadAggTest::Organization.new(name: "Test Org")
|
464
|
+
organizations.put(organization)
|
465
|
+
|
466
|
+
user = ReeDaoLoadAggTest::User.new(name: "John", age: 33, organization_id: organization.id)
|
467
|
+
users.put(user)
|
468
|
+
|
469
|
+
expect {
|
470
|
+
users_agg_without_dao.call(users.all, only: [:books], except: [:books])
|
471
|
+
}.to raise_error(ArgumentError, "you can't use both :only and :except for \"books\" keys")
|
472
|
+
}
|
473
|
+
|
388
474
|
it {
|
389
475
|
organizations.delete_all
|
390
476
|
users.delete_all
|
data/lib/ree_lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ree_lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.65
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruslan Gatiyatov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ree
|