apiwork 0.4.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/apiwork/adapter/serializer/resource/base.rb +15 -0
  3. data/lib/apiwork/adapter/serializer/resource/default/contract_builder.rb +3 -2
  4. data/lib/apiwork/adapter/standard/capability/writing/contract_builder.rb +2 -2
  5. data/lib/apiwork/api/base.rb +67 -17
  6. data/lib/apiwork/api/element.rb +33 -2
  7. data/lib/apiwork/api/object.rb +70 -5
  8. data/lib/apiwork/api/router.rb +16 -0
  9. data/lib/apiwork/configuration/validatable.rb +1 -0
  10. data/lib/apiwork/configuration.rb +2 -0
  11. data/lib/apiwork/contract/element.rb +17 -2
  12. data/lib/apiwork/contract/object/coercer.rb +24 -2
  13. data/lib/apiwork/contract/object/deserializer.rb +5 -1
  14. data/lib/apiwork/contract/object/transformer.rb +15 -2
  15. data/lib/apiwork/contract/object/validator.rb +45 -2
  16. data/lib/apiwork/contract/object.rb +77 -7
  17. data/lib/apiwork/element.rb +33 -0
  18. data/lib/apiwork/export/base.rb +1 -4
  19. data/lib/apiwork/export/builder_mapper.rb +184 -0
  20. data/lib/apiwork/export/open_api.rb +9 -2
  21. data/lib/apiwork/export/sorbus.rb +5 -1
  22. data/lib/apiwork/export/sorbus_mapper.rb +3 -7
  23. data/lib/apiwork/export/type_analysis.rb +20 -6
  24. data/lib/apiwork/export/type_script.rb +4 -1
  25. data/lib/apiwork/export/type_script_mapper.rb +25 -2
  26. data/lib/apiwork/export/zod.rb +9 -0
  27. data/lib/apiwork/export/zod_mapper.rb +22 -1
  28. data/lib/apiwork/introspection/dump/action.rb +1 -1
  29. data/lib/apiwork/introspection/dump/param.rb +36 -20
  30. data/lib/apiwork/introspection/dump/type.rb +31 -25
  31. data/lib/apiwork/introspection/param/array.rb +26 -0
  32. data/lib/apiwork/introspection/param/base.rb +16 -18
  33. data/lib/apiwork/introspection/param/binary.rb +36 -0
  34. data/lib/apiwork/introspection/param/boolean.rb +36 -0
  35. data/lib/apiwork/introspection/param/date.rb +36 -0
  36. data/lib/apiwork/introspection/param/date_time.rb +36 -0
  37. data/lib/apiwork/introspection/param/decimal.rb +26 -0
  38. data/lib/apiwork/introspection/param/integer.rb +26 -0
  39. data/lib/apiwork/introspection/param/number.rb +26 -0
  40. data/lib/apiwork/introspection/param/record.rb +71 -0
  41. data/lib/apiwork/introspection/param/string.rb +26 -0
  42. data/lib/apiwork/introspection/param/time.rb +36 -0
  43. data/lib/apiwork/introspection/param/uuid.rb +36 -0
  44. data/lib/apiwork/introspection/param.rb +1 -0
  45. data/lib/apiwork/object.rb +244 -2
  46. data/lib/apiwork/representation/attribute.rb +1 -1
  47. data/lib/apiwork/representation/base.rb +105 -0
  48. data/lib/apiwork/representation/element.rb +15 -5
  49. data/lib/apiwork/version.rb +1 -1
  50. metadata +4 -2
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Apiwork
4
+ module Introspection
5
+ module Param
6
+ # @api public
7
+ # Record param representing key-value maps with typed values.
8
+ #
9
+ # @example Basic usage
10
+ # param.type # => :record
11
+ # param.record? # => true
12
+ # param.scalar? # => false
13
+ #
14
+ # @example Value type
15
+ # param.of # => Param (value type) or nil
16
+ class Record < Base
17
+ # @api public
18
+ # The default for this param.
19
+ #
20
+ # @return [Object, nil]
21
+ def default
22
+ @dump[:default]
23
+ end
24
+
25
+ # @api public
26
+ # The example for this param.
27
+ #
28
+ # @return [Object, nil]
29
+ def example
30
+ @dump[:example]
31
+ end
32
+
33
+ # @api public
34
+ # The value type for this record.
35
+ #
36
+ # @return [Param::Base, nil]
37
+ def of
38
+ @of ||= @dump[:of] ? Param.build(@dump[:of]) : nil
39
+ end
40
+
41
+ # @api public
42
+ # Whether this param is a record.
43
+ #
44
+ # @return [Boolean]
45
+ def record?
46
+ true
47
+ end
48
+
49
+ # @api public
50
+ # Whether this param is concrete.
51
+ #
52
+ # @return [Boolean]
53
+ def concrete?
54
+ true
55
+ end
56
+
57
+ # @api public
58
+ # Converts this param to a hash.
59
+ #
60
+ # @return [Hash]
61
+ def to_h
62
+ result = super
63
+ result[:default] = default
64
+ result[:example] = example
65
+ result[:of] = of&.to_h
66
+ result
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -24,6 +24,22 @@ module Apiwork
24
24
  # param.enum_reference? # => false
