Giter Club home page Giter Club logo

rage's Introduction

Rage

Gem Version Tests Ruby Requirement

Inspired by Deno and built on top of Iodine, this is a Ruby web framework that is based on the following design principles:

  • Rails compatible API - Rails' API is clean, straightforward, and simply makes sense. It was one of the reasons why Rails was so successful in the past.

  • High performance - some think performance is not a major metric for a framework, but it's not true. Poor performance is a risk, and in today's world, companies refuse to use risky technologies.

  • API-only - separation of concerns is one of the most fundamental principles in software development. Backend and frontend are very different layers with different goals and paths to those goals. Separating BE code from FE code results in a much more sustainable architecture compared with classic Rails monoliths.

  • Acceptance of modern Ruby - the framework includes a fiber scheduler, which means your code never blocks while waiting on IO.

Installation

Install the gem:

$ gem install rage-rb

Create a new app:

$ rage new my_app

Switch to your new application and install dependencies:

$ cd my_app
$ bundle

Start up the server and visit http://localhost:3000.

$ rage s

Start coding!

Getting Started

This gem is designed to be a drop-in replacement for Rails in API mode. Public API is mostly expected to match Rails, however, sometimes it's a little bit more strict.

Check out in-depth API docs for more information:

Also, see the following integration guides:

Example

A sample controller could look like this:

require "net/http"

class PagesController < RageController::API
  rescue_from SocketError do |_|
    render json: { message: "error" }, status: 500
  end

  before_action :set_metadata

  def show
    page = Net::HTTP.get(URI("https://httpbin.org/json"))
    render json: { page: page, metadata: @metadata }
  end

  private

  def set_metadata
    @metadata = { format: "json", time: Time.now.to_i }
  end
end

Apart from RageController::API as a parent class, this is mostly a regular Rails controller. However, the main difference is under the hood - Rage runs every request in a separate fiber. During the call to Net::HTTP.get, the fiber is automatically paused, enabling the server to process other requests. Once the HTTP request is finished, the fiber will be resumed, potentially allowing to process hundreds of requests simultaneously.

To make this controller work, we would also need to update config/routes.rb. In this case, the file would look the following way:

Rage.routes.draw do
  get "page", to: "pages#show"
end

ℹ️ Note: Rage will automatically pause a fiber and continue to process other fibers on HTTP, PostgreSQL, and MySQL calls. Calls to Thread.join and Ractor.join will also automatically pause the current fiber.

Additionally, Fiber.await can be used to run several requests in parallel:

require "net/http"

class PagesController < RageController::API
  def index
    pages = Fiber.await([
      Fiber.schedule { Net::HTTP.get(URI("https://httpbin.org/json")) },
      Fiber.schedule { Net::HTTP.get(URI("https://httpbin.org/html")) },
    ])

    render json: { pages: pages }
  end
end

ℹ️ Note: When using Fiber.await, it is important to wrap any instance of IO into a fiber using Fiber.schedule.

Benchmarks

hello world

class ArticlesController < ApplicationController
  def index
    render json: { hello: "world" }
  end
end

Requests per second

waiting on IO

require "net/http"

class ArticlesController < ApplicationController
  def index
    Net::HTTP.get(URI("<endpoint-that-responds-in-one-second>"))
    head :ok
  end
end

Time to complete 100 requests

Upcoming releases

Status Changes
Gem configuration by env.
Add skip_before_action.
Add rescue_from.
Router updates:
 • make the root helper work correctly with scope;
 • support the defaults option;
CLI updates:
 • routes task;
 • console task;
Support the :if and :unless options in before_action.
Allow to set response headers.
Expose the params object.
Support header authentication with authenticate_with_http_token.
Router updates:
 • add the resources route helper;
 • add the namespace route helper;
Add request logging.
Automatic code reloading in development with Zeitwerk.
Support conditional get with etag and last_modified.
Expose the cookies and session objects.
Expose the send_data and send_file methods.
Implement Iodine-based equivalent of Action Cable.

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 the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/rage-rb/rage. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

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

Code of Conduct

Everyone interacting in the Rage project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

rage's People

Contributors

