shale-builder 0.1.9 → 0.2.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: 1ad79ec1b93dc534e3c8fb9b6b2a141bc186148b4ce21cbd3ce1f090b3445323
4
- data.tar.gz: f9b8d364e8418d94b69046257d9470ff26596601fbffd5b3454f82ef152d98d7
3
+ metadata.gz: a1194476cdc1f12fedaee4208834a474caf3397d0b4cab907f20648d5e812394
4
+ data.tar.gz: ce1363ceced738925bbe89abc807daa9e7cc54099244181083e0c35364d5c76d
5
5
  SHA512:
6
- metadata.gz: 96d7fcf6887a218e486fded1f9b0cee50cf275f0788482d4a2a1a0e5bc65712b86ea708d596d1b0b9c40dbb548091dc1324cb6c6dca567ae56f50a06d1222f2c
7
- data.tar.gz: 1e861780af38b06aee8440419a7d67313f83d535954793362a27a7ae196c6bd49c0485369186655b11602194dcffea4ed6f6a7b8c16f64fa2a6b5ec3a256162d
6
+ metadata.gz: 8fb3b29c2765d93b8cbcdd35ec04085d50bbc918bb6c5e2bec62ce80cfeb75d2af3a815956b68d31b882e7c46db8929f48039cb8a0880b4b50766581de0a811d
7
+ data.tar.gz: 3e2c7f826e65b70ac6c2efca789b836ac476594bee5e93d265c56a88f9ec2921fdff7a5352baf33a2ca1a887efdb824d24b2335481fb9fb5bda64547e69c7b05
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.2.0] - 2024-06-11
2
+
3
+ - Add support for `return_type` and `setter_type` in custom primitive shale types
4
+ - Add a more thorough description of sorbet and tapioca support in the README
5
+
1
6
  ## [0.1.9] - 2024-06-03
2
7
 
3
8
  - Fix the signature of `new` class method
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shale-builder (0.1.9)
4
+ shale-builder (0.2.0)
5
5
  booleans (>= 0.1)
6
6
  shale (< 2.0)
7
7
  sorbet-runtime (> 0.5)
data/README.md CHANGED
@@ -51,11 +51,7 @@ class Amount < Shale::Mapper
51
51
  include Shale::Builder
52
52
 
53
53
  attribute :value, Shale::Type::Float
54
- attribute :currency, Shale::Type::String, doc: <<~DOC
55
- This is some custom documentation that can be used by sorbet.
56
- It will be used by the tapioca DSL compiler
57
- to generate the RBI documentation for this attribute.
58
- DOC
54
+ attribute :currency, Shale::Type::String
59
55
  end
60
56
  ```
61
57
 
@@ -74,36 +70,6 @@ amount = Amount.build do |a|
74
70
  end
75
71
  ```
76
72
 
77
- If you use sorbet and run `bundle exec tapioca dsl` you'll get the following RBI file.
78
-
79
- ```rb
80
- # typed: true
81
-
82
- class Amount
83
- include ShaleAttributeMethods
84
-
85
- module ShaleAttributeMethods
86
- sig { returns(T.nilable(Float)) }
87
- def value; end
88
-
89
- sig { params(value: T.nilable(Float)).returns(T.nilable(Float)) }
90
- def value=(value); end
91
-
92
- # This is some custom documentation that can be used by sorbet.
93
- # It will be used by the tapioca DSL compiler
94
- # to generate the RBI documentation for this attribute.
95
- sig { returns(T.nilable(String)) }
96
- def currency; end
97
-
98
- # This is some custom documentation that can be used by sorbet.
99
- # It will be used by the tapioca DSL compiler
100
- # to generate the RBI documentation for this attribute.
101
- sig { params(value: T.nilable(String)).returns(T.nilable(String)) }
102
- def currency=(value); end
103
- end
104
- end
105
- ```
106
-
107
73
  ### Building nested objects
108
74
 
109
75
  It's kind of pointless when you've got a flat structure.
@@ -247,6 +213,145 @@ transaction = Transaction.build do |t|
247
213
  end
