defi 3.0.0 → 3.0.1
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 +4 -4
- data/LICENSE.md +1 -1
- data/README.md +2 -9
- data/lib/defi/method.rb +58 -52
- data/lib/defi/value.rb +38 -48
- data/lib/defi.rb +21 -15
- data/lib/kernel.rb +27 -24
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbd2a5befa5ac9808bfe1c121549311dfed58c0a48070b9708ec46621a101255
|
4
|
+
data.tar.gz: b1f16e2e70d07e377e7f662a807afb1afbe9cc971535cb683d5000b19b0306de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a673ab6344aa7f6ebe0b04ff7556b0f3d5524cec97f26810613858afe874f96362081a293cabadcdcf8a09da1c10c75ef8fa0e5a3efc39fc3f075660febc6a9a
|
7
|
+
data.tar.gz: a8c78c9725743ba1efeb8e3ac12afb5dca6403d8a7d6b714142814db42d7d60b075b5a3d5431a2145b33319f2c6d08742e50fe91d4e7ea5916579a8185b4bcdd
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
[](https://github.com/fixrb/defi/tags)
|
4
4
|
[](https://rubydoc.info/github/fixrb/defi/main)
|
5
|
-
[](https://github.com/fixrb/defi/actions?query=workflow%3Aruby+branch%3Amain)
|
6
|
-
[](https://github.com/fixrb/defi/actions?query=workflow%3Arubocop+branch%3Amain)
|
7
5
|
[](https://github.com/fixrb/defi/raw/main/LICENSE.md)
|
8
6
|
|
9
7
|
**Defi** is a streamlined Ruby library designed for the specification of method arguments while respecting their signatures.
|
@@ -83,11 +81,6 @@ __Defi__ follows [Semantic Versioning 2.0](https://semver.org/).
|
|
83
81
|
|
84
82
|
The [gem](https://rubygems.org/gems/defi) is available as open source under the terms of the [MIT License](https://github.com/fixrb/defi/raw/main/LICENSE.md).
|
85
83
|
|
86
|
-
|
84
|
+
## Sponsors
|
87
85
|
|
88
|
-
|
89
|
-
This project is sponsored by:<br />
|
90
|
-
<a href="https://sashite.com/"><img
|
91
|
-
src="https://github.com/fixrb/defi/raw/main/img/sashite.png"
|
92
|
-
alt="Sashité" /></a>
|
93
|
-
</p>
|
86
|
+
This project is sponsored by [Sashité](https://sashite.com/)
|
data/lib/defi/method.rb
CHANGED
@@ -2,18 +2,19 @@
|
|
2
2
|
|
3
3
|
module Defi
|
4
4
|
# Represents a method to be applied against an object.
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# Encapsulates method name, arguments, keyword arguments and blocks
|
6
|
+
# for dynamic method invocation with proper error handling.
|
7
7
|
class Method < ::BasicObject
|
8
8
|
# Initialize a new Method object.
|
9
9
|
#
|
10
|
-
# @param name
|
11
|
-
# @param args
|
12
|
-
# @param opts
|
13
|
-
# @param block [Proc]
|
14
|
-
#
|
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
|
15
16
|
def initialize(name, *args, **opts, &block)
|
16
|
-
raise ::ArgumentError, name.class
|
17
|
+
raise ::ArgumentError, "Method name must be a Symbol, got: #{name.class}" unless name.is_a?(::Symbol)
|
17
18
|
|
18
19
|
@name = name
|
19
20
|
@args = args
|
@@ -23,19 +24,23 @@ module Defi
|
|
23
24
|
|
24
25
|
# Applies the method to the given object.
|
25
26
|
#
|
26
|
-
# @
|
27
|
-
#
|
28
|
-
#
|
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
|
29
32
|
#
|
30
|
-
# @
|
31
|
-
#
|
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
|
32
39
|
def to(object)
|
33
40
|
Value.new { object.public_send(@name, *@args, **@opts, &@block) }
|
34
41
|
end
|
35
42
|
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# @return [Hash] The properties of the method.
|
43
|
+
# @return [Hash] Method properties
|
39
44
|
def to_h
|
40
45
|
{
|
41
46
|
name: @name,
|
@@ -45,53 +50,54 @@ module Defi
|
|
45
50
|
}
|
46
51
|
end
|
47
52
|
|
48
|
-
#
|
49
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
50
|
-
|
51
|
-
# Returns a string representation of the method.
|
53
|
+
# @return [String] Human-readable representation
|
52
54
|
#
|
53
55
|
# @example
|
54
|
-
#
|
55
|
-
#
|
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
|
56
67
|
#
|
57
|
-
# @
|
68
|
+
# @example
|
69
|
+
# Defi::Method.new(:+, 1).to_s # => ".+(1)"
|
70
|
+
# Defi::Method.new(:map) { |x| x }.to_s # => ".map(<Proc>)"
|
58
71
|
def to_s
|
59
|
-
|
60
|
-
return string if @args.empty? && @opts.empty? && @block.nil?
|
72
|
+
return ".#{@name}" if no_arguments?
|
61
73
|
|
62
|
-
|
63
|
-
|
64
|
-
stringified_block = "<Proc>" unless @block.nil?
|
74
|
+
".#{@name}(#{stringified_arguments})"
|
75
|
+
end
|
65
76
|
|
66
|
-
|
67
|
-
stringified_items << stringified_args unless @args.empty?
|
68
|
-
stringified_items << stringified_opts unless @opts.empty?
|
69
|
-
stringified_items << stringified_block unless @block.nil?
|
77
|
+
private
|
70
78
|
|
71
|
-
|
79
|
+
def no_arguments?
|
80
|
+
@args.empty? && @opts.empty? && @block.nil?
|
72
81
|
end
|
73
82
|
|
74
|
-
|
75
|
-
|
83
|
+
def stringified_arguments
|
84
|
+
[
|
85
|
+
args_string,
|
86
|
+
opts_string,
|
87
|
+
block_string
|
88
|
+
].compact.join(", ")
|
89
|
+
end
|
76
90
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
# add = Defi::Method.new(:+, 1)
|
81
|
-
# add.inspect # => "Defi(name: :+, args: [1], opts: {}, block: nil)"
|
82
|
-
#
|
83
|
-
# @return [String] The human-readable representation of the method.
|
84
|
-
def inspect
|
85
|
-
inspected_name = @name.inspect
|
86
|
-
inspected_args = @args.inspect
|
87
|
-
inspected_opts = @opts.inspect
|
88
|
-
inspected_block = @block.nil? ? "nil" : "<Proc>"
|
91
|
+
def args_string
|
92
|
+
@args.inspect[1..-2] unless @args.empty?
|
93
|
+
end
|
89
94
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
+
def opts_string
|
96
|
+
@opts.inspect[1..-2] unless @opts.empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
def block_string
|
100
|
+
"<Proc>" if @block
|
95
101
|
end
|
96
102
|
end
|
97
103
|
end
|
data/lib/defi/value.rb
CHANGED
@@ -1,93 +1,83 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Defi
|
4
|
-
# Represents a result of an operation, encapsulating
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
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.
|
9
10
|
class Value
|
10
11
|
RAISE = "raise"
|
11
12
|
RETURN = "return"
|
12
13
|
|
13
|
-
# @return [#object_id] The returned or
|
14
|
+
# @return [#object_id] The returned value or caught exception
|
14
15
|
attr_reader :object
|
15
16
|
|
16
|
-
# Initializes a Value object
|
17
|
-
# Captures any exception raised during the block execution.
|
17
|
+
# Initializes a Value object by executing the provided block.
|
18
18
|
#
|
19
|
-
# @example
|
19
|
+
# @example Successful execution
|
20
20
|
# value = Defi::Value.new { 1 + 1 }
|
21
21
|
# value.call # => 2
|
22
|
+
# value.raised? # => false
|
22
23
|
#
|
23
|
-
# @example
|
24
|
-
# value = Defi::Value.new { raise
|
25
|
-
# value.
|
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.
|
26
32
|
#
|
27
|
-
# @yieldreturn [#object_id]
|
28
|
-
# rubocop:disable Lint/RescueException
|
33
|
+
# @yieldreturn [#object_id] Result or exception from block execution
|
29
34
|
def initialize
|
30
35
|
@object = yield
|
31
36
|
@raised = false
|
32
|
-
rescue ::Exception => e
|
37
|
+
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
33
38
|
@object = e
|
34
39
|
@raised = true
|
35
40
|
end
|
36
|
-
# rubocop:enable Lint/RescueException
|
37
41
|
|
38
|
-
# Returns the
|
42
|
+
# Returns the result or raises the captured exception.
|
43
|
+
#
|
44
|
+
# @example With successful result
|
45
|
+
# Value.new { "success" }.call # => "success"
|
39
46
|
#
|
40
|
-
# @example
|
41
|
-
#
|
42
|
-
# value.call # => "Hello"
|
47
|
+
# @example With exception
|
48
|
+
# Value.new { raise "error" }.call # raises RuntimeError: error
|
43
49
|
#
|
44
|
-
# @return [#object_id] The
|
50
|
+
# @return [#object_id] The operation result
|
51
|
+
# @raise [Exception] The captured exception if raised? is true
|
45
52
|
def call
|
46
53
|
raise object if raised?
|
47
54
|
|
48
55
|
object
|
49
56
|
end
|
50
57
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# @example
|
54
|
-
# value = Defi::Value.new { raise 'Error' }
|
55
|
-
# value.raised? # => true
|
56
|
-
#
|
57
|
-
# @return [Boolean] True if an exception was raised, otherwise false.
|
58
|
+
# @return [Boolean] true if execution raised an exception
|
58
59
|
def raised?
|
59
60
|
@raised
|
60
61
|
end
|
61
62
|
|
62
|
-
#
|
63
|
-
|
64
|
-
|
63
|
+
# @return [String] Human-readable representation
|
64
|
+
def inspect
|
65
|
+
"Value(object: #{object}, raised: #{raised?})"
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Hash] Value properties
|
65
69
|
def to_h
|
66
|
-
{
|
67
|
-
raised: raised?,
|
68
|
-
object:
|
69
|
-
}
|
70
|
+
{ raised: raised?, object: }
|
70
71
|
end
|
71
72
|
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# @return [String] The string representation of the Value object.
|
73
|
+
# @return [String] String representation showing outcome type and value
|
75
74
|
def to_s
|
76
75
|
"#{raise_or_return} #{object}"
|
77
76
|
end
|
78
77
|
|
79
|
-
# Returns a human-readable representation of the Value object.
|
80
|
-
#
|
81
|
-
# @return [String] The human-readable representation of the Value object.
|
82
|
-
def inspect
|
83
|
-
"Value(object: #{object}, raised: #{raised?})"
|
84
|
-
end
|
85
|
-
|
86
78
|
private
|
87
79
|
|
88
|
-
#
|
89
|
-
#
|
90
|
-
# @return [String] A "raise" or "return" string.
|
80
|
+
# @return [String] Execution outcome type
|
91
81
|
def raise_or_return
|
92
82
|
raised? ? RAISE : RETURN
|
93
83
|
end
|
data/lib/defi.rb
CHANGED
@@ -2,27 +2,33 @@
|
|
2
2
|
|
3
3
|
# Namespace for the Defi library.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
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
8
|
#
|
9
|
-
# @example
|
10
|
-
# require "defi"
|
11
|
-
#
|
12
|
-
# @example Adding 2 to 1
|
13
|
-
# # Create a Defi method object for addition with an argument of 2
|
9
|
+
# @example Basic arithmetic operation
|
14
10
|
# addition = Defi(:+, 2)
|
15
|
-
# addition.
|
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"
|
16
20
|
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
21
|
+
# @example Block usage
|
22
|
+
# map_double = Defi(:map) { |x| x * 2 }
|
23
|
+
# map_double.to([1, 2, 3]).call # => [2, 4, 6]
|
20
24
|
#
|
21
|
-
#
|
22
|
-
# result
|
25
|
+
# @example Error handling
|
26
|
+
# result = Defi(:undefined_method).to(42)
|
27
|
+
# result.raised? # => true
|
28
|
+
# result.object # => #<NoMethodError: ...>
|
23
29
|
#
|
24
30
|
module Defi
|
25
31
|
end
|
26
32
|
|
27
|
-
#
|
33
|
+
# Load core components
|
28
34
|
require_relative "kernel"
|
data/lib/kernel.rb
CHANGED
@@ -2,41 +2,44 @@
|
|
2
2
|
|
3
3
|
require_relative File.join("defi", "method")
|
4
4
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
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
9
|
module Kernel
|
10
|
-
# Disabling the RuboCop rule for method naming conventions
|
11
|
-
# to define a method with an uppercase name for stylistic reasons.
|
12
10
|
# rubocop:disable Naming/MethodName
|
13
11
|
|
14
12
|
# Creates a new Defi::Method instance.
|
15
|
-
# This method provides a
|
16
|
-
#
|
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.
|
17
15
|
#
|
18
|
-
# @
|
19
|
-
#
|
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
20
|
#
|
21
|
-
# @example
|
22
|
-
#
|
23
|
-
# addition = Defi(:+, 2)
|
24
|
-
# addition.inspect # => "Defi(name: :+, args: [2], opts: {}, block: nil)"
|
21
|
+
# @example Basic method without arguments
|
22
|
+
# Defi(:to_s)
|
25
23
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
24
|
+
# @example Method with positional arguments
|
25
|
+
# Defi(:+, 2)
|
26
|
+
# Defi(:[], 0, 2) # For array/string slicing
|
29
27
|
#
|
30
|
-
#
|
31
|
-
#
|
28
|
+
# @example Method with keyword arguments
|
29
|
+
# Defi(:transform, x: 1, y: 2)
|
32
30
|
#
|
33
|
-
# @
|
31
|
+
# @example Method with a block
|
32
|
+
# Defi(:map) { |x| x * 2 }
|
34
33
|
#
|
35
|
-
# @
|
36
|
-
|
37
|
-
|
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)
|
38
42
|
end
|
39
43
|
|
40
|
-
# Re-enabling the RuboCop rule for method naming conventions.
|
41
44
|
# rubocop:enable Naming/MethodName
|
42
45
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: defi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Challenge library.
|
14
14
|
email: contact@cyril.email
|
@@ -27,7 +27,7 @@ licenses:
|
|
27
27
|
- MIT
|
28
28
|
metadata:
|
29
29
|
rubygems_mfa_required: 'true'
|
30
|
-
post_install_message:
|
30
|
+
post_install_message:
|
31
31
|
rdoc_options: []
|
32
32
|
require_paths:
|
33
33
|
- lib
|
@@ -35,15 +35,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
35
35
|
requirements:
|
36
36
|
- - ">="
|
37
37
|
- !ruby/object:Gem::Version
|
38
|
-
version: 3.
|
38
|
+
version: 3.1.0
|
39
39
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '0'
|
44
44
|
requirements: []
|
45
|
-
rubygems_version: 3.
|
46
|
-
signing_key:
|
45
|
+
rubygems_version: 3.3.27
|
46
|
+
signing_key:
|
47
47
|
specification_version: 4
|
48
48
|
summary: Challenge library.
|
49
49
|
test_files: []
|