rsamoilov avatar arikarim avatar alex-rogachev avatar tonekk avatar heysyam99 avatar cuneyter avatar

Stargazers

Hien Vuong avatar  avatar  avatar Alex Counsell avatar Ismail Mechbal avatar Daniel Pereira avatar Kaizhao Zhang avatar Michael Crowther avatar Artyom Peredery avatar Charlie avatar Neil Atkinson avatar  avatar  avatar Ivan Marynych avatar Volodymyr  avatar Michał Czyż avatar Leandro Rezende avatar Artem Napolskih avatar weak4 avatar Caroline Lee avatar Stepan Chebannyi avatar Fco. Javier Clavero Álvarez avatar Bruno Pagno avatar Netmentor avatar  avatar Serhii avatar Marie Ingabire avatar Alberto Colón Viera avatar Steven Harman avatar Daniel Suárez Cáceres avatar Balazs Varga avatar Râu Cao avatar lenilsonjr avatar  avatar Roman avatar Ivan Leschinsky avatar Krzysztof Piotrowski avatar Gerard Fowley avatar Mateusz Mroz avatar felix avatar Gleb Glazov avatar Mark24 avatar Novtopro He avatar Julien avatar Michał Gilewski avatar Go avatar Hooopo avatar Oğulcan Girginç avatar Arnaud Berthomier avatar  avatar Ricardo Pontes avatar Bojan avatar ervinismu avatar Bertra[N]d Gauriat avatar  avatar Tero Tasanen avatar le-hu avatar Luiz Fernando Signorelli avatar Jim avatar Martin Mareš avatar Denis Oster avatar Homayoon Hedayatifard avatar Zhazha_JiaYiZhen avatar Wei Zhu avatar André Arko avatar Jeremiah Bohling avatar Hussein Morsy avatar Jack Boberg avatar Alex Maslov avatar Alexey Vasilyev avatar Sharon Rosner avatar swfz avatar Niiaz Iakupov avatar DM avatar Vasiliy Novikov avatar Mario Zugaj avatar Yu Takabatake avatar Misha Merkushin avatar Erwin Kroon avatar Damián Le Nouaille avatar Ben Barber avatar  avatar Denis Ilyasov avatar Jan Štol avatar Ilya Kamenko avatar James Mead avatar  avatar YOSHIKI HIDAKA avatar  avatar TalaatMagdy avatar  avatar cdesch avatar Maxime avatar Dino Reić avatar Christoph Grabo avatar roman avatar Andrew Mason avatar Lucas Paiva avatar Hung Le avatar Alek Malaszkiewicz avatar

Watchers

Lucian avatar Rafael Masson avatar Gregory Buchanan avatar  avatar Kotov Aleksandr avatar Sanchit Samuel avatar Homayoon Hedayatifard avatar  avatar aditya avatar  avatar Rustam Ibragimov avatar Debobroto avatar  avatar

rage's Issues

[Controller] Implement `after_action`

Implement after_action, that allows to register a callback to be executed after a successful action.
You can use the current implementation of before_action as a reference.

Make sure to thoroughly cover the change with tests and add documentation using YARD. Also, please document the differences between this implementation and the Rails implementation.

💡 The change should be made in rage/controller/api.rb.
💡 Use yard server --reload to verify your documentation changes.

❗ Do not hesitate to use benchmark-ips whenever there are different implementation options. When working on gems, performance is much more important than readability.

Please comment on this issue or assign to yourself in case you have started to work on it.

Rails integraion

This looks amazing! Great job.

We currently have an existing Rails app with certain requests, with 10-20sec external http requests, that could benefit tremendously from this.

Would we see the same performance gains by simply mounting the router within the rails router?

# config/routes.rb

Rails.application.routes.draw do
  # Mounts the Rage at the "/blazing_fast" path
  mount OtherRackApp, at: '/blazing_fast'

  # Your regular Rails routes
  # ...
end

[Controller] Allow to access request headers

Expose a request object with the headers property to allow users to access request headers. Users should be able to access headers data by both meta-variable names (e.g. HTTP_CONTENT_TYPE) and original names (e.g. Content-Type).

Example:

request.headers["Content-Type"]

