kirei 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +91 -0
- data/kirei.gemspec +2 -3
- data/lib/boot.rb +1 -2
- data/lib/cli/commands/new_app/base_directories.rb +3 -0
- data/lib/cli/commands/new_app/execute.rb +4 -0
- data/lib/cli/commands/new_app/files/app.rb +23 -1
- data/lib/cli/commands/new_app/files/config_ru.rb +34 -0
- data/lib/cli/commands/new_app/files/db_rake.rb +178 -0
- data/lib/cli/commands/new_app/files/irbrc.rb +4 -4
- data/lib/cli/commands/new_app/files/rakefile.rb +27 -0
- data/lib/cli/commands/new_app/files/routes.rb +31 -0
- data/lib/cli/commands/start.rb +2 -2
- data/lib/kirei/app.rb +72 -0
- data/lib/kirei/app_base.rb +3 -1
- data/lib/kirei/base_controller.rb +8 -6
- data/lib/kirei/base_model.rb +10 -1
- data/lib/kirei/logger.rb +3 -1
- data/lib/kirei/middleware.rb +32 -0
- data/lib/kirei/router.rb +61 -0
- data/lib/kirei/version.rb +1 -1
- metadata +14 -22
- data/lib/kirei/base.rb +0 -8
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 8a37402ff7c216a16e3cc2a279d477e91d7ed8c40fd58169a8c598e47efd90d7
         | 
| 4 | 
            +
              data.tar.gz: 1fd249f44b20dc1dfba0ace6ea52f6de6f67ee47e4c2a7f511438ceafba4985f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d6d29c323e8b3438a0c9775f2b92312182a709443aa04843145bfed76226d71e2d78081361b178dc6293dfefa75571d525981b5ed84fee2664c93a880eb5f6fa
         | 
| 7 | 
            +
              data.tar.gz: 6b33ff256a0a199333d789c81ff70f4dca49225069f0c854fe0f4cfec4c6a68c918a6966b92c93ef76aebd14117029c5f3e7ad36d65d7d74033c5d7a0f905ab4
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,16 @@ | |
| 1 | 
            +
            # Changelog
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            ## [Unreleased]
         | 
| 2 4 |  | 
| 3 5 | 
             
            ## [0.1.0] - 2023-09-02
         | 
| 4 6 |  | 
| 5 7 | 
             
            - Initial release
         | 
| 8 | 
            +
            - added base model
         | 
| 9 | 
            +
            - added database connection
         | 
| 10 | 
            +
            - WIP: basic cli to scaffold a new project
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ## [0.2.0] - 2023-09-02
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            - added routing
         | 
| 15 | 
            +
            - added base controller
         | 
| 16 | 
            +
            - added database tasks (create, drop, migrate, rollback, generate migration)
         | 
    
        data/README.md
    CHANGED
    
    | @@ -49,6 +49,10 @@ bundle exec kirei new "MyApp" | |
| 49 49 |  | 
| 50 50 | 
             
            ### Quick Start
         | 
| 51 51 |  | 
| 52 | 
            +
            Find a test app in the [spec/test_app](spec/test_app) directory. It is a fully functional example of a Kirei app.
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            #### Models
         | 
| 55 | 
            +
             | 
| 52 56 | 
             
            All models must inherit from `T::Struct` and include `Kirei::BaseModel`. They must implement `id` which must hold the primary key of the table. The primary key must be named `id` and be of type `T.any(String, Integer)`.
         | 
| 53 57 |  | 
| 54 58 | 
             
            ```ruby
         | 
| @@ -86,6 +90,93 @@ first_user = User.resolve_first(query) # T.nilable(User) | |
| 86 90 | 
             
            first_user = User.from_hash(query.first.stringify_keys)
         | 
| 87 91 | 
             
            ```
         | 
