defi 3.0.0 → 3.0.1

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: bd965274ab9b7a6dd1303d7aa7b4c1da9c87551c6197a5075ea1f6a8c409df52
4
- data.tar.gz: 2fc6a867f949feeb94e971347313fd1b734c5851bb1f770e77bc6b2c0d72e9d8
3
+ metadata.gz: cbd2a5befa5ac9808bfe1c121549311dfed58c0a48070b9708ec46621a101255
4
+ data.tar.gz: b1f16e2e70d07e377e7f662a807afb1afbe9cc971535cb683d5000b19b0306de
5
5
  SHA512:
6
- metadata.gz: 99d0012c6768b9e38db3a149cb9021c3fdad056705748079e8e33ca6b7e05f55ec551ea1b784eb2cfba31dd3bae2f5454d75eeb8469fa5372321c192c42dcf99
7
- data.tar.gz: 789d8cd29d0cb8d608980c88b995d5d188e93febf868715113a1b274fe35cb54f2cd01f5b7a0f57d3e5ba804099c3129ab824e7ecfc0b50cf6b903df926bd935
6
+ metadata.gz: a673ab6344aa7f6ebe0b04ff7556b0f3d5524cec97f26810613858afe874f96362081a293cabadcdcf8a09da1c10c75ef8fa0e5a3efc39fc3f075660febc6a9a
7
+ data.tar.gz: a8c78c9725743ba1efeb8e3ac12afb5dca6403d8a7d6b714142814db42d7d60b075b5a3d5431a2145b33319f2c6d08742e50fe91d4e7ea5916579a8185b4bcdd
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2024 Cyril Kato
3
+ Copyright (c) 2015-2025 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
@@ -2,8 +2,6 @@
2
2
 
