Polycrystal

Integrate Crystal code into ruby sing the Anyolite

Right now it uses a forked with tiny modifications to linking and initialization: https://github.com/ahrushetskyi/anyolite

Installation

Now (tested only on MacOS and ruby 3.0.4)

Clone repo with submodules

git clone [email protected]:ahrushetskyi/polycrystal.git
# or
git clone https://github.com/ahrushetskyi/polycrystal.git

Compile C extension and Anyolite glue objects

cd ext/polycrystal
ruby extconf.rb
make

Check out sample app:

# from repository root
cd sample_project
irb -r ./sample

then following should work in the irb console:

CrystalModule::CrystalClass.new.crystal_method
CrystalModule::CrystalClass.new.return_object
CrystalModule::CrystalClass.new.return_object.some_method
CrystalModule::CrystalClass.new.recv_arg(arg: 42)

Planned

Add this line to your application's Gemfile:

gem 'polycrystal'

And then execute:

$ bundle

Or install it yourself as:

$ gem install polycrystal

Usage

require 'polycrystal'

Polycrystal::Registry.register(
    # directory with crystal files, added to crystal CRYSTAL_PATH
    path: File.expand_path("#{__dir__}/crystal"),
    # file, that should be loaded. Transformed into `require "sample"` in crystal entrypoint, should be accessible from :path
    file: 'sample.cr', 
    # This gets wrapped by Anyolite
    modules: ['CrystalModule'] 
)

# cpmpile and load 
# should be called once, after all Polycrystal::Registry#register calls
Polycrystal.load

Set custom properties

# directory for crystal entrypoint and compiled library. 
build_path = File.expand_path("#{__dir__}/build") 
FileUtils.mkdir_p(build_path)


Polycrystal.load(
    # directory for crystal entrypoint and compiled library. 
    build_path: build_path,
    # used to find lib with installed shards. SHARDS_INSTALL_PATH is used if present
    shardfile: "./crystal/shard.yml", 
    # Polycrystal::NO_PRECOMPILE - compile everytime
    # Polycrystal::LAZY_COMPILE - compile if not yet compiled
    # Polycrystal::REQUIRE_AOT - not compile, require to be precompiled
    precompile: Polycrystal::LAZY_COMPILE, # by default
)

TODO

  1. Test suite
  2. Remove C code from this extension.
    • C code is not required. Crystal code may be directly compiled to extension and loaded using standard requre
    • To achieve that, anyolite glue files should be compiled to object files and linked to existing ruby correctly. I got segfault when I built glue files outside of ruby extension
  3. Code should not be recompiled if it was not changed
    • Rudimentary implementation is present, but more stable is preferrable: Polycrystal.load(precompile: Polycrystal::LAZY_COMPILE)
  4. Ability to precompile all code on demand, e.g. for Docker images
    • It is possible to do that right now by calling Polycrystal.load(precompile: Polycrystal::LAZY_COMPILE) in separate command, while loading Crystal module using Polycrystal.load(precompile: Polycrystal::REQUIRE_AOT)
  5. make shards work. DONE, except:
    • Anyolite can't be loaded from shards, because it's postinstall script downloads and compiles it's own mruby

Development

git clone [email protected]:ahrushetskyi/polycrystal.git
# or
git clone https://github.com/ahrushetskyi/polycrystal.git

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/polycrystal.

License

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