Make sure to thoroughly cover the change with tests and add documentation using YARD. Also, please don't use the Rack::Request object.

💡 The change should be made in rage/controller/api.rb.
💡 Use yard server --reload to verify your documentation changes.

❗ Do not hesitate to use benchmark-ips whenever there are different implementation options. When working on gems, performance is much more important than readability.

Please comment on this issue or assign to yourself in case you have started to work on it.

[Controller] Implement block version of `before_action`

Currently, before_action only allows method names as a handler. Amend the current implementation to also allow the following form:

before_action do
  Photo.first
end

You can use the current implementation of rescue_from as a reference.

Make sure to thoroughly cover the change with tests and add documentation using YARD. Also, please document the differences between this implementation and the Rails implementation.

💡 The change should be made in rage/controller/api.rb.
💡 Use yard server --reload to verify your documentation changes.

❗ Do not hesitate to use benchmark-ips whenever there are different implementation options. When working on gems, performance is much more important than readability.

Releasing connections in ActiveRecord 7.1+

The ActiveRecord connection pool is designed so that if a thread (or a fiber) checks out a connection, the connection will remain attached to this thread until the server has finished processing the request.

This makes sense in a threaded environment but doesn't make sense for Rage. Consider the following code:

def index
  unless ApiToken.exists?(token: params[:token])
    head :forbidden
    return
  end

  Net::HTTP.get(URI("..."))
end

This code makes a request to the DB (ApiToken.exist?) and then sends an HTTP request. In Rails, the ActiveRecord connection, checked out with the ApiToken.exist? call, will remain attached to the thread which performs the request until the action (and consequently the HTTP request) has finished.

However, this doesn't make sense for Rage - while the current fiber is paused, waiting for the HTTP request to finish, other fibers could use the DB connection. Hence, we need to release ActiveRecord connections not once the whole action has finished but once a DB request has been completed.

Rage implements this using the Fiber.defer method. Unfortunately, something has changed in ActiveRecord 7.1, and while this approach works in ActiveRecord 7.0.8.1, it doesn't work reliably in ActiveRecord 7.1 anymore and thus has been disabled.

Goal: Make changes to allow releasing DB connections once a DB request has completed with ActiveRecord 7.1+.

Errors:

