functionable 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d0373eae031682977e0b0b675e1a448c760f5028291e8859c2ad867183a9da3
4
- data.tar.gz: ebb2e10a2989723277ea225cfe87b912471d0d8321af005ddb60a687acbec669
3
+ metadata.gz: c45d720e30ecc411d843fa883f806e9d7ce1214de6cd82293d6bfa2f1116b541
4
+ data.tar.gz: 2ea29d5add529473a0c51731bdf55f77d11a991dfc2f57970e2756cdb3467e75
5
5
  SHA512:
6
- metadata.gz: 89a3de952523e9236074581784c317623f64e27c24c2888b60a815f704cf1b518b2b16e7e062481843d7285bc34d4a387170bc7cd674c03caa957cf79737ff4b
7
- data.tar.gz: be97ad64ee0a5eedba64fb5062dec6b619e164e2a0a01460c0050263effba8c110ec4ddc5152847d8fab6ab549bb6c2e0ed2b372524577ea90a158cd06f0d95f
6
+ metadata.gz: 7dcd4d168cedae7291839e4c4017a249c1b48fed84d9d846c249b64d3416b731fa3811d00b2c7530cae6e6d90b87eaaaf703ffcf9903b34666ef0fedbe7fd758
7
+ data.tar.gz: 50fb7b77b3e3118f4982edbd326dc6b9b8353216d8f36e131d9fa6386515cd5d4c2d1c39fe5dc7a64bd0c08108755fd9136bcebf16b604cb2822ccfb68e42395
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -337,29 +337,41 @@ end
337
337
 
338
338
  == Benchmarks
339
339
 
340
- When you lean into the power of functional programming in Ruby, you gain performance and lower your memory footprint since you are creating the minimal amount of objects necessary. In terms of CPU performance, here's a comparison:
340
+ When you lean into the power of functional programming in Ruby, you gain performance and lower your memory footprint since you are creating the minimal amount of objects necessary. In terms of CPU performance, here's a benchmark script (see `bin/benchmark` included in this project):
341
341
 
342
342
  [source,ruby]
343
343
  ----
344
+ #! /usr/bin/env ruby
345
+ # frozen_string_literal: true
346
+
344
347
  require "bundler/inline"
345
348
 
346
349
  gemfile true do
347
350
  source "https://rubygems.org"
348
351
 
349
352
  gem "benchmark-ips"
350
- gem "functionable"
353
+ gem "functionable", path: ".."
354
+ end
355
+
356
+ module ModuleSelf
357
+ extend self
358
+
359
+ def call(message = "benchmark") = message
351
360
  end
352
361
 
353
- ProcExample = proc { |message = "benchmark"| message }
354
- LambdaExample = -> message = "benchmark" { message }
362
+ module ModuleFunction
363
+ module_function
355
364
 
356
- module ModuleExample
365
+ def call(message = "benchmark") = message
366
+ end
367
+
368
+ module ModuleFunctionable
357
369
  extend Functionable
358
370
 
359
371
  def call(message = "benchmark") = message
360
372
  end
361
373
 
362
- class ClassExample
374
+ class ClassFunction
363
375
  def initialize message = "benchmark"
364
376
  @message = message
365
377
  end
@@ -371,16 +383,23 @@ class ClassExample
371
383
  attr_reader :message
372
384
  end
373
385
 
374
- memoized_function = ClassExample.new
386
+ proc_function = proc { |message = "message"| message }
387
+ lambda_function = -> message = "benchmark" { message }
388
+ memoized_instance = ClassFunction.new
389
+ memoized_method = memoized_instance.method :call
375
390
 
376
391
  Benchmark.ips do |benchmark|
377
392
  benchmark.config time: 5, warmup: 2
378
393
 
379
- benchmark.report("Proc") { ProcExample.call }
380
- benchmark.report("Lambda") { LambdaExample.call }
381
- benchmark.report("Module") { ModuleExample.call }
382
- benchmark.report("Class (new)") { ClassExample.new.call }
383
- benchmark.report("Class (memoized)") { memoized_function.call }
394
+ benchmark.report("Proc") { proc_function.call }
395
+ benchmark.report("Lambda") { lambda_function.call }
396
+ benchmark.report("Module (function)") { ModuleFunction.call }
397
+ benchmark.report("Module (functionable)") { ModuleFunctionable.call }
398
+ benchmark.report("Module (self)") { ModuleSelf.call }
399
+ benchmark.report("Class (new)") { ClassFunction.new.call }
400
+ benchmark.report("Class (memoized)") { memoized_instance.call }
401
+ benchmark.report("Method (new)") { memoized_instance.method(:call).call }
402
+ benchmark.report("Method (memoized)") { memoized_method.call }
384
403
 