25
25
  # end
26
26
  class String < Base
27
+ # @api public
28
+ # The default for this param.
29
+ #
30
+ # @return [Object, nil]
31
+ def default
32
+ @dump[:default]
33
+ end
34
+
35
+ # @api public
36
+ # The example for this param.
37
+ #
38
+ # @return [Object, nil]
39
+ def example
40
+ @dump[:example]
41
+ end
42
+
27
43
  # @api public
28
44
  # The format for this param.
29
45
  #
@@ -48,6 +64,14 @@ module Apiwork
48
64
  @dump[:max]
49
65
  end
50
66
 
67
+ # @api public
68
+ # Whether this param is concrete.
69
+ #
70
+ # @return [Boolean]
71
+ def concrete?
72
+ true
73
+ end
74
+
51
75
  # @api public
52
76
  # Whether this param is scalar.
53
77
  #
@@ -110,7 +134,9 @@ module Apiwork
110
134
  # @return [Hash]
111
135
  def to_h
112
136
  result = super
137
+ result[:default] = default
113
138
  result[:enum] = enum if enum?
139
+ result[:example] = example
114
140
  result[:format] = format
115
141
  result[:max] = max
116
142
  result[:min] = min
@@ -20,6 +20,30 @@ module Apiwork
20
20
  # param.enum_reference? # => false
21
21
  # end
22
22
  class Time < Base
23
+ # @api public
24
+ # The default for this param.
25
+ #
26
+ # @return [Object, nil]
27
+ def default
28
+ @dump[:default]
29
+ end
30
+
31
+ # @api public
32
+ # The example for this param.
33
+ #
34
+ # @return [Object, nil]
35
+ def example
36
+ @dump[:example]
37
+ end
38
+
39
+ # @api public
40
+ # Whether this param is concrete.
41
+ #
42
+ # @return [Boolean]
43
+ def concrete?
44
+ true
45
+ end
46
+
23
47
  # @api public
24
48
  # Whether this param is scalar.
25
49
  #
@@ -67,6 +91,18 @@ module Apiwork
67
91
  def formattable?
68
92
  false
69
93
  end
94
+
95
+ # @api public
96
+ # Converts this param to a hash.
97
+ #
98
+ # @return [Hash]
99
+ def to_h
100
+ result = super
101
+ result[:default] = default
102
+ result[:enum] = enum if enum?
103
+ result[:example] = example
104
+ result
105
+ end
70
106
  end
71
107
  end
72
108
  end
@@ -20,6 +20,30 @@ module Apiwork
20
20
  # param.enum_reference? # => false
21
21
  # end
22
22
  class UUID < Base
23
+ # @api public
24
+ # The default for this param.
25
+ #
26
+ # @return [Object, nil]
27
+ def default
28
+ @dump[:default]
29
+ end
30
+
31
+ # @api public
32
+ # The example for this param.
33
+ #
34
+ # @return [Object, nil]
35
+ def example
36
+ @dump[:example]
37
+ end
38
+
39
+ # @api public
40
+ # Whether this param is concrete.
41
+ #
42
+ # @return [Boolean]
43
+ def concrete?
44
+ true
45
+ end
46
+
23
47
  # @api public
24
48
  # Whether this param is scalar.