3
3
  [![Version](https://img.shields.io/github/v/tag/fixrb/defi?label=Version&logo=github)](https://github.com/fixrb/defi/tags)
4
4
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/fixrb/defi/main)
5
- [![Ruby](https://github.com/fixrb/defi/workflows/Ruby/badge.svg?branch=main)](https://github.com/fixrb/defi/actions?query=workflow%3Aruby+branch%3Amain)
6
- [![RuboCop](https://github.com/fixrb/defi/workflows/RuboCop/badge.svg?branch=main)](https://github.com/fixrb/defi/actions?query=workflow%3Arubocop+branch%3Amain)
7
5
  [![License](https://img.shields.io/github/license/fixrb/defi?label=License&logo=github)](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
- <p>
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
- # This class encapsulates the method name, its arguments, keyword arguments,
6
- # and an optional block, enabling dynamic method invocation.
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 [Symbol] The name of the method.
11
- # @param args [Array] Any arguments of the method.
12
- # @param opts [Hash] Any keyword arguments of the method.
13
- # @param block [Proc] Any block argument of the method.
14
- # @raise [ArgumentError] If the name is not a symbol.
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.inspect unless name.is_a?(::Symbol)
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
- # @example
27
- # add = Defi::Method.new(:+, 1)
28
- # add.to(2).call # => 3
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
- # @param object [#object_id] The object to method.
31
- # @return [Defi::Value] The actual value, to raise or to return.
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
- # Returns a hash containing the method's properties.
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
- # rubocop:disable Metrics/AbcSize
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
- # add = Defi::Method.new(:+, 1)
55
- # add.to_s # => ".+(1)"
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
- # @return [String] The string representation of the method.
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
- string = ".#{@name}"
60
- return string if @args.empty? && @opts.empty? && @block.nil?
72
+ return ".#{@name}" if no_arguments?
61
73
 
62
- stringified_args = @args.inspect[1..-2]
63
- stringified_opts = @opts.inspect[1..-2]
64
- stringified_block = "<Proc>" unless @block.nil?
74
+ ".#{@name}(#{stringified_arguments})"
75
+ end
65
76
 
66
- stringified_items = []
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
- "#{string}(#{stringified_items.join(", ")})"
79
+ def no_arguments?
80
+ @args.empty? && @opts.empty? && @block.nil?
72
81
  end
73
82
 
74
- # rubocop:enable Metrics/AbcSize
75
- # rubocop:enable Metrics/CyclomaticComplexity
83
+ def stringified_arguments
84
+ [
85
+ args_string,
86
+ opts_string,
87
+ block_string
88
+ ].compact.join(", ")
89
+ end
76
90
 
77
- # Returns a human-readable representation of the method.
78
- #
79
- # @example
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
- "Defi(" \
91
- "name: #{inspected_name}, " \
92
- "args: #{inspected_args}, " \
93
- "opts: #{inspected_opts}, " \
94
- "block: #{inspected_block})"
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 either the returned value
5
- # or an exception raised during the execution.
6
- #
7
- # This class is used to handle the outcome of a method invocation, allowing
8
- # to distinguish between successful results and exceptions.
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 the raised object.
14
+ # @return [#object_id] The returned value or caught exception
14
15
  attr_reader :object
15
16
 
16
- # Initializes a Value object with the result of the provided block.
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 Handling an exception
24
- # value = Defi::Value.new { raise 'Error' }
25
- # value.call # raises 'Error'
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] The result of the block or the exception raised.
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 object if no exception was raised, otherwise raises the exception.
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
- # value = Defi::Value.new { "Hello" }
42
- # value.call # => "Hello"
47
+ # @example With exception
48
+ # Value.new { raise "error" }.call # raises RuntimeError: error
43
49
  #
44
- # @return [#object_id] The returned object or raises the captured exception.
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
- # Checks if an exception was raised during the execution.
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
- # Returns a hash containing the properties of the Value object.
63
- #
64
- # @return [Hash] The properties of the Value object.
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
- # Returns a string representation of the Value object.
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
- # Returns a string indicating whether the object was raised or returned.
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
- # This file serves as the entry point for the Defi library, establishing the
6
- # Defi namespace and requiring necessary components. It is typically required
7
- # at the beginning of using the Defi library in an application.
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 Requiring the Defi library in a Ruby application
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.inspect # => "Defi(name: :+, args: [2], opts: {}, block: nil)"
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
- # # Apply the addition to the number 1
18
- # result = addition.to(1)
19
- # result # => Value(object: 3, raised: false)
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
- # # Execute the addition and get the result
22
- # result.call # => 3
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
- # Require additional components of the Defi library.
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
- # Extension of the Kernel module to include the Defi method.
6
- # The Defi method is a convenient way to create Method objects
7
- # that encapsulate a method name and its arguments, offering a
8
- # dynamic approach to method invocation.
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 simple and elegant way to encapsulate
16
- # a method name and its arguments for later invocation.
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
- # @example Creating a Defi method without arguments
19
- # Defi(:foo).inspect # => "Defi(name: :foo, args: [], opts: {}, block: nil)"
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 Adding 2 to 1
22
- # # Create a Defi method object for addition with an argument of 2
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
- # # Apply the addition to the number 1
27
- # result = addition.to(1)
28
- # result # => Value(object: 3, raised: false)
24
+ # @example Method with positional arguments
25
+ # Defi(:+, 2)
26
+ # Defi(:[], 0, 2) # For array/string slicing
29
27
  #
30
- # # Execute the addition and get the result
31
- # result.call # => 3
28
+ # @example Method with keyword arguments
29
+ # Defi(:transform, x: 1, y: 2)
32
30
  #
33
- # @param method_name [Symbol] The method name to be sent to an object.
31
+ # @example Method with a block
32
+ # Defi(:map) { |x| x * 2 }
34
33
  #
35
- # @return [Defi::Method] An instance of Defi::Method encapsulating the method name and provided arguments.
36
- def Defi(method_name, ...)
37
- ::Defi::Method.new(method_name, ...)
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.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-01-25 00:00:00.000000000 Z
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.2.0
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.4.19
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: []