385
404
  benchmark.compare!
386
405
  end
@@ -391,27 +410,41 @@ When you run the above benchmark, you should see the following results:
391
410
  ----
392
411
  ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +YJIT +PRISM [arm64-darwin24.6.0]
393
412
  Warming up --------------------------------------
394
- Proc 2.370M i/100ms
395
- Lambda 2.335M i/100ms
396
- Module 4.153M i/100ms
397
- Class (new) 1.394M i/100ms
398
- Class (memoized) 4.341M i/100ms
413
+ Proc 2.268M i/100ms
414
+ Lambda 2.327M i/100ms
415
+ Module (function) 3.984M i/100ms
416
+ Module (functionable)
417
+ 4.143M i/100ms
418
+ Module (self) 4.177M i/100ms
419
+ Class (new) 1.266M i/100ms
420
+ Class (memoized) 4.128M i/100ms
421
+ Method (new) 775.573k i/100ms
422
+ Method (memoized) 2.053M i/100ms
399
423
  Calculating -------------------------------------
400
- Proc 25.039M0.5%) i/s (39.94 ns/i) - 125.624M in 5.017274s
401
- Lambda 25.657M (± 0.3%) i/s (38.98 ns/i) - 128.450M in 5.006465s
402
- Module 59.812M (± 2.0%) i/s (16.72 ns/i) - 303.169M in 5.070730s
403
- Class (new) 15.891M (± 1.3%) i/s (62.93 ns/i) - 80.870M in 5.089769s
404
- Class (memoized) 58.271M1.5%) i/s (17.16 ns/i) - 295.161M in 5.066395s
424
+ Proc 24.944M1.5%) i/s (40.09 ns/i) - 124.748M in 5.002287s
425
+ Lambda 25.683M (± 0.6%) i/s (38.94 ns/i) - 130.294M in 5.073248s
426
+ Module (function) 58.738M (± 2.9%) i/s (17.02 ns/i) - 294.792M in 5.022900s
427
+ Module (functionable)
428
+ 58.607M2.5%) i/s (17.06 ns/i) - 294.182M in 5.022770s
429
+ Module (self) 57.811M (± 2.4%) i/s (17.30 ns/i) - 292.388M in 5.060572s
430
+ Class (new) 14.801M (± 1.3%) i/s (67.56 ns/i) - 74.684M in 5.046650s
431
+ Class (memoized) 59.130M (± 0.4%) i/s (16.91 ns/i) - 297.230M in 5.026825s
432
+ Method (new) 9.030M (± 1.4%) i/s (110.74 ns/i) - 45.759M in 5.068493s
433
+ Method (memoized) 24.870M (± 0.2%) i/s (40.21 ns/i) - 125.231M in 5.035364s
405
434
 
406
435
  Comparison:
407
- Module: 59812197.4 i/s
408
- Class (memoized): 58271006.1 i/s - same-ish: difference falls within error
409
- Lambda: 25657201.2 i/s - 2.33x slower
410
- Proc: 25039056.2 i/s - 2.39x slower
411
- Class (new): 15891475.5 i/s - 3.76x slower
412
- ----
413
-
414
- As you can see, a functional module is the fastest while a memoized class comes in at a very close second (despite creating an additional object). Everything else is much slower.
436
+ Class (memoized): 59129953.7 i/s
437
+ Module (function): 58738432.2 i/s - same-ish: difference falls within error
438
+ Module (functionable): 58607417.9 i/s - same-ish: difference falls within error
439
+ Module (self): 57810666.8 i/s - same-ish: difference falls within error
440
+ Lambda: 25683494.8 i/s - 2.30x slower
441
+ Proc: 24943941.2 i/s - 2.37x slower
442
+ Method (memoized): 24870425.2 i/s - 2.38x slower
443
+ Class (new): 14801271.5 i/s - 3.99x slower
444
+ Method (new): 9029806.7 i/s - 6.55x slower
445
+ ----
446
+
447
+ As you can see, a functional module is one of the fastest while everything else is much slower.
415
448
 
416
449
  == Development
417
450
 
data/functionable.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "functionable"
5
- spec.version = "0.0.0"
5
+ spec.version = "0.1.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/functionable"
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.signing_key = Gem.default_key_path
23
23
  spec.cert_chain = [Gem.default_cert_path]
24
24
 
25
- spec.required_ruby_version = "~> 3.4"
25
+ spec.required_ruby_version = ">= 3.4"
26
26
 
27
27
  spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
28
28
  spec.files = Dir["*.gemspec", "lib/**/*"]
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: functionable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -63,7 +63,7 @@ require_paths:
63
63
  - lib
64
64
  required_ruby_version: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.4'
69
69
  required_rubygems_version: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file