Ruby Gherkin HTML CSS JavaScript Shell
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
bin
features
lib
script
spec
.gitignore
.rspec
.ruby-version
CHANGELOG.md
Gemfile
Guardfile
LICENSE.txt
README.md
Rakefile
katapult.gemspec
katapult.png

README.md

Katapult

Katapult is a kickstart generator for Rails applications. It creates new Rails applications with lots of pre-configuration and offers makandra-flavored code generation from an application model. These two features significally speed up the initial phase of a Rails project by doing in minutes what otherwise would cost you weeks. After modeling your application, which typically takes about an hour, you can instantly start implementing the meat of your application.

Katapult only supports a single Ruby and Rails version, currently it's Rails 5.1.4 and Ruby 2.5.0.

Prerequisites

Katapult uses PostgreSQL as database, so you'll need to install that upfront. Also, it drops the asset pipeline in favor of Webpacker, so you'll need Node and Yarn (see https://makandracards.com/makandra/47477).

Also, it requires the Bundler and Rake Ruby gems, which are probably already installed on your system.

Installation

Install the katapult gem with

gem install katapult

If you intend to extend an existing application, add it to the development group in your Gemfile.

Usage

katapult does two distinct things for you:

  1. It creates a new Rails application, set up with many standard gems, snippets, useful configuration, databases, testing libraries etc.
  2. It generates code from an application model, i.e. it creates models and views, controllers, styles etc.

You may use both or only one of them. Read on for details.

1) Creating a new Rails application

Run the following command:

katapult new $APPLICATION_NAME

This will create a new Rails application and prepare it in more than 20 steps. Read the BasicsGenerator for details: Its methods are executed one-by-one, while the method names are a description of what they do.

Alternative: Using Katapult in an existing Rails application

katapult expects a fresh application (which it would usually generate itself). If you have an existing Rails application, you may use katapult, but be warned: it is not designed to respect existing files, although it will usually ask before overwriting something.

After adding it to the Gemfile, run the basics generator manually:

bin/rails generate katapult:basics

2) Generating code from an application model

After running katapult new, you will find a default application model in lib/katapult/application_model.rb. It contains a full example of katapult's features that you should replace with your application model.

When you are done, transform the model using:

katapult fire [path/to/application_model]

The path is optional and only needs to be specified when you've renamed the application model file. Note that you may well use separate model files for separate runs.

See an overview of the DSL below. The respective sections hold examples of what options are available to each element. For details, dive into lib/generators/katapult where all generators are stored. The method names of a generator tell what it does.

Generic DSL syntax example

The DSL consists of elements, e.g. Model or WebUI. Each katapult element has the following syntax, taking a name, options, and a block:

element_type 'name', options: 'example' do |element|
  element.some_method
end

Model

Takes a name and a block. Generates a Rails model, a migration, and a spec.

model 'Customer' do |customer|
  # customer.attr :name etc, see Attribute element
  # customer.belongs_to :group, see Association element
end

Attribute

Defined on Model; takes a name and options. Adds a database field in the model migration, form fields in a WebUI, and configuration code in the model as needed.

# Default type :string
model.attr :name

# Inferred type :email (when attr name matches /email/)
model.attr :email

# Inferred type :password. Password fields are rendered as password_field in
# forms, but never rendered in show views.
model.attr :password

# Specify assignable values. Available options: allow_blank, default
model.attr :age, type: :integer, assignable_values: 18..99, allow_blank: true

# Will be rendered as number_field in forms, and with a € sign in show views
model.attr :income, type: :money

# All attribute types take an optional default
model.attr :homepage, type: :url, default: 'http://www.makandra.de'

# Boolean fields are modeled as flags. Default required!
model.attr :locked, type: :flag, default: false

# JSON fields are supported
model.attr :prefer, type: :json # PostgreSQL "jsonb"
model.attr :avoid, type: :plain_json # PostgreSQL "json"

Association

Defined on Model; takes the name of another model just like you called it in the model. Adds a foreign key attribute to the model and belongs_to/has_many calls to the respective models.

model 'Customer' do |customer|
  customer.belongs_to 'Group'
end

model 'Group'

WebUI

Takes a name, options and a block. Generates controller, routes, views, and a passing Cucumber feature.

web_ui 'Customer', model: 'User' do |web_ui|
  web_ui.crud # Create all the standard rails actions

  # web_ui.action :custom etc, see Action element
end