| 88 92 |  | 
| 93 | 
            +
            #### Database Migrations
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            Read the [Sequel Migrations](https://github.com/jeremyevans/sequel/blob/5.78.0/doc/schema_modification.rdoc) documentation for detailed information.
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            ```ruby
         | 
| 98 | 
            +
            Sequel.migration do
         | 
| 99 | 
            +
              up do
         | 
| 100 | 
            +
                create_table(:airports) do
         | 
| 101 | 
            +
                  primary_key :id
         | 
| 102 | 
            +
                  String :name, null: false
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              down do
         | 
| 107 | 
            +
                drop_table(:airports)
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
            end
         | 
| 110 | 
            +
            ```
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            Applying migrations:
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            ```shell
         | 
| 115 | 
            +
            # create the database
         | 
| 116 | 
            +
            bundle exec rake db:create
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            # drop the database
         | 
| 119 | 
            +
            bundle exec rake db:drop
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            # apply all pending migrations
         | 
| 122 | 
            +
            bundle exec rake db:migrate
         | 
| 123 | 
            +
             | 
| 124 | 
            +
            # roll back the last n migration
         | 
| 125 | 
            +
            STEPS=1 bundle exec rake db:rollback
         | 
| 126 | 
            +
             | 
| 127 | 
            +
            # run db/seeds.rb to seed the database
         | 
| 128 | 
            +
            bundle exec rake db:migrate
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            # scaffold a new migration file
         | 
| 131 | 
            +
            bundle exec rake 'db:migration[CreateAirports]'
         | 
| 132 | 
            +
            ```
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            #### Routing
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            Define routes anywhere in your app; by convention, they are defined in `config/routes.rb`:
         | 
| 137 | 
            +
             | 
| 138 | 
            +
            ```ruby
         | 
| 139 | 
            +
            # config/routes.rb
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            Kirei::Router.add_routes([
         | 
| 142 | 
            +
              Kirei::Router::Route.new(
         | 
| 143 | 
            +
                verb: "GET",
         | 
| 144 | 
            +
                path: "/livez",
         | 
| 145 | 
            +
                controller: Controllers::Health,
         | 
| 146 | 
            +
                action: "livez",
         | 
| 147 | 
            +
              ),
         | 
| 148 | 
            +
             | 
| 149 | 
            +
              Kirei::Router::Route.new(
         | 
| 150 | 
            +
                verb: "GET",
         | 
| 151 | 
            +
                path: "/airports",
         | 
| 152 | 
            +
                controller: Controllers::Airports,
         | 
| 153 | 
            +
                action: "index",
         | 
| 154 | 
            +
              ),
         | 
| 155 | 
            +
            ])
         | 
| 156 | 
            +
            ```
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            #### Controllers
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            Controllers can be defined anywhere; by convention, they are defined in the `app/controllers` directory:
         | 
| 161 | 
            +
             | 
| 162 | 
            +
            ```ruby
         | 
| 163 | 
            +
            module Controllers
         | 
| 164 | 
            +
              class Airports < Kirei::BaseController
         | 
| 165 | 
            +
                extend T::Sig
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                sig { returns(Kirei::Middleware::RackResponseType) }
         | 
| 168 | 
            +
                def index
         | 
| 169 | 
            +
                  airports = Airport.all
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  # or use a serializer
         | 
| 172 | 
            +
                  data = Oj.dump(airports.map(&:serialize))
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                  render(status: 200, body: data)
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
              end
         | 
| 177 | 
            +
            end
         | 
| 178 | 
            +
            ```
         | 
| 179 | 
            +
             | 
| 89 180 | 
             
            ## Contributions
         | 
| 90 181 |  | 
| 91 182 | 
             
            We welcome contributions from the community. Before starting work on a major feature, please get in touch with us either via email or by opening an issue on GitHub. "Major feature" means anything that changes user-facing features or significant changes to the codebase itself.
         | 
    
        data/kirei.gemspec
    CHANGED
    
    | @@ -45,13 +45,12 @@ Gem::Specification.new do |spec| | |
| 45 45 |  | 
| 46 46 | 
             
              # Utilities
         | 
| 47 47 | 
             
              spec.add_dependency "oj", "~> 3.0"
         | 
| 48 | 
            -
              spec.add_dependency "rake", "~> 13.0"
         | 
| 49 48 | 
             
              spec.add_dependency "sorbet-runtime", "~> 0.5"
         | 
| 50 49 | 
             
              spec.add_dependency "tzinfo-data", "~> 1.0" # for containerized environments, e.g. on AWS ECS
         | 
| 51 50 |  | 
| 52 51 | 
             
              # Web server & routing
         | 
| 53 | 
            -
              spec.add_dependency " | 
| 54 | 
            -
              spec.add_dependency " | 
| 52 | 
            +
              spec.add_dependency "puma", "~> 6.0"
         | 
| 53 | 
            +
              spec.add_dependency "rack", "~> 3.0"
         | 
| 55 54 |  | 
| 56 55 | 
             
              # Database (Postgres)
         | 
| 57 56 | 
             
              spec.add_dependency "pg", "~> 1.0"
         | 
    
        data/lib/boot.rb
    CHANGED
    
    | @@ -15,8 +15,7 @@ require "bundler/setup" | |
| 15 15 | 
             
            require "logger"
         | 
| 16 16 | 
             
            require "sorbet-runtime"
         | 
| 17 17 | 
             
            require "oj"
         | 
| 18 | 
            -
            require " | 
| 19 | 
            -
            require "sinatra/namespace" # from sinatra-contrib
         | 
| 18 | 
            +
            require "rack"
         | 
| 20 19 | 
             
            require "pg"
         | 
| 21 20 | 
             
            require "sequel" # "sequel_pg" is auto-required by "sequel"
         | 
| 22 21 |  | 
| @@ -9,7 +9,11 @@ module Cli | |
| 9 9 | 
             
                    def self.call(app_name:)
         | 
| 10 10 | 
             
                      BaseDirectories.call
         | 
| 11 11 | 
             
                      Files::App.call(app_name)
         | 
| 12 | 
            +
                      Files::ConfigRu.call(app_name)
         | 
| 13 | 
            +
                      Files::DbRake.call(app_name)
         | 
| 12 14 | 
             
                      Files::Irbrc.call
         | 
| 15 | 
            +
                      Files::Rakefile.call
         | 
| 16 | 
            +
                      Files::Routes.call
         | 
| 13 17 |  | 
| 14 18 | 
             
                      Kirei::Logger.logger.info(
         | 
| 15 19 | 
             
                        "Kirei app '#{app_name}' scaffolded successfully!",
         | 
| @@ -10,11 +10,33 @@ module Cli | |
| 10 10 | 
             
                      end
         | 
| 11 11 |  | 
| 12 12 | 
             
                      def self.content(app_name)
         | 
| 13 | 
            +
                        snake_case_app_name = app_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
         | 
| 14 | 
            +
             | 
| 13 15 | 
             
                        <<~RUBY
         | 
| 14 16 | 
             
                          # typed: true
         | 
| 15 17 | 
             
                          # frozen_string_literal: true
         | 
| 16 18 |  | 
| 17 | 
            -
                           | 
| 19 | 
            +
                          # First: check if all gems are installed correctly
         | 
| 20 | 
            +
                          require "bundler/setup"
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                          # Second: load all gems
         | 
| 23 | 
            +
                          #         we have runtime/production ("default") and development gems ("development")
         | 
| 24 | 
            +
                          Bundler.require(:default)
         | 
| 25 | 
            +
                          Bundler.require(:development) if ENV["RACK_ENV"] == "development"
         | 
| 26 | 
            +
                          Bundler.require(:test) if ENV["RACK_ENV"] == "test"
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                          # Third: load all initializers
         | 
| 29 | 
            +
                          Dir[File.join(__dir__, "config/initializers", "*.rb")].each { require(_1) }
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                          # Fourth: load all application code
         | 
| 32 | 
            +
                          Dir[File.join(__dir__, "app/**/*", "*.rb")].each { require(_1) }
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                          # Fifth: load configs
         | 
| 35 | 
            +
                          Dir[File.join(__dir__, "config", "*.rb")].each { require(_1) }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                          class #{app_name} < Kirei::AppBase
         | 
| 38 | 
            +
                            # Kirei configuration
         | 
| 39 | 
            +
                            config.app_name = "#{snake_case_app_name}"
         | 
| 18 40 | 
             
                          end
         | 
| 19 41 | 
             
                        RUBY
         | 
| 20 42 | 
             
                      end
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            # typed: false
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Cli
         | 
| 4 | 
            +
              module Commands
         | 
| 5 | 
            +
                module NewApp
         | 
| 6 | 
            +
                  module Files
         | 
| 7 | 
            +
                    class ConfigRu
         | 
| 8 | 
            +
                      def self.call(app_name)
         | 
| 9 | 
            +
                        File.write("config.ru", content(app_name))
         | 
| 10 | 
            +
                      end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      def self.content(app_name)
         | 
| 13 | 
            +
                        <<~RUBY
         | 
| 14 | 
            +
                          # typed: false
         | 
| 15 | 
            +
                          # frozen_string_literal: true
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                          require_relative("app")
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                          # Load middlewares here
         | 
| 20 | 
            +
                          use(Rack::Reloader, 0) if #{app_name}.environment == "development"
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                          # Launch the app
         | 
| 23 | 
            +
                          run(#{app_name}.new)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                          # "use" all controllers
         | 
| 26 | 
            +
                          # store all routes in a global variable to render (localhost only)
         | 
| 27 | 
            +
                          # put "booted" statement
         | 
| 28 | 
            +
                        RUBY
         | 
| 29 | 
            +
                      end
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| @@ -0,0 +1,178 @@ | |
| 1 | 
            +
            # typed: false
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # rubocop:disable Metrics/ClassLength
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Cli
         | 
| 6 | 
            +
              module Commands
         | 
| 7 | 
            +
                module NewApp
         | 
| 8 | 
            +
                  module Files
         | 
| 9 | 
            +
                    class DbRake
         | 
| 10 | 
            +
                      def self.call(app_name)
         | 
| 11 | 
            +
                        # set db_name to snake_case version of app_name
         | 
| 12 | 
            +
                        db_name = app_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
         | 
| 13 | 
            +
                        File.write("lib/tasks/db.rake", content(app_name, db_name))
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                      def self.content(app_name, db_name)
         | 
| 17 | 
            +
                        <<~RUBY
         | 
| 18 | 
            +
                          # typed: false
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                          # run on the database server once:
         | 
| 21 | 
            +
                          #
         | 
| 22 | 
            +
                          #   CREATE DATABASE #{db_name}_${environment};
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                          require_relative "../../app"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                          namespace :db do
         | 
| 27 | 
            +
                            # RACK_ENV=development bundle exec rake db:create
         | 
| 28 | 
            +
                            desc "Create the database"
         | 
| 29 | 
            +
                            task :create do
         | 
| 30 | 
            +
                              envs = ENV.key?("RACK_ENV") ? [ENV.fetch("RACK_ENV")] : %w[development test]
         | 
| 31 | 
            +
                              envs.each do |env|
         | 
| 32 | 
            +
                                ENV["RACK_ENV"] = env
         | 
| 33 | 
            +
                                db_name = "#{db_name}_#{env}"
         | 
| 34 | 
            +
                                puts("Creating database \#{db_name}...")
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                                reset_memoized_class_level_instance_vars(#{app_name})
         | 
| 37 | 
            +
                                url = #{app_name}.default_db_url.dup # frozen string
         | 
| 38 | 
            +
                                url.gsub!(db_name, "postgres")
         | 
| 39 | 
            +
                                puts("Connecting to \#{url.gsub(%r{://.*@}, "_REDACTED_")}")
         | 
| 40 | 
            +
                                db = Sequel.connect(url)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                                begin
         | 
| 43 | 
            +
                                  db.execute("CREATE DATABASE \#{db_name}")
         | 
| 44 | 
            +
                                  puts("Created database \#{db_name}.")
         | 
| 45 | 
            +
                                rescue Sequel::DatabaseError, PG::DuplicateDatabase
         | 
| 46 | 
            +
                                  puts("Database \#{db_name} already exists, skipping.")
         | 
| 47 | 
            +
                                end
         | 
| 48 | 
            +
                              end
         | 
| 49 | 
            +
                            end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                            desc "Drop the database"
         | 
| 52 | 
            +
                            task :drop do
         | 
| 53 | 
            +
                              envs = ENV.key?("RACK_ENV") ? [ENV.fetch("RACK_ENV")] : %w[development test]
         | 
| 54 | 
            +
                              envs.each do |env|
         | 
| 55 | 
            +
                                ENV["RACK_ENV"] = env
         | 
| 56 | 
            +
                                db_name = "#{db_name}_\#{env}"
         | 
| 57 | 
            +
                                puts("Dropping database \#{db_name}...")
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                                reset_memoized_class_level_instance_vars(#{app_name})
         | 
| 60 | 
            +
                                url = #{app_name}.default_db_url.dup  # frozen string
         | 
| 61 | 
            +
                                url.gsub!(db_name, "postgres")
         | 
| 62 | 
            +
                                puts("Connecting to \#{url.gsub(%r{://.*@}, "_REDACTED_")}")
         | 
| 63 | 
            +
                                db = Sequel.connect(url)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                                begin
         | 
| 66 | 
            +
                                  db.execute("DROP DATABASE \#{db_name} (FORCE)")
         | 
| 67 | 
            +
                                  puts("Dropped database \#{db_name}.")
         | 
| 68 | 
            +
                                rescue Sequel::DatabaseError, PG::DuplicateDatabase
         | 
| 69 | 
            +
                                  puts("Database \#{db_name} does not exists, nothing to drop.")
         | 
| 70 | 
            +
                                end
         | 
| 71 | 
            +
                              end
         | 
| 72 | 
            +
                            end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                            desc "Run migrations"
         | 
| 75 | 
            +
                            task :migrate do
         | 
| 76 | 
            +
                              Sequel.extension(:migration)
         | 
| 77 | 
            +
                              envs = ENV.key?("RACK_ENV") ? [ENV.fetch("RACK_ENV")] : %w[development test]
         | 
| 78 | 
            +
                              envs.each do |env|
         | 
| 79 | 
            +
                                ENV["RACK_ENV"] = env
         | 
| 80 | 
            +
                                db_name = "#{db_name}_\#{env}"
         | 
| 81 | 
            +
                                reset_memoized_class_level_instance_vars(#{app_name})
         | 
| 82 | 
            +
                                db = Sequel.connect(#{app_name}.default_db_url)
         | 
| 83 | 
            +
                                Sequel::Migrator.run(db, File.join(#{app_name}.root, "db/migrate"))
         | 
| 84 | 
            +
                                current_version = db[:schema_migrations].order(:filename).last[:filename].to_i
         | 
| 85 | 
            +
                                puts "Migrated \#{db_name} to version \#{current_version}!"
         | 
| 86 | 
            +
                              end
         | 
| 87 | 
            +
                            end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                            desc "Rollback the last migration"
         | 
| 90 | 
            +
                            task :rollback do
         | 
| 91 | 
            +
                              envs = ENV.key?("RACK_ENV") ? [ENV.fetch("RACK_ENV")] : %w[development test]
         | 
| 92 | 
            +
                              Sequel.extension(:migration)
         | 
| 93 | 
            +
                              envs.each do |env|
         | 
| 94 | 
            +
                                ENV["RACK_ENV"] = env
         | 
| 95 | 
            +
                                db_name = "#{db_name}_\#{env}"
         | 
| 96 | 
            +
                                reset_memoized_class_level_instance_vars(#{app_name})
         | 
| 97 | 
            +
                                db = Sequel.connect(#{app_name}.default_db_url)
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                                steps = (ENV["STEPS"] || 1).to_i + 1
         | 
| 100 | 
            +
                                versions = db[:schema_migrations].order(:filename).all
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                                if versions[-steps].nil?
         | 
| 103 | 
            +
                                  puts "No more migrations to rollback"
         | 
| 104 | 
            +
                                else
         | 
| 105 | 
            +
                                  target_version = versions[-steps][:filename].to_i
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                                  Sequel::Migrator.run(db, File.join(#{app_name}.root, "db/migrate"), target: target_version)
         | 
| 108 | 
            +
                                  puts "Rolled back \#{db_name} \#{steps} steps to version \#{target_version}"
         | 
| 109 | 
            +
                                end
         | 
| 110 | 
            +
                              end
         | 
| 111 | 
            +
                            end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                            desc "Seed the database"
         | 
| 114 | 
            +
                            task :seed do
         | 
| 115 | 
            +
                              load File.join(#{app_name}.root, "db/seeds.rb")
         | 
| 116 | 
            +
                            end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                            desc "Generate a new migration file"
         | 
| 119 | 
            +
                            task :migration, [:name] do |_t, args|
         | 
| 120 | 
            +
                              require "fileutils"
         | 
| 121 | 
            +
                              require "time"
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                              # Ensure the migrations directory exists
         | 
| 124 | 
            +
                              migrations_dir = File.join(#{app_name}.root, "db/migrate")
         | 
| 125 | 
            +
                              FileUtils.mkdir_p(migrations_dir)
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                              # Generate the migration number
         | 
| 128 | 
            +
                              migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S")
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                              # Sanitize and format the migration name
         | 
| 131 | 
            +
                              formatted_name = args[:name].to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                              # Combine them to create the filename
         | 
| 134 | 
            +
                              filename = "\#{migration_number}_\#{formatted_name}.rb"
         | 
| 135 | 
            +
                              file_path = File.join(migrations_dir, filename)
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                              # Define the content of the migration file
         | 
| 138 | 
            +
                              content = <<~MIGRATION
         | 
| 139 | 
            +
                                # typed: strict
         | 
| 140 | 
            +
                                # frozen_string_literal: true
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                                Sequel.migration do
         | 
| 143 | 
            +
                                  up do
         | 
| 144 | 
            +
                                    # your code here
         | 
| 145 | 
            +
                                  end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                                  down do
         | 
| 148 | 
            +
                                    # your code here
         | 
| 149 | 
            +
                                  end
         | 
| 150 | 
            +
                                end
         | 
| 151 | 
            +
                              MIGRATION
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                              # Write the migration file
         | 
| 154 | 
            +
                              File.write(file_path, content)
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                              puts "Generated migration: db/migrate/\#{filename}"
         | 
| 157 | 
            +
                            end
         | 
| 158 | 
            +
                          end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                          def reset_memoized_class_level_instance_vars(app)
         | 
| 161 | 
            +
                            %i[
         | 
| 162 | 
            +
                              @default_db_name
         | 
| 163 | 
            +
                              @default_db_url
         | 
| 164 | 
            +
                              @raw_db_connection
         | 
| 165 | 
            +
                            ].each do |ivar|
         | 
| 166 | 
            +
                              app.remove_instance_variable(ivar) if app.instance_variable_defined?(ivar)
         | 
| 167 | 
            +
                            end
         | 
| 168 | 
            +
                          end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                        RUBY
         | 
| 171 | 
            +
                      end
         | 
| 172 | 
            +
                    end
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
              end
         | 
| 176 | 
            +
            end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
            # rubocop:enable Metrics/ClassLength
         | 
| @@ -16,10 +16,10 @@ module Cli | |
| 16 16 | 
             
                          # Kirei needs to know where the root of the project is
         | 
| 17 17 | 
             
                          APP_ROOT = File.expand_path(__dir__)
         | 
| 18 18 |  | 
| 19 | 
            -
                          ENV[ | 
| 20 | 
            -
                          ENV[ | 
| 21 | 
            -
                          require( | 
| 22 | 
            -
                          require_relative( | 
| 19 | 
            +
                          ENV["RACK_ENV"] ||= "development"
         | 
| 20 | 
            +
                          ENV["APP_VERSION"] ||= (ENV["GIT_SHA"] ||= `git rev-parse --short HEAD`.to_s.chomp.freeze)
         | 
| 21 | 
            +
                          require("dotenv/load") if %w[test development].include?(ENV["RACK_ENV"])
         | 
| 22 | 
            +
                          require_relative("app")
         | 
| 23 23 | 
             
                        RUBY
         | 
| 24 24 | 
             
                      end
         | 
| 25 25 | 
             
                    end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            # typed: false
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Cli
         | 
| 4 | 
            +
              module Commands
         | 
| 5 | 
            +
                module NewApp
         | 
| 6 | 
            +
                  module Files
         | 
| 7 | 
            +
                    class Rakefile
         | 
| 8 | 
            +
                      def self.call
         | 
| 9 | 
            +
                        File.write("Rakefile", content)
         | 
| 10 | 
            +
                      end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      def self.content
         | 
| 13 | 
            +
                        <<~RUBY
         | 
| 14 | 
            +
                          # typed: false
         | 
| 15 | 
            +
                          # frozen_string_literal: true
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                          require "rake"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                          Dir.glob("lib/tasks/**/*.rake").each { import(_1) }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                        RUBY
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            # typed: false
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Cli
         | 
| 4 | 
            +
              module Commands
         | 
| 5 | 
            +
                module NewApp
         | 
| 6 | 
            +
                  module Files
         | 
| 7 | 
            +
                    class Routes
         | 
| 8 | 
            +
                      def self.call
         | 
| 9 | 
            +
                        File.write("config/routes.rb", content)
         | 
| 10 | 
            +
                      end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      def self.content
         | 
| 13 | 
            +
                        <<~RUBY
         | 
| 14 | 
            +
                          # typed: strict
         | 
| 15 | 
            +
                          # frozen_string_literal: true
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                          Kirei::Router.add_routes([
         | 
| 18 | 
            +
                            # Kirei::Router::Route.new(
         | 
| 19 | 
            +
                            #   verb: "GET",
         | 
| 20 | 
            +
                            #   path: "/livez",
         | 
| 21 | 
            +
                            #   controller: Controllers::HealthController,
         | 
| 22 | 
            +
                            #   action: "livez",
         | 
| 23 | 
            +
                            # )
         | 
| 24 | 
            +
                          ])
         | 
| 25 | 
            +
                        RUBY
         | 
| 26 | 
            +
                      end
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
    
        data/lib/cli/commands/start.rb
    CHANGED
    
    | @@ -9,8 +9,8 @@ module Cli | |
| 9 9 | 
             
                    case args[0]
         | 
| 10 10 | 
             
                    when "new"
         | 
| 11 11 | 
             
                      app_name = args[1] || "MyApp"
         | 
| 12 | 
            -
                       | 
| 13 | 
            -
                      app_name = app_name. | 
| 12 | 
            +
                      app_name = app_name.gsub(/[-\s]/, "_")
         | 
| 13 | 
            +
                      app_name = app_name.split("_").map(&:capitalize).join if app_name.include?("_")
         | 
| 14 14 | 
             
                      NewApp::Execute.call(app_name: app_name)
         | 
| 15 15 | 
             
                    else
         | 
| 16 16 | 
             
                      Kirei::Logger.logger.info("Unknown command")
         | 
    
        data/lib/kirei/app.rb
    ADDED
    
    | @@ -0,0 +1,72 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative("middleware")
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # rubocop:disable Metrics/AbcSize, Layout/LineLength
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Kirei
         | 
| 9 | 
            +
              class App
         | 
| 10 | 
            +
                include Middleware
         | 
| 11 | 
            +
                extend T::Sig
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                sig { params(params: T::Hash[String, T.untyped]).void }
         | 
| 14 | 
            +
                def initialize(params: {})
         | 
| 15 | 
            +
                  @router = T.let(Router.instance, Router)
         | 
| 16 | 
            +
                  @params = T.let(params, T::Hash[String, T.untyped])
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                sig { returns(T::Hash[String, T.untyped]) }
         | 
| 20 | 
            +
                attr_reader :params
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                sig { params(env: RackEnvType).returns(RackResponseType) }
         | 
| 23 | 
            +
                def call(env)
         | 
| 24 | 
            +
                  http_verb = T.cast(env.fetch("REQUEST_METHOD"), String)
         | 
| 25 | 
            +
                  req_path = T.cast(env.fetch("REQUEST_PATH"), String)
         | 
| 26 | 
            +
                  # reject requests from unexpected hosts -> allow configuring allowed hosts in a `cors.rb` file
         | 
| 27 | 
            +
                  #   ( offer a scaffold for this file )
         | 
| 28 | 
            +
                  # -> use https://github.com/cyu/rack-cors
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  route = Router.instance.get(http_verb, req_path)
         | 
| 31 | 
            +
                  return [404, {}, ["Not Found"]] if route.nil?
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  params = if route.verb == "GET"
         | 
| 34 | 
            +
                    query = T.cast(env.fetch("QUERY_STRING"), String)
         | 
| 35 | 
            +
                    query.split("&").to_h do |p|
         | 
| 36 | 
            +
                      k, v = p.split("=")
         | 
| 37 | 
            +
                      k = T.cast(k, String)
         | 
| 38 | 
            +
                      [k, v]
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  else
         | 
| 41 | 
            +
                    # TODO: based on content-type, parse the body differently
         | 
| 42 | 
            +
                    #       build-in support for JSON & XML
         | 
| 43 | 
            +
                    body = T.cast(env.fetch("rack.input"), T.any(IO, StringIO))
         | 
| 44 | 
            +
                    res = Oj.load(body.read, Kirei::OJ_OPTIONS)
         | 
| 45 | 
            +
                    body.rewind # TODO: maybe don't rewind if we don't need to?
         | 
| 46 | 
            +
                    T.cast(res, T::Hash[String, T.untyped])
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  instance = route.controller.new(params: params)
         | 
| 50 | 
            +
                  instance.public_send(route.action)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                sig do
         | 
| 54 | 
            +
                  params(
         | 
| 55 | 
            +
                    status: Integer,
         | 
| 56 | 
            +
                    body: String,
         | 
| 57 | 
            +
                    headers: T::Hash[String, String],
         | 
| 58 | 
            +
                  ).returns(RackResponseType)
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
                def render(status:, body:, headers: {})
         | 
| 61 | 
            +
                  # merge default headers
         | 
| 62 | 
            +
                  # support a "type" to set content-type header? (or default to json, and users must set the header themselves for other types?)
         | 
| 63 | 
            +
                  [
         | 
| 64 | 
            +
                    status,
         | 
| 65 | 
            +
                    headers,
         | 
| 66 | 
            +
                    [body],
         | 
| 67 | 
            +
                  ]
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            # rubocop:enable Metrics/AbcSize, Layout/LineLength
         | 
    
        data/lib/kirei/app_base.rb
    CHANGED
    
    
| @@ -1,14 +1,16 @@ | |
| 1 1 | 
             
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 | 
            +
            require_relative("app")
         | 
| 5 | 
            +
             | 
| 4 6 | 
             
            module Kirei
         | 
| 5 | 
            -
              class BaseController <  | 
| 7 | 
            +
              class BaseController < Kirei::App
         | 
| 6 8 | 
             
                extend T::Sig
         | 
| 7 | 
            -
                register(Sinatra::Namespace)
         | 
| 9 | 
            +
                # register(Sinatra::Namespace)
         | 
| 8 10 |  | 
| 9 | 
            -
                before do
         | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
                end
         | 
| 11 | 
            +
                # before do
         | 
| 12 | 
            +
                #   Thread.current[:request_id] = request.env["HTTP_X_REQUEST_ID"].presence ||
         | 
| 13 | 
            +
                #                                 "req_#{AppBase.environment}_#{SecureRandom.uuid}"
         | 
| 14 | 
            +
                # end
         | 
| 13 15 | 
             
              end
         | 
| 14 16 | 
             
            end
         | 
    
        data/lib/kirei/base_model.rb
    CHANGED
    
    | @@ -60,6 +60,10 @@ module Kirei | |
| 60 60 | 
             
                  def where(hash)
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 |  | 
| 63 | 
            +
                  sig { abstract.returns(T.untyped) }
         | 
| 64 | 
            +
                  def all
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 63 67 | 
             
                  sig { abstract.params(hash: T.untyped).returns(T.untyped) }
         | 
| 64 68 | 
             
                  def create(hash)
         | 
| 65 69 | 
             
                  end
         | 
| @@ -123,6 +127,11 @@ module Kirei | |
| 123 127 | 
             
                    resolve(db.where(hash))
         | 
| 124 128 | 
             
                  end
         | 
| 125 129 |  | 
| 130 | 
            +
                  sig { override.returns(T::Array[T.attached_class]) }
         | 
| 131 | 
            +
                  def all
         | 
| 132 | 
            +
                    resolve(db.all)
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
             | 
| 126 135 | 
             
                  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
         | 
| 127 136 | 
             
                  # default values defined in the model are used, if omitted in the hash
         | 
| 128 137 | 
             
                  sig do
         | 
| @@ -182,7 +191,7 @@ module Kirei | |
| 182 191 | 
             
                  # "strict" defaults to "false".
         | 
| 183 192 | 
             
                  sig do
         | 
| 184 193 | 
             
                    override.params(
         | 
| 185 | 
            -
                      query: Sequel::Dataset,
         | 
| 194 | 
            +
                      query: T.any(Sequel::Dataset, T::Array[T::Hash[Symbol, T.untyped]]),
         | 
| 186 195 | 
             
                      strict: T.nilable(T::Boolean),
         | 
| 187 196 | 
             
                    ).returns(T::Array[T.attached_class])
         | 
| 188 197 | 
             
                  end
         | 
    
        data/lib/kirei/logger.rb
    CHANGED
    
    | @@ -30,7 +30,9 @@ module Kirei | |
| 30 30 | 
             
              #
         | 
| 31 31 | 
             
              # NOTE: The log transformer must return an array of strings to allow emitting multiple lines per log event.
         | 
| 32 32 | 
             
              #
         | 
| 33 | 
            -
              class Logger | 
| 33 | 
            +
              class Logger
         | 
| 34 | 
            +
                extend T::Sig
         | 
| 35 | 
            +
             | 
| 34 36 | 
             
                FILTERED = "[FILTERED]"
         | 
| 35 37 |  | 
| 36 38 | 
             
                @instance = T.let(nil, T.nilable(Kirei::Logger))
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Kirei
         | 
| 5 | 
            +
              module Middleware
         | 
| 6 | 
            +
                # https://github.com/rack/rack/blob/main/UPGRADE-GUIDE.md#rack-3-upgrade-guide
         | 
| 7 | 
            +
                RackResponseType = T.type_alias do
         | 
| 8 | 
            +
                  [
         | 
| 9 | 
            +
                    Integer,
         | 
| 10 | 
            +
                    T::Hash[String, String], # in theory, the values are allowed to be arrays of integers for binary representations
         | 
| 11 | 
            +
                    T.any(T::Array[String], Proc),
         | 
| 12 | 
            +
                  ]
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                RackEnvType = T.type_alias do
         | 
| 16 | 
            +
                  T::Hash[
         | 
| 17 | 
            +
                    String,
         | 
| 18 | 
            +
                    T.any(
         | 
| 19 | 
            +
                      T::Array[T.untyped],
         | 
| 20 | 
            +
                      IO,
         | 
| 21 | 
            +
                      T::Boolean,
         | 
| 22 | 
            +
                      String,
         | 
| 23 | 
            +
                      Numeric,
         | 
| 24 | 
            +
                      TCPSocket,
         | 
| 25 | 
            +
                      Puma::Client,
         | 
| 26 | 
            +
                      StringIO,
         | 
| 27 | 
            +
                      Puma::Configuration,
         | 
| 28 | 
            +
                    )
         | 
| 29 | 
            +
                  ]
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
    
        data/lib/kirei/router.rb
    ADDED
    
    | @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require("singleton")
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Kirei
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              # Usage:
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              # Router.add_routes([
         | 
| 11 | 
            +
              #   Route.new(
         | 
| 12 | 
            +
              #     verb: "GET",
         | 
| 13 | 
            +
              #     path: "/livez",
         | 
| 14 | 
            +
              #     controller: Controllers::HealthController,
         | 
| 15 | 
            +
              #     action: "livez",
         | 
| 16 | 
            +
              #   ),
         | 
| 17 | 
            +
              # ])
         | 
| 18 | 
            +
              #
         | 
| 19 | 
            +
              class Router
         | 
| 20 | 
            +
                extend T::Sig
         | 
| 21 | 
            +
                include ::Singleton
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                class Route < T::Struct
         | 
| 24 | 
            +
                  const :verb, String
         | 
| 25 | 
            +
                  const :path, String
         | 
| 26 | 
            +
                  const :controller, T.class_of(BaseController)
         | 
| 27 | 
            +
                  const :action, String
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                RoutesHash = T.type_alias do
         | 
| 31 | 
            +
                  T::Hash[String, Route]
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                sig { void }
         | 
| 35 | 
            +
                def initialize
         | 
| 36 | 
            +
                  @routes = T.let({}, RoutesHash)
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                sig { returns(RoutesHash) }
         | 
| 40 | 
            +
                attr_reader :routes
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                sig do
         | 
| 43 | 
            +
                  params(
         | 
| 44 | 
            +
                    verb: String,
         | 
| 45 | 
            +
                    path: String,
         | 
| 46 | 
            +
                  ).returns(T.nilable(Route))
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                def get(verb, path)
         | 
| 49 | 
            +
                  key = "#{verb} #{path}"
         | 
| 50 | 
            +
                  routes[key]
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                sig { params(routes: T::Array[Route]).void }
         | 
| 54 | 
            +
                def self.add_routes(routes)
         | 
| 55 | 
            +
                  routes.each do |route|
         | 
| 56 | 
            +
                    key = "#{route.verb} #{route.path}"
         | 
| 57 | 
            +
                    instance.routes[key] = route
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
    
        data/lib/kirei/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: kirei
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Ludwig Reinmiedl
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024- | 
| 11 | 
            +
            date: 2024-03-09 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: oj
         | 
| @@ -24,20 +24,6 @@ dependencies: | |
| 24 24 | 
             
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: '3.0'
         | 
| 27 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            -
              name: rake
         | 
| 29 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            -
                requirements:
         | 
| 31 | 
            -
                - - "~>"
         | 
| 32 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: '13.0'
         | 
| 34 | 
            -
              type: :runtime
         | 
| 35 | 
            -
              prerelease: false
         | 
| 36 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            -
                requirements:
         | 
| 38 | 
            -
                - - "~>"
         | 
| 39 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: '13.0'
         | 
| 41 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 28 | 
             
              name: sorbet-runtime
         | 
| 43 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -67,21 +53,21 @@ dependencies: | |
| 67 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 68 54 | 
             
                    version: '1.0'
         | 
| 69 55 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            -
              name:  | 
| 56 | 
            +
              name: puma
         | 
| 71 57 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 58 | 
             
                requirements:
         | 
| 73 59 | 
             
                - - "~>"
         | 
| 74 60 | 
             
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            -
                    version: ' | 
| 61 | 
            +
                    version: '6.0'
         | 
| 76 62 | 
             
              type: :runtime
         | 
| 77 63 | 
             
              prerelease: false
         | 
| 78 64 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 65 | 
             
                requirements:
         | 
| 80 66 | 
             
                - - "~>"
         | 
| 81 67 | 
             
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            -
                    version: ' | 
| 68 | 
            +
                    version: '6.0'
         | 
| 83 69 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            -
              name:  | 
| 70 | 
            +
              name: rack
         | 
| 85 71 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 72 | 
             
                requirements:
         | 
| 87 73 | 
             
                - - "~>"
         | 
| @@ -159,16 +145,22 @@ files: | |
| 159 145 | 
             
            - lib/cli/commands/new_app/base_directories.rb
         | 
| 160 146 | 
             
            - lib/cli/commands/new_app/execute.rb
         | 
| 161 147 | 
             
            - lib/cli/commands/new_app/files/app.rb
         | 
| 148 | 
            +
            - lib/cli/commands/new_app/files/config_ru.rb
         | 
| 149 | 
            +
            - lib/cli/commands/new_app/files/db_rake.rb
         | 
| 162 150 | 
             
            - lib/cli/commands/new_app/files/irbrc.rb
         | 
| 151 | 
            +
            - lib/cli/commands/new_app/files/rakefile.rb
         | 
| 152 | 
            +
            - lib/cli/commands/new_app/files/routes.rb
         | 
| 163 153 | 
             
            - lib/cli/commands/start.rb
         | 
| 164 154 | 
             
            - lib/kirei.rb
         | 
| 155 | 
            +
            - lib/kirei/app.rb
         | 
| 165 156 | 
             
            - lib/kirei/app_base.rb
         | 
| 166 | 
            -
            - lib/kirei/base.rb
         | 
| 167 157 | 
             
            - lib/kirei/base_controller.rb
         | 
| 168 158 | 
             
            - lib/kirei/base_model.rb
         | 
| 169 159 | 
             
            - lib/kirei/config.rb
         | 
| 170 160 | 
             
            - lib/kirei/helpers.rb
         | 
| 171 161 | 
             
            - lib/kirei/logger.rb
         | 
| 162 | 
            +
            - lib/kirei/middleware.rb
         | 
| 163 | 
            +
            - lib/kirei/router.rb
         | 
| 172 164 | 
             
            - lib/kirei/version.rb
         | 
| 173 165 | 
             
            - sorbet/rbi/shims/base_model.rbi
         | 
| 174 166 | 
             
            homepage: https://github.com/swiknaba/kirei
         | 
| @@ -192,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 192 184 | 
             
                - !ruby/object:Gem::Version
         | 
| 193 185 | 
             
                  version: '0'
         | 
| 194 186 | 
             
            requirements: []
         | 
| 195 | 
            -
            rubygems_version: 3.5. | 
| 187 | 
            +
            rubygems_version: 3.5.6
         | 
| 196 188 | 
             
            signing_key:
         | 
| 197 189 | 
             
            specification_version: 4
         | 
| 198 190 | 
             
            summary: Kirei is a strictly typed Ruby micro/REST-framework for building scaleable
         |