defi 3.0.1 → 4.0.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: cbd2a5befa5ac9808bfe1c121549311dfed58c0a48070b9708ec46621a101255
4
- data.tar.gz: b1f16e2e70d07e377e7f662a807afb1afbe9cc971535cb683d5000b19b0306de
3
+ metadata.gz: 147abcfe45309cf8e5e5df3cf02dbcaeaccd2c421841ab017844206dd1218ed1
4
+ data.tar.gz: 8d82cceb4e3e68f29ee6ae8632369cf9c4d2bdfdc3d3ba1a1cd3de5659cad8bc
5
5
  SHA512:
6
- metadata.gz: a673ab6344aa7f6ebe0b04ff7556b0f3d5524cec97f26810613858afe874f96362081a293cabadcdcf8a09da1c10c75ef8fa0e5a3efc39fc3f075660febc6a9a
7
- data.tar.gz: a8c78c9725743ba1efeb8e3ac12afb5dca6403d8a7d6b714142814db42d7d60b075b5a3d5431a2145b33319f2c6d08742e50fe91d4e7ea5916579a8185b4bcdd
6
+ metadata.gz: 9c0076455aa06379af57797aff1c160fce9bd1d930f45702a95eea4836b0c77270f9bcdac8cb4f00b4c5fe364766cb0a8a07b3f4c0800606366df9408debe882
7
+ data.tar.gz: '0379b004d430b65a97b2f56d2a968457ec37a41510a08f253899060e7645937b7c29e234e2d6a9bbca75b991edde71485ade15d64cb0f61a7b348fd750d2e092'
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2025 Cyril Kato
3
+ Copyright (c) 2015-2026 Cyril Kato
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -4,78 +4,71 @@
4
4
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/fixrb/defi/main)
5
5
  [![License](https://img.shields.io/github/license/fixrb/defi?label=License&logo=github)](https://github.com/fixrb/defi/raw/main/LICENSE.md)
6
6
 
7
- **Defi** is a streamlined Ruby library designed for the specification of method arguments while respecting their signatures.
8
- Rather than representing method signatures themselves, Defi focuses on providing a way to furnish methods with appropriate arguments, thereby preparing them for invocation.
9
-
10
- This approach serves as an alternative to traditional methods like `Object#method` and `UnboundMethod`.
11
- Where `Object#method` is bound to a specific object and `UnboundMethod` requires compatibility with the method’s originating class, Defi offers a more flexible and universal way to prepare method calls.
12
- It allows method arguments to be specified in advance and then applied to any compatible object – those equipped with corresponding methods.
13
-
14
- Defi is particularly useful in scenarios where you need to apply a set of method arguments across different objects to observe the varying outcomes, whether they be returned values or exceptions.
15
- This makes it an ideal tool for testing, method comparison across different implementations, or any situation where method behavior needs to be assessed dynamically across various objects.
7
+ Defi prepares a method call, a name with its arguments, and sends it to any object, keeping what came back: the value returned, or the exception raised. The same call can be sent to as many objects as you like, to compare what each one does with it.
16
8
 
17
9
  ## Installation
18
10
 
19
- Add this line to your application's Gemfile:
20
-
21
11
  ```ruby
12
+ # Gemfile
22
13
  gem "defi"
23
14
  ```
24
15
 
25
- And then execute:
16
+ Defi requires Ruby 3.3 or later, and depends on nothing.
26
17
 
27
- ```sh
28
- bundle install
29
- ```
18
+ ## Usage
30
19
 
31
- Or install it yourself as:
20
+ A challenge is a method name, with positional arguments, keyword arguments and a block, as you would write them after a dot:
32
21
 
33
- ```sh
34
- gem install defi
35
- ```
22
+ ```ruby
23
+ require "defi"
36
24
 
37
- ## Usage
25
+ challenge = Defi::Challenge.new(:fetch, :b, 0)
26
+ challenge.to_s # => ".fetch(:b, 0)"
27
+ ```
38
28
 
39
- The `Defi` library simplifies the task of applying method signatures to various objects, regardless of their type (instances, modules, etc.).
40
- Below are some detailed examples to demonstrate its versatility and ease of use:
29
+ Sent to an object with `to`, it brings back a value: what the method returned, or what it raised.
41
30
 
42
- ### Example 1: Multiplying Numbers
31
+ ```ruby
32
+ value = challenge.to({ b: 2 })
33
+ value.raised? # => false
34
+ value.object # => 2
35
+ value.call # => 2
36
+
37
+ value = Defi::Challenge.new(:fetch, :b).to({})
38
+ value.raised? # => true
39
+ value.object # => #<KeyError: key not found: :b>
40
+ value.call # raises the KeyError again
41
+ ```
43
42
 
44
- Suppose you want to multiply the number `6` by `7`.
45
- With `Defi`, this can be elegantly done as follows:
43
+ Keyword arguments and the block go through as they are:
46
44
 
47
45
  ```ruby
48
- result = Defi(:*, 7).to(6).call
49
- puts result # Output: 42
46
+ Defi::Challenge.new(:encode, "US-ASCII", undef: :replace).to("café").object # => "caf?"
47
+ Defi::Challenge.new(:map) { |n| n * 2 }.to([1, 2]).object # => [2, 4]
50
48
  ```
51
49
 
52
- Here, `Defi(:*, 7)` creates a challenge with the multiplication method (`:*`) and the argument `7`.
53
- The `.to(6)` method specifies that this challenge should be applied to the number `6`.
54
- Finally, `.call` executes the challenge, yielding the result `42`.
50
+ ## What comes back
55
51
 
56
- ### Example 2: Invoking an Undefined Method
52
+ The message is sent with `public_send`: a private method, or a `BasicObject`, which has no `public_send`, gives a `NoMethodError`. `public_send` protects the named method only: a challenge of `send` or `instance_eval`, which are public, reaches what they reach.
57
53
 
58
- `Defi` also elegantly handles cases where the method might not exist on the target object.
59
- For instance:
54
+ A challenge keeps as its value the exceptions a method raises on its own: a `StandardError`, a `ScriptError` (such as `NotImplementedError`), a `SystemStackError`, or the `SystemExit` of an `exit` or an `abort`. What is not the method's doing goes through: an `Interrupt`, a `SignalException`, a `NoMemoryError`, the exception a `Timeout` uses to end its block (a `Timeout` given a class to raise, such as `RuntimeError`, is kept like any `StandardError`), and any other subclass of `Exception`. `Defi::Value::RAISED` lists the classes kept. `call` raises the exception again, the same object, with its own cause.
60
55
 
61
- ```ruby
62
- begin
63
- Defi(:boom).to("foo").call
64
- rescue NoMethodError => e
65
- puts e.message # Output: undefined method `boom' for "foo":String
66
- end
67
- ```
56
+ `to_s` writes the call as `.name(1, key: 2, &block)`: the arguments and the keys by their `inspect`, which runs their code and can change from one Ruby to the next (a Hash in 3.4, a Set in 4.0), the block as `&block`.
57
+
58
+ A challenge and a value are frozen. Their arguments are the objects given, not copies: a mutable argument stays shared with the caller.
68
59
 
69
- In this example, we attempt to call the non-existent method `boom` on the string `"foo"`.
70
- `Defi` correctly raises a `NoMethodError`, showing that the method `boom` is undefined for a `String` object.
60
+ ## Changes in 4.0
71
61
 
72
- ## Contact
62
+ Compared with 3.0.1:
73
63
 
74
- * Source code: https://github.com/fixrb/defi/issues
64
+ - `Defi::Method` becomes `Defi::Challenge`, a plain class, no longer a `BasicObject`, in `defi/challenge.rb`: `require "defi/method"` becomes `require "defi"`. `Kernel#Defi`, which every object received as a public method, is gone: write `Defi::Challenge.new`.
65
+ - `to` keeps the exceptions of the method only, where 3.0.1 caught every `Exception`, `Timeout` and `Interrupt` included. A name that is not a Symbol raises `ArgumentError`, as documented, with a new message; the `BasicObject` could not even `raise`. `call` keeps the cause of the exception it raises again.
66
+ - `Challenge#to_s` writes keyword arguments as `key: value` and the block as `&block`. `args` and `opts` are frozen. `Value.new` takes the object and whether it was raised; `Value::RAISE` and `Value::RETURN` are gone, as are `to_h` on both classes, `to_s` on a value and the custom `inspect` methods.
67
+ - Ruby 3.3 or later; tested on 3.3, 3.4, 4.0 and head.
75
68
 
76
69
  ## Versioning
77
70
 
78
- __Defi__ follows [Semantic Versioning 2.0](https://semver.org/).
71
+ Defi follows [Semantic Versioning 2.0](https://semver.org/).
79
72
 
80
73
  ## License
81
74
 
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "value"
4
+
5
+ module Defi
6
+ # A method call prepared in advance: a name, positional arguments, keyword
7
+ # arguments and a block, to send to any object with {#to}. A challenge is
8
+ # frozen, and sends its message as `public_send` does: a private method is
9
+ # a `NoMethodError`, while a public one that reaches further, such as
10
+ # `send` or `instance_eval`, does what it does.
11
+ class Challenge
12
+ # @return [Symbol] the name of the method
13
+ attr_reader :name
14
+
15
+ # @return [Array] the positional arguments, frozen
16
+ attr_reader :args
17
+
18
+ # @return [Hash] the keyword arguments, frozen
19
+ attr_reader :opts
20
+
21
+ # @return [Proc, nil] the block
22
+ attr_reader :block
23
+
24
+ # @param name [Symbol] the name of the method
25
+ # @param args [Array] the positional arguments
26
+ # @param opts [Hash] the keyword arguments
27
+ # @param block [Proc] the block
28
+ # @raise [ArgumentError] when the name is not a Symbol
29
+ def initialize(name, *args, **opts, &block)
30
+ raise ::ArgumentError, "the name of the method must be a Symbol" unless name.instance_of?(::Symbol)
31
+
32
+ @name = name
33
+ @args = args.freeze
34
+ @opts = opts.freeze
35
+ @block = block
36
+ freeze
37
+ end
38
+
39
+ # Sends the message to an object. What the method raises comes back as
40
+ # the value, as long as it is the method's own doing: a `StandardError`,
41
+ # a `ScriptError` (such as `NotImplementedError`), a `SystemStackError`
42
+ # or a `SystemExit`. An `Interrupt`, a signal, a `NoMemoryError` and the
43
+ # exception a `Timeout` uses to end the block go through.
44
+ #
45
+ # @param object [Object] the receiver; a `BasicObject` has no
46
+ # `public_send`, so the value is a `NoMethodError`
47
+ # @return [Defi::Value] what came back
48
+ def to(object)
49
+ Value.new(object.public_send(name, *args, **opts, &block), false)
50
+ rescue *Value::RAISED => e
51
+ Value.new(e, true)
52
+ end
53
+
54
+ # @return [String] the call, as `.name(1, key: 2, &block)`: the arguments
55
+ # and the keys as their `inspect` writes them (user code, which runs
56
+ # here), the block as `&block`
57
+ def to_s
58
+ parts = args.map(&:inspect) + opts.map { |key, value| "#{keyword(key)} #{value.inspect}" }
59
+ parts << "&block" if block
60
+ parts.empty? ? ".#{name}" : ".#{name}(#{parts.join(", ")})"
61
+ end
62
+
63
+ private
64
+
65
+ # A keyword as Ruby writes it: `key:` for a Symbol, quoted when its
66
+ # inspect is, `"key" =>` otherwise.
67
+ def keyword(key)
68
+ key.instance_of?(::Symbol) ? "#{key.inspect[1..]}:" : "#{key.inspect} =>"
69
+ end
70
+ end
71
+ end
data/lib/defi/value.rb CHANGED
@@ -1,85 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Defi
4
- # Represents a result of an operation, encapsulating both successful returns
5
- # and exceptions. This class intentionally catches all exceptions (Exception)
6
- # instead of StandardError to maintain complete control over method execution
7
- # outcomes, particularly in testing contexts. This ensures that system-level
8
- # exceptions like SystemExit cannot prematurely terminate test execution with
9
- # potentially false positive results.
4
+ # What came back from a challenge: the object returned, or the exception
5
+ # raised. A value is frozen.
10
6
  class Value
11
- RAISE = "raise"
12
- RETURN = "return"
7
+ # The exceptions a method raises on its own, which a challenge keeps as
8
+ # its value. Anything else, an interruption or a signal, a shortage of
9
+ # memory, the end of a `Timeout`, goes through.
10
+ RAISED = [::StandardError, ::ScriptError, ::SystemStackError, ::SystemExit].freeze
13
11
 
14
- # @return [#object_id] The returned value or caught exception
12
+ # @return [Object] the object returned, or the exception raised
15
13
  attr_reader :object
16
14
 
17
- # Initializes a Value object by executing the provided block.
18
- #
19
- # @example Successful execution
20
- # value = Defi::Value.new { 1 + 1 }
21
- # value.call # => 2
22
- # value.raised? # => false
23
- #
24
- # @example Exception handling
25
- # value = Defi::Value.new { raise TypeError, "Invalid type" }
26
- # value.raised? # => true
27
- # value.object # => #<TypeError: Invalid type>
28
- #
29
- # @note This implementation catches Exception instead of StandardError
30
- # to provide complete control over method execution outcomes,
31
- # including system-level exceptions when needed.
32
- #
33
- # @yieldreturn [#object_id] Result or exception from block execution
34
- def initialize
35
- @object = yield
36
- @raised = false
37
- rescue ::Exception => e # rubocop:disable Lint/RescueException
38
- @object = e
39
- @raised = true
15
+ # @param object [Object] the object returned, or the exception raised
16
+ # @param raised [Boolean] whether the method raised: `true` or `false`,
17
+ # as given
18
+ def initialize(object, raised)
19
+ @object = object
20
+ @raised = raised
21
+ freeze
40
22
  end
41
23
 
42
- # Returns the result or raises the captured exception.
43
- #
44
- # @example With successful result
45
- # Value.new { "success" }.call # => "success"
46
- #
47
- # @example With exception
48
- # Value.new { raise "error" }.call # raises RuntimeError: error
49
- #
50
- # @return [#object_id] The operation result
51
- # @raise [Exception] The captured exception if raised? is true
52
- def call
53
- raise object if raised?
54
-
55
- object
56
- end
57
-
58
- # @return [Boolean] true if execution raised an exception
24
+ # @return [Boolean] whether the method raised
59
25
  def raised?
60
26
  @raised
61
27
  end
62
28
 
63
- # @return [String] Human-readable representation
64
- def inspect
65
- "Value(object: #{object}, raised: #{raised?})"
66
- end
67
-
68
- # @return [Hash] Value properties
69
- def to_h
70
- { raised: raised?, object: }
71
- end
72
-
73
- # @return [String] String representation showing outcome type and value
74
- def to_s
75
- "#{raise_or_return} #{object}"
76
- end
77
-
78
- private
29
+ # @return [Object] the object returned
30
+ # @raise [Exception] the exception raised, again, with its own cause
31
+ def call
32
+ raise object, cause: object.cause if raised?
79
33
 
80
- # @return [String] Execution outcome type
81
- def raise_or_return
82
- raised? ? RAISE : RETURN
34
+ object
83
35
  end
84
36
  end
85
37
  end
data/lib/defi.rb CHANGED
@@ -1,34 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Namespace for the Defi library.
4
- #
5
- # Defi provides a flexible way to specify method calls with arguments
6
- # for later execution. It supports method chaining, exception handling,
7
- # and value inspection.
8
- #
9
- # @example Basic arithmetic operation
10
- # addition = Defi(:+, 2)
11
- # addition.to(1).call # => 3
12
- #
13
- # @example String manipulation
14
- # upcase = Defi(:upcase)
15
- # upcase.to("hello").call # => "HELLO"
16
- #
17
- # @example Method with keyword arguments
18
- # format = Defi(:format, precision: 2)
19
- # format.to(3.14159).call # => "3.14"
20
- #
21
- # @example Block usage
22
- # map_double = Defi(:map) { |x| x * 2 }
23
- # map_double.to([1, 2, 3]).call # => [2, 4, 6]
24
- #
25
- # @example Error handling
26
- # result = Defi(:undefined_method).to(42)
27
- # result.raised? # => true
28
- # result.object # => #<NoMethodError: ...>
29
- #
3
+ # Prepares a method call, a name with its arguments, and sends it to any
4
+ # object, keeping what came back: the value returned, or the exception
5
+ # raised.
6
+ #
7
+ # @example
8
+ # challenge = Defi::Challenge.new(:+, 2)
9
+ # challenge.to(40).object # => 42
10
+ # challenge.to("a").call # raises TypeError: no implicit conversion of Integer into String
30
11
  module Defi
31
12
  end
32
13
 
33
- # Load core components
34
- require_relative "kernel"
14
+ require_relative "defi/challenge"
15
+ require_relative "defi/value"
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: defi
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-31 00:00:00.000000000 Z
11
+ date: 2026-10-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Challenge library.
13
+ description: 'Prepares a method call, a name with its arguments, and sends it to any
14
+ object, keeping what came back: the value returned, or the exception raised.'
14
15
  email: contact@cyril.email
15
16
  executables: []
16
17
  extensions: []
@@ -19,14 +20,17 @@ files:
19
20
  - LICENSE.md
20
21
  - README.md
21
22
  - lib/defi.rb
22
- - lib/defi/method.rb
23
+ - lib/defi/challenge.rb
23
24
  - lib/defi/value.rb
24
- - lib/kernel.rb
25
- homepage: https://github.com/fixrb/defi
25
+ homepage: https://fixrb.dev/gems/defi/
26
26
  licenses:
27
27
  - MIT
28
28
  metadata:
29
+ bug_tracker_uri: https://github.com/fixrb/defi/issues
30
+ changelog_uri: https://github.com/fixrb/defi#changes-in-40
31
+ documentation_uri: https://rubydoc.info/gems/defi
29
32
  rubygems_mfa_required: 'true'
33
+ source_code_uri: https://github.com/fixrb/defi
30
34
  post_install_message:
31
35
  rdoc_options: []
32
36
  require_paths:
@@ -35,15 +39,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
35
39
  requirements:
36
40
  - - ">="
37
41
  - !ruby/object:Gem::Version
38
- version: 3.1.0
42
+ version: 3.3.0
39
43
  required_rubygems_version: !ruby/object:Gem::Requirement
40
44
  requirements:
41
45
  - - ">="
42
46
  - !ruby/object:Gem::Version
43
47
  version: '0'
44
48
  requirements: []
45
- rubygems_version: 3.3.27
49
+ rubygems_version: 3.5.22
46
50
  signing_key:
47
51
  specification_version: 4
48
- summary: Challenge library.
52
+ summary: A method call prepared in advance, to send to any object
49
53
  test_files: []
data/lib/defi/method.rb DELETED
@@ -1,105 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Defi
4
- # Represents a method to be applied against an object.
5
- # Encapsulates method name, arguments, keyword arguments and blocks
6
- # for dynamic method invocation with proper error handling.
7
- class Method < ::BasicObject
8
- # Initialize a new Method object.
9
- #
10
- # @param name [Symbol] The method name
11
- # @param args [Array] Positional arguments
12
- # @param opts [Hash] Keyword arguments
13
- # @param block [Proc] Optional block
14
- #
15
- # @raise [ArgumentError] If name is not a Symbol, raises with the actual class received
16
- def initialize(name, *args, **opts, &block)
17
- raise ::ArgumentError, "Method name must be a Symbol, got: #{name.class}" unless name.is_a?(::Symbol)
18
-
19
- @name = name
20
- @args = args
21
- @opts = opts
22
- @block = block
23
- end
24
-
25
- # Applies the method to the given object.
26
- #
27
- # @param object [#object_id] Target object for method invocation
28
- # @return [Defi::Value] Result wrapper containing return value or exception
29
- #
30
- # @example Basic arithmetic
31
- # Defi::Method.new(:+, 1).to(2).call # => 3
32
- #
33
- # @example Block usage
34
- # Defi::Method.new(:map) { |x| x * 2 }.to([1, 2, 3]).call # => [2, 4, 6]
35
- #
36
- # @example Error handling
37
- # result = Defi::Method.new(:undefined).to(42)
38
- # result.raised? # => true
39
- def to(object)
40
- Value.new { object.public_send(@name, *@args, **@opts, &@block) }
41
- end
42
-
43
- # @return [Hash] Method properties
44
- def to_h
45
- {
46
- name: @name,
47
- args: @args,
48
- opts: @opts,
49
- block: @block
50
- }
51
- end
52
-
53
- # @return [String] Human-readable representation
54
- #
55
- # @example
56
- # Defi::Method.new(:+, 1).inspect
57
- # # => "Defi(name: :+, args: [1], opts: {}, block: nil)"
58
- def inspect
59
- "Defi(" \
60
- "name: #{@name.inspect}, " \
61
- "args: #{@args.inspect}, " \
62
- "opts: #{@opts.inspect}, " \
63
- "block: #{@block.nil? ? "nil" : "<Proc>"})"
64
- end
65
-
66
- # @return [String] String representation of the method call
67
- #
68
- # @example
69
- # Defi::Method.new(:+, 1).to_s # => ".+(1)"
70
- # Defi::Method.new(:map) { |x| x }.to_s # => ".map(<Proc>)"
71
- def to_s
72
- return ".#{@name}" if no_arguments?
73
-
74
- ".#{@name}(#{stringified_arguments})"
75
- end
76
-
77
- private
78
-
79
- def no_arguments?
80
- @args.empty? && @opts.empty? && @block.nil?
81
- end
82
-
83
- def stringified_arguments
84
- [
85
- args_string,
86
- opts_string,
87
- block_string
88
- ].compact.join(", ")
89
- end
90
-
91
- def args_string
92
- @args.inspect[1..-2] unless @args.empty?
93
- end
94
-
95
- def opts_string
96
- @opts.inspect[1..-2] unless @opts.empty?
97
- end
98
-
99
- def block_string
100
- "<Proc>" if @block
101
- end
102
- end
103
- end
104
-
105
- require_relative "value"
data/lib/kernel.rb DELETED
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative File.join("defi", "method")
4
-
5
- # Core Ruby module extended to provide the Defi method globally.
6
- # This extension allows for convenient method encapsulation and
7
- # delayed execution through the Defi method, accessible anywhere
8
- # in the Ruby environment.
9
- module Kernel
10
- # rubocop:disable Naming/MethodName
11
-
12
- # Creates a new Defi::Method instance.
13
- # This method provides a flexible way to encapsulate a method name along with its
14
- # arguments, keyword arguments, and an optional block for later invocation.
15
- #
16
- # @param method_name [Symbol] The method name to be sent to an object
17
- # @param args [Array] Positional arguments to be passed to the method
18
- # @param opts [Hash] Keyword arguments to be passed to the method
19
- # @param block [Proc] Optional block to be passed to the method
20
- #
21
- # @example Basic method without arguments
22
- # Defi(:to_s)
23
- #
24
- # @example Method with positional arguments
25
- # Defi(:+, 2)
26
- # Defi(:[], 0, 2) # For array/string slicing
27
- #
28
- # @example Method with keyword arguments
29
- # Defi(:transform, x: 1, y: 2)
30
- #
31
- # @example Method with a block
32
- # Defi(:map) { |x| x * 2 }
33
- #
34
- # @example Complex method call
35
- # Defi(:reduce, 0, &:+) # Sum an array
36
- #
37
- # @raise [ArgumentError] If method_name is not a Symbol
38
- #
39
- # @return [Defi::Method] An instance of Defi::Method encapsulating the method call
40
- def Defi(method_name, *args, **opts, &block)
41
- ::Defi::Method.new(method_name, *args, **opts, &block)
42
- end
43
-
44
- # rubocop:enable Naming/MethodName
45
- end