crystalruby 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95d9eecc4d47a8d9f83417779c6174eea95ebeea593e5127a89b6cfbc7884664
4
- data.tar.gz: b4f241f826e4f2b6c704bda0fd01c201e79a9bc26027bd4702717fd371687650
3
+ metadata.gz: ca096d0563b6201c3ef4f084fff3304cfa212fda88e81085580b2de5ff10536f
4
+ data.tar.gz: ccc68dc96c30f973c9bafcbaec75a2461bbaa275e32913a0781c4cc5488f034f
5
5
  SHA512:
6
- metadata.gz: d98f1e4a671679cfb8d9da45298954e01def202802bd5a64db9d0d9cba08de0776971d031648642f402fe0310d741dc6b2d163253884ad25082298226c1be1a0
7
- data.tar.gz: 141658885f763ca3088a7058131e7227434920d6213e755e21f85d6bb4d68a062a2a3163127f4e9f0db03a8c9a27a0549837714b38789647028075cc3b77660c
6
+ metadata.gz: 134e9888d563673d78dc0b9075a239ee3bab6c4a07eb63ff903c748b97684ec87e9bb33011e9f276504f855edd2a25c29860ebc626aa181f74350f68ace8b9e8
7
+ data.tar.gz: f3f7a25d12459178e5c8d3cb6a46cfa0e375f65099cdcde15c834a1ba0872198b8475919ec7e5472fa10529bfb71ede67e0edfb88105be5eb220226f2d0ba4ad
data/README.md CHANGED
@@ -295,6 +295,131 @@ end
295
295
  MyModule.add("1", "2")
