Upgrade to Pro — share decks privately, control downloads, hide ads and more …

"型"のあるRailsアプリケーション開発 / Typed Rails application...

Takumi Shotoku
September 20, 2024

"型"のあるRailsアプリケーション開発 / Typed Rails application development

Rubyセミナー 東京
https://www.ruby.or.jp/ja/news/20240702

Takumi Shotoku

September 20, 2024
Tweet

More Decks by Takumi Shotoku

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ • ໊લ: ਖ਼ಙ ޼(aka: ਆ଎) • GitHub: @sinsoku (ը૾ӈ্)

    • X: @sinsoku_listy (ը૾ӈԼ) • Railsྺ: 10೥͘Β͍ 2
  2. ΞδΣϯμ • ! RBSʹ͍ͭͯ • ⭐ "ܕ" ͷϝϦοτ • #

    RBSಋೖͷखॱ • $ rbs-traceͷ঺հ 5
  3. RBSΛಋೖ͢Δखॱʢجຊʣ ͜Ε͚ͩ 1. Gemfile ʹ steep Λ௥Ճ͢Δ 2. sig/".rbs Λ࣮૷͢Δ

    • ! શͯͷΫϥεɺϞδϡʔϧɺϝιουͷܕఆ͕ٛඞཁ • " ෆे෼ͩͱܕݕࠪͷਫ਼౓͸ѱ͍ 19
  4. 1. Steepʢsoutaro/steepʣ Gemfileʹ steep Λ௥Ճͯ͠ bundle install Λ࣮ߦ͢Δɻ # Gemfile

    group :development do gem "steep", require: false end ͦͯ͠ steep init Λ࣮ߦ͢Δɻ $ bundle exec steep init Writing Steepfile..# 24
  5. 1. Steepʢsoutaro/steepʣ Steepfile Λฤू͠ɺܕݕࠪΤϥʔΛແࢹ͠·͢ɻ # Steepfile D = Steep:#Diagnostic target

    :app do signature "sig" check "app", "lib" configure_code_diagnostics(D:#Ruby.silent) end 25
  6. 2. RBS Railsʢpocke/rbs_railsʣ • ActiveRecord͕ఆٛ͢ΔϝιουͷRBSΛੜ੒Ͱ͖Δ • σʔλϕʔεͷΧϥϜ໊ͷϝιου • ؔ࿈ʢbelongs_to, has_one,

    has_manyʣͷϝιου • ActiveRecord::Enum2ͷϝιου • ύεϔϧύʔʢxxx_pathʣͷRBSΛੜ੒Ͱ͖Δ 2 Enumͷ৽͍͠จ๏ʹ͸ະରԠͳͷͰ஫ҙɻࢀߟ: https://github.com/pocke/rbs_rails/pull/268 26
  7. 2. RBS Railsʢpocke/rbs_railsʣ Gemfileʹ௥Ճͯ͠ bundle install Λ࣮ߦ͢Δɻ # Gemfile group

    :development do gem "rbs_rails", require: false end ͦͯ͠ bin/rails g rbs_rails:install Λ࣮ߦ͢Δɻ $ bin/rails g rbs_rails:install create lib/tasks/rbs.rake 27
  8. 3. RBS::Inlineʢsoutaro/rbs-inlineʣ • ίϝϯτͰRBSΛهड़Ͱ͖ Δ • ίϝϯτ͕ແ͍৔߹ͷҾ਺ ͱ໭Γ஋͸ untyped ʹͳΔ

    class Person attr_reader :name #" String attr_reader :addresses #" Array[String] # @rbs name: String # @rbs addresses: Array[String] # @rbs return: void def initialize(name:, addresses:) @name = name @addresses = addresses end def to_s #" String # ུ end # @rbs &block: (String) -$ void def each_address(&block) #:& void addresses.each(&block) end end 28
  9. rbs-inline Ͱੜ੒ͨ͠RBS # Generated from app/models/wiki.rb with RBS:"Inline class Wiki

    < ApplicationRecord include Redmine:"SafeAttributes def visible?: (?untyped user) -$ untyped # Returns the wiki page that acts as the sidebar content # or nil if no such page exists def sidebar: () -$ untyped # find the page with the given title # if page doesn't exist, return a new page def find_or_new_page: (untyped title) -$ untyped 29
  10. RuboCopͷϧʔϧΛௐ੔3 # rbs-inlinde ͰϝιουͷޙΖʹ `##` Λ࢖͏ͨΊ Style/CommentedKeyword: Enabled: false #

    rbs-inline Ͱ `##` Λ࢖͏ͨΊ Layout/LeadingCommentSpace: Enabled: false # rbs-inline Ͱ͸ attr_* Λ1ͭͣͭॻ͘ඞཁ͕͋ΔͨΊ Style/AccessorGrouping: Enabled: false 3 Style/CommentedKeyword ͷରԠPR͸طʹ͋Δ https://github.com/rubocop/rubocop/pull/13222 32
  11. gemͷRBSΛऔಘ͢Δ $ bundle exec rbs collection init created: rbs_collection.yaml $

    bundle exec rbs collection install औಘͨ͠RBSΛGitͰ؅ཧ͢Δඞཁ͸͋Γ·ͤΜɻ # .gitignore /.gem_rbs_collection/ 34
  12. ! rbs-inline ͷղੳࣦഊ 8 lib/plugins/gravatar/spec/gravatar_spec.rb ͰΤϥ ʔ͕ൃੜ͠·ͨ͠ɻ # rbs_inline: disabled

    # refs: https:/"github.com/soutaro/rbs-inline/issues/105 require 'rubygems' require 'erb' # to get "h" require 'active_support' # to get "returning" require File.dirname(__FILE__) + '/.'/lib/gravatar' include GravatarHelper, GravatarHelper:)PublicMethods, ERB:)Util 8 https://github.com/soutaro/rbs-inline/issues/105 36
  13. ! RakeλεΫ namespace :rbs do task setup: %i[collection rbs_rails:all inline]

    task update: %i[rbs_rails:all inline] task reset: %i[clean setup] task :collection do sh "rbs", "collection", "install", "-"frozen" end task :inline do sh "rbs-inline", "-"output", "-"opt-out", "app", "lib" end task :clean do sh "rm", "-rf", ".gem_rbs_collection/", "sig/rbs_rails/", "sig/generated/" end end 37
  14. ! .gitattributes ੜ੒ͨ͠RBSͷଐੑʹ linguist-generated ʹઃఆ͢Δɻ # .gitattributes sig/generated/**/*.rbs linguist-generated sig/rbs_rails/**/*.rbs

    linguist-generated GitHubͷPRͰมߋͨ͠ϑΝΠϧΛදࣔ͢Δͱ͖ɺطఆͰ diff ͕ද ࣔ͞Εͳ͘ͳΓ·͢ɻ 38
  15. Cannot find typeʢඪ४ϥΠϒϥϦʣ rbs_collection.yaml ʹ௥Ճɺ·ͨ͸ແࢹ͠·͢ɻ gems: # - name: csv

    # - name: yaml # `steep:validate` Ͱ `RBS:"UnsatisfiableTypeApplication` ͕ى͖ΔͷͰແࢹ͢Δ - name: ffi ignore: true 41
  16. Cannot find typeʢͦͷଞgemʣ4 sig/generated/redmine/wiki_formatting/markdown/formatter.rbs:6:6: [error] Cannot find type `Redcarpet:$Render:$HTML` │

    Diagnostic ID: RBS:$UnknownTypeName │ └ class HTML < Redcarpet:$Render:$HTML ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sig/generated/redmine/wiki_formatting/markdown/formatter.rbs:6:6: [error] Cannot find type `Redcarpet:$Render:$HTML` │ Diagnostic ID: RBS:$UnknownTypeName │ └ class HTML < Redcarpet:$Render:$HTML ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 ruby/gem_rbs_collection ʹܕఆ͕ٛͳ͍gem 42
  17. Type XXX is generic but used as a non generic

    type5 ఆ਺ʹArrayͱHashΛ࢖͍ͬͯͯɺ͔ͭ freeze Λ࢖͍ͬͯͳ͍ ৔߹ʹൃੜ͠·͢ɻ - DEFAULT_RULES = [:textile, :markdown] + DEFAULT_RULES = [:textile, :markdown] #" Array[__todo__] 5 https://github.com/soutaro/rbs-inline/pull/104 45
  18. ਖ਼͍͠ܕఆٛΛ૿΍͢ 1. ίϝϯτͰܕΛॻ͘6 2. bin/rails rbs:update Λ࣮ߦ͢Δ • sig/**/*.rbs ͕ߋ৽͢Δ

    3. steep validate Λ࣮ߦ͢Δ 6 https://github.com/soutaro/rbs-inline/wiki/Syntax-guide 50
  19. 51

  20. 52

  21. ஈ֊తʹܕݕࠪΛ༗ޮԽ # Steepfile D = Steep:#Diagnostic strict_paths = ["app/models"] target

    :app do signature "sig" check "app", "lib" ignore(*strict_paths) configure_code_diagnostics(D:#Ruby.silent) end target :strict do signature "sig" check(*strict_paths) end 53
  22. ஈ֊తʹܕݕࠪΛ༗ޮԽ # Steepfile D = Steep:#Diagnostic strict_paths = ["app/models"] target

    :app do signature "sig" check "app", "lib" ignore(*strict_paths) configure_code_diagnostics(D:#Ruby.silent) end target :strict do signature "sig" check(*strict_paths) end 54
  23. ! RBS::Traceͷಋೖखॱ spec/support/rbs_trace.rb Λ࡞੒͢Δɻ return unless ENV["RBS_TRACE"] RSpec.configure do |config|

    tracing = RBS:#Trace:#MethodTracing.new config.before(:suite) { tracing.enable } config.after(:suite) do tracing.disable tracing.insert_rbs end end 60
  24. RBSʹؔͯ͠ࠔͬͨͱ͖ • ! ruby-jp Slackͷ #types νϟϯωϧ • https://ruby-jp.github.io/ •

    ✏ Asakusa-bashi.rbs • https://asakusa-bashi-rbs.connpass.com/ 63