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

Checking Ruby Programs without Types

Checking Ruby Programs without Types

Tokyo Rubyist Meetup 2016-11-25

Soutaro Matsumoto

November 25, 2016

More Decks by Soutaro Matsumoto

Other Decks in Programming


  1. Checking Ruby Programs without Types Soutaro Matsumoto

  2. @soutaro • Worked for analysis of Ruby programs for PhD

    • Co-founded Ubiregi Inc.
 (left 2016) • Working for SideCI
  3. Querly • Pattern based Ruby program check tool • $

    gem install querly
 https://github.com/soutaro/querly • Sponsored by SideCI (Actcat)
  4. rules: - id: sample.update_all pattern: update_all message: update_all skips validations

    $ querly check . team.rb:10:4 team.members.update_all(…) update_all is … querly.yml class Team … team.members.update_all(food: :fish) zoo.update_alligator … team.rb
  5. Goal • Not on syntactic issues (LINT) • Not to

    prove correctness (Types, Theorem prover) Code Review Assistance on Semantics
  6. team.members.update_all(food: :fish) People.all.find_each do |member|
 end • Using 30x

    faster UpdatePeopleJob looks better • Is it safe to skip validation and callbacks? • Is iterating all people too slow?
  7. • LINT tool for project specific rules • Encourages users

    to add their custom rules • Define rules by simple pattern, not by Ruby
  8. person.save(validate: false)

  9. person.save(validate: false) Method Name Receiver Argument

  10. Using Receiver JSON.parse • YAML.parse(source) • x.parse(source) • parse(source) •

    JSON.parse(src) • JSON.parse(src, symbolize_names: false) Match No Match
  11. Using Receiver self.pp • x.pp(1) • self.pp(x) • pp(name: name)

  12. Using Receiver group...order • Post.published.

  13. Using Arguments try(&:symbol:) • account.try(:name) • account.try {|a| a.name }

    • account.try(&:name)
  14. Using Keyword save(validate: false) • record.save(validate: true) • record.save() •

    record.save(validate: !skip) • record.save(validate: false)
  15. Using Keyword self.string(:symbol:, !null: _, ...) • string :name, null:

    true • string :name, null: false • string :name • string :name, encoding: :utf8mb4
  16. Using Context save [!conditional] • record.save • result = record.save

    … if result • … unless record.save • record.save or return
  17. Workflow Assumption • Run Querly on CI, when Pull Request

    is open • Filter warnings based on diff
  18. Promoted https://sideci.com

  19. Working with Querly 1. Find bad program pattern 2. Add

    rules for the pattern 3. Run Querly 4. Fix code or ignore warning
  20. Code Review Automation id: com.assert_selector_without_count pattern: "assert_selector(..., !count: _, ...)"

    message: Specify count: option when you are using assert_selector assert_selector “div.category-name”
  21. Share Best Practice id: sample.order pattern: “order(:string:)” message: Use order(key:

    :desc) form for descending order account.customers.order(“last_visited_at DESC”)
  22. Admit Bad Code • We have recently introduced caching of

    account’s attributes, but could not find good way to discard caches on reload • This is not very good implementation but we want to accept the change because existing code works fine • What happen for new code in the future? - id: sample.account.reload pattern: - account.reload - @account.reload - accounts.reload message: | Reloading account object does not discard cached values
  23. Deleting Monkey Patches • Stop defining monkey patch to add

    blank alt when not specified - id: sample.image_tag pattern: “image_tag(..., !alt:_, ...)” message: Specify alt attribute; a blank string?
  24. Conclusion • Querly helps your code review
 https://github.com/soutaro/querly • Experiment

    for checking programs without advanced program analysis (types)