Skip to content

johansenja/lap

Repository files navigation

Lap

Don't write your code, and rbs types! Write the rbs types first, then generate a template to fill in with business logic.

A lapidary (or lapidist) is someone who cuts, polishes, or engraves precious stones.

Usage

$ lap sig/file.rbs # outputs to stdout
$ lap sig/file.rbs > lib/file.rb # output into a file

Example

  1. Plan your project/module/class by writing some blueprints:
# sig/lib/bank/account.rbs
module Bank
  class Account
    attr_reader interest_rate: Float
    attr_reader owner: Bank::Customer
    attr_reader balance: Float

    def initialize: (Bank::Customer owner, Float interest_rate, ?Float balance) -> void

    type date_or_dt = Date | DateTime

    # can optionally specify when the transaction should take place
    def deposit: (Float amount, ?when: date_or_dt) -> Float

    # can optionally specify when the transaction should take place
    def withdraw: (Float amount, ?when: date_or_dt) -> Float

    # must filter results by specifying `to` and `from` params
    def transactions: (from: date_or_dt, to: date_or_dt) -> Array[Bank::Transaction]
  end
end
  1. Generate your ruby templates
$ lap sig/lib/bank/account.rbs > lib/bank/account.rb

(Generates lib/bank/account.rb)

module Bank
  class Account
    attr_reader :interest_rate
    attr_reader :owner
    attr_reader :balance

    def initialize(owner, interest_rate, balance = nil)
      # returns void
    end

    # can optionally specify when the transaction should take place
    def deposit(amount, when: nil)
      # TODO: return Float
    end

    # can optionally specify when the transaction should take place
    def withdraw(amount, when: nil)
      # TODO: return Float
    end

    # must filter results by specifying `to` and `from` params
    def transactions(to:, from:)
      # TODO: return Array
    end
  end
end
  1. Fill in your business logic!
module Bank
  class Account
    attr_reader :interest_rate
    attr_reader :owner
    attr_reader :balance

    def initialize(owner, interest_rate, balance = 0)
        @owner = owner
        @interest_rate = interest_rate
        @balance = balance
    end

    # can optionally specify when the transaction should take place
    def deposit(amount, when: nil)
      @balance += amount
    end

    # can optionally specify when the transaction should take place
    def withdraw(amount, when: nil)
      @balance -= amount
    end

    # must filter results by specifying `to` and `from` params
    def transactions(to:, from:)
      Transaction.where("created_at BETWEEN ? AND ?", from, to)
    end
  end
end

From here, you now have some ruby code which you can type check!

Experimental:

There is an experimental feature which allows you to specify some ruby logic within your rbs files for your methods. You specify it between @!begin and @!end, eg.:

# take some moeny out of the customers account
# @!begin
#   @balance -= amount
# @!end
def withdraw(Float amount) -> Float

This would produce:

# take some moeny out of the customers account
def withdraw(amount)
  @balance -= amount
end

Installation

Add this line to your application's Gemfile:

gem 'lap'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install lap

Configuration

You can specify preferences in a .lap.yml file in your project directory. Example

indent: 4 # default is 2
frozen_string_literals: false # add 'frozen_string_literal: true' to top of file; default is true
# preferred line length in characters; default is 100. Note "preferred" - not always a guarantee
preferred_line_length: 80

Coverage

Currently not every feature of RBS is supported - yet! (contributions welcome!)

Feature Coverage
classes (includes nested)
modules (includes nested)
class methods
instance methods
required positional arguments
optional positional arguments
required keyword arguments
optional keyword arguments
method comments
access modifiers
attr_reader
attr_writer
attr_accessor
include
extend
methods with blocks
method overloading ⚠️
procs ⚠️
constants ⚠️
interfaces ⚠️

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/johansenja/lap.

License

The gem is available as open source under the terms of the MIT License.