graphql 1.9.0.pre4 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +1 -0
- data/lib/graphql/execution/execute.rb +16 -14
- data/lib/graphql/execution/interpreter/runtime.rb +14 -12
- data/lib/graphql/integer_encoding_error.rb +12 -0
- data/lib/graphql/schema.rb +11 -8
- data/lib/graphql/schema/default_type_error.rb +1 -1
- data/lib/graphql/schema/member/instrumentation.rb +10 -7
- data/lib/graphql/schema/resolver.rb +10 -10
- data/lib/graphql/tracing.rb +6 -1
- data/lib/graphql/types/float.rb +1 -1
- data/lib/graphql/types/int.rb +11 -2
- data/lib/graphql/version.rb +1 -1
- data/readme.md +7 -7
- data/spec/dummy/config/locales/en.yml +1 -1
- data/spec/graphql/int_type_spec.rb +19 -0
- data/spec/graphql/language/document_from_schema_definition_spec.rb +2 -2
- data/spec/support/dummy/schema.rb +12 -0
- data/spec/support/jazz.rb +7 -5
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb79bf185d3d89d53f50ad5f0ae1cc93e3480acb
|
4
|
+
data.tar.gz: 46c04d4e296ea2b3b520d6df50f82d76da5ec641
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78e070c3df4abd9e2d649ba0e5f1e7fdcef9b0241572a30bf233d516fa28b7eee9afa0fd2d650db835556dff87f4eddb344aefce8825019569aa7e55ff28f780
|
7
|
+
data.tar.gz: eb138cb5d2274c815ea42ec2eff4371cf34023ad817e4009302cb6de6da7deea213ccfaa2169d86a6a8c2b684f9e4fc8bd0780060163a764960d22af1a48bb25
|
data/lib/graphql.rb
CHANGED
@@ -89,6 +89,7 @@ require "graphql/runtime_type_error"
|
|
89
89
|
require "graphql/invalid_null_error"
|
90
90
|
require "graphql/invalid_name_error"
|
91
91
|
require "graphql/unresolved_type_error"
|
92
|
+
require "graphql/integer_encoding_error"
|
92
93
|
require "graphql/string_encoding_error"
|
93
94
|
require "graphql/query"
|
94
95
|
require "graphql/internal_representation"
|
@@ -281,20 +281,22 @@ module GraphQL
|
|
281
281
|
)
|
282
282
|
when GraphQL::TypeKinds::UNION, GraphQL::TypeKinds::INTERFACE
|
283
283
|
query = field_ctx.query
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
284
|
+
resolved_type_or_lazy = field_type.resolve_type(value, field_ctx)
|
285
|
+
query.schema.after_lazy(resolved_type_or_lazy) do |resolved_type|
|
286
|
+
possible_types = query.possible_types(field_type)
|
287
|
+
|
288
|
+
if !possible_types.include?(resolved_type)
|
289
|
+
parent_type = field_ctx.irep_node.owner_type
|
290
|
+
type_error = GraphQL::UnresolvedTypeError.new(value, field_defn, parent_type, resolved_type, possible_types)
|
291
|
+
field_ctx.schema.type_error(type_error, field_ctx)
|
292
|
+
PROPAGATE_NULL
|
293
|
+
else
|
294
|
+
resolve_value(
|
295
|
+
value,
|
296
|
+
resolved_type,
|
297
|
+
field_ctx,
|
298
|
+
)
|
299
|
+
end
|
298
300
|
end
|
299
301
|
else
|
300
302
|
raise("Unknown type kind: #{field_type.kind}")
|
@@ -270,18 +270,20 @@ module GraphQL
|
|
270
270
|
write_in_response(path, r)
|
271
271
|
r
|
272
272
|
when "UNION", "INTERFACE"
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
273
|
+
resolved_type_or_lazy = query.resolve_type(type, value)
|
274
|
+
after_lazy(resolved_type_or_lazy, path: path, field: field) do |resolved_type|
|
275
|
+
possible_types = query.possible_types(type)
|
276
|
+
|
277
|
+
if !possible_types.include?(resolved_type)
|
278
|
+
parent_type = field.owner
|
279
|
+
type_error = GraphQL::UnresolvedTypeError.new(value, field, parent_type, resolved_type, possible_types)
|
280
|
+
schema.type_error(type_error, context)
|
281
|
+
write_in_response(path, nil)
|
282
|
+
nil
|
283
|
+
else
|
284
|
+
resolved_type = resolved_type.metadata[:type_class]
|
285
|
+
continue_field(path, value, field, resolved_type, ast_node, next_selections, is_non_null)
|
286
|
+
end
|
285
287
|
end
|
286
288
|
when "OBJECT"
|
287
289
|
object_proxy = begin
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class IntegerEncodingError < GraphQL::RuntimeTypeError
|
4
|
+
# The value which couldn't be encoded
|
5
|
+
attr_reader :integer_value
|
6
|
+
|
7
|
+
def initialize(value)
|
8
|
+
@integer_value = value
|
9
|
+
super('Integer out of bounds.')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -509,17 +509,20 @@ module GraphQL
|
|
509
509
|
yield(type, object, ctx)
|
510
510
|
end
|
511
511
|
|
512
|
-
if type_result.respond_to?(:graphql_definition)
|
513
|
-
type_result = type_result.graphql_definition
|
514
|
-
end
|
515
|
-
|
516
512
|
if type_result.nil?
|
517
513
|
nil
|
518
|
-
elsif !type_result.is_a?(GraphQL::BaseType)
|
519
|
-
type_str = "#{type_result} (#{type_result.class.name})"
|
520
|
-
raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
|
521
514
|
else
|
522
|
-
type_result
|
515
|
+
after_lazy(type_result) do |resolved_type_result|
|
516
|
+
if resolved_type_result.respond_to?(:graphql_definition)
|
517
|
+
resolved_type_result = resolved_type_result.graphql_definition
|
518
|
+
end
|
519
|
+
if !resolved_type_result.is_a?(GraphQL::BaseType)
|
520
|
+
type_str = "#{resolved_type_result} (#{resolved_type_result.class.name})"
|
521
|
+
raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
|
522
|
+
else
|
523
|
+
resolved_type_result
|
524
|
+
end
|
525
|
+
end
|
523
526
|
end
|
524
527
|
end
|
525
528
|
|
@@ -6,7 +6,7 @@ module GraphQL
|
|
6
6
|
case type_error
|
7
7
|
when GraphQL::InvalidNullError
|
8
8
|
ctx.errors << type_error
|
9
|
-
when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError
|
9
|
+
when GraphQL::UnresolvedTypeError, GraphQL::StringEncodingError, GraphQL::IntegerEncodingError
|
10
10
|
raise type_error
|
11
11
|
end
|
12
12
|
end
|
@@ -91,7 +91,7 @@ module GraphQL
|
|
91
91
|
# For lists with nil, we need another nil check here
|
92
92
|
nil
|
93
93
|
else
|
94
|
-
|
94
|
+
concrete_type_or_lazy = case @inner_return_type
|
95
95
|
when GraphQL::UnionType, GraphQL::InterfaceType
|
96
96
|
ctx.query.resolve_type(@inner_return_type, inner_obj)
|
97
97
|
when GraphQL::ObjectType
|
@@ -100,12 +100,15 @@ module GraphQL
|
|
100
100
|
raise "unexpected proxying type #{@inner_return_type} for #{inner_obj} at #{ctx.owner_type}.#{ctx.field.name}"
|
101
101
|
end
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
103
|
+
# .resolve_type may have returned a lazy
|
104
|
+
ctx.schema.after_lazy(concrete_type_or_lazy) do |concrete_type|
|
105
|
+
if concrete_type && (object_class = concrete_type.metadata[:type_class])
|
106
|
+
# use the query-level context here, since it won't be field-specific anyways
|
107
|
+
query_ctx = ctx.query.context
|
108
|
+
object_class.authorized_new(inner_obj, query_ctx)
|
109
|
+
else
|
110
|
+
inner_obj
|
111
|
+
end
|
109
112
|
end
|
110
113
|
end
|
111
114
|
end
|
@@ -200,13 +200,13 @@ module GraphQL
|
|
200
200
|
# See if any object can be found for this ID
|
201
201
|
loaded_application_object = object_from_id(lookup_as_type, id, context)
|
202
202
|
context.schema.after_lazy(loaded_application_object) do |application_object|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
203
|
+
if application_object.nil?
|
204
|
+
raise LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
205
|
+
end
|
206
|
+
# Double-check that the located object is actually of this type
|
207
|
+
# (Don't want to allow arbitrary access to objects this way)
|
208
|
+
resolved_application_object_type = context.schema.resolve_type(lookup_as_type, application_object, context)
|
209
|
+
context.schema.after_lazy(resolved_application_object_type) do |application_object_type|
|
210
210
|
possible_object_types = context.schema.possible_types(lookup_as_type)
|
211
211
|
if !possible_object_types.include?(application_object_type)
|
212
212
|
raise LoadApplicationObjectFailedError.new(argument: argument, id: id, object: application_object)
|
@@ -230,11 +230,11 @@ module GraphQL
|
|
230
230
|
application_object
|
231
231
|
end
|
232
232
|
end
|
233
|
-
rescue LoadApplicationObjectFailedError => err
|
234
|
-
# pass it to a handler
|
235
|
-
load_application_object_failed(err)
|
236
233
|
end
|
237
234
|
end
|
235
|
+
rescue LoadApplicationObjectFailedError => err
|
236
|
+
# pass it to a handler
|
237
|
+
load_application_object_failed(err)
|
238
238
|
end
|
239
239
|
|
240
240
|
def load_application_object_failed(err)
|
data/lib/graphql/tracing.rb
CHANGED
@@ -27,7 +27,7 @@ module GraphQL
|
|
27
27
|
# tracer MyTracer # <= responds to .trace(key, data, &block)
|
28
28
|
# end
|
29
29
|
#
|
30
|
-
# @example Adding a tracer to a query
|
30
|
+
# @example Adding a tracer to a single query
|
31
31
|
# MySchema.execute(query_str, context: { backtrace: true })
|
32
32
|
#
|
33
33
|
# Events:
|
@@ -45,6 +45,11 @@ module GraphQL
|
|
45
45
|
# execute_field | `{ context: GraphQL::Query::Context::FieldResolutionContext?, field: GraphQL::Schema::Field?, path: Array<String, Integer>?}`
|
46
46
|
# execute_field_lazy | `{ context: GraphQL::Query::Context::FieldResolutionContext?, field: GraphQL::Schema::Field?, path: Array<String, Integer>?}`
|
47
47
|
#
|
48
|
+
# Note that `execute_field` and `execute_field_lazy` receive different data in different settings:
|
49
|
+
#
|
50
|
+
# - When using {GraphQL::Execution::Interpreter}, they receive `{field:, path:}`
|
51
|
+
# - Otherwise, they receive `{context: ...}`
|
52
|
+
#
|
48
53
|
module Tracing
|
49
54
|
# Objects may include traceable to gain a `.trace(...)` method.
|
50
55
|
# The object must have a `@tracers` ivar of type `Array<<#trace(k, d, &b)>>`.
|
data/lib/graphql/types/float.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module GraphQL
|
4
4
|
module Types
|
5
5
|
class Float < GraphQL::Schema::Scalar
|
6
|
-
description "Represents signed double-precision fractional values as specified by [IEEE 754](
|
6
|
+
description "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point)."
|
7
7
|
|
8
8
|
def self.coerce_input(value, _ctx)
|
9
9
|
value.is_a?(Numeric) ? value.to_f : nil
|
data/lib/graphql/types/int.rb
CHANGED
@@ -5,12 +5,21 @@ module GraphQL
|
|
5
5
|
class Int < GraphQL::Schema::Scalar
|
6
6
|
description "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1."
|
7
7
|
|
8
|
+
MIN = -(2**31)
|
9
|
+
MAX = (2**31) - 1
|
10
|
+
|
8
11
|
def self.coerce_input(value, _ctx)
|
9
12
|
value.is_a?(Numeric) ? value.to_i : nil
|
10
13
|
end
|
11
14
|
|
12
|
-
def self.coerce_result(value,
|
13
|
-
value.to_i
|
15
|
+
def self.coerce_result(value, ctx)
|
16
|
+
value = value.to_i
|
17
|
+
if value >= MIN && value <= MAX
|
18
|
+
value
|
19
|
+
else
|
20
|
+
err = GraphQL::IntegerEncodingError.new(value)
|
21
|
+
ctx.schema.type_error(err, ctx)
|
22
|
+
end
|
14
23
|
end
|
15
24
|
|
16
25
|
default_scalar true
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -4,12 +4,12 @@
|
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/graphql.svg)](https://rubygems.org/gems/graphql)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/rmosolgo/graphql-ruby/badges/gpa.svg)](https://codeclimate.com/github/rmosolgo/graphql-ruby)
|
6
6
|
[![Test Coverage](https://codeclimate.com/github/rmosolgo/graphql-ruby/badges/coverage.svg)](https://codeclimate.com/github/rmosolgo/graphql-ruby)
|
7
|
-
[![built with love](https://cloud.githubusercontent.com/assets/2231765/6766607/d07992c6-cfc9-11e4-813f-d9240714dd50.png)](
|
7
|
+
[![built with love](https://cloud.githubusercontent.com/assets/2231765/6766607/d07992c6-cfc9-11e4-813f-d9240714dd50.png)](https://rmosolgo.github.io/react-badges/)
|
8
8
|
|
9
|
-
A Ruby implementation of [GraphQL](
|
9
|
+
A Ruby implementation of [GraphQL](https://graphql.org/).
|
10
10
|
|
11
|
-
- [Website](https://
|
12
|
-
- [API Documentation](
|
11
|
+
- [Website](https://graphql-ruby.org/)
|
12
|
+
- [API Documentation](https://www.rubydoc.info/gems/graphql)
|
13
13
|
- [Newsletter](https://tinyletter.com/graphql-ruby)
|
14
14
|
|
15
15
|
## Installation
|
@@ -33,11 +33,11 @@ $ rails generate graphql:install
|
|
33
33
|
|
34
34
|
After this, you may need to run `bundle install` again, as by default graphiql-rails is added on installation.
|
35
35
|
|
36
|
-
Or, see ["Getting Started"](https://
|
36
|
+
Or, see ["Getting Started"](https://graphql-ruby.org/).
|
37
37
|
|
38
38
|
## Upgrade
|
39
39
|
|
40
|
-
I also sell [GraphQL::Pro](
|
40
|
+
I also sell [GraphQL::Pro](https://graphql.pro) which provides several features on top of the GraphQL runtime, including [Pundit authorization](https://graphql-ruby.org/authorization/pundit_integration), [CanCan authorization](https://graphql-ruby.org/authorization/can_can_integration), [Pusher-based subscriptions](https://graphql-ruby.org/subscriptions/pusher_implementation) and [persisted queries](https://graphql-ruby.org/operation_store/overview). Besides that, Pro customers get email support and an opportunity to support graphql-ruby's development!
|
41
41
|
|
42
42
|
## Goals
|
43
43
|
|
@@ -49,4 +49,4 @@ I also sell [GraphQL::Pro](http://graphql.pro) which provides several features o
|
|
49
49
|
|
50
50
|
- __Say hi & ask questions__ in the [#ruby channel on Slack](https://graphql-slack.herokuapp.com/) or [on Twitter](https://twitter.com/rmosolgo)!
|
51
51
|
- __Report bugs__ by posting a description, full stack trace, and all relevant code in a [GitHub issue](https://github.com/rmosolgo/graphql-ruby/issues).
|
52
|
-
- __Start hacking__ with the [Development guide](
|
52
|
+
- __Start hacking__ with the [Development guide](https://graphql-ruby.org/development).
|
@@ -12,5 +12,24 @@ describe GraphQL::INT_TYPE do
|
|
12
12
|
assert_nil GraphQL::INT_TYPE.coerce_isolated_input("55")
|
13
13
|
assert_nil GraphQL::INT_TYPE.coerce_isolated_input(true)
|
14
14
|
end
|
15
|
+
|
16
|
+
describe "handling boundaries" do
|
17
|
+
let(:context) { GraphQL::Query.new(Dummy::Schema, "{ __typename }").context }
|
18
|
+
|
19
|
+
it "accepts result values in bounds" do
|
20
|
+
assert_equal 0, GraphQL::INT_TYPE.coerce_result(0, context)
|
21
|
+
assert_equal (2**31) - 1, GraphQL::INT_TYPE.coerce_result((2**31) - 1, context)
|
22
|
+
assert_equal -(2**31), GraphQL::INT_TYPE.coerce_result(-(2**31), context)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "replaces values, if configured to do so" do
|
26
|
+
assert_equal Dummy::Schema::MAGIC_INT_COERCE_VALUE, GraphQL::INT_TYPE.coerce_result(99**99, context)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "raises on values out of bounds" do
|
30
|
+
assert_raises(GraphQL::IntegerEncodingError) { GraphQL::INT_TYPE.coerce_result(2**31, context) }
|
31
|
+
assert_raises(GraphQL::IntegerEncodingError) { GraphQL::INT_TYPE.coerce_result(-(2**31 + 1), context) }
|
32
|
+
end
|
33
|
+
end
|
15
34
|
end
|
16
35
|
end
|
@@ -433,7 +433,7 @@ describe GraphQL::Language::DocumentFromSchemaDefinition do
|
|
433
433
|
}
|
434
434
|
|
435
435
|
# Represents signed double-precision fractional values as specified by [IEEE
|
436
|
-
# 754](
|
436
|
+
# 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
|
437
437
|
scalar Float
|
438
438
|
|
439
439
|
# Represents a unique identifier that is Base64 obfuscated. It is often used to
|
@@ -698,7 +698,7 @@ describe GraphQL::Language::DocumentFromSchemaDefinition do
|
|
698
698
|
}
|
699
699
|
|
700
700
|
# Represents signed double-precision fractional values as specified by [IEEE
|
701
|
-
# 754](
|
701
|
+
# 754](https://en.wikipedia.org/wiki/IEEE_floating_point).
|
702
702
|
scalar Float
|
703
703
|
|
704
704
|
# Represents a unique identifier that is Base64 obfuscated. It is often used to
|
@@ -473,6 +473,18 @@ module Dummy
|
|
473
473
|
def self.resolve_type(type, obj, ctx)
|
474
474
|
Schema.types[obj.class.name.split("::").last]
|
475
475
|
end
|
476
|
+
|
477
|
+
# This is used to confirm that the hook is called:
|
478
|
+
MAGIC_INT_COERCE_VALUE = -1
|
479
|
+
|
480
|
+
def self.type_error(err, ctx)
|
481
|
+
if err.is_a?(GraphQL::IntegerEncodingError) && err.integer_value == 99**99
|
482
|
+
MAGIC_INT_COERCE_VALUE
|
483
|
+
else
|
484
|
+
super
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
476
488
|
if TESTING_INTERPRETER
|
477
489
|
use GraphQL::Execution::Interpreter
|
478
490
|
end
|
data/spec/support/jazz.rb
CHANGED
@@ -320,10 +320,12 @@ module Jazz
|
|
320
320
|
possible_types Musician, Ensemble
|
321
321
|
|
322
322
|
def self.resolve_type(object, context)
|
323
|
-
|
324
|
-
Ensemble
|
325
|
-
|
326
|
-
|
323
|
+
GraphQL::Execution::Lazy.new do
|
324
|
+
if object.is_a?(Models::Ensemble)
|
325
|
+
Ensemble
|
326
|
+
else
|
327
|
+
Musician
|
328
|
+
end
|
327
329
|
end
|
328
330
|
end
|
329
331
|
end
|
@@ -352,7 +354,7 @@ module Jazz
|
|
352
354
|
def now_playing; Models.data["Ensemble"].first; end
|
353
355
|
|
354
356
|
# For asserting that the object is initialized once:
|
355
|
-
field :object_id,
|
357
|
+
field :object_id, String, null: false
|
356
358
|
field :inspect_context, [String], null: false
|
357
359
|
field :hashyEnsemble, Ensemble, null: false
|
358
360
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.9.0
|
4
|
+
version: 1.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -437,6 +437,7 @@ files:
|
|
437
437
|
- lib/graphql/id_type.rb
|
438
438
|
- lib/graphql/input_object_type.rb
|
439
439
|
- lib/graphql/int_type.rb
|
440
|
+
- lib/graphql/integer_encoding_error.rb
|
440
441
|
- lib/graphql/interface_type.rb
|
441
442
|
- lib/graphql/internal_representation.rb
|
442
443
|
- lib/graphql/internal_representation/document.rb
|
@@ -986,7 +987,7 @@ files:
|
|
986
987
|
- spec/support/skylight.rb
|
987
988
|
- spec/support/star_wars/schema.rb
|
988
989
|
- spec/support/static_validation_helpers.rb
|
989
|
-
homepage:
|
990
|
+
homepage: https://github.com/rmosolgo/graphql-ruby
|
990
991
|
licenses:
|
991
992
|
- MIT
|
992
993
|
metadata: {}
|
@@ -1001,9 +1002,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
1001
1002
|
version: 2.2.0
|
1002
1003
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
1003
1004
|
requirements:
|
1004
|
-
- - "
|
1005
|
+
- - ">="
|
1005
1006
|
- !ruby/object:Gem::Version
|
1006
|
-
version:
|
1007
|
+
version: '0'
|
1007
1008
|
requirements: []
|
1008
1009
|
rubyforge_project:
|
1009
1010
|
rubygems_version: 2.6.13
|