{"id":24755253,"url":"https://github.com/katzer/mruby-shelf","last_synced_at":"2025-10-11T01:31:36.254Z","repository":{"id":22505540,"uuid":"91619551","full_name":"katzer/mruby-shelf","owner":"katzer","description":"Modular webserver interface for mruby","archived":false,"fork":false,"pushed_at":"2024-08-25T15:04:47.000Z","size":87,"stargazers_count":24,"open_issues_count":1,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-08-25T16:25:00.579Z","etag":null,"topics":["interface-builder","mruby-gem","rack"],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/katzer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-05-17T20:58:01.000Z","updated_at":"2024-08-25T16:25:03.373Z","dependencies_parsed_at":"2024-08-25T16:25:02.714Z","dependency_job_id":"c046377e-1628-4035-8dc0-805f04010da8","html_url":"https://github.com/katzer/mruby-shelf","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katzer%2Fmruby-shelf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katzer%2Fmruby-shelf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katzer%2Fmruby-shelf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katzer%2Fmruby-shelf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/katzer","download_url":"https://codeload.github.com/katzer/mruby-shelf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236018641,"owners_count":19082129,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["interface-builder","mruby-gem","rack"],"created_at":"2025-01-28T12:37:58.452Z","updated_at":"2025-10-11T01:31:30.972Z","avatar_url":"https://github.com/katzer.png","language":"Ruby","readme":"# Shelf, a modular webserver interface for mruby \u003cbr\u003e [![Build Status](https://travis-ci.com/katzer/mruby-shelf.svg?branch=master)](https://travis-ci.com/katzer/mruby-shelf) [![Build status](https://ci.appveyor.com/api/projects/status/n6wh7qwk3nuhf26e/branch/master?svg=true)](https://ci.appveyor.com/project/katzer/mruby-shelf/branch/master) [![codebeat badge](https://codebeat.co/assets/svg/badges/A-398b39-669406e9e1b136187b91af587d4092b0160370f271f66a651f444b990c2730e9.svg)](https://codebeat.co/projects/github-com-katzer-mruby-shelf-master)\n\nInspired by [Rack][rack], empowers [mruby][mruby], a work in progress!\n\n\u003e Rack provides a minimal, modular, and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.\n\u003e\n\u003e The exact details of this are described in the Rack specification, which all Rack applications should conform to.\n\u003e\n\u003e -- \u003ccite\u003ehttps://github.com/rack/rack\u003c/cite\u003e\n\n```ruby\nShelf::Builder.app do\n  run -\u003e(env) { [200, {}, ['A barebones shelf app']] }\nend\n```\n\n## Installation\n\nAdd the line below to your `build_config.rb`:\n\n```ruby\nMRuby::Build.new do |conf|\n  # ... (snip) ...\n  conf.gem 'mruby-shelf'\nend\n```\n\nOr add this line to your aplication's `mrbgem.rake`:\n\n```ruby\nMRuby::Gem::Specification.new('your-mrbgem') do |spec|\n  # ... (snip) ...\n  spec.add_dependency 'mruby-shelf'\nend\n```\n\n## Builder\n\nThe Rack::Builder DSL is compatible with Shelf::Builder. Shelf uses [mruby-r3][mruby-r3] for the path dispatching to add some nice extras.\n\n```ruby\napp = Shelf::Builder.app do\n  run -\u003e(env) { [200, { 'content-type' =\u003e 'text/plain' }, ['A barebones shelf app']] }\nend\n\napp.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/')\n# =\u003e [200, { 'content-type' =\u003e 'text/plain' }, ['A barebones shelf app']]\n\napp.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/info')\n# =\u003e [404, { 'content-type' =\u003e 'text/plain', 'X-Cascade' =\u003e 'pass' }, ['Not Found']]\n```\n\nUsing middleware layers is dead simple:\n\n```ruby\nclass NoContent\n  def initialize(app)\n    @app = app\n  end\n\n  def call(env)\n    [204, @app.call(env)[1], []]\n  end\nend\n\napp = Shelf::Builder.app do\n  use NoContent\n  run -\u003e(env) { [200, { ... }, ['A barebones shelf app']] }\nend\n\napp.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/')\n# =\u003e [204, { ... }, []]\n```\n\nMounted routes may contain slugs and can be restricted to a certain HTTP method:\n\n```ruby\napp = Shelf::Builder.app do\n  get('/users/{id}') { run -\u003e(env) { [200, { ... }, [env['shelf.request.query_hash'][:id]]] } }\nend\n\napp.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/users/1')\n# =\u003e [200, { ... }, ['1']]\n\napp.call('REQUEST_METHOD' =\u003e 'PUT', 'PATH_INFO' =\u003e '/users/1')\n# =\u003e [405, { ... }, ['Method Not Allowed']]\n```\n\nRoutes can store any kind of additional data:\n\n```ruby\napp = Shelf::Builder.app do\n  get('data', [Object.new]) { run -\u003e(env) { [200, { ... }, env['shelf.r3.data']] } }\nend\n\napp.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/data')\n# =\u003e [200, { ... }, ['#\u003cObject:0x007fd5739dfe40\u003e']]\n```\n\n## Handler\n\nThe Rack::Handler class is mostly compatible with Shelf::Handler except that it takes the handler class instead of the path string.\n\n```ruby\nShelf::Handler.register 'h2o', H2O::Shelf::Handler\n```\n\nPer default Shelf uses its built-in handler for [mruby-simplehttpserver][mruby-simplehttpserver]:\n\n```ruby\nShelf::Handler.default\n# =\u003e Shelf::Handler::SimpleHttpServer\n```\n\nHowver its possible to customize that:\n\n```ruby\nENV['SHELF_HANDLER'] = 'h2o'\n```\n\n## Server\n\nThe Rack::Server API is mostly compatible with Shelf::Server except that there's no _config.ru_ file, built-in opt parser. Only the main options (:app, :port, :host, ...) are supported. Also note that :host and :port are written downcase!\n\n```ruby\nShelf::Server.start(\n  app: -\u003e(e) {\n    [200, { 'Content-Type' =\u003e 'text/html' }, ['hello world']]\n  },\n  server: 'simplehttpserver'\n)\n```\n\nThe default middleware stack can be extended per environment:\n\n```ruby\nShelf::Server.middleware[:production] \u003c\u003c MyCustomMiddleware\n```\n\n## Middleware\n\nShelf comes with some useful middlewares. These can be defined by app or by environment.\n\n- ContentLength\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::ContentLength\n    run -\u003e(env) { [200, {}, ['A barebones shelf app']] }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/')\n  # =\u003e [200, { 'Content-Length' =\u003e 21 }, ['A barebones shelf app']]\n  ```\n\n- ContentType\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::ContentLength\n    use Shelf::ContentType, 'text/plain'\n    run -\u003e(env) { [200, {}, ['A barebones shelf app']] }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/')\n  # =\u003e [200, { 'Content-Length' =\u003e 21, 'Content-Type' =\u003e 'text/plain' }, ['A barebones shelf app']]\n  ```\n\n- QueryParser\n\n  ```ruby\n  app = Shelf::Builder.app do\n    map('/users/{id}') do\n      use Shelf::QueryParser\n      run -\u003e(env) { [200, env['shelf.request.query_hash'], []] }\n    end\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/users/1', 'QUERY_STRING' =\u003e 'field=age\u0026field=name')\n  # =\u003e [200, { 'id' =\u003e '1', 'field' =\u003e ['age', 'name'] }, []]\n  ```\n\n- Head\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::Head\n    run -\u003e(env) { [200, {}, ['A barebones shelf app']] }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'HEAD', 'PATH_INFO' =\u003e '/')\n  # =\u003e [200, { 'Content-Length' =\u003e 21 }, []]\n  ```\n\n- Static\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::Static, urls: { '/' =\u003e 'index.html' }, root: 'public'\n    run -\u003e(env) { [200, {}, ['A barebones shelf app']] }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/')\n  # =\u003e [200, { 'Content-Length' =\u003e xxx, 'Content-Type' =\u003e 'text/html; charset=utf-8' }, ['\u003chtml\u003e...\u003c/html\u003e']]\n  ```\n\n  - See [here][static] for more samples\n  - Requires [mruby-io][mruby-io]\n\n- Logger\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::Logger, Logger::INFO\n    run -\u003e(env) { [200, {}, [Log-Level: \"#{env['shelf.logger'].level}\"] }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/')\n  # =\u003e [200, {}, ['Log-Level: 1']]\n  ```\n\n  - Writes to `env[SHELF_ERRORS]` which is _$stderr_ by default\n  - Requires [mruby-logger][mruby-logger]\n\n- CommonLogger\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::CommonLogger, Logger.new\n    run -\u003e(env) { [200, {}, ['A barebones shelf app']] }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/index.html')\n  # =\u003e 127.0.0.1 - [23/05/2017:18:03:36 +0200] \"GET /index.html HTTP/1.1\" 200 2326\n  ```\n\n  - Requires [mruby-logger][mruby-logger], mruby-time and mruby-sprintf\n\n- CatchError\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::CatchError\n    run -\u003e(env) { undef_method_call }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/')\n  # =\u003e [500, { 'Content-Length' =\u003e 21, 'Content-Type' =\u003e 'text/plain' }, ['Internal Server Error']]\n  ```\n\n  - Requires [mruby-io][mruby-io]\n  - Writes all expection traces to `env[SHELF_ERRORS]`\n  - Response body contains the stack trace under development mode\n\n- Deflater\n\n  ```ruby\n  app = Shelf::Builder.app do\n    use Shelf::Deflater\n    run -\u003e(env) { [200, {}, ['A barebones shelf app']] }\n  end\n\n  app.call('REQUEST_METHOD' =\u003e 'GET', 'PATH_INFO' =\u003e '/', 'Accept-Encoding' =\u003e 'gzip')\n  # =\u003e [200, { 'Content-Encoding' =\u003e 'gzip', ... }, ['...']]\n  ```\n\n  - Requires [mruby-shelf-deflater][mruby-shelf-deflater]\n  - Supported compression algorithms are `gzip`, `deflate` and `identity`\n\n## Development\n\nClone the repo:\n    \n    $ git clone https://github.com/katzer/mruby-shelf.git \u0026\u0026 cd mruby-shelf/\n\nCompile the source:\n\n    $ rake compile\n\nRun the tests:\n\n    $ rake test\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/katzer/mruby-shelf.\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\n## Authors\n\n- Sebastián Katzer, Fa. appPlant GmbH\n\n## License\n\nThe mgem is available as open source under the terms of the [MIT License][license].\n\nMade with :yum: in Leipzig\n\n© 2017 [appPlant GmbH][appplant]\n\n[rack]: https://github.com/rack/rack\n[mruby]: https://github.com/mruby/mruby\n[mruby-r3]: https://github.com/katzer/mruby-r3\n[mruby-logger]: https://github.com/katzer/mruby-logger\n[mruby-io]: https://github.com/iij/mruby-io\n[mruby-shelf-deflater]: https://github.com/katzer/mruby-shelf-deflater\n[mruby-simplehttpserver]: https://github.com/matsumotory/mruby-simplehttpserver\n[static]: mrblib/shelf/static.rb#L31\n[license]: http://opensource.org/licenses/MIT\n[appplant]: www.appplant.de\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkatzer%2Fmruby-shelf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkatzer%2Fmruby-shelf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkatzer%2Fmruby-shelf/lists"}