Skip to content

Commit

Permalink
v0.1.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Verseth committed May 13, 2024
1 parent 09a2ba3 commit 7ef59f0
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [0.1.4] - 2024-05-13

- Add a tapioca compiler for shale and shale builder

## [0.1.3] - 2023-11-23

- Change shale version dependency from `< 1.0` to `< 2.0`
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
shale-builder (0.1.3)
shale-builder (0.1.4)
shale (< 2.0)

GEM
Expand Down
2 changes: 1 addition & 1 deletion lib/shale/builder/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
module Shale
module Builder
# @return [String]
VERSION = '0.1.3'
VERSION = '0.1.4'
end
end
103 changes: 103 additions & 0 deletions lib/tapioca/dsl/compilers/shale.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# typed: true
# frozen_string_literal: true

module Tapioca
module Compilers
class Shale < Tapioca::Dsl::Compiler
ConstantType = type_member { { fixed: T.class_of(::Shale::Mapper) } }

class << self
sig { override.returns(T::Enumerable[Module]) }
def gather_constants
# Collect all the classes that inherit from Shale::Mapper
all_classes.select { |c| c < ::Shale::Mapper }
end
end

sig { override.void }
def decorate
# Create a RBI definition for each class that inherits from Shale::Mapper
root.create_path(constant) do |klass|
has_shale_builder = includes_shale_builder(constant)

# For each attribute defined in the class
constant.attributes.each_value do |attribute|
non_nilable_type, nilable_type = shale_type_to_sorbet_type(attribute)
type = nilable_type
if attribute.collection?
type = "T.nilable(T::Array[#{non_nilable_type}])"
end

if has_shale_builder && attribute.type < ::Shale::Mapper
sigs = T.let([], T::Array[RBI::Sig])
# simple getter
sigs << klass.create_sig(
parameters: { block: 'NilClass' },
return_type: type,
)
# getter with block
sigs << klass.create_sig(
parameters: { block: "T.proc.params(arg0: #{non_nilable_type}).void" },
return_type: non_nilable_type
)
klass.create_method_with_sigs(
attribute.name,
sigs: sigs,
parameters: [RBI::BlockParam.new('block')],
)
else
klass.create_method(attribute.name, return_type: type)
end

# setter
klass.create_method(
"#{attribute.name}=",
parameters: [create_param('value', type: type)],
return_type: type,
)
end
end

end

private

sig { params(klass: Class).returns(T.nilable(T::Boolean)) }
def includes_shale_builder(klass)
return false unless defined?(::Shale::Builder)

klass < ::Shale::Builder
end

SHALE_TYPES_MAP = T.let(
{
::Shale::Type::Value => Object,
::Shale::Type::String => String,
::Shale::Type::Float => Float,
::Shale::Type::Integer => Integer,
::Shale::Type::Time => Time,
::Shale::Type::Date => Date,
}.freeze,
T::Hash[Class, Class],
)

sig { params(attribute: ::Shale::Attribute).returns([String, String]) }
def shale_type_to_sorbet_type(attribute)
return_type = SHALE_TYPES_MAP[attribute.type]
return complex_shale_type_to_sorbet_type(attribute) unless return_type
return [T.must(return_type.name), T.must(return_type.name)] if attribute.collection? || attribute.default.is_a?(return_type)

[T.must(return_type.name), "T.nilable(#{return_type.name})"]
end

sig { params(attribute: ::Shale::Attribute).returns([String, String]) }
def complex_shale_type_to_sorbet_type(attribute)
return [T.cast(attribute.type.to_s, String), "T.nilable(#{attribute.type})"] unless attribute.type.respond_to?(:return_type)

return_type_string = attribute.type.return_type.to_s
[return_type_string, return_type_string]
end

end
end
end

0 comments on commit 7ef59f0

Please sign in to comment.