25
49
  #
@@ -67,6 +91,18 @@ module Apiwork
67
91
  def formattable?
68
92
  false
69
93
  end
94
+
95
+ # @api public
96
+ # Converts this param to a hash.
97
+ #
98
+ # @return [Hash]
99
+ def to_h
100
+ result = super
101
+ result[:default] = default
102
+ result[:enum] = enum if enum?
103
+ result[:example] = example
104
+ result
105
+ end
70
106
  end
71
107
  end
72
108
  end
@@ -18,6 +18,7 @@ module Apiwork
18
18
  when :binary then Binary.new(dump)
19
19
  when :unknown then Unknown.new(dump)
20
20
  when :array then Array.new(dump)
21
+ when :record then Record.new(dump)
21
22
  when :object then Object.new(dump)
22
23
  when :union then Union.new(dump)
23
24
  when :literal then Literal.new(dump)
@@ -1129,6 +1129,103 @@ module Apiwork
1129
1129
  )
1130
1130
  end
1131
1131
 
1132
+ # @api public
1133
+ # Defines an unknown.
1134
+ #
1135
+ # @param name [Symbol]
1136
+ # The name.
1137
+ # @param as [Symbol, nil] (nil)
1138
+ # The target attribute name.
1139
+ # @param default [Object, nil] (nil)
1140
+ # The default value.
1141
+ # @param deprecated [Boolean] (false)
1142
+ # Whether deprecated. Metadata included in exports.
1143
+ # @param description [String, nil] (nil)
1144
+ # The description. Metadata included in exports.
1145
+ # @param example [Object, nil] (nil)
1146
+ # The example value. Metadata included in exports.
1147
+ # @param nullable [Boolean] (false)
1148
+ # Whether the value can be `null`.
1149
+ # @param optional [Boolean] (false)
1150
+ # Whether the param is optional.
1151
+ # @param required [Boolean] (false)
1152
+ # Whether the param is required.
1153
+ # @return [void]
1154
+ #
1155
+ # @example Opaque metadata
1156
+ # unknown :metadata
1157
+ def unknown(
1158
+ name,
1159
+ as: nil,
1160
+ default: nil,
1161
+ deprecated: false,
1162
+ description: nil,
1163
+ example: nil,
1164
+ nullable: false,
1165
+ optional: false,
1166
+ required: false
1167
+ )
1168
+ param(
1169
+ name,
1170
+ as:,
1171
+ default:,
1172
+ deprecated:,
1173
+ description:,
1174
+ example:,
1175
+ nullable:,
1176
+ optional:,
1177
+ required:,
1178
+ type: :unknown,
1179
+ )
1180
+ end
1181
+
1182
+ # @api public
1183
+ # Defines an optional unknown.
1184
+ #
1185
+ # @param name [Symbol]
1186
+ # The name.
1187
+ # @param as [Symbol, nil] (nil)
1188
+ # The target attribute name.
1189
+ # @param default [Object, nil] (nil)
1190
+ # The default value.
1191
+ # @param deprecated [Boolean] (false)
1192
+ # Whether deprecated. Metadata included in exports.
1193
+ # @param description [String, nil] (nil)
1194
+ # The description. Metadata included in exports.
1195
+ # @param example [Object, nil] (nil)
1196
+ # The example value. Metadata included in exports.
1197
+ # @param nullable [Boolean] (false)
1198
+ # Whether the value can be `null`.
1199
+ # @param required [Boolean] (false)
1200
+ # Whether the param is required.
1201
+ # @return [void]
1202
+ #
1203
+ # @example Optional metadata
1204
+ # unknown? :metadata
1205
+ def unknown?(
1206
+ name,
1207
+ as: nil,
1208
+ default: nil,
1209
+ deprecated: false,
1210
+ description: nil,
1211
+ example: nil,
1212
+ nullable: false,
1213
+ required: false
1214
+ )
1215
+ param(
1216
+ name,
1217
+ as:,
1218
+ default:,
1219
+ deprecated:,
1220
+ description:,
1221
+ example:,
1222
+ nullable:,
1223
+ required:,
1224
+ optional: true,
1225
+ type: :unknown,
1226
+ )
1227
+ end
1228
+
1132
1229
  # @api public
