tapioca-compilers-dry_struct 0.0.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 +7 -0
- data/CHANGELOG.md +0 -0
- data/README.md +66 -0
- data/lib/tapioca/dsl/compilers/dry_struct.rb +328 -0
- data/tapioca-compilers-dry_struct.gemspec +31 -0
- metadata +135 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9dcbe2532639837d3887debbc6b919d0e6181ce40af168e8c0ef74ab1efdf21e
|
4
|
+
data.tar.gz: 81e38049ba86b21f99967514aa1bc9b6f87c60fa7a7d8b5d395633098b265d55
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e0df50ffae3ca81b5236ecbb6c9d57b424841454067ffe5ce8f0d453b9e367706527f3940546b417f8055595bd13971cabef2a903f0c298bf28306935f1bbdeb
|
7
|
+
data.tar.gz: 5d2ba85b1a2399808f847407803c3b34a55dda5a474c6b766f836a432b05ff6289dc4f46ec75a2582b44ec3c2909595411d43406e6c0f26642d17fe5ad55bdf5
|
data/CHANGELOG.md
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
**[WARNING] THIS APP IS ALPHA VERSION!!!**
|
2
|
+
|
3
|
+
This script is a [Tapioca's custom DSL compiler](https://github.com/Shopify/tapioca#writing-custom-dsl-compilers) for [dry-struct](https://dry-rb.org/gems/dry-struct/main/).
|
4
|
+
|
5
|
+
# References
|
6
|
+
|
7
|
+
https://discourse.dry-rb.org/t/dry-rb-sorbet-can-we-unite/961
|
8
|
+
|
9
|
+
https://github.com/Shopify/tapioca/issues/1210
|
10
|
+
|
11
|
+
# Installation
|
12
|
+
|
13
|
+
cp lib/tapioca/dsl/compilers/dry_struct.rb PATH_TO_YOUR_PROJECT/sorbet/tapioca/compilers/dry_struct.rb
|
14
|
+
|
15
|
+
-----------------------------------
|
16
|
+
|
17
|
+
Add this line to your application’s Gemfile:
|
18
|
+
|
19
|
+
```
|
20
|
+
gem 'tapioca-compilers-dry_struct'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
```
|
26
|
+
$ bundle
|
27
|
+
```
|
28
|
+
|
29
|
+
> all the gem needs to do is to place the DSL compiler inside the lib/tapioca/dsl/compilers folder and it will be automatically discovered and loaded by Tapioca.
|
30
|
+
>
|
31
|
+
> https://github.com/Shopify/tapioca/blob/v0.10.2/README.md#writing-custom-dsl-compilers
|
32
|
+
|
33
|
+
Tapioca automatically load the compiler inside gem, just you need to do is type a command below.
|
34
|
+
|
35
|
+
```
|
36
|
+
$ bundle exec tapioca dsl
|
37
|
+
```
|
38
|
+
|
39
|
+
# Development
|
40
|
+
|
41
|
+
Execute `./bin/dsl` generates rbi files under `sorbet/rbi/dsl/`.
|
42
|
+
If you need to test another dry-struct, add or edit rb files under `spec/examples/` and generate rbi files.
|
43
|
+
|
44
|
+
A compiler itself exists in `lib/tapioca/dsl/compilers/dry_struct.rb`.
|
45
|
+
|
46
|
+
# Test
|
47
|
+
|
48
|
+
```
|
49
|
+
bundle exec rake spec
|
50
|
+
```
|
51
|
+
|
52
|
+
# Environment Variables
|
53
|
+
|
54
|
+
## DRY_PREFER_PLAIN_TIME
|
55
|
+
|
56
|
+
\ | Ruby `Time` is typed as
|
57
|
+
------- | --------
|
58
|
+
0(DEFAULT) | `::ActiveSupport::TimeWithZone`
|
59
|
+
1 | `::Time`
|
60
|
+
|
61
|
+
## DRY_USE_EXPERIMENTAL_SHAPE
|
62
|
+
|
63
|
+
\ | `Types::Hash.schema(name: Types::String, age: Types::Integer)` is typed as
|
64
|
+
------- | --------
|
65
|
+
0(DEFAULT) | `::T::Hash[::T.untyped, ::T.untyped]`
|
66
|
+
1 | `{ name: ::String, age: ::Integer }`
|
@@ -0,0 +1,328 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'dry-types'
|
4
|
+
require 'dry-struct'
|
5
|
+
begin
|
6
|
+
require 'dry-monads'
|
7
|
+
rescue LoadError
|
8
|
+
# NOP
|
9
|
+
end
|
10
|
+
|
11
|
+
module Tapioca
|
12
|
+
module Compilers
|
13
|
+
# tapioca's [custom DSL compilers](https://github.com/Shopify/tapioca/blob/main/README.md#writing-custom-dsl-compilers)
|
14
|
+
# for [dry-struct](https://dry-rb.org/gems/dry-struct/).
|
15
|
+
class DryStruct < Tapioca::Dsl::Compiler
|
16
|
+
extend T::Sig
|
17
|
+
|
18
|
+
VERSION = '0.0.0'
|
19
|
+
|
20
|
+
# Convert Dry AST to type informations
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# ```
|
24
|
+
# compiler = DryAstCompiler.new
|
25
|
+
# DryStructClass.schema.each do |s|
|
26
|
+
# attribute_info = compiler.visit(s.to_ast)
|
27
|
+
#
|
28
|
+
# # => { name: 'attr_name01', required: true, type: String }
|
29
|
+
# # => { name: 'attr_name02', required: true, type: Integer }
|
30
|
+
# # => { name: 'attr_name03', required: true, type: [String] }
|
31
|
+
# # => { name: 'attr_name04', required: true, type: [[String]] }
|
32
|
+
# # => { name: 'attr_name05', required: true, type: Hash }
|
33
|
+
# # => { name: 'attr_name06', required: true, type: Date }
|
34
|
+
# # => { name: 'attr_name07', required: true, type: DateTime }
|
35
|
+
# # => { name: 'attr_name08', required: true, type: Time }
|
36
|
+
# # => { name: 'attr_name09', required: true, type: Set }
|
37
|
+
# # => { name: 'attr_name10', required: true, type: Range }
|
38
|
+
# # => { name: 'attr_name11', required: true, type: YourKlass }
|
39
|
+
# # => { name: 'attr_name12', required: true, type: #<DryAstCompiler::Undefined> }
|
40
|
+
# # => { name: 'attr_name13', required: true, type: #<DryAstCompiler::Sum> }
|
41
|
+
# # => { name: 'attr_name14', required: true, type: #<DryAstCompiler::Map> }
|
42
|
+
# # => { name: 'attr_name15', required: true, type: #<DryAstCompiler::Schema> }
|
43
|
+
# do
|
44
|
+
# ```
|
45
|
+
class DryAstCompiler
|
46
|
+
# Represents dry's any type
|
47
|
+
class Undefined
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
'Undefined'
|
51
|
+
end
|
52
|
+
|
53
|
+
def inspect
|
54
|
+
to_s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Represents dry's sum type
|
59
|
+
class Sum
|
60
|
+
attr_reader :types
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@types = ::Set.new
|
64
|
+
end
|
65
|
+
|
66
|
+
def size
|
67
|
+
@types.size
|
68
|
+
end
|
69
|
+
|
70
|
+
def <<(arg)
|
71
|
+
if arg.is_a?(Sum)
|
72
|
+
arg.types.each { |t| @types << t }
|
73
|
+
else
|
74
|
+
@types << arg
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def map(&block)
|
79
|
+
@types.map(&block)
|
80
|
+
end
|
81
|
+
|
82
|
+
def first
|
83
|
+
@types.first
|
84
|
+
end
|
85
|
+
|
86
|
+
def include_undefined?
|
87
|
+
@types.any? { |t| t.is_a?(Undefined) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def include_nilclass?
|
91
|
+
@types.include?(::NilClass)
|
92
|
+
end
|
93
|
+
|
94
|
+
def delete_nilclass!
|
95
|
+
@types.reject! { |t| t == ::NilClass }
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_s
|
99
|
+
"Sum(#{@types.map(&:to_s).join(',')})"
|
100
|
+
end
|
101
|
+
|
102
|
+
def inspect
|
103
|
+
to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Represents dry's schema type
|
108
|
+
class Schema
|
109
|
+
def initialize(attribute_infos)
|
110
|
+
@attribute_infos = attribute_infos
|
111
|
+
end
|
112
|
+
|
113
|
+
def map(&block)
|
114
|
+
@attribute_infos.map(&block)
|
115
|
+
end
|
116
|
+
|
117
|
+
def empty?
|
118
|
+
@attribute_infos.empty?
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Represents dry's map type
|
123
|
+
class Map
|
124
|
+
attr_reader :key, :value
|
125
|
+
|
126
|
+
def initialize(key, value)
|
127
|
+
@key = key
|
128
|
+
@value = value
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def visit(node)
|
133
|
+
meth, rest = node
|
134
|
+
public_send(:"visit_#{meth}", rest)
|
135
|
+
end
|
136
|
+
|
137
|
+
def visit_key(node)
|
138
|
+
name, required, rest = node
|
139
|
+
{
|
140
|
+
name: name,
|
141
|
+
required: required,
|
142
|
+
type: visit(rest)
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
def visit_constructor(node)
|
147
|
+
a, _ = node
|
148
|
+
visit(a)
|
149
|
+
end
|
150
|
+
|
151
|
+
def visit_struct(node)
|
152
|
+
type, _ = node
|
153
|
+
type
|
154
|
+
end
|
155
|
+
|
156
|
+
def visit_sum(node)
|
157
|
+
type = Sum.new
|
158
|
+
node.each do |n|
|
159
|
+
next if n.is_a?(::Hash)
|
160
|
+
type << visit(n)
|
161
|
+
end
|
162
|
+
type
|
163
|
+
end
|
164
|
+
|
165
|
+
def visit_and(node)
|
166
|
+
# NOP
|
167
|
+
end
|
168
|
+
|
169
|
+
def visit_array(node)
|
170
|
+
type = visit(node[0])
|
171
|
+
[type]
|
172
|
+
end
|
173
|
+
|
174
|
+
def visit_constrained(node)
|
175
|
+
types = node.map { |r| visit(r) }.reject(&:nil?)
|
176
|
+
types.size == 1 ? types[0] : types
|
177
|
+
end
|
178
|
+
|
179
|
+
def visit_nominal(node)
|
180
|
+
type, _option = node
|
181
|
+
type
|
182
|
+
end
|
183
|
+
|
184
|
+
def visit_predicate(_node)
|
185
|
+
# NOP
|
186
|
+
end
|
187
|
+
|
188
|
+
def visit_schema(node)
|
189
|
+
Schema.new(node[0].map { |n| visit(n) })
|
190
|
+
end
|
191
|
+
|
192
|
+
def visit_hash(_node)
|
193
|
+
::Hash
|
194
|
+
end
|
195
|
+
|
196
|
+
def visit_map(node)
|
197
|
+
Map.new(visit(node[0]), visit(node[1]))
|
198
|
+
end
|
199
|
+
|
200
|
+
def visit_enum(node)
|
201
|
+
visit(node[0][1][0])
|
202
|
+
end
|
203
|
+
|
204
|
+
def visit_any(_node)
|
205
|
+
Undefined.new
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
ConstantType = type_member {{ fixed: ::T.class_of(::Dry::Struct) }}
|
210
|
+
|
211
|
+
sig { override.void }
|
212
|
+
def decorate
|
213
|
+
compiler = DryAstCompiler.new
|
214
|
+
root.create_path(constant) do |klass|
|
215
|
+
constant.schema.each do |s|
|
216
|
+
attribute_info = compiler.visit(s.to_ast)
|
217
|
+
if ::Dry::Types.const_defined?(:Maybe) && s.type.class == ::Dry::Types::Maybe
|
218
|
+
sorbet_type = '::T.any(::Dry::Monads::Maybe::Some, ::Dry::Monads::Maybe::None)'
|
219
|
+
else
|
220
|
+
sorbet_type = self.class.to_sorbet_type(attribute_info[:type], attribute_info[:required])
|
221
|
+
end
|
222
|
+
klass.create_method(
|
223
|
+
attribute_info[:name].to_s,
|
224
|
+
return_type: sorbet_type,
|
225
|
+
)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
sig { override.returns(::T::Enumerable[Module]) }
|
231
|
+
def self.gather_constants
|
232
|
+
all_classes.select { |c| c < ::Dry::Struct }
|
233
|
+
end
|
234
|
+
|
235
|
+
sig { params(type: T.untyped, required: T::Boolean).returns(String) }
|
236
|
+
def self.to_sorbet_type(type, required)
|
237
|
+
base = if type.is_a?(DryAstCompiler::Sum)
|
238
|
+
sum_to_sorbet_type(type)
|
239
|
+
elsif type.is_a?(DryAstCompiler::Schema)
|
240
|
+
env('DRY_USE_EXPERIMENTAL_SHAPE') ? experimental_schema_to_sorbet_type(type) : '::T::Hash[::T.untyped, ::T.untyped]'
|
241
|
+
elsif type.is_a?(DryAstCompiler::Map)
|
242
|
+
map_to_sorbet_type(type)
|
243
|
+
elsif type.is_a?(DryAstCompiler::Undefined)
|
244
|
+
'::T.untyped'
|
245
|
+
elsif type.is_a?(::Array)
|
246
|
+
"::T::Array[#{to_sorbet_type(type[0], true)}]"
|
247
|
+
elsif type == ::Hash
|
248
|
+
'::T::Hash[::T.untyped, ::T.untyped]'
|
249
|
+
elsif type == ::Time
|
250
|
+
env('DRY_PREFER_PLAIN_TIME') ? '::Time' : '::ActiveSupport::TimeWithZone'
|
251
|
+
elsif type == ::Range
|
252
|
+
'::T::Range[::T.untyped]'
|
253
|
+
elsif type == ::Set
|
254
|
+
'::T::Set[::T.untyped]'
|
255
|
+
elsif type == ::TrueClass || type == ::FalseClass
|
256
|
+
'::T::Boolean'
|
257
|
+
elsif type.nil?
|
258
|
+
'::NilClass'
|
259
|
+
else
|
260
|
+
"::#{type.name}"
|
261
|
+
end
|
262
|
+
if base == '::T.untyped' || base == '::NilClass'
|
263
|
+
base
|
264
|
+
else
|
265
|
+
if required
|
266
|
+
base
|
267
|
+
else
|
268
|
+
if base.start_with?('::T.nilable')
|
269
|
+
base
|
270
|
+
else
|
271
|
+
"::T.nilable(#{base})"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
sig { params(sum: DryAstCompiler::Sum).returns(String) }
|
278
|
+
def self.sum_to_sorbet_type(sum)
|
279
|
+
return '::T.untyped' if sum.include_undefined?
|
280
|
+
|
281
|
+
if sum.include_nilclass?
|
282
|
+
sum.delete_nilclass!
|
283
|
+
if sum.size < 2
|
284
|
+
"::T.nilable(#{to_sorbet_type(sum.first, true)})"
|
285
|
+
elsif (sum.types - [::TrueClass, ::FalseClass]).empty?
|
286
|
+
'::T.nilable(::T::Boolean)'
|
287
|
+
else
|
288
|
+
"::T.nilable(::T.any(#{sum.map { |t| to_sorbet_type(t, true) }.join(', ')}))"
|
289
|
+
end
|
290
|
+
else
|
291
|
+
if (sum.types - [::TrueClass, ::FalseClass]).empty?
|
292
|
+
'::T::Boolean'
|
293
|
+
elsif sum.size == 1
|
294
|
+
to_sorbet_type(sum.first, true)
|
295
|
+
else
|
296
|
+
"::T.any(#{sum.map { |t| to_sorbet_type(t, true) }.join(', ')})"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
sig { params(map: DryAstCompiler::Map).returns(String) }
|
302
|
+
def self.map_to_sorbet_type(map)
|
303
|
+
"::T::Hash[#{map.key}, #{map.value}]"
|
304
|
+
end
|
305
|
+
|
306
|
+
sig { params(schema: DryAstCompiler::Schema).returns(String) }
|
307
|
+
def self.experimental_schema_to_sorbet_type(schema)
|
308
|
+
return '::T::Hash[::T.untyped, ::T.untyped]' if schema.empty?
|
309
|
+
|
310
|
+
sigs = schema.map do |i|
|
311
|
+
sorbet_type = to_sorbet_type(i[:type], i[:required])
|
312
|
+
i[:name].is_a?(::String) ? "'#{i[:name]}' => #{sorbet_type}" : "#{i[:name]}: #{sorbet_type}"
|
313
|
+
end
|
314
|
+
|
315
|
+
"{ #{sigs.join(', ')} }"
|
316
|
+
end
|
317
|
+
|
318
|
+
sig { params(key: String).returns(T::Boolean) }
|
319
|
+
def self.env(key)
|
320
|
+
v = ENV[key]
|
321
|
+
return false if v.nil?
|
322
|
+
return false if v == '0'
|
323
|
+
true
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "tapioca-compilers-dry_struct"
|
5
|
+
spec.authors = ["Yuki Jikumaru"]
|
6
|
+
spec.email = ["jikumaruyuki@gmail.com"]
|
7
|
+
spec.license = "MIT"
|
8
|
+
spec.version = "0.0.0"
|
9
|
+
|
10
|
+
spec.summary = "Tapioca's compiler for dry-struct"
|
11
|
+
spec.description = spec.summary
|
12
|
+
spec.homepage = "https://github.com/YukiJikumaru/tapioca-compilers-dry_struct"
|
13
|
+
spec.files = Dir["README.md", "CHANGELOG.md", "tapioca-compilers-dry_struct.gemspec", "lib/tapioca/dsl/compilers/dry_struct.rb"]
|
14
|
+
spec.require_paths = ["lib"]
|
15
|
+
|
16
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
17
|
+
spec.metadata["changelog_uri"] = "https://github.com/YukiJikumaru/tapioca-compilers-dry_struct/blob/main/CHANGELOG.md"
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/YukiJikumaru/tapioca-compilers-dry_struct"
|
19
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/YukiJikumaru/tapioca-compilers-dry_struct/issues"
|
20
|
+
|
21
|
+
spec.required_ruby_version = ">= 2.7.0"
|
22
|
+
|
23
|
+
# to update dependencies edit project.yml
|
24
|
+
spec.add_runtime_dependency "tapioca", ">= 0.10"
|
25
|
+
spec.add_runtime_dependency "dry-struct", ">= 1.2"
|
26
|
+
spec.add_runtime_dependency "dry-monads", ">= 1.2"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler"
|
29
|
+
spec.add_development_dependency "rake"
|
30
|
+
spec.add_development_dependency "rspec"
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tapioca-compilers-dry_struct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yuki Jikumaru
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-10-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tapioca
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.10'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.10'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-struct
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-monads
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Tapioca's compiler for dry-struct
|
98
|
+
email:
|
99
|
+
- jikumaruyuki@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- CHANGELOG.md
|
105
|
+
- README.md
|
106
|
+
- lib/tapioca/dsl/compilers/dry_struct.rb
|
107
|
+
- tapioca-compilers-dry_struct.gemspec
|
108
|
+
homepage: https://github.com/YukiJikumaru/tapioca-compilers-dry_struct
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata:
|
112
|
+
allowed_push_host: https://rubygems.org
|
113
|
+
changelog_uri: https://github.com/YukiJikumaru/tapioca-compilers-dry_struct/blob/main/CHANGELOG.md
|
114
|
+
source_code_uri: https://github.com/YukiJikumaru/tapioca-compilers-dry_struct
|
115
|
+
bug_tracker_uri: https://github.com/YukiJikumaru/tapioca-compilers-dry_struct/issues
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 2.7.0
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubygems_version: 3.1.6
|
132
|
+
signing_key:
|
133
|
+
specification_version: 4
|
134
|
+
summary: Tapioca's compiler for dry-struct
|
135
|
+
test_files: []
|