스타일리시한 Rails 개발(2021/01/07)

이것은 내가 시도해 본 일지다.

전제 지식


루비의 유형을 포착하지 못한 주변 사람들은 이 근처를 읽어보는 게 좋을 것 같아요.
https://techlife.cookpad.com/entry/2020/12/09/120454
https://pocke.hatenablog.com/entry/2020/12/18/230235

rbs,type,steep


참고 사이트는 아래와 같다(이하 내용만 하고 상세한 내용은 생략한다)
https://qiita.com/Anharu/items/d2ac8b0670e8eb5a2f8d

차리다


$ ruby -v
# ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
$ gem install steep

실제


다음의 실현을 토대로 설명한다.
def plus(x, y)
  x + y
end

p plus(1, 2)
먼저 typeprof를 통해 유형 정보로 rbs 파일을 생성한다.
$ typeprof app.rb -o sig/app.rbs
rbs의 내용 현황은 다음과 같다.
# Revealed types
#  app.rb:5 #=> Integer

# Classes
class Object
  private
  def plus: (Integer x, Integer y) -> Integer
end
다음에 steep init 명령을 사용할 때 절차 파일을 생성하기 때문에 다음과 같이 이 명령을 편집합니다.
Stepfile의 기법을 자세히 설명하는 페이지를 찾지 못했지만 Pocke의 설명은 다음과 같다.
https://pocke.hatenablog.com/entry/2020/12/25/183535
target :lib do
  # rbsファイルがあるディレクトリ の指定
  signature "sig"

  # 解析したいrubyコードのディレクトリ/ファイル
  check "app.rb"

  # (以下、今は不要だが一旦載せておく)
  # gem_rbs 内の gems ディレクトリへのパスを指定
  # repo_path "gem_rbs/gems"

  # rbs gem, gem_rbs からrequireしたいライブラリ名を指定
  # library 'pathname'
end
까지 금형 검사를 할 수 있다.
$ steep check
# エラーがなければ、何も表示されない
plus에 전달되는 매개 변수를 문자열 등으로 설정할 때 검사하는 중 오류가 발생했습니다.
$ steep check
# app.rb:5:10: ArgumentTypeMismatch: receiver=::Object, expected=::Integer, actual=::String ("a")

vscode로 보완해 볼게요.