# Short syntax with inferred model name 'User'
web_ui 'User', &:crud

Action

Defined on WebUI; takes a name and options. Adds an action to the controller, and a route as needed.

# Select single Rails actions
web_ui.action :index
web_ui.action :show
web_ui.action :create # also creates :new
web_ui.action :update # also creates :edit
web_ui.action :destroy

# Add custom actions
web_ui.action :custom_action, method: :post, scope: :member
web_ui.action :other_action, method: :get, scope: :collection

Crud

Shortcut for creating a model together with a WebUI with CRUD actions.

crud 'Customer' do |customer|
  customer.attr :name
end

Navigation

Generates a main menu with links to the index pages of all WebUIs.

navigation

Authenticate

Takes the name of the user model (currently only User is supported) and an email address. Generates authentication with Clearance.

authenticate 'User', system_email: 'system@example.com'

The given email address will be configured as the sender for all mails sent by Rails, including Clearance mails like password reset requests.

Development

Getting started + continuing development

Katapult is tested with RSpec and Cucumber + Aruba (API-Doc).

For its full-stack integration tests, katapult requires a PostgreSQL account. Create a dedicated account on your local PostgreSQL server:

$> sudo -u postgres psql
postgres=# CREATE ROLE katapult WITH createdb LOGIN;

Whenever you start working on katapult, you should run script/update, which will guide you through a quick update process.

Architecture

katapult is roughly split into three parts: the katapult binary in bin/, the model in lib/katapult/ and the generators in lib/generators. Also, there is a script/ directory that holds some scripts to ease development. It is not part of the katapult gem, however.

The generators of katapult base on the rails/generators you probably know from generating migration files or scaffolds; however, it lifts their usage on a new level by invoking generators programmatically with a "model object". Instead of plain text input, the katapult generators can explore the whole application model. They are all to be run from within a Rails application.

There are three base generators that can be considered the next-lower level API of katapult:

  • basics generator: Enhances a pristine Rails app with all of the basic configuration katapult brings.
  • app_model generator: Installs a boilerplate application model that serves as a starting point for modeling your own application.
  • transform generator: Parses the application model into an internal representation, which will be turned into code by all the other generators.

Note that the katapult binary is the only Rails-independent part of Katapult; everything else runs in the context of the Rails appplication.

Suggested workflow

When adding a feature to katapult, it will usually take you some time to figure out how exactly the generated code should look like. You'll be switching between katapult's tests, its generators and the generated code.

Here's a the suggested process:

  1. Run a scenario (create one if needed)
  2. Tag that scenario with @no-clobber. This will leave the generated test app untouched in subsequent test runs.
  3. Make a commit inside the generated test application, so you'll have a clean working directory: script/kta git add --all && script/kta git commit -m 'x'
  4. Modify the test app as needed. Boot a development server with script/kta rails s if you like.
  5. Re-run the @no-clobber scenario (modify it as needed) until test and test app meet the expectations.
  6. Now look at the git diff in the test app and model everything with katapult's generators.
  7. Remove the @no-clobber tag and run the scenario normally to see if it's still green. Remember to stop the development server first.

Guidelines

Please respect the following guidelines during development:

  • The application model should be order-agnostic. There is a #prepare_render method in ApplicationModel for things that need to happen between parsing and rendering the application model.

Debugging

Add the @announce-output tag to katapult features in order to have any output logged to your terminal. Note that each step will print all output to date, so you will see things multiple times.

To precisely debug errors occurring inside the generated application, use script/kta. You could also just cd to the test app directory, but since it is destroyed between test runs, you'd need to cd ../../aruba/katapult_test_app after each test.

When fixing issues in the generated app, make a commit in the app first. When you've fixed it, the diff will show you what you need to port back to katapult.

Typical issues

Be sure to check this list when you encounter strange issues during development.

  • Spring was running in a directory that does not exist any more. This will screw subsequent spring invocations. Run ps aux | grep spring and kill suspect processes.
  • An outdated Rails application in tmp/cached_*
  • Timeout error because of a script waiting for user input

Fast tests

Generating basics and transforming the application model take quite some time (about 20s), because it boots the Rails application, resolves Yarn dependencies and migrates databases. To speed that up, katapult tests cache prepared Rails applications in tmp/.

When debugging test suite speed, bundle exec cucumber --format usage is your friend.

Credits

Development: Dominik Schöler from makandra
Katapult image: Nemo