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 +4 -4
- data/README.md +125 -0
- data/lib/crystalruby/template.rb +1 -1
- data/lib/crystalruby/templates/inline_chunk.cr +6 -0
- data/lib/crystalruby/version.rb +1 -1
- data/lib/crystalruby.rb +17 -3
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca096d0563b6201c3ef4f084fff3304cfa212fda88e81085580b2de5ff10536f
|
4
|
+
data.tar.gz: ccc68dc96c30f973c9bafcbaec75a2461bbaa275e32913a0781c4cc5488f034f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/crystalruby/template.rb
CHANGED
@@ -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
|
|
data/lib/crystalruby/version.rb
CHANGED
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.
|
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]
|
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.
|
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.
|
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
|