1133
1230
  # Defines an object.
1134
1231
  #
@@ -1267,6 +1364,22 @@ module Apiwork
1267
1364
  # decimal :price
1268
1365
  # end
1269
1366
  # end
1367
+ #
1368
+ # @example Array of discriminated union
1369
+ # array :notifications do
1370
+ # union discriminator: :type do
1371
+ # variant tag: 'email' do
1372
+ # object do
1373
+ # string :address
1374
+ # end
1375
+ # end
1376
+ # variant tag: 'sms' do
1377
+ # object do
1378
+ # string :phone
1379
+ # end
1380
+ # end
1381
+ # end
1382
+ # end
1270
1383
  def array(
1271
1384
  name,
1272
1385
  as: nil,
@@ -1320,6 +1433,22 @@ module Apiwork
1320
1433
  # array? :labels do
1321
1434
  # string
1322
1435
  # end
1436
+ #
1437
+ # @example Optional array of discriminated union
1438
+ # array? :items do
1439
+ # union discriminator: :type do
1440
+ # variant tag: 'text' do
1441
+ # object do
1442
+ # string :content
1443
+ # end
1444
+ # end
1445
+ # variant tag: 'image' do
1446
+ # object do
1447
+ # string :url
1448
+ # end
1449
+ # end
1450
+ # end
1451
+ # end
1323
1452
  def array?(
1324
1453
  name,
1325
1454
  as: nil,
@@ -1346,6 +1475,113 @@ module Apiwork
1346
1475
  )
1347
1476
  end
1348
1477
 
1478
+ # @api public
1479
+ # Defines a record.
1480
+ #
1481
+ # @param name [Symbol]
1482
+ # The name.
1483
+ # @param as [Symbol, nil] (nil)
1484
+ # The target attribute name.
1485
+ # @param default [Object, nil] (nil)
1486
+ # The default value.
1487
+ # @param deprecated [Boolean] (false)
1488
+ # Whether deprecated. Metadata included in exports.
1489
+ # @param description [String, nil] (nil)
1490
+ # The description. Metadata included in exports.
1491
+ # @param nullable [Boolean] (false)
1492
+ # Whether the value can be `null`.
1493
+ # @param optional [Boolean] (false)
1494
+ # Whether the param is optional.
1495
+ # @param required [Boolean] (false)
1496
+ # Whether the param is required.
1497
+ # @yield block defining value type
1498
+ # @return [void]
1499
+ #
1500
+ # @example Record of integers
1501
+ # record :scores do
1502
+ # integer
1503
+ # end
1504
+ #
1505
+ # @example Record of objects
1506
+ # record :settings do
1507
+ # object do
1508
+ # string :value
1509
+ # boolean :enabled
1510
+ # end
1511
+ # end
1512
+ def record(
1513
+ name,
1514
+ as: nil,
1515
+ default: nil,
1516
+ deprecated: false,
1517
+ description: nil,
1518
+ nullable: false,
1519
+ optional: false,
1520
+ required: false,
1521
+ &block
1522
+ )
1523
+ param(
1524
+ name,
1525
+ as:,
1526
+ default:,
1527
+ deprecated:,
1528
+ description:,
1529
+ nullable:,
1530
+ optional:,
1531
+ required:,
1532
+ type: :record,
1533
+ &block
1534
+ )
1535
+ end
1536
+
1537
+ # @api public
1538
+ # Defines an optional record.
1539
+ #
1540
+ # @param name [Symbol]
1541
+ # The name.
1542
+ # @param as [Symbol, nil] (nil)
1543
+ # The target attribute name.
1544
+ # @param default [Object, nil] (nil)
1545
+ # The default value.
1546
+ # @param deprecated [Boolean] (false)
1547
+ # Whether deprecated. Metadata included in exports.
1548
+ # @param description [String, nil] (nil)
1549
+ # The description. Metadata included in exports.
1550
+ # @param nullable [Boolean] (false)
1551
+ # Whether the value can be `null`.
1552
+ # @param required [Boolean] (false)
1553
+ # Whether the param is required.
1554
+ # @yield block defining value type
1555
+ # @return [void]
1556
+ #
1557
+ # @example Optional record
1558
+ # record? :metadata do
1559
+ # string
1560
+ # end
1561
+ def record?(
1562
+ name,
1563
+ as: nil,
1564
+ default: nil,
1565
+ deprecated: false,
1566
+ description: nil,
1567
+ nullable: false,
1568
+ required: false,
1569
+ &block
1570
+ )
1571
+ param(
1572
+ name,
1573
+ as:,
1574
+ default:,
1575
+ deprecated:,
1576
+ description:,
1577
+ nullable:,
1578
+ required:,
1579
+ optional: true,
1580
+ type: :record,
1581
+ &block
1582
+ )
1583
+ end
1584
+
1349
1585
  # @api public
1350
1586
  # Defines a union.
1351
1587
  #
@@ -1552,6 +1788,8 @@ module Apiwork
1552
1788
  optional: false,
1553
1789
  required: false
1554
1790
  )
