{"id":19692484,"url":"https://github.com/johansenja/gloss","last_synced_at":"2025-05-07T03:42:39.572Z","repository":{"id":53187628,"uuid":"325588215","full_name":"johansenja/gloss","owner":"johansenja","description":"Gloss is a language project which brings Crystal-like features to Ruby.","archived":false,"fork":false,"pushed_at":"2021-04-01T23:54:27.000Z","size":2471,"stargazers_count":5,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-31T05:51:11.602Z","etag":null,"topics":["crystal","ruby","ruby3","type-definitions","type-safety"],"latest_commit_sha":null,"homepage":"","language":"Crystal","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/johansenja.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}},"created_at":"2020-12-30T15:45:18.000Z","updated_at":"2024-07-17T00:07:18.000Z","dependencies_parsed_at":"2022-09-08T16:40:10.788Z","dependency_job_id":null,"html_url":"https://github.com/johansenja/gloss","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johansenja%2Fgloss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johansenja%2Fgloss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johansenja%2Fgloss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johansenja%2Fgloss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johansenja","download_url":"https://codeload.github.com/johansenja/gloss/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252810271,"owners_count":21807759,"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":["crystal","ruby","ruby3","type-definitions","type-safety"],"created_at":"2024-11-11T19:13:32.635Z","updated_at":"2025-05-07T03:42:39.534Z","avatar_url":"https://github.com/johansenja.png","language":"Crystal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ![Gloss](./logo.svg \"Gloss\")\n[![Gem Version](https://badge.fury.io/rb/gloss.svg)](https://rubygems.org/gems/gloss)\n[![Tests](https://github.com/johansenja/gloss/workflows/Tests/badge.svg)](https://github.com/johansenja/gloss/actions?query=workflow%3ATests)\n[![Total Downloads](http://ruby-gem-downloads-badge.herokuapp.com/gloss?type=total\u0026color=green\u0026label=downloads%20(total)\u0026total_label=)](https://rubygems.org/gems/gloss)\n[![Current Version](http://ruby-gem-downloads-badge.herokuapp.com/gloss?color=green\u0026label=downloads%20(current%20version)\u0026metric=true)](https://rubygems.org/gems/gloss)\n\n[Gloss](https://en.wikipedia.org/wiki/Gloss_(annotation)) is a language project inspired by [Crystal](https://github.com/crystal-lang/crystal), Ruby's [RBS](https://github.com/ruby/rbs), [Steep](https://github.com/soutaro/steep) and [TypeScript](https://github.com/microsoft/TypeScript). It compiles to pure Ruby.\n\n### Current features\n\n- Type checking, via optional type annotations\n- Compile-time macros\n- Enums\n- Tuples and Named Tuples\n- All ruby files are valid gloss files (a small exceptions for now; workarounds are mostly available)\n- Other syntactic sugar\n\n### Current Status\n\nThis project is at a stage where the core non-crystal parts are written in Gloss and compile to ruby (essentially self-hosting), albeit with the type checking being fairly loose. However the project is still in the very early stages; with (as of yet) no Linux support nor error handling (see roadmap below). Use at your own discretion!\n\n## Examples:\n\n#### Type checking:\n\n```crystal\nclass HelloWorld\n  def perform : String\n    str = \"Hello world\"\n    puts str\n    str\n  end\nend\n\nresult : String = HelloWorld.perform # Error =\u003e No singleton method `perform` for HelloWorld\nresult : Integer = HelloWorld.new.perform # Incompatible assignment =\u003e can't assign string to integer\nresult : String = HelloWorld.new.perform # OK\nresult.length # OK =\u003e 11\n```\n\n#### Macros:\n\n```crystal\n# src/lib/http_client.gl\n\nclass HttpClient\n\n  @base_url : String\n\n  def initialize(@base_url); end\n\n  {% for verb in %w[get post put patch delete] %}\n    def {{verb}}(path : String, headers : Hash[untyped, untyped]?, body : Hash[untyped, untyped]?)\n      {% if verb == \"get\" %}\n        warn \"ignoring body #{body} for get request\" unless body.nil?\n        # business logic\n      {% elsif %w[post patch put].include? verb %}\n        body : String = body.to_json\n        # business logic\n      {% else %}\n        # delete request business logic\n      {% end %}\n    end\n  {% end %}\nend\n```\n\ncompiles to:\n\n```ruby\n# lib/http_client.rb\n# frozen_string_literal: true\n\nclass HttpClient\n  # @type ivar base_url: String\n\n  def initialize(base_url)\n    @base_url = base_url\n  end\n\n  def get(path, headers, body)\n    warn \"ignoring body #{body} for get request\" unless body.nil?\n    # business logic\n  end\n\n  def post(path, headers, body)\n    # @type var body: String\n    body = body.to_json\n    # business logic\n  end\n\n  def put(path, headers, body)\n    # @type var body: String\n    body = body.to_json\n    # business logic\n  end\n\n  def patch(path, headers, body)\n    # @type var body: String\n    body = body.to_json\n    # business logic\n  end\n\n  def delete(path, headers, body)\n    # delete request business logic\n  end\nend\n```\n\n#### Enums:\n\n```crystal\nclass Language\n  enum Lang\n    R = \"Ruby\"\n    C = \"Crystal\"\n    TS = \"TypeScript\"\n    P = \"Python\"\n  end\n\n  def favourite_language(language : Lang)\n    puts \"my favourite language is #{language}\"\n  end\nend\n\nLanguage.new.favourite_language(Language::Lang::R)\n```\n\n#### Tuples + Named Tuples:\n\nCurrently, named tuples can only have symbols as keys, and are distinguished from hashes by the use of the post ruby-1.9 syntax `key: value` (for named tuple) vs `:key =\u003e value` (for hash) - see example below. **This is liable to change to ensure maximum compatibility with existing ruby code**.\n\n```crystal\ntuple = {\"hello\", \"world\"}\narray = [\"hello\", \"world\"]\nnamed_tuple = { hello: \"world\" }\nhash = { :hello =\u003e \"world\" }\n\narray \u003c\u003c \"!\" # OK\ntuple \u003c\u003c \"!\" # Error\nhash[\"key\"] = \"value\" # OK\nnamed_tuple[\"key\"] = \"value\" # Error\n```\n\n#### Other syntactic suger:\n\n```crystal\nclass MyClass\n  def initialize(@var1, @@var2)\n  end\nend\n```\n\ncompiles to\n\n```ruby\nclass MyClass\n  def initialize(var1, var2)\n    @var1 = var1\n    @var2 = var2\n  end\nend\n```\n\n```crystal\nstr = \"abc\"\ncase str\nwhen \"a\"\n  \"only a\"\nwhen .start_with?(\"a\")\n  \"starts with a\"\nwhen String\n  \"definitely a string\"\nend\n```\n\ncompiles to\n\n```ruby\nstr = \"abc\"\ncase str\nwhen \"a\"\n  \"only a\"\nwhen -\u003e(x) { x.start_with?(\"a\") }\n  \"starts with a\"\nwhen String\n  \"any other string\"\nend\n```\n\n#### Abstract classes (roadmap)\n\n```crystal\nabstract class BaseClass\n  attr_reader :var\n\n  def initialize(@var); end\nend\n\nclass Child \u003c BaseClass\n  def what_is_var\n    \"var is #{var}\"\n  end\nend\n\nBaseClass.new(123) # Error - can't instantiate abstract class\nChild.new(123).what_is_var # Ok - \"var is 123\"\n```\n\n## Getting started:\n\n**Note: This gem currently requires Crystal to be installed. If you don't wish to install it, or run into other installation problems, consider using the Docker image:**\n\n```dockerfile\nFROM johansenja/gloss:latest\n# ...\n```\n\n```ruby\n# Gemfile\ngroup :development do\n  gem \"gloss\"\nend\n```\n\nthen\n\n`bundle install`\n\nthen\n\n`gloss init # create .gloss.yml config file`\n\nthen\n\n`mkdir src \u0026\u0026 echo \"puts 'hello world'\" \u003e src/hello_world.gl`\n\nthen\n\n`vi .gloss.yml # set entrypoint to src/hello_world.gl`\n\nthen\n\n`gloss build`\n\nthen\n\n`ruby ./hello_world.rb`\n\n## Example Projects:\n\n- This one! Gloss is mostly self-hosting, so check out the `./src` and `./.gloss.yml`, or the generated output in `./lib`\n- [onefiveone](https://github.com/johansenja/onefiveone) - A Roman Numeral CLI. Read the accompanying article [here](https://johansenja.medium.com/ruby-crystal-pt-ii-a-simple-app-using-gloss-368ff849db67)\n- More to come (including web apps)! Also check out `Used by` section in the sidebar\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohansenja%2Fgloss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohansenja%2Fgloss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohansenja%2Fgloss/lists"}