Skip to content

Commit

Permalink
Implement InexactStruct DSL compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-mannino committed Nov 16, 2024
1 parent 5c70e84 commit e2e68d9
Show file tree
Hide file tree
Showing 18 changed files with 379 additions and 1 deletion.
29 changes: 29 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.7', '3.0', '3.2', '3.3']

steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true
- name: Lint
run: bundle exec rubocop
- name: Run tests
run: bundle exec rspec
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
15 changes: 15 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
AllCops:
NewCops: enable
Exclude:
- 'spec/fixtures/**/*'
TargetRubyVersion: 3.0
SuggestExtensions: false

Metrics/MethodLength:
Enabled: false

Metrics/BlockLength:
Enabled: false

Style/Documentation:
Enabled: false
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.3.6
11 changes: 11 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

source 'http://rubygems.org'

gemspec

gem 'debug'
gem 'rspec'
gem 'rubocop'
gem 'sorbet-static-and-runtime'
gem 'tapioca'
111 changes: 111 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
PATH
remote: .
specs:
inexact-struct-dsl-compiler (0.0.1)
tapioca (>= 0.13)

GEM
remote: http://rubygems.org/
specs:
ast (2.4.2)
debug (1.9.2)
irb (~> 1.10)
reline (>= 0.3.8)
diff-lcs (1.5.1)
erubi (1.13.0)
io-console (0.7.2)
irb (1.14.1)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.8.2)
language_server-protocol (3.17.0.3)
netrc (0.11.0)
parallel (1.26.3)
parser (3.3.6.0)
ast (~> 2.4.1)
racc
prism (1.2.0)
psych (5.2.0)
stringio
racc (1.8.1)
rainbow (3.1.1)
rbi (0.2.1)
prism (~> 1.0)
sorbet-runtime (>= 0.5.9204)
rdoc (6.7.0)
psych (>= 4.0.0)
regexp_parser (2.9.2)
reline (0.5.11)
io-console (~> 0.5)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.2)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.1)
rubocop (1.68.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.4, < 3.0)
rubocop-ast (>= 1.32.2, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.36.1)
parser (>= 3.3.1.0)
ruby-progressbar (1.13.0)
sorbet (0.5.11647)
sorbet-static (= 0.5.11647)
sorbet-runtime (0.5.11647)
sorbet-static (0.5.11647-aarch64-linux)
sorbet-static (0.5.11647-universal-darwin)
sorbet-static (0.5.11647-x86_64-linux)
sorbet-static-and-runtime (0.5.11647)
sorbet (= 0.5.11647)
sorbet-runtime (= 0.5.11647)
spoom (1.5.0)
erubi (>= 1.10.0)
prism (>= 0.28.0)
sorbet-static-and-runtime (>= 0.5.10187)
thor (>= 0.19.2)
stringio (3.1.2)
tapioca (0.16.4)
bundler (>= 2.2.25)
netrc (>= 0.11.0)
parallel (>= 1.21.0)
rbi (~> 0.2)
sorbet-static-and-runtime (>= 0.5.11087)
spoom (>= 1.2.0)
thor (>= 1.2.0)
yard-sorbet
thor (1.3.2)
unicode-display_width (2.6.0)
yard (0.9.37)
yard-sorbet (0.9.0)
sorbet-runtime
yard

PLATFORMS
aarch64-linux
universal-darwin
x86_64-linux

DEPENDENCIES
debug
inexact-struct-dsl-compiler!
rspec
rubocop
sorbet-static-and-runtime
tapioca

BUNDLED WITH
2.5.23
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Paul
Copyright (c) 2024 Paul Mannino

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
Empty file added README.md
Empty file.
23 changes: 23 additions & 0 deletions inexact-struct-dsl-compiler.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

require_relative 'lib/inexact_struct_dsl_compiler/version'

Gem::Specification.new do |spec|
spec.name = 'inexact-struct-dsl-compiler'
spec.version = InexactStructDslCompiler::VERSION
spec.authors = ['Paul Mannino']
spec.email = ['pmannino.code@gmail.com']
spec.homepage = 'https://github.com/paul-mannino/inexact-struct-dsl-compiler'
spec.summary = 'A Tapioca DSL compiler for T::InexactStruct'
spec.description = 'A Tapioca DSL compiler that adds'
spec.license = 'MIT'

spec.metadata['allowed_push_host'] = 'https://rubygems.org'
spec.metadata['homepage_uri'] = spec.homepage
spec.metadata['source_code_uri'] = spec.homepage

spec.required_ruby_version = '>= 3.0.0'

spec.add_dependency 'tapioca', '>=0.13'
spec.metadata['rubygems_mfa_required'] = 'true'
end
5 changes: 5 additions & 0 deletions lib/inexact_struct_dsl_compiler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

require 'tapioca'

module InexactStructDslCompiler; end
5 changes: 5 additions & 0 deletions lib/inexact_struct_dsl_compiler/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

module InexactStructDslCompiler
VERSION = '0.0.1'
end
40 changes: 40 additions & 0 deletions lib/tapioca/dsl/compilers/inexact_struct.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# typed: true
# frozen_string_literal: true

module Tapioca
module Compilers
class InexactStruct < Tapioca::Dsl::Compiler
extend T::Sig

ConstantType = type_member { { fixed: T.class_of(T::InexactStruct) } }

sig { override.returns(T::Enumerable[Module]) }
def self.gather_constants
all_classes.select { |c| c < T::InexactStruct }.reject do |c|
c.name =~ /^(Tapioca|RBI|Spoom|T|YARDSorbet)::/
end
end

sig { override.void }
def decorate
root.create_path(constant) do |klass|
klass.create_method('initialize', parameters: build_parameters, return_type: 'void')
end
end

sig {returns(T::Array[RBI::TypedParam])}
def build_parameters
constant.props.map do |name, prop|
type = prop.fetch(:type_object).to_s
if prop[:default]
create_kw_opt_param(name.to_s, type: type, default: 'T.unsafe(nil)')
elsif T::Props::Utils.optional_prop?(prop)
create_kw_opt_param(name.to_s, type: type, default: 'nil')
else
create_kw_param(name.to_s, type: type)
end
end
end
end
end
end
11 changes: 11 additions & 0 deletions spec/fixtures/bar.rbi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions spec/fixtures/baz.rbi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions spec/fixtures/foo.rbi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions spec/inexact_struct_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# typed: false
# frozen_string_literal: true

require 'spec_helper'
require 'tmpdir'

describe 'Tapioca::Compilers::InexactStruct' do
# rubocop:disable Lint/ConstantDefinitionInBlock
class Foo < T::InexactStruct
const :r, Float, default: 1.0
end

class Bar < Foo
const :x, T::Boolean
const :y, T.nilable(String)
const :z, T.any(Integer, T::Boolean)
end

class Baz < T::InexactStruct
const :a, Integer
const :b, String
const :c, Bar
const :c2, T.nilable(Foo), default: Foo.new
const :d, T::Hash[String, String]
const :e, T.untyped
end
# rubocop:enable Lint/ConstantDefinitionInBlock

let(:tmp_dir) { Dir.mktmpdir }

around(:each) do |example|
DslCommand.build(
requested_constants: requested_constants,
outpath: Pathname.new(tmp_dir)
).run
example.run
ensure
FileUtils.remove_entry(tmp_dir)
end

let(:requested_constants) { [] }

it 'generates rbi files and they are identical to test data' do
expected = Dir['./spec/fixtures/*.rbi']
actual = Dir[File.join(tmp_dir, '*.rbi')]
expect(expected.size).to eq(actual.size)
expected.zip(actual).each do |expected_example, actual_example|
expect(File.read(expected_example)).to(eq(File.read(actual_example)))
end
end

context 'with requested_constants' do
let(:requested_constants) { ['Foo'] }

it 'generates rbi files only for requested_constants' do
actual = Dir[File.join(tmp_dir, '*.rbi')]
expect(actual.size).to eq(1)
expect(actual.first).to match(/foo.rbi$/)
end
end
end
7 changes: 7 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

require 'tapioca'
require 'tapioca/internal'
require './spec/support/dsl_command'

RSpec.configure
Loading

0 comments on commit e2e68d9

Please sign in to comment.