{"id":15062800,"url":"https://github.com/daveyarwood/rubylisp","last_synced_at":"2025-04-10T10:11:21.215Z","repository":{"id":56891086,"uuid":"87886886","full_name":"daveyarwood/rubylisp","owner":"daveyarwood","description":"A Lisp dialect of Ruby","archived":false,"fork":false,"pushed_at":"2018-01-05T01:55:26.000Z","size":78,"stargazers_count":25,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T04:40:30.434Z","etag":null,"topics":["clojure","interop","lisp","lisp-dialect","ruby","scripting","scripting-language"],"latest_commit_sha":null,"homepage":"","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/daveyarwood.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-11T04:04:49.000Z","updated_at":"2024-07-29T23:10:27.000Z","dependencies_parsed_at":"2022-08-20T16:00:54.100Z","dependency_job_id":null,"html_url":"https://github.com/daveyarwood/rubylisp","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/daveyarwood%2Frubylisp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveyarwood%2Frubylisp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveyarwood%2Frubylisp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daveyarwood%2Frubylisp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daveyarwood","download_url":"https://codeload.github.com/daveyarwood/rubylisp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248198885,"owners_count":21063628,"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":["clojure","interop","lisp","lisp-dialect","ruby","scripting","scripting-language"],"created_at":"2024-09-24T23:46:44.901Z","updated_at":"2025-04-10T10:11:21.194Z","avatar_url":"https://github.com/daveyarwood.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RubyLisp (rbl)\n\nA Lisp dialect of Ruby.\n\n## Why?\n\nLisps are great, but I haven't found one usable enough (by my own standards) for scripting. [Clojure][clojure] is my favorite language from a design perpective, and the fact that you can leverage existing JVM libraries is super convenient. But there's just one problem -- its startup time is _so slow_.\n\n[Common Lisp][commonlisp] is nice; it's a powerful Lisp, and it's fast. But it's not always\neasy to find X existing library to do Y thing, it's maybe a little too\nlow-level for my liking, and the tooling situation is not so great.\n\n[Ruby][ruby] is great for scripting, cross-platform, and has hella good libraries, but there's just one problem -- it's not a Lisp.\n\nI've played around with the [make-a-lisp][mal] guide a few times in the past to\nbuild Lisps for fun in languages like Rust. I thought it would be interesting to\ntry and build for myself the convenient scripting Lisp that I always wanted. It turns out that it's super easy to write a Lisp interpreter, but it's awful time-consuming to build a whole language from scratch. I had a shower thought that the Ruby standard library can already do about 80% of the things a faithful Lisp should do, so maybe the path of least resistance to building the Lisp of my dreams is to write the interpreter in Ruby and totally cheat on all of the function implementations by delegating to functions and types that have already been implemented in the Ruby stdlib.\n\nI think I was right. Check it out, everyone -- you can write your Ruby scripts in Lisp now!\n\n## Features\n\n\u003e NOTE: RubyLisp is still in early development. If you find something is broken\n\u003e or missing, please file an issue, or better yet, fork this repo, add/fix it\n\u003e yourself, and make a Pull Request!\n\n* Syntax and stdlib functions heavily influenced by Clojure.\n* Easy, convenient Ruby inter-op.\n* Fire up a REPL or run it in a script.\n* Immutable linked lists, vectors, and hashes courtesy of the [Hamster][hamster]\n  library.\n* Clojure-style atoms, courtesy of [concurrent-ruby][concurrent].\n* _(TODO)_ Clojure-style macros.\n* _(TODO)_ Clojure-style namespaces.\n* _(TODO)_ Dependency management / the ability to use some sort of build tool to\n  include Ruby libraries and use them via inter-op.\n\n## Examples\n\n### It's basically Clojure\n\nMany of the affordances of the Clojure standard library are implemented as part\nof the `rbl.core` namespace, which is included by default:\n\n```clojure\nuser\u003e (prn 'oh :hello \"hi\" 1 2.3 '(abc def) ['g ()] '{:h ijk})\noh :hello \"hi\" 1 2.3 (abc def) [g ()] {:h ijk}\nnil\n\nuser\u003e (take 20 (map inc (reverse (range 100))))\n(101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82)\n```\n\n### Module/Class members\n\nMembers of Ruby modules and classes may be accessed in a familiar way, by appending `::` to the module or class:\n\n```clojure\nuser\u003e Kernel::ARGV\n[]\n\nuser\u003e Encoding::Converter::CR_NEWLINE_DECORATOR\n8192\n\nuser\u003e File::SEPARATOR\n\"/\"\n```\n\n### Instance methods\n\nInstance methods are called like Lisp functions. The reader will recognize any symbol that starts with `.` as an instance method, and send it as a message to the second element in the S-expression.\n\nFor example, `(.+ 1 2)` in RubyLisp is equivalent to `1.send(:+, 2)` in Ruby.\n\n```clojure\nuser\u003e (def f (File::open \"/tmp/ugh.txt\"))\n#\u003cFile:/tmp/ugh.txt\u003e\n\nuser\u003e (.methods f)\n[:size :path :truncate :lstat :atime :mtime :ctime :birthtime :chmod :chown ...\n:! :== :!= :__send__ :equal? :instance_eval :instance_exec :__id__]\n\nuser\u003e (.readbyte f)\n66\n\nuser\u003e (.size f)\n365\n```\n\n### Immutable lists\n\nThe `list` function and `quote` form (e.g. `'(1 2 3)`) create immutable lists from the [Hamster][hamster] library:\n\n```clojure\nuser\u003e (class (list 1 2 3))\nHamster::Cons\n\nuser\u003e (class '(abc def))\nHamster::Cons\n\nuser\u003e (cons 'foo (quote (bar baz)))\n(foo bar baz)\n```\n\n### Immutable vectors\n\nSimilarly, the `vector` and `vec` functions, as well as the square bracket literal form, create immutable vectors:\n\n```clojure\nuser\u003e (vector 1 2 3)\n[1 2 3]\n\nuser\u003e (vec (list 1 2 3))\n[1 2 3]\n\nuser\u003e (= [1 2 3] (vector 1 2 3))\ntrue\n\nuser\u003e (class [1 2 3])\nHamster::Vector\n```\n\n### Immutable maps\n\nThe `hash-map` function or the curly brace literal form can be used to create an immutable map:\n\n```clojure\nuser\u003e (map? (hash-map 'a 1 'b 2 'c 3))\ntrue\n\nuser\u003e {:a 1 \"b\" 2 'C 3}\n{:a 1, C 3, \"b\" 2}\n```\n\n### Keywords (a.k.a. Symbols)\n\nA keyword (in Clojure and therefore RubyLisp parlance) begins with a `:`. In Ruby, this data type is called, somewhat confusingly, a Symbol.\n\n```clojure\nuser\u003e (class :floop)\nSymbol\n\nuser\u003e (= :snoob (.to_sym \"snoob\"))\ntrue\n```\n\nRubyLisp monkey-patches the Symbol class to make it behave like a Clojure keyword; you can call it like a function in order to retrieve a value from a hash map:\n\n```clojure\nuser\u003e (def barbara {:age 7 :species \"greyhound\"})\n{:age 7, :species \"greyhound\"}\n\nuser\u003e (:species barbara)\n\"greyhound\"\n```\n\n### Instance variables\n\nBut that's not all -- you can also use keywords to get the value of an instance variable:\n\n```clojure\n;; FIXME: This is a contrived example because it is not yet possible to easily\n;; define a class in RubyLisp.\n\n;; rbl.core/=@ is provided as a convenient way to set instance variables on any\n;; object... even a string!\nuser\u003e (def s \"my string\")\n\"my string\"\n\nuser\u003e (=@ s :object_level 9001)\n9001\n\n;; instance variables can then be retrieved by using a keyword as a function\nuser\u003e (:object_level s)\n9001\n```\n\nThe above example is a little nonsensical (although a testament to the whimsy\nof Ruby), but the pair of `=@` and keyword-used-as-a-function will be more\nuseful once there is a convenient way to define classes in RubyLisp.\n\n### Mutable arrays and hashes\n\nYou can still use Ruby's mutable data structures via inter-op, if you insist:\n\n```clojure\nuser\u003e (def a (.dup (.to_a [1 2 3 4 5])))\n[1 2 3 4 5]\n\nuser\u003e (class a)\nArray\n\nuser\u003e (.\u003c\u003c a 6)\n[1 2 3 4 5 6]\n\nuser\u003e a\n[1 2 3 4 5 6]\n\nuser\u003e (def h (.to_h {}))\n{}\n\nuser\u003e (class h)\nHash\n\nuser\u003e (.merge! h {:a 3})\n{:a 3}\n\nuser\u003e h\n{:a 3}\n```\n\n## Installation\n\nRun this:\n\n```bash\n$ gem install rbl\n```\n\n## Usage\n\nTo start a REPL:\n\n```bash\n$ rbl\n```\n\nTo interpret a file containing RubyLisp code:\n\n```bash\n$ rbl my_sweet_rubylisp_script.rbl\n```\n\nOr, if you'd like, you can include a shebang, make the script executable and run it directly:\n\n```\n$ cat \u003c\u003c EOF \u003e reticulate_splines.rbl\n#!/usr/bin/env rbl\n(print \"Reticulating splines... \")\n(Kernel::sleep 2)\n(println \"done.\")\nEOF\n\n$ chmod +x reticulate_splines.rbl\n\n$ ./reticulate_splines.rbl\nReticulating splines... done.\n```\n\n## Development\n\nAfter 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.\n\nTo 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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nContributions welcome!\n\nAs a general rule, I want RubyLisp to mirror the behavior of Clojure as closely\nas possible. If you have a favorite Clojure function/macro and it isn't included\nin RubyLisp yet, why not add it yourself and make a Pull Request? :)\n\n## License\n\nCopyright © 2017 Dave Yarwood\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n[clojure]: https://clojure.org\n[commonlisp]: https://en.wikipedia.org/wiki/Common_Lisp\n[ruby]: http://ruby-lang.org\n[mal]: https://github.com/kanaka/mal\n[hamster]: https://github.com/hamstergem/hamster\n[concurrent]: https://github.com/ruby-concurrency/concurrent-ruby\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaveyarwood%2Frubylisp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaveyarwood%2Frubylisp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaveyarwood%2Frubylisp/lists"}