vscode의 extensions로 steep 설치를 검색하면 OK.
https://github.com/soutaro/steep-vscode
문서와 같이 다음을 주의하십시오.이하가 적절하게 진행되지 않으면 아무것도 검사하지 않을 것이다.
  • bundle exec steep langserver를 실행하고 유형 검사를 진행하기 때문에 Gemfile이 명령을 실행해야 합니다
  • .
  • 루트 폴더에는 Stepfile
  • 이 필요합니다.
    설치 후 편집기에서 보완 검사를 진행합니다!
    Image from Gyazo
    배열 조작에도 보충 작용이 있다.
    Image from Gyazo

    rbs_rails 테스트


    참고 사이트는 아래와 같다(이하 내용만 하고 상세한 내용은 생략한다)
    https://pocke.hatenablog.com/entry/2020/12/25/183535
    우선 절차에 따라 제작된 창고도 미리 공개한다.
    https://github.com/nullnull/rails_with_rbs_rails_sample/commits/main

    생성 rbs


    프로그램은 참고 사이트를 참조하세요.다음은 만재점(2021년 1월 7일까지.rbs rails 버전 0.8.0)
  • rails new rails_with_rbs_rails_sample --api 이후bin/rake rbs_rails:all 각종 오류가 발생할 수 있으므로 필요하지 않은 라이브러리를 잠시 무시
  • https://github.com/pocke/rbs_rails/issues/81
  • 블로그에서 보듯이 bundle exec rbs -rlogger -rpathname -rmutex_m -rdate --repo=gem_rbs/gems -ractivesupport -ractionpack -ractivejob -ractivemodel -ractionview -ractiverecord -rrailties -I sig validate를 시도할 때 다음과 같은 오류가 발생했습니다.
  • /Users/foo/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/rbs-1.0.0/stdlib/logger/0/log_device.rbs:3:4...3:24: Could not find mixin: MonitorMixin (RBS::NoMixinFoundError)
    
    후속 단계가 적절하게 이동하기 때문에 잠시 무시합니다.

    steep의 집행


    $ bundle exec steep check
    app/mailers/application_mailer.rb:2:2: NoMethodError: type=singleton(::Object), method=default (default from: '[email protected]')
    app/mailers/application_mailer.rb:3:2: NoMethodError: type=singleton(::Object), method=layout (layout 'mailer')
    
    rails 디렉터리에 대해 유형 검사를 할 수 있습니다.의외의 오류가 적습니다. 대단합니다. clap:
    지금까지 액션이었습니다.메일의 형식 정의가 부족한 오류입니까?
    스스로 모델을 적절하게 생성한다.
    $ bin/rails generate model post title:string body:text
    $ bin/rails db:migrate
    
    생성 단계에서 Post 클래스에 해당하는 rbs 파일이 없기 때문에 유형 검사를 하지 않습니다.rbs를 다시 생성합니다.
    겸사겸사rails는 실제로 rails를 실행하여 rbs 파일을 생성하기 때문에, 예를 들어 rails에서 MySQL을 사용하면 mysql도 미리 시작해야 한다.
    $ bin/rake rbs_rails:all
    
    Post 클래스에 적절히 장착
    class Post < ApplicationRecord
      def foo
        title.split(',')
      end
    end
    
    title은nilable이므로 오류가 발생했습니다!느낌이 좋다.
    vscode의steep extension에서 이 유형의 정보를 반영하기 위해서는 매번 restart가 필요하기 때문에 vscode의 명령 팔레트(Shift+Cmd+P)에서 진행Steep: Restart all합니다.
    그나저나 title&.split처럼 쓰면 오류를 방지할 수 있지만 vscode의 보완이라면 스트링형 방법은 후보가 되지 않아 사용하기 어렵다.
    디렉터 설치 여부도 확인
    $ bundle exec steep check
    # ...mailerのエラーは省略
    app/models/post.rb:3:4: NoMethodError: type=(::String | nil), method=split (title.split(','))
    

    유형 정의 추가


    그 전에 rbs_rails에서 자동으로 생성된 유형 정의만 사용할 수 있다. 예를 들어 상기Post#foo와 같은 자제적인 방법은 스스로 유형을 추가해야 한다.
    우선, 블로그에 소개된 바와 같이 rbs prototype로 만들어 보세요.
    class PostsController < ApplicationController
      def show
        post = Post.last
        {
          title: post.title # 型が補完されている
        }
      end
    end
    
    # サンプル実装
    class Post < ApplicationRecord
      def foo
        [1].map { |x| x + 1 }
      end
    
      def bar
        title
      end
    end
    
    의 출력 결과는 다음과 같다.프로타입의 이름과 같이 자신의 진행형 정의를 바탕으로 원형을 생성할 수 있다(=반환값은 단순한 상황을 제외하고는untyped이다).
    $ bundle exec rbs prototype rb app/models/**/*.rb > sig/models.rbs
    
    type proof도 마찬가지로 다음과 같이 해봤습니다.foo 첨부 모형.
    # sig/models-prototype.rbs
    
    class ApplicationRecord < ActiveRecord::Base
    end
    
    class Post < ApplicationRecord
      def foo: () -> untyped
    
      def bar: () -> untyped
    end
    
    $ typeprof app/models/**/*.rb -o sig/models.rbs
    
    Foo#bar사용Foo#title하기 때문에 typeproof에서 타이틀이 적힌 유형 정의sig/rbs_rails/app/models/post.rbs를 참조할 수 있었으면 좋겠지만 이 방법을 알 수 없습니다.
    (2021/01/10 추기) type proof의 문서에는 일반적으로 bow:
    https://github.com/ruby/typeprof/blob/master/doc/doc.ja.md
    다음은 가능하지만 현재 상태라면 typeproof의 오류가 됩니다.(또한, rbs 파일을 지정하는 데 더 좋은 느낌을 줄 수 있다)
    # sig/models-typeprof.rbs
    
    # Classes
    class ApplicationRecord
    end
    
    class Post < ApplicationRecord
      def foo: -> Array[Integer]
      def bar: -> untyped
    end
    
    issue를 미리 세웠다.
    https://github.com/ruby/typeprof/issues/27
    일단 자신의 힘으로 바를 정의하면 유형 검사를 문제없이 진행할 수 있기 때문에 계속해서 진행한다.

    실제 Rails 애플리케이션에


    운용 중인 rails 응용 프로그램에서 상술한 절차를 실행해 보세요(절차 생략).
    다음 오류입니다.
    $ typeprof gem_rbs/gems/**/*.rbs sig/rbs_rails**/*.rbs app/models/post.rb -o sig/post.rbs
    /Users/foo/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/typeprof-0.11.0/lib/typeprof/import.rb:262:in `each_class_decl': undefined method `decls' for nil:NilClass (NoMethodError)
    
    잘못된 이름처럼 정의가 중복된 것 같습니다.코드를 보면 엔움과 scope의 이중 방법으로 정의된 코드 수정이 있기 때문입니다.이런 식으로 검사하는 건 어려워요. (중복 정의 같은 건 적어요.) (말하면서 하는 얼굴)
    수정 후 다시 금형 검사를 진행하면 대량의 오류가 발생할 수 있다.기본적으로 NoMethod Error이므로 type proof를 사용하여 직접 만드는 방법을 정의합니다.
    rbs에서 다시 한 번 오류가 발생했습니다.
  • enum을 다시 쓰면DuplicatedMethodDefinitionError이 된다.원래부터 과속 금지설이 있었지만 어떻게든 필요할 때 이런 유형의 수정은 번거롭다.
  • InvalidTypeApplicationError 잘 모르겠지만 에너마이트, 레인지 등으로 오류가 발생했다.이 근처의 대상은 읽히지 않았습니까?일시적 해소 처리.
  • 이것을 극복하더라도 대량NoMethodError이 있을 수 있지만 남은 오류를 대략적으로 분석하면 다음과 같다.
  • 의존성gem의 rbs 부족(이것은 상당히 많은 것 같다)
  • 잘 모르는 이유 오류(steep이 안 되는지 이쪽이 안 되는지 판별할 수 없음)
  • 총결산


    드디어 루비도 유형 안전 개발의 미래를 볼 수 있게 됐다.실제 응용으로는 아직 도착하지 않았지만, 나는 계속 지원하고 싶다. (rbs 부근의 사람들에게 정말 고맙다.)
    사용자로서 먼저 눈앞에 필요한 것은 다음과 같다.
  • rbsrails로 rbs생성->typeproof에서 적당한 형식으로 rbs생성->어떻게든 필요한 유형만 적으세요->steep로 자동으로 읽어 편집기에 반영된 흐름을 예쁘게 회전시킵니다
  • 의존성gem의 rbs
  • 또한 루비스트의 rbs력이 향상되지 않으면 rds 정의가 부족한 상황에서 신속하게 추가하기 어렵다
  • 좋은 웹페이지 즐겨찾기