1

I'm experimenting with some of the RBS type check in Ruby 3. I can't seem to use the classes inside the rbs/stdlib (https://github.com/ruby/rbs/tree/master/stdlib) such as BigDecimal.

This sample test:

# file lib/user.rb
require 'bigdecimal'

class User
  def initialize(name:, money:)
    @name, @money = name, money
  end

  attr_reader :name, :money

  def test(money)
    puts "Hi #{name}, money=#{money}"
  end
end

u = User.new(name: "John", money: BigDecimal(0, 0))
u.test(BigDecimal(10,0))
# file sig/user.rbs
class User
  def initialize: (name: String name, money: BigDecimal money) -> untyped

  attr_reader name: String

  attr_reader money: BigDecimal

  def test: (BigDecimal money) -> nil
end

Upon running the check, I got the error Could not find BigDecimal (RBS::NoTypeFoundError). It seems that RBS does not load the BigDecimal from stdlib.

$ RBS_TEST_TARGET='User' RUBYOPT='-rrbs/test/setup' ruby lib/user.rb
I, [2021-04-19T12:05:25.376487 #14618]  INFO -- : Setting up hooks for ::User
I, [2021-04-19T12:05:25.376576 #14618]  INFO -- rbs: Installing runtime type checker in User...
I, [2021-04-19T12:05:25.377558 #14618]  INFO -- : Setting up hooks for ::User
I, [2021-04-19T12:05:25.377581 #14618]  INFO -- rbs: Installing runtime type checker in User...
/Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/errors.rb:104:in `check!': sig/user.rbs:6:21...6:31: Could not find BigDecimal (RBS::NoTypeFoundError)
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/variance_calculator.rb:114:in `type'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/variance_calculator.rb:83:in `in_method_type'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:528:in `block (2 levels) in validate_type_params'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:527:in `each'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:527:in `block in validate_type_params'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder/method_builder.rb:48:in `block in each'
    from /usr/local/Cellar/ruby/3.0.1/lib/ruby/3.0.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
    from /usr/local/Cellar/ruby/3.0.1/lib/ruby/3.0.0/tsort.rb:431:in `each_strongly_connected_component_from'
    from /usr/local/Cellar/ruby/3.0.1/lib/ruby/3.0.0/tsort.rb:349:in `block in each_strongly_connected_component'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder/method_builder.rb:65:in `each_value'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder/method_builder.rb:65:in `tsort_each_node'
    from /usr/local/Cellar/ruby/3.0.1/lib/ruby/3.0.0/tsort.rb:347:in `call'
    from /usr/local/Cellar/ruby/3.0.1/lib/ruby/3.0.0/tsort.rb:347:in `each_strongly_connected_component'
    from /usr/local/Cellar/ruby/3.0.1/lib/ruby/3.0.0/tsort.rb:316:in `each_strongly_connected_component'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder/method_builder.rb:43:in `each'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:490:in `validate_type_params'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:150:in `block (2 levels) in build_instance'
    from <internal:kernel>:90:in `tap'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:146:in `block in build_instance'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:775:in `try_cache'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/definition_builder.rb:136:in `build_instance'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/test/tester.rb:45:in `install!'
    from /Users/someone/.gem/ruby/3.0.1/gems/rbs-1.1.1/lib/rbs/test/setup.rb:69:in `block in <top (required)>'
    from lib/user.rb:13:in `<class:User>'
    from lib/user.rb:3:in `<main>'

How would I be able to load the BigDecimal (and other stdlib types) in RBS?

Thanks.

BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Linh
  • 535
  • 1
  • 6
  • 13
  • I don’t understand `BigDecimal(0, 0)`. The initializer takes a string. – matt Apr 19 '21 at 03:34
  • There are multiple initialisers. They are effectively the same. The second param is the number of significant digits, 0 means very big/default. irb(main):006:0> BigDecimal("0") == BigDecimal(0, 0) => true RubyMine complains on a single argument usage. BigDecimal('0') -> error 'Missing argument 'digits'. Required 2, 'initial, digits, exception:…' ' – Linh Apr 19 '21 at 05:48
  • The two arguments initialiser give a higher precision. irb(main):009:0> BigDecimal("1.55").precision => 3 irb(main):010:0> BigDecimal(1.55, 0).precision => 37 – Linh Apr 19 '21 at 05:55
  • 1
    To load stdlib libraries you can use the `RBS_TEST_OPT` env variable (as in `RBS_TEST_OPT='-r set -r pathname -I sig'`) [see](https://github.com/ruby/rbs/blob/master/docs/sigs.md#environment-variables). What's unclear to me is you're trying to test your signatures but just using the ruby command, is that on purpose? – Sebastián Palma Apr 19 '21 at 07:16
  • Thanks Sebastian. What's value of `RBS_TEST_OPT` I need to set to? What does `-r set -r pathname` means? I understand `-I sig` points to the folder of containing the `.rbs` file. I tried: `RBS_TEST_TARGET='User' RUBYOPT='-rrbs/test/setup' RBS_TEST_OPT='-r set -r pathname -I sig' ruby lib/user.rb` and this command still failed with the same error ("Could not find BigDecimal (RBS::NoTypeFoundError") – Linh Apr 19 '21 at 13:34
  • Oh I worked it out now. The `pathname` is the name of the 'thing' I need to include, in this case `bigdecimal`. This command works: `RBS_TEST_TARGET='User' RUBYOPT='-rrbs/test/setup' RBS_TEST_OPT='-r set -r bigdecimal -I sig' ruby lib/user.rb` . Thank you so much, Sebastian. The documentation is so vague. – Linh Apr 19 '21 at 13:43
  • > _What's unclear to me is you're trying to test your signatures but just using the ruby command_ ===> What else do you suggest me to use @SebastianPalma? I thought I need to run either the ruby program or a rake task/test. I want to give a reproducable example, hence I show the ruby command as the simplest set up. – Linh Apr 19 '21 at 13:47

0 Answers0