1791
+ reference_type = to || name
1792
+
1555
1793
  param(
1556
1794
  name,
1557
1795
  as:,
@@ -1561,7 +1799,8 @@ module Apiwork
1561
1799
  nullable:,
1562
1800
  optional:,
1563
1801
  required:,
1564
- type: to || name,
1802
+ custom_type: reference_type,
1803
+ type: reference_type,
1565
1804
  )
1566
1805
  end
1567
1806
 
@@ -1598,6 +1837,8 @@ module Apiwork
1598
1837
  nullable: false,
1599
1838
  required: false
1600
1839
  )
1840
+ reference_type = to || name
1841
+
1601
1842
  param(
1602
1843
  name,
1603
1844
  as:,
@@ -1606,8 +1847,9 @@ module Apiwork
1606
1847
  description:,
1607
1848
  nullable:,
1608
1849
  required:,
1850
+ custom_type: reference_type,
1609
1851
  optional: true,
1610
- type: to || name,
1852
+ type: reference_type,
1611
1853
  )
1612
1854
  end
1613
1855
 
@@ -117,7 +117,7 @@ module Apiwork
117
117
  element.validate!
118
118
  @element = element
119
119
  type = element.type
120
- @of = element.inner&.type if element.type == :array
120
+ @of = element.inner&.type if [:array, :record].include?(element.type)
121
121
  end
122
122
 
123
123
  if owner_representation_class.model_class.present?
@@ -69,6 +69,7 @@ module Apiwork
69
69
  class_attribute :inheritance, default: nil, instance_accessor: false
70
70
 
71
71
  class_attribute :_adapter_config, default: {}, instance_accessor: false
72
+ class_attribute :type_definitions, default: {}, instance_accessor: false
72
73
 
73
74
  # @!attribute [r] context
74
75
  # @api public
@@ -540,6 +541,110 @@ module Apiwork
540
541
  )
541
542
  end
542
543
 
544
+ # @api public
545
+ # Defines an object type for this representation.
546
+ #
547
+ # The type is copied to the contract that uses this representation. Attributes can reference
548
+ # it by name via `type:`. In exports, the type is scoped to the contract.
549
+ #
550
+ # @param name [Symbol]
551
+ # The object name.
552
+ # @param deprecated [Boolean] (false)
553
+ # Whether deprecated. Metadata included in exports.
554
+ # @param description [String, nil] (nil)
555
+ # The description. Metadata included in exports.
556
+ # @param example [Object, nil] (nil)
557
+ # The example. Metadata included in exports.
558
+ # @yieldparam object [API::Object]
559
+ # @return [void]
560
+ #
561
+ # @example Define and reference
562
+ # object :address do
563
+ # string :street
564
+ # string :city
565
+ # string :postal_code
566
+ # end
567
+ #
568
+ # attribute :shipping_address, type: :address
569
+ # attribute :billing_address, type: :address
570
+ def object(
571
+ name,
572
+ deprecated: false,
573
+ description: nil,
574
+ example: nil,
575
+ &block
576
+ )
577
+ self.type_definitions = type_definitions.merge(
578
+ name.to_sym => {
579
+ block:,
580
+ kind: :object,
581
+ options: {
582
+ deprecated:,
583
+ description:,
584
+ example:,
585
+ },
586
+ },
587
+ )
588
+ end
589
+
590
+ # @api public
591
+ # Defines a union type for this representation.
592
+ #
593
+ # The type is copied to the contract that uses this representation. Attributes can reference
594
+ # it by name via `type:`. In exports, the type is scoped to the contract.
595
+ #
596
+ # @param name [Symbol]
597
+ # The union name.
598
+ # @param deprecated [Boolean] (false)
599
+ # Whether deprecated. Metadata included in exports.
600
+ # @param description [String, nil] (nil)
601
+ # The description. Metadata included in exports.
602
+ # @param discriminator [Symbol, nil] (nil)
603
+ # The discriminator field name.
604
+ # @param example [Object, nil] (nil)
605
+ # The example. Metadata included in exports.
606
+ # @yieldparam union [API::Union]
607
+ # @return [void]
608
+ #
609
+ # @example Define and reference
610
+ # union :content_block, discriminator: :kind do
611
+ # variant tag: 'text' do
612
+ # object do
613
+ # string :body
614
+ # end
615
+ # end
616
+ # variant tag: 'image' do
617
+ # object do
618
+ # string :url
619
+ # integer :width
620
+ # integer :height
621
+ # end
622
+ # end
623
+ # end
624
+ #
625
+ # attribute :content, type: :content_block
626
+ def union(
627
+ name,
628
+ deprecated: false,
629
+ description: nil,
630
+ discriminator: nil,
631
+ example: nil,
632
+ &block
633
+ )
634
+ self.type_definitions = type_definitions.merge(
635
+ name.to_sym => {
636
+ block:,
637
+ kind: :union,
638
+ options: {
639
+ deprecated:,
640
+ description:,
641
+ discriminator:,
642
+ example:,
643
+ },
644
+ },
645
+ )
646
+ end
647
+
543
648
  # @api public
544
649
  # The type name for this representation.
545
650
  #
@@ -11,10 +11,11 @@ module Apiwork
11
11
  # Only complex types are allowed at the top level:
12
12
  # - {#object} for key-value structures
13
13
  # - {#array} for ordered collections
14
+ # - {#record} for key-value maps with typed values
14
15
  # - {#union} for polymorphic structures
15
16
  #
16
17
  # Inside these blocks, the full type DSL is available including
17
- # nested objects, arrays, primitives, and unions.
18
+ # nested objects, arrays, records, primitives, and unions.
18
19
  #
19
20
  # @see API::Element Block context for array elements
20
21
  # @see API::Object Block context for object fields
@@ -74,15 +75,15 @@ module Apiwork
74
75
  # end
75
76
  class Element < Apiwork::Element
76
77
  def validate!
77
- raise ConfigurationError, 'must define exactly one type (object, array, or union)' unless @defined
78
+ raise ConfigurationError, 'must define exactly one type (object, array, record, or union)' unless @defined
78
79
  end
79
80
 
80
81
  # @api public
81
82
  # Defines the element type.
82
83
  #
83
- # Only complex types (:object, :array, :union) are allowed.
84
+ # Only complex types (:object, :array, :record, :union) are allowed.
84
85
  #
85
- # @param type [Symbol] [:array, :object, :union]
86
+ # @param type [Symbol] [:array, :object, :record, :union]
86
87
  # The element type.
87
88
  # @param discriminator [Symbol, nil] (nil)
88
89
  # The discriminator field name. Unions only.
@@ -110,6 +111,15 @@ module Apiwork
110
111
  @inner = inner
111
112
  @shape = inner.shape
112
113
  @defined = true
114
+ when :record
115
+ raise ConfigurationError, 'record requires a block' unless block
116
+
117
+ inner = API::Element.new
118
+ block.arity.positive? ? yield(inner) : inner.instance_eval(&block)
119
+ inner.validate!
120
+ @type = :record
121
+ @inner = inner
122
+ @defined = true
113
123
  when :union
114
124
  raise ConfigurationError, 'union requires a block' unless block
115
125
 
@@ -120,7 +130,7 @@ module Apiwork
120
130
  @discriminator = discriminator
121
131
  @defined = true
122
132
  else
123
- raise ConfigurationError, "Representation::Element only supports :object, :array, :union - got #{type.inspect}"
133
+ raise ConfigurationError, "Representation::Element only supports :object, :array, :record, :union - got #{type.inspect}"
124
134
  end
125
135
  end
126
136
  end