Skip to content

Commit

Permalink
Setup sorbet and add the doc attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
Verseth committed May 13, 2024
1 parent 02b5fbd commit 3f3b3b8
Show file tree
Hide file tree
Showing 55 changed files with 114,983 additions and 24 deletions.
6 changes: 6 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ AllCops:
TargetRubyVersion: 3.0
Exclude:
- lib/tapioca/**/*.rb

Style/DocumentationMethod:
Enabled: false

Style/TrailingCommaInArguments:
Enabled: false
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ gem 'rake', '~> 13.0' # automation tasks
gem 'rubocop-espago', '~> 1.0' # ruby linter
gem 'shoulda-context', '~> 2.0' # more pleasant test syntax
gem 'solargraph', '~> 0.48' # language server
gem 'tapioca', '> 0.13' # RBI generator for sorbet
35 changes: 35 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,43 @@ PATH
remote: .
specs:
shale-builder (0.1.5)
booleans (>= 0.1)
shale (< 2.0)
sorbet-runtime (> 0.5)

GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
backport (1.2.0)
benchmark (0.2.1)
booleans (0.1.1)
byebug (11.1.3)
diff-lcs (1.5.0)
e2mmap (0.1.0)
erubi (1.12.0)
jaro_winkler (1.5.4)
json (2.6.3)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
minitest (5.17.0)
netrc (0.11.0)
nokogiri (1.14.2-arm64-darwin)
racc (~> 1.4)
nokogiri (1.14.2-x86_64-linux)
racc (~> 1.4)
parallel (1.22.1)
parser (3.2.1.0)
ast (~> 2.4.1)
prism (0.29.0)
racc (1.6.2)
rainbow (3.1.1)
rake (13.0.6)
rbi (0.1.13)
prism (>= 0.18.0, < 1.0.0)
sorbet-runtime (>= 0.5.9204)
regexp_parser (2.7.0)
reverse_markdown (2.1.1)
nokogiri
Expand Down Expand Up @@ -66,12 +75,37 @@ GEM
thor (~> 1.0)
tilt (~> 2.0)
yard (~> 0.9, >= 0.9.24)
sorbet (0.5.11372)
sorbet-static (= 0.5.11372)
sorbet-runtime (0.5.11372)
sorbet-static (0.5.11372-universal-darwin)
sorbet-static (0.5.11372-x86_64-linux)
sorbet-static-and-runtime (0.5.11372)
sorbet (= 0.5.11372)
sorbet-runtime (= 0.5.11372)
spoom (1.3.2)
erubi (>= 1.10.0)
prism (>= 0.19.0)
sorbet-static-and-runtime (>= 0.5.10187)
thor (>= 0.19.2)
tapioca (0.14.1)
bundler (>= 2.2.25)
netrc (>= 0.11.0)
parallel (>= 1.21.0)
rbi (>= 0.1.4, < 0.2)
sorbet-static-and-runtime (>= 0.5.11087)
spoom (>= 1.2.0)
thor (>= 1.2.0)
yard-sorbet
thor (1.2.1)
tilt (2.1.0)
unicode-display_width (2.4.2)
webrick (1.7.0)
yard (0.9.28)
webrick (~> 1.7.0)
yard-sorbet (0.8.1)
sorbet-runtime (>= 0.5)
yard (>= 0.9)

PLATFORMS
arm64-darwin-20
Expand All @@ -86,6 +120,7 @@ DEPENDENCIES
shale-builder!
shoulda-context (~> 2.0)
solargraph (~> 0.48)
tapioca (> 0.13)

BUNDLED WITH
2.4.7
27 changes: 27 additions & 0 deletions bin/tapioca
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application 'tapioca' is installed as part of a gem, and
# this file is here to facilitate running it.
#

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)

bundle_binstub = File.expand_path("bundle", __dir__)

if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("tapioca", "tapioca")
15 changes: 15 additions & 0 deletions lib/shale/attribute.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true
# typed: true

require 'shale'

module Shale
class Attribute # rubocop:disable Style/Documentation
extend T::Sig

# Contains the documentation comment for the shale attribute
# in a Ruby String.
sig { returns(T.nilable(String)) }
attr_accessor :doc
end
end
61 changes: 40 additions & 21 deletions lib/shale/builder.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# frozen_string_literal: true
# typed: true

require 'shale'
require 'sorbet-runtime'

require_relative 'builder/version'
require_relative 'attribute'

module Shale
# It's meant to be included in subclasses of `Shale::Mapper`
Expand Down Expand Up @@ -37,21 +40,21 @@ module Shale
# end
#
module Builder
extend T::Helpers

class << self
extend T::Sig

# Gets called after including this module in a module or class.
#
# @param mod [Module, Class]
# @return [void]
sig { params(mod: Module).void }
def included(mod)
mod.extend ClassMethods
Builder.prepare_mod(mod)
end