ActiveRecord::StatementInvalid (wrong argument type nil (expected PG::TypeMap)):
activerecord-7.1.0/lib/active_record/core.rb:411:in `rescue in cached_find_by'
activerecord-7.1.0/lib/active_record/core.rb:408:in `cached_find_by'
activerecord-7.1.0/lib/active_record/core.rb:251:in `find'
NoMethodError (undefined method `key?' for nil:NilClass):
activerecord-7.1.0/lib/active_record/connection_adapters/postgresql_adapter.rb:832:in `get_oid_type'
activerecord-7.1.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:67:in `block (2 levels) in internal_exec_query'
activerecord-7.1.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:64:in `each'
activerecord-7.1.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:64:in `each_with_index'
activerecord-7.1.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:64:in `block in internal_exec_query'
activerecord-7.1.0/lib/active_record/connection_adapters/postgresql_adapter.rb:880:in `execute_and_clear'
activerecord-7.1.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:61:in `internal_exec_query'

[Router] Implement `mount`

Add the mount route helper.

mount allows to mount a Rack-based application to be used within the host application. It should internally use match with the via: :all option.

Example:

mount SomeRackApp, at: "some_route"
mount(SomeRackApp => "some_route")

Make sure to thoroughly cover the change with tests and add documentation using YARD.

💡 The change should be made in rage/router/dsl.rb.
💡 Use yard server --reload to verify your documentation changes.

Please comment on this issue or assign to yourself in case you have started to work on it.

[CLI] Implement the `routes` console task

Enable users to examine available routes by running rage routes. The output should be pretty much similar to rails routes and include the Verb, URI Pattern, and Controller#Action fields.

💡 The change should be made in lib/rage/cli.rb.

[Router] Implement the `namespace` route helper

Add the namespace route helper to enable users to organize groups of controllers under a namespace.

Example:

namespace "admin" do
  get "/comments", to: "comments#index"
end

Make sure to thoroughly cover the change with tests and add documentation using YARD.

💡 The change should be made in rage/router/dsl.rb.
💡 Use yard server --reload to verify your documentation changes.

❗ Do not hesitate to use benchmark-ips whenever there are different implementation options. When working on gems, performance is much more important than readability.

Please comment on this issue or assign to yourself in case you have started to work on it.

Error installing on M1 Mac

I tried to install rage-rb on a Mac an got this error:

$ gem install rage-rb
Fetching rage-iodine-3.0.4.gem
Fetching rage-rb-0.7.0.gem
Building native extensions. This could take a while...
ERROR:  Error installing rage-rb:
	ERROR: Failed to build gem native extension.

    current directory: /Users/paul/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/rage-iodine-3.0.4/ext/iodine
/Users/paul/.rbenv/versions/3.3.0/bin/ruby extconf.rb
detected `kqueue`
checking for -lcrypto... yes
checking for -lssl... yes
detected OpenSSL library, testing for version and required functions.
confirmed OpenSSL to be version 1.1.0 or above (OpenSSL 3.0.7 1 Nov 2022)...
* compiling with HAVE_OPENSSL.
creating Makefile

current directory: /Users/paul/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/rage-iodine-3.0.4/ext/iodine
make DESTDIR\= sitearchdir\=./.gem.20240313-81054-x8yfmh sitelibdir\=./.gem.20240313-81054-x8yfmh clean

current directory: /Users/paul/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/rage-iodine-3.0.4/ext/iodine
make DESTDIR\= sitearchdir\=./.gem.20240313-81054-x8yfmh sitelibdir\=./.gem.20240313-81054-x8yfmh
compiling fio.c
In file included from fio.c:13:
./fio.h:346:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC
    ^
./fio.h:531:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
./fio.h:2245:5: warning: '__BIG_ENDIAN__' is not defined, evaluates to 0 [-Wundef]
#if __BIG_ENDIAN__
    ^
./fio.h:2482:5: warning: 'FIO_USE_RISKY_HASH' is not defined, evaluates to 0 [-Wundef]
#if FIO_USE_RISKY_HASH
    ^
./fio.h:2865:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
./fio.h:3069:5: warning: 'DEBUG_SPINLOCK' is not defined, evaluates to 0 [-Wundef]
#if DEBUG_SPINLOCK
    ^
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
./fio.h:3133:25: warning: 'FIO_FORCE_MALLOC_TMP' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
                        ^
In file included from fio.c:16:
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
./fio.h:3133:25: warning: 'FIO_FORCE_MALLOC_TMP' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
                        ^
In file included from fio.c:20:
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
fio.c:73:26: warning: 'FIO_ENGINE_EPOLL' is not defined, evaluates to 0 [-Wundef]
#if !FIO_ENGINE_POLL && !FIO_ENGINE_EPOLL && !FIO_ENGINE_KQUEUE && !FIO_ENGINE_WSAPOLL
                         ^
In file included from fio.c:321:
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
fio.c:406:24: warning: 'FIO_ENGINE_WSAPOLL' is not defined, evaluates to 0 [-Wundef]
#if FIO_ENGINE_POLL || FIO_ENGINE_WSAPOLL
                       ^
fio.c:413:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:500:33: warning: implicit conversion loses integer precision: 'intptr_t' (aka 'long') to 'uint32_t' (aka 'unsigned int') [-Wshorten-64-to-32]
    fio_data->max_protocol_fd = fd;
                              ~ ^~
fio.c:953:13: warning: implicit conversion loses integer precision: 'ssize_t' (aka 'long') to 'int' [-Wshorten-64-to-32]
    int r = read(fio_thread_data->fd_wait, &data, sizeof(data));
        ~   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fio.c:986:13: warning: implicit conversion loses integer precision: 'ssize_t' (aka 'long') to 'int' [-Wshorten-64-to-32]
    int r = write(fd, (void *)&data, sizeof(data));
        ~   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fio.c:1135:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:1623:6: warning: 'FIO_DISABLE_HOT_RESTART' is not defined, evaluates to 0 [-Wundef]
#if !FIO_DISABLE_HOT_RESTART
     ^
fio.c:1671:6: warning: 'FIO_DISABLE_HOT_RESTART' is not defined, evaluates to 0 [-Wundef]
#if !FIO_DISABLE_HOT_RESTART
     ^
fio.c:1740:6: warning: 'FIO_DISABLE_HOT_RESTART' is not defined, evaluates to 0 [-Wundef]
#if !FIO_DISABLE_HOT_RESTART
     ^
fio.c:1771:6: warning: 'FIO_DISABLE_HOT_RESTART' is not defined, evaluates to 0 [-Wundef]
#if !FIO_DISABLE_HOT_RESTART
     ^
fio.c:1945:5: warning: 'FIO_ENGINE_EPOLL' is not defined, evaluates to 0 [-Wundef]
#if FIO_ENGINE_EPOLL
    ^
fio.c:2205:29: error: incompatible function pointer types initializing 'void (*)(void *, void *)' with an expression of type 'void (intptr_t)' (aka 'void (long)') [-Wincompatible-function-pointer-types]
        fio_defer_push_task(fio_force_close_in_poll,
                            ^~~~~~~~~~~~~~~~~~~~~~~
fio.c:1189:36: note: expanded from macro 'fio_defer_push_task'
        (fio_defer_task_s){.func = func_, .arg1 = arg1_, .arg2 = arg2_},       \
                                   ^~~~~
fio.c:2400:5: warning: 'FIO_ENGINE_WSAPOLL' is not defined, evaluates to 0 [-Wundef]
#if FIO_ENGINE_WSAPOLL
    ^
fio.c:2184:26: warning: implicit conversion loses integer precision: 'size_t' (aka 'unsigned long') to 'int' [-Wshorten-64-to-32]
  int timeout_millisec = fio_timer_calc_first_interval();
      ~~~~~~~~~~~~~~~~   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fio.c:3318:60: warning: implicit conversion loses integer precision: 'intptr_t' (aka 'long') to 'int' [-Wshorten-64-to-32]
static void fio_sock_perform_close_fd(intptr_t fd) { close(fd); }
                                                     ~~~~~ ^~
fio.c:3335:17: warning: implicit conversion loses integer precision: 'ssize_t' (aka 'long') to 'int' [-Wshorten-64-to-32]
  int written = fd_data(fd).rw_hooks->write(
      ~~~~~~~   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
fio.c:432:21: note: expanded from macro 'fd_data'
#define fd_data(fd) (fio_data->info[(uintptr_t)(fd)])
                    ^
fio.c:3388:5: warning: 'USE_SENDFILE_LINUX' is not defined, evaluates to 0 [-Wundef]
#if USE_SENDFILE_LINUX /* linux sendfile API */
    ^
fio.c:3403:7: warning: 'USE_SENDFILE_BSD' is not defined, evaluates to 0 [-Wundef]
#elif USE_SENDFILE_BSD || USE_SENDFILE_APPLE /* FreeBSD / Apple API */
      ^
fio.c:3357:32: warning: implicit conversion loses integer precision: 'intptr_t' (aka 'long') to 'int' [-Wshorten-64-to-32]
    asked = pread(packet->data.fd, buff,
            ~~~~~ ~~~~~~~~~~~~~^~
fio.c:3376:10: warning: implicit conversion loses integer precision: 'ssize_t' (aka 'long') to 'int' [-Wshorten-64-to-32]
  return total;
  ~~~~~~ ^~~~~
fio.c:3412:33: warning: implicit conversion loses integer precision: 'intptr_t' (aka 'long') to 'int' [-Wshorten-64-to-32]
    ret = sendfile(packet->data.fd, fd, packet->offset, &act_sent, NULL, 0);
          ~~~~~~~~ ~~~~~~~~~~~~~^~
fio.c:3423:10: warning: implicit conversion loses integer precision: 'off_t' (aka 'long long') to 'int' [-Wshorten-64-to-32]
  return act_sent;
  ~~~~~~ ^~~~~~~~
fio.c:3677:24: warning: 'FIO_ENGINE_WSAPOLL' is not defined, evaluates to 0 [-Wundef]
#if FIO_ENGINE_POLL || FIO_ENGINE_WSAPOLL
                       ^
fio.c:4438:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:4471:24: warning: 'FIO_ENGINE_WSAPOLL' is not defined, evaluates to 0 [-Wundef]
#if FIO_ENGINE_POLL || FIO_ENGINE_WSAPOLL
                       ^
fio.c:4494:24: warning: 'FIO_ENGINE_WSAPOLL' is not defined, evaluates to 0 [-Wundef]
#if FIO_ENGINE_POLL || FIO_ENGINE_WSAPOLL
                       ^
fio.c:4483:20: warning: implicit conversion loses integer precision: 'ssize_t' (aka 'long') to 'uint32_t' (aka 'unsigned int') [-Wshorten-64-to-32]
  fio_data->capa = capa;
                 ~ ^~~~
fio.c:4590:16: warning: implicit conversion loses integer precision: 'size_t' (aka 'unsigned long') to 'int' [-Wshorten-64-to-32]
  int events = fio_poll();
      ~~~~~~   ^~~~~~~~~~
fio.c:4728:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
In file included from fio.c:6107:
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
In file included from fio.c:6112:
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
./fio.h:5281:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
In file included from fio.c:6118:
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
In file included from fio.c:6775:
./fio.h:3133:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
    ^
./fio.h:3133:25: warning: 'FIO_FORCE_MALLOC_TMP' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
                        ^
fio.c:6807:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:7156:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:7319:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:7749:5: warning: 'FIO_FORCE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_FORCE_MALLOC
    ^
fio.c:7991:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:8247:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
fio.c:8321:5: warning: 'FIO_MEM_DUMP' is not defined, evaluates to 0 [-Wundef]
#if FIO_MEM_DUMP
    ^
fio.c:8333:5: warning: 'FIO_OVERRIDE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_OVERRIDE_MALLOC
    ^
fio.c:8425:5: warning: 'FIO_OVERRIDE_MALLOC' is not defined, evaluates to 0 [-Wundef]
#if FIO_OVERRIDE_MALLOC
    ^
fio.c:8596:5: warning: '__BIG_ENDIAN__' is not defined, evaluates to 0 [-Wundef]
#if __BIG_ENDIAN__ /* SipHash is Little Endian */
    ^
fio.c:9335:6: warning: '__BIG_ENDIAN__' is not defined, evaluates to 0 [-Wundef]
#if !__BIG_ENDIAN__
     ^
fio.c:9721:5: warning: 'DEBUG' is not defined, evaluates to 0 [-Wundef]
#if DEBUG
    ^
59 warnings and 1 error generated.
make: *** [fio.o] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/paul/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/rage-iodine-3.0.4 for inspection.
Results logged to /Users/paul/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/extensions/arm64-darwin-23/3.3.0/rage-iodine-3.0.4/gem_make.out

[Controller] Allow to set response headers

Expose a headers object to allow users to set custom headers.

Example:

headers["Content-Type"] = "application/pdf"

Make sure to thoroughly cover the change with tests and add documentation using YARD.

Also, Rack::Response should not be used to implement this.

💡 The change should be made in rage/controller/api.rb.
💡 Use yard server --reload to verify your documentation changes.

❗ Do not hesitate to use benchmark-ips whenever there are different implementation options. When working on gems, performance is much more important than readability.

Install requirements missing - Should indicate 3.1 is required

Tried to install using ruby 3.0 and it WILL install, but installs OLD version of gem, with broken rage new my_app feature.

There appears to be a problem using the built in rage new my_app feature.

Repo Steps:

  1. docker run -it ruby:3.0-buster bash
  2. gem install rage-rb
  3. rage new my_app
  4. cd my_app
  5. cat Gemfile

Expected output:

source "https://rubygems.org"

gem "rage-rb"

# Build JSON APIs with ease
# gem "alba"

Actual output:

source "https://rubygems.org"

gem "rage"

# Build JSON APIs with ease
# gem "alba"

NOTE:
gem "rage" is a Video Game support gem for using ruby to build video games and is drastically different than this rage gem :)

CONCLUSION:
Figured out from gem spec rage-rb requires Ruby 3.1 or better. Should be documented on Homepage probably.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.