296
296
  ```
297
297
 
298
+ ## Inline Chunks
299
+
300
+ `crystalruby` also allows you to write inline Crystal code that does not require binding to Ruby. This can be useful for e.g. performing setup or teardown operations.
301
+
302
+ Follow these steps for a toy example of how we can use crystalized ruby and inline chunks to expose the [crystal-redis](https://github.com/stefanwille/crystal-redis) library to Ruby.
303
+
304
+ 1. Start our toy project
305
+
306
+ ```bash
307
+ mkdir crystalredis
308
+ cd crystalredis
309
+ bundle init
310
+ ```
311
+
312
+ 2. Add dependencies to our Gemfile and run `bundle install`
313
+
314
+ ```ruby
315
+ # frozen_string_literal: true
316
+
317
+ source "https://rubygems.org"
318
+
319
+ gem 'crystalruby'
320
+
321
+ # Let's see if performance is comparable to that of the redis gem.
322
+ gem 'benchmark-ips'
323
+ gem 'redis'
324
+ ```
325
+
326
+ 3. Write our Redis client
327
+
328
+ ```ruby
329
+ # Filename: crystalredis.rb
330
+ require 'crystalruby'
331
+
332
+ module CrystalRedis
333
+
334
+ crystal do
335
+ CLIENT = Redis.new
336
+ def self.client
337
+ CLIENT
338
+ end
339
+ end
340
+
341
+ crystalize [key: :string, value: :string] => :void
342
+ def set(key, value)
343
+ client.set(key, value)
344
+ end
345
+
346
+ crystalize [key: :string] => :string
347
+ def get(key)
348
+ client.get(key).to_s
349
+ end
350
+ end
351
+ ```
352
+
353
+ 4. Load the modules (without running them) to generate our Crystal project skeleton.
354
+
355
+ ```bash
356
+ bundle exec ruby crystalredis.rb
357
+ ```
358
+
359
+ 5. Add the missing Redis dependency to our shard.yml
360
+
361
+ ```yaml
362
+ # filename: crystalruby/src/shard.yml
363
+ dependencies:
364
+ redis:
365
+ github: stefanwille/crystal-redis
366
+ ```
367
+
368
+ ```ruby
369
+ # filename: main.cr
370
+ require "redis"
371
+ require "./generated/index"
372
+ ```
373
+
374
+ ```bash
375
+ bundle exec crystalruby install
376
+ ```
377
+
378
+ 6. Compile and benchmark our new module in Ruby
379
+
380
+ ```ruby
381
+ # Filename: benchmark.rb
382
+ # Let's compare the performance of our CrystalRedis module to the Ruby Redis gem
383
+ require_relative "crystalredis"
384
+ require 'redis'
385
+ require 'benchmark/ips'
386
+
387
+ Benchmark.ips do |x|
388
+ rbredis = Redis.new
389
+
390
+ x.report(:crredis) do
391
+ CrystalRedis.set("hello", "world")
392
+ CrystalRedis.get("hello")
393
+ end
394
+
395
+ x.report(:rbredis) do
396
+ rbredis.set("hello", "world")
397
+ rbredis.get("hello")
398
+ end
399
+ end
400
+ ```
401
+
402
+ 7. Run the benchmark
403
+
404
+ ```bash
405
+ $ bundle exec ruby benchmark.rb
406
+ ```
407
+
408
+ ### Output
409
+
410
+ ```bash
411
+
412
+ #crystalredis wins! (Warm up during first run will be slow for crredis, due to first compilation)
413
+
414
+ ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin22]
415
+ Warming up --------------------------------------
416
+ crredis 1.946k i/100ms
417
+ rbredis 1.749k i/100ms
418
+ Calculating -------------------------------------
419
+ crredis 22.319k (± 1.7%) i/s - 112.868k in 5.058448s
420
+ rbredis 16.861k (± 9.1%) i/s - 83.952k in 5.024941s
421
+ ```
422
+
298
423
  ## Release Builds
299
424
 
300
425
  You can control whether CrystalRuby builds in debug or release mode by setting following config option
@@ -1,7 +1,7 @@
1
1
  module CrystalRuby
2
2
  module Template
3
3
  Dir[File.join(File.dirname(__FILE__), "templates", "*.cr")].each do |file|
4
- template_name = File.basename(file, File.extname(file)).capitalize
4
+ template_name = File.basename(file, File.extname(file)).split("_").map(&:capitalize).join
5
5
  const_set(template_name, File.read(file))
6
6
  end
7
7
 
@@ -0,0 +1,6 @@
1
+ # This is the template used for writing inline chunks of Crystal code without direct
2
+ # Ruby integration
3
+
4
+ module %{module_name}
5
+ %{body}
6
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Crystalruby
4
- VERSION = "0.1.8"
4
+ VERSION = "0.1.9"
5
5
  end
data/lib/crystalruby.rb CHANGED
@@ -22,6 +22,19 @@ module CrystalRuby
22
22
  @crystalize_next = { raw: type.to_sym == :raw, args: args, returns: returns, block: block }
23
23
  end
24
24
 
25
+ def crystal(type = :src, &block)
26
+ inline_crystal_body = Template.render(
27
+ Template::InlineChunk,
28
+ {
29
+ module_name: name,
30
+ body: block.source.lines[
31
+ type == :raw ? 2...-2 : 1...-1
32
+ ].join("\n")
33
+ }
34
+ )
35
+ CrystalRuby.write_chunk(self, body: inline_crystal_body)
36
+ end
37
+
25
38
  def crtype(&block)
26
39
  TypeBuilder.with_injected_type_dsl(self) do
27
40
  TypeBuilder.build(&block)
@@ -56,7 +69,7 @@ module CrystalRuby
56
69
  args ||= {}
57
70
  @crystalize_next = nil
58
71
  function = build_function(self, method_name, args, returns, function_body)
59
- CrystalRuby.write_function(self, name: function[:name], body: function[:body]) do
72
+ CrystalRuby.write_chunk(self, name: function[:name], body: function[:body]) do
60
73
  extend FFI::Library
61
74
  ffi_lib "#{config.crystal_lib_dir}/#{config.crystal_lib_name}"
62
75
  attach_function method_name, fname, function[:ffi_types], function[:return_ffi_type]
@@ -226,6 +239,7 @@ module CrystalRuby
226
239
  extend FFI::Library
227
240
  ffi_lib "#{config.crystal_lib_dir}/#{config.crystal_lib_name}"
228
241
  attach_function "init!", :init, [:pointer], :void
242
+ send(:remove_const, :ErrorCallback) if defined?(ErrorCallback)
229
243
  const_set(:ErrorCallback, FFI::Function.new(:void, %i[string string]) do |error_type, message|
230
244
  error_type = error_type.to_sym
231
245
  is_exception_type = Object.const_defined?(error_type) && Object.const_get(error_type).ancestors.include?(Exception)
@@ -314,7 +328,7 @@ module CrystalRuby
314
328
 
315
329
  def self.attach!
316
330
  @block_store.each do |function|
317
- function[:compile_callback].call
331
+ function[:compile_callback]&.call
318
332
  end
319
333
  @attached = true
320
334
  end
@@ -335,7 +349,7 @@ module CrystalRuby
335
349
  File.read(digest_file_name) if File.exist?(digest_file_name)
336
350
  end
337
351
 
338
- def self.write_function(owner, name:, body:, &compile_callback)
352
+ def self.write_chunk(owner, body:, name: Digest::MD5.hexdigest(body), &compile_callback)
339
353
  @block_store ||= []
340
354
  @block_store << { owner: owner, name: name, body: body, compile_callback: compile_callback }
341
355
  FileUtils.mkdir_p("#{config.crystal_src_dir}/#{config.crystal_codegen_dir}")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crystalruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
@@ -87,6 +87,7 @@ files:
87
87
  - lib/crystalruby/template.rb
88
88
  - lib/crystalruby/templates/function.cr
89
89
  - lib/crystalruby/templates/index.cr
90
+ - lib/crystalruby/templates/inline_chunk.cr
90
91
  - lib/crystalruby/typebuilder.rb
91
92
  - lib/crystalruby/typemaps.rb
92
93
  - lib/crystalruby/types.rb