248
214
  ```
249
215
 
216
+ ### Sorbet support
217
+
218
+ Shale-builder adds support for sorbet and tapioca.
219
+
220
+ You can leverage an additional `doc` keyword argument in `attribute` definitions.
221
+ It will be used to generate a comment in the RBI file.
222
+
223
+ ```rb
224
+ require 'shale/builder'
225
+
226
+ class Amount < Shale::Mapper
227
+ include Shale::Builder
228
+
229
+ attribute :value, Shale::Type::Float
230
+ attribute :currency, Shale::Type::String, doc: <<~DOC
231
+ This is some custom documentation that can be used by sorbet.
232
+ It will be used by the tapioca DSL compiler
233
+ to generate the RBI documentation for this attribute.
234
+ DOC
235
+ end
236
+ ```
237
+
238
+ If you use sorbet and run `bundle exec tapioca dsl` you'll get the following RBI file.
239
+
240
+ ```rb
241
+ # typed: true
242
+
243
+ # DO NOT EDIT MANUALLY
244
+ # This is an autogenerated file for dynamic methods in `Amount`.
245
+ # Please instead update this file by running `bin/tapioca dsl Amount`.
246
+
247
+ class Amount
248
+ include ShaleAttributeMethods
249
+
250
+ module ShaleAttributeMethods
251
+ sig { returns(T.nilable(Float)) }
252
+ def value; end
253
+
254
+ sig { params(value: T.nilable(Float)).returns(T.nilable(Float)) }
255
+ def value=(value); end
256
+
257
+ # This is some custom documentation that can be used by sorbet.
258
+ # It will be used by the tapioca DSL compiler
259
+ # to generate the RBI documentation for this attribute.
260
+ sig { returns(T.nilable(String)) }
261
+ def currency; end
262
+
263
+ # This is some custom documentation that can be used by sorbet.
264
+ # It will be used by the tapioca DSL compiler
265
+ # to generate the RBI documentation for this attribute.
266
+ sig { params(value: T.nilable(String)).returns(T.nilable(String)) }
267
+ def currency=(value); end
268
+ end
269
+ end
270
+ ```
271
+
272
+ #### Primitive types
273
+
274
+ If you define custom primitive types in Shale by inheriting from `Shale::Type::Value`
275
+ you can describe the return type of the getter of the field that uses this primitive type by defining the `return_type` method that returns a sorbet type.
276
+
277
+ ```rb
278
+ def self.return_type = T.nilable(String)
279
+ ```
280
+
281
+ You can also describe the accepted argument type in the setter by defining the `setter_type` method that returns a sorbet type.
282
+
283
+ ```rb
284
+ def self.setter_type = T.any(String, Float, Integer)
285
+ ```
286
+
287
+ Here is a full example.
288
+
289
+ ```rb
290
+ # typed: true
291
+ require 'shale/builder'
292
+
293
+ # Cast from XML string to BigDecimal.
294
+ # And from BigDecimal to XML string.
295
+ class BigDecimalShaleType < Shale::Type::Value
296
+ class << self
297
+ extend T::Sig
298
+
299
+ # the return type of the field that uses this class as its type
300
+ def return_type = T.nilable(BigDecimal)
301
+ # the type of the argument given to a setter of the field
302
+ # that uses this class as its type
303
+ def setter_type = T.any(BigDecimal, String, NilClass)
304
+
305
+ # Decode from XML.
306
+ sig { params(value: T.any(BigDecimal, String, NilClass)).returns(T.nilable(BigDecimal)) }
307
+ def cast(value)
308
+ return if value.nil?
309
+
310
+ BigDecimal(value)
311
+ end
312
+
313
+ # Encode to XML.
314
+ #
315
+ # @param value: Value to convert to XML
316
+ sig { params(value: T.nilable(BigDecimal)).returns(T.nilable(String)) }
317
+ def as_xml_value(value)
318
+ return if value.nil?
319
+
320
+ value.to_s('F')
321
+ end
322
+ end
323
+ end
324
+
325
+ class Amount < Shale::Mapper
326
+ include Shale::Builder
327
+
328
+ # `value` uses BigDecimalShaleType as its type
329
+ attribute :value, BigDecimalShaleType
330
+ end
331
+ ```
332
+
333
+ After running `bundle exec tapioca dsl` you'll get the following RBI file.
334
+
335
+ ```rb
336
+ # typed: true
337
+
338
+ # DO NOT EDIT MANUALLY
339
+ # This is an autogenerated file for dynamic methods in `Amount`.
340
+ # Please instead update this file by running `bin/tapioca dsl Amount`.
341
+
342
+ class Amount
343
+ include ShaleAttributeMethods
344
+
345
+ module ShaleAttributeMethods
346
+ sig { returns(T.nilable(::BigDecimal)) }
347
+ def value; end
348
+
349
+ sig { params(value: T.nilable(T.any(::BigDecimal, ::String))).returns(T.nilable(T.any(::BigDecimal, ::String))) }
350
+ def value=(value); end
351
+ end
352
+ end
353
+ ```
354
+
250
355
  ## Development
251
356
 
252
357
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Shale
4
4
  module Builder
5
- VERSION = '0.1.9'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
@@ -37,7 +37,7 @@ module Tapioca
37
37
  attribute_names = constant.attributes.keys.sort
38
38
  attribute_names.each do |attribute_name|
39
39
  attribute = T.let(constant.attributes[attribute_name], ::Shale::Attribute)
40
- non_nilable_type, nilable_type = shale_type_to_sorbet_type(attribute)
40
+ non_nilable_type, nilable_type = shale_type_to_sorbet_return_type(attribute)
41
41
  type = nilable_type
42
42
  if attribute.collection?
43
43
  type = "T.nilable(T::Array[#{non_nilable_type}])"
@@ -69,6 +69,12 @@ module Tapioca
69
69
  mod.create_method(attribute.name, return_type: type, comments: comments)
70
70
  end
71
71
 
72
+ non_nilable_type, nilable_type = shale_type_to_sorbet_setter_type(attribute)
73
+ type = nilable_type
74
+ if attribute.collection?
75
+ type = "T.nilable(T::Array[#{non_nilable_type}])"
76
+ end
77
+
72
78
  # setter
73
79
  mod.create_method(
74
80
  "#{attribute.name}=",
@@ -106,22 +112,44 @@ module Tapioca
106
112
  )
107
113
 
108
114
  sig { params(attribute: ::Shale::Attribute).returns([String, String]) }
109
- def shale_type_to_sorbet_type(attribute)
115
+ def shale_type_to_sorbet_return_type(attribute)
110
116
  return_type = SHALE_TYPES_MAP[attribute.type]
111
- return complex_shale_type_to_sorbet_type(attribute) unless return_type
117
+ return complex_shale_type_to_sorbet_return_type(attribute) unless return_type
112
118
  return [T.must(return_type.name), T.must(return_type.name)] if attribute.collection? || attribute.default.is_a?(return_type)
113
119
 
114
120
  [T.must(return_type.name), "T.nilable(#{return_type.name})"]
115
121
  end
116
122
 
117
123
  sig { params(attribute: ::Shale::Attribute).returns([String, String]) }
118
- def complex_shale_type_to_sorbet_type(attribute)
124
+ def complex_shale_type_to_sorbet_return_type(attribute)
119
125
  return [T.cast(attribute.type.to_s, String), "T.nilable(#{attribute.type})"] unless attribute.type.respond_to?(:return_type)
120
126
 
121
127
  return_type_string = attribute.type.return_type.to_s
122
128
  [return_type_string, return_type_string]
123
129
  end
124
130
 
131
+ sig { params(attribute: ::Shale::Attribute).returns([String, String]) }
132
+ def shale_type_to_sorbet_setter_type(attribute)
133
+ setter_type = SHALE_TYPES_MAP[attribute.type]
134
+ return complex_shale_type_to_sorbet_setter_type(attribute) unless setter_type
135
+ return [T.must(setter_type.name), T.must(setter_type.name)] if attribute.collection? || attribute.default.is_a?(setter_type)
136
+
137
+ [T.must(setter_type.name), "T.nilable(#{setter_type.name})"]
138
+ end
139
+
140
+ sig { params(attribute: ::Shale::Attribute).returns([String, String]) }
141
+ def complex_shale_type_to_sorbet_setter_type(attribute)
142
+ if attribute.type.respond_to?(:setter_type)
143
+ setter_type_string = attribute.type.setter_type.to_s
144
+ [setter_type_string, setter_type_string]
145
+ elsif attribute.type.respond_to?(:return_type)
146
+ return_type_string = attribute.type.return_type.to_s
147
+ [return_type_string, return_type_string]
148
+ else
149
+ [T.cast(attribute.type.to_s, String), "T.nilable(#{attribute.type})"]
150
+ end
151
+ end
152
+
125
153
  end
126
154
  end
127
155
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shale-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mateusz Drewniak
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-03 00:00:00.000000000 Z
11
+ date: 2024-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: booleans