# Prepares the received module or class
# for dynamic method definition.
#
# @param mod [Module, Class]
# @return [void]
sig { params(mod: Module).void }
def prepare_mod(mod)
builder_methods_module = ::Module.new
mod.instance_variable_set :@builder_methods_module, builder_methods_module
Expand All @@ -61,36 +64,50 @@ def prepare_mod(mod)

# Class methods provided by `Shale::Builder`
module ClassMethods
# @param subclass [Class]
# @return [void]
extend T::Sig
extend T::Generic
abstract!
has_attached_class!

sig { params(subclass: Class).void }
def inherited(subclass)
super
Builder.prepare_mod(subclass)
end

# Contains overridden getter methods for attributes
# with complex types (so that they accept a block for building)
#
# @return [Module]
sig { returns(Module) }
attr_reader :builder_methods_module

# @return [Class, nil]
attr_accessor :request_class

# @yieldparam [self]
# @return [self]
def build
sig { params(_block: T.proc.params(arg0: T.attached_class).void).returns(T.attached_class) }
def build(&_block)
body = new
yield(body)

body
end

# @param name [String, Symbol]
# @param type [Class]
# @return [void]
def attribute(name, type, *args, collection: false, **kwargs, &block)
super
sig { abstract.returns(T.attached_class) }
def new; end

sig { abstract.returns(T::Hash[Symbol, Shale::Attribute]) }
def attributes; end

sig do
params(
name: T.any(String, Symbol),
type: Class,
collection: T::Boolean,
default: T.nilable(Proc),
doc: T.nilable(String),
kwargs: Object,
block: T.nilable(T.proc.void),
).void
end
def attribute(name, type, collection: false, default: nil, doc: nil, **kwargs, &block)
super(name, type, collection: collection, default: default, **kwargs, &block)
attributes[name.to_sym]&.doc = doc # add doc to the attribute
return unless type < ::Shale::Mapper

if collection
Expand Down Expand Up @@ -121,5 +138,7 @@ def #{name} # def amount

end

mixes_in_class_methods(ClassMethods)

end
end
1 change: 0 additions & 1 deletion lib/shale/builder/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

module Shale
module Builder
# @return [String]
VERSION = '0.1.5'
end
end
16 changes: 15 additions & 1 deletion lib/tapioca/dsl/compilers/shale.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# frozen_string_literal: true

require 'shale'
require 'booleans'
begin
require 'shale/builder'
rescue LoadError
Expand All @@ -10,9 +11,12 @@
module Tapioca
module Compilers
class Shale < Tapioca::Dsl::Compiler
extend T::Sig
ConstantType = type_member { { fixed: T.class_of(::Shale::Mapper) } }

class << self
extend T::Sig

sig { override.returns(T::Enumerable[Module]) }
def gather_constants
# Collect all the classes that inherit from Shale::Mapper
Expand All @@ -28,11 +32,16 @@ def decorate

# For each attribute defined in the class
constant.attributes.each_value do |attribute|
attribute = T.let(attribute, ::Shale::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
comments = T.let([], T::Array[RBI::Comment])
if shale_builder_defined? && attribute.doc
comments << RBI::Comment.new(T.must(attribute.doc))
end

if has_shale_builder && attribute.type < ::Shale::Mapper
sigs = T.let([], T::Array[RBI::Sig])
Expand All @@ -49,17 +58,19 @@ def decorate
klass.create_method_with_sigs(
attribute.name,
sigs: sigs,
comments: comments,
parameters: [RBI::BlockParam.new('block')],
)
else
klass.create_method(attribute.name, return_type: type)
klass.create_method(attribute.name, return_type: type, comments: comments)
end

# setter
klass.create_method(
"#{attribute.name}=",
parameters: [create_param('value', type: type)],
return_type: type,
comments: comments,
)
end
end
Expand All @@ -75,6 +86,9 @@ def includes_shale_builder(klass)
klass < ::Shale::Builder
end

sig { returns(T::Boolean) }
def shale_builder_defined? = Boolean(defined?(::Shale::Builder))

SHALE_TYPES_MAP = T.let(
{
::Shale::Type::Value => Object,
Expand Down
5 changes: 4 additions & 1 deletion shale-builder.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ Gem::Specification.new do |spec|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(__dir__) do
`git ls-files -z`.split("\x0").reject do |f|
(File.expand_path(f) == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
(File.expand_path(f) == __FILE__) ||
f.match(%r{\A(?:(?:bin|test|spec|features|sorbet)/|\.(?:git|circleci)|appveyor)})
end
end
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']

# Uncomment to register a new dependency of your gem
spec.add_dependency 'booleans', '>= 0.1'
spec.add_dependency 'shale', '< 2.0'
spec.add_dependency 'sorbet-runtime', '> 0.5'
spec.metadata['rubygems_mfa_required'] = 'true'
end
4 changes: 4 additions & 0 deletions sorbet/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--dir
.
--ignore=tmp/
--ignore=vendor/
1 change: 1 addition & 0 deletions sorbet/rbi/annotations/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/*.rbi linguist-vendored=true
Loading

0 comments on commit 3f3b3b8

Please sign in to comment.