Skip to content

Commit

Permalink
steepによる型チェックを修正してCIに組み込んだ
Browse files Browse the repository at this point in the history
- `Gimei.addresses`の戻り値の型がおかしかったので直した
- Romajiの型がないので必要なものだけ定義した
- Array#sampleの戻り値にnilが含まれるためにエラーになっていたのをtype assertionを利用して解決した
  - ref: [steep/guides/src/nil-optional/nil-optional.md at master · soutaro/steep](https://github.com/soutaro/steep/blob/master/guides/src/nil-optional/nil-optional.md#handling-unwanted-nils)

- 次の2つのエラーは [`steep check` uses wrong context for `#define_method` in a singleton · Issue #380 · soutaro/steep](soutaro/steep#380
  - 実装側を変更することで対応した
  - 型のために実装を変えるのはあまりやりたくはないのだけど、define_methodよりclass_evalのほうが速いので許容した

```
lib/gimei.rb:44:13: [error] Unexpected positional argument
│ Diagnostic ID: Ruby::UnexpectedPositionalArgument
│
└         name(gender).public_send(method_name)
               ~~~~~~

lib/gimei/name.rb:19:12: [error] Unexpected positional argument
│ Diagnostic ID: Ruby::UnexpectedPositionalArgument
│
└         new(gender).public_send(method_name)
              ~~~~~~
```

- 次の2つのエラーは特異クラスに`extend Forwardable`する方法が現状ないため無視するようにした

```

lib/gimei.rb:27:4: [error] Type `singleton(::Class)` does not have method `def_delegators`
│ Diagnostic ID: Ruby::NoMethod
│
└     def_delegators 'Gimei::Name', :male, :female
      ~~~~~~~~~~~~~~

lib/gimei.rb:28:4: [error] Type `singleton(::Class)` does not have method `def_delegators`
│ Diagnostic ID: Ruby::NoMethod
│
└     def_delegators :address, :prefecture, :city, :town
      ~~~~~~~~~~~~~~
```

- `Gimei.names`と`@names`はsteepに期待通りに解釈させる方法が見つからなかったのでひとまずuntypedのままにしておく
  • Loading branch information
willnet committed Jan 17, 2024
1 parent f4c48a1 commit 439f534
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 17 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ jobs:
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true

- name: Run type check
run: bundle exec steep check --with-expectations
continue-on-error: ${{ matrix.allow_failures == 'true' }}
- name: Run test
run: |
set -xe
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ source 'https://rubygems.org'
# Specify your gem's dependencies in gimei.gemspec
gemspec
gem 'simplecov', require: false
gem 'steep', require: false
13 changes: 13 additions & 0 deletions Steepfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
D = Steep::Diagnostic

target :lib do
signature "sig"

check "lib"

library "forwardable"
library "yaml"

configure_code_diagnostics(D::Ruby.strict)
end

10 changes: 6 additions & 4 deletions lib/gimei.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
class Gimei
extend Forwardable

GENDERS = [:male, :female].freeze
GENDERS = [:male, :female].freeze #: [:male, :female]

def_delegators :@name,
:first, :last, :gender,
Expand Down Expand Up @@ -40,9 +40,11 @@ def addresses
end

%i[kanji hiragana katakana romaji first last family given].each do |method_name|
define_method(method_name) do |gender = nil|
name(gender).public_send(method_name)
end
class_eval(<<~METHOD, __FILE__, __LINE__ + 1)
def #{method_name}(gender = nil)
new(gender).#{method_name}
end
METHOD
end

def address
Expand Down
6 changes: 3 additions & 3 deletions lib/gimei/address.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def romaji
end

def initialize
@prefectures = Gimei.addresses['addresses']['prefecture'].sample(random: Gimei.config.rng)
@prefectures = Gimei.addresses['addresses']['prefecture'].sample(random: Gimei.config.rng) #: [String, String, String]
end

alias_method :to_s, :kanji
Expand All @@ -67,7 +67,7 @@ def romaji
end

def initialize
@cities = Gimei.addresses['addresses']['city'].sample(random: Gimei.config.rng)
@cities = Gimei.addresses['addresses']['city'].sample(random: Gimei.config.rng) #: [String, String, String]
end

alias_method :to_s, :kanji
Expand All @@ -91,7 +91,7 @@ def romaji
end

def initialize
@towns = Gimei.addresses['addresses']['town'].sample(random: Gimei.config.rng)
@towns = Gimei.addresses['addresses']['town'].sample(random: Gimei.config.rng) #: [String, String, String]
end

alias_method :to_s, :kanji
Expand Down
15 changes: 9 additions & 6 deletions lib/gimei/name.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ def female
end

%i[kanji hiragana katakana romaji first last family given].each do |method_name|
define_method(method_name) do |gender = nil|
new(gender).public_send(method_name)
end
class_eval(<<~METHOD, __FILE__, __LINE__ + 1)
def #{method_name}(gender = nil)
new(gender).#{method_name}
end
METHOD
end
end

def initialize(gender = nil)
@gender = gender || Gimei::GENDERS.sample(random: Gimei.config.rng)
@gender = gender || Gimei::GENDERS.sample(random: Gimei.config.rng) #: :male | :female
@first = First.new @gender
@last = Last.new
end
Expand Down Expand Up @@ -71,7 +73,7 @@ def female
def_delegators :@name, :kanji, :hiragana, :katakana, :to_s, :romaji

def initialize(gender = nil)
@gender = gender || Gimei::GENDERS.sample(random: Gimei.config.rng)
@gender = gender || Gimei::GENDERS.sample(random: Gimei.config.rng) #: :male | :female
@name = NameWord.new(Gimei.names['first_name'][@gender.to_s].sample(random: Gimei.config.rng))
end

Expand All @@ -89,7 +91,8 @@ class Last
def_delegators :@name, :kanji, :hiragana, :katakana, :to_s, :romaji

def initialize
@name = NameWord.new(Gimei.names['last_name'].sample(random: Gimei.config.rng))
name = Gimei.names['last_name'].sample(random: Gimei.config.rng) #: [String, String, String]
@name = NameWord.new(name)
end
end

Expand Down
6 changes: 3 additions & 3 deletions sig/gimei.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Gimei

GENDERS: [:male, :female]
extend Forwardable
self.@names: untyped # (Hash['first_name', Hash[('male' | 'female'), [String, String, String]]] | Hash['last_name', [String, String, String]])
self.@names: untyped # (Hash['first_name', Hash[('male' | 'female'), Array[[String, String, String]]]] | Hash['last_name', Array[[String, String, String]]])
self.@addresses: Hash['addresses', Hash[('prefecture' | 'city' | 'town'), [String, String, String]]]
self.@unique: UniqueGenerator
self.@config: Config
Expand All @@ -13,8 +13,8 @@ class Gimei
def self.male: -> Name
def self.female: -> Name
def self.name: (?gender_type? gender) -> Name
def self.names: -> untyped # (Hash['first_name', Hash[('male' | 'female'), [String, String, String]]] | Hash['last_name', [String, String, String]])
def self.addresses: -> Hash['addresses', Hash[('prefecture' | 'city' | 'town'), [String, String, String]]]
def self.names: -> untyped # (Hash['first_name', Hash[('male' | 'female'), Array[[String, String, String]]]] | Hash['last_name', Array[[String, String, String]]])
def self.addresses: -> Hash['addresses', Hash[('prefecture' | 'city' | 'town'), Array[[String, String, String]]]]
def self.kanji: -> String
def self.hiragana: -> String
def self.katakana: -> String
Expand Down
4 changes: 4 additions & 0 deletions sig/gimei/romaji.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Romaji
def self.romaji2kana: (String, Hash[Symbol, Symbol]?) -> String
def self.kana2romaji: (String) -> String
end
23 changes: 23 additions & 0 deletions steep_expectations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
- file: lib/gimei.rb
diagnostics:
- range:
start:
line: 27
character: 4
end:
line: 27
character: 18
severity: ERROR
message: Type `singleton(::Class)` does not have method `def_delegators`
code: Ruby::NoMethod
- range:
start:
line: 28
character: 4
end:
line: 28
character: 18
severity: ERROR
message: Type `singleton(::Class)` does not have method `def_delegators`
code: Ruby::NoMethod

0 comments on commit 439f534

Please sign in to comment.