tins 1.56.0 → 1.57.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: fd2090b923a690d351489aa80cb8792b6b06de766300a287c7ae9f82eb53321a
4
- data.tar.gz: b61fd2f899759c53373f9809f59ad74b11a2241adb70fa00cb73c024bf517c6a
3
+ metadata.gz: 495d7cdbe014ddf4d784dc67f16d6956a7abc7cacd61519cb9f2e82c1150a6bf
4
+ data.tar.gz: 486eed8c0a2c3cad0927ea935a290dfcf478e820478fc4f49060f8f1c8d170c4
5
5
  SHA512:
6
- metadata.gz: 74d027369ff665630a795b0a97590c0047d53d09f9dfc2d07064ae837950ef0f48bf1155d249e300f04ee8672f1c0301ad821f837f559e5a4e20c4b732bea5be
7
- data.tar.gz: dbd9d024a5f71f4d116ae320010616072d72bb5082ed6e7eef1c24320e0bf2011056d58c24d67d8de7112afe23b3ebd6954b52376dc95eab184493d912d87f87
6
+ metadata.gz: a6f0055b6921c6ea2adfe4b99e46f54fc846c1e571f0e94c8bd0af42dbb877b3a5eab1d88f8320c3f78e2766b0344e8c5d2e598b518bb5dcf320dfc0936ff11a
7
+ data.tar.gz: 27e271bdf9858d5924fb56fafef2ae52867cba5e5b9c83c34892a236afac8b0833da040696888e9d029052d406332cc45f5a4123d72fc417ac70132d3b5cdcf5
data/CHANGES.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-09-15 v1.57.0
4
+
5
+ * Add keyword and block forwarding to `Expose#expose`
6
+ * Add `**kwargs` and `&block` forwarding to `__send__` in
7
+ `lib/tins/expose.rb`
8
+ * Restructure guards so `method_name.nil?` is checked first, preventing
9
+ kwargs from shadowing the method name
10
+ * Update YARD docs to reflect new dispatch order and remove stale `@raise
11
+ [ArgumentError]`
12
+ * Add `with_kw` and `with_block` fixture methods and three new tests in
13
+ `tests/expose_test.rb` covering kwargs, block, and combined forwarding
14
+ * Add keyword argument support to `Full#full?`
15
+ * Add `**kwargs` to `full?` method signature in `lib/tins/xt/full.rb` and
16
+ forward via `__send__`
17
+ * Update YARD documentation with `@param kwargs`
18
+ * Add `test_full_with_kwargs` in `tests/blank_full_test.rb` verifying
19
+ `**kwargs` forwarding and blank result handling
20
+ * Add keyword argument support to `AskAndSend`
21
+ * Add `**kwargs` to all four methods in `lib/tins/ask_and_send.rb`
22
+ (`ask_and_send`, `ask_and_send!`, `ask_and_send_or_self`,
23
+ `ask_and_send_or_self!`) and forward them via `__send__`
24
+ * Update YARD documentation with `@param kwargs` for each method
25
+ * Add test fixtures `foo_kw`, `foo_args`, `bar_kw`, `bar_args` in
26
+ `tests/ask_and_send_test.rb`
27
+ * Add 8 new test cases covering `**kwargs`, `*args`, and `&block`
28
+ forwarding across all four `AskAndSend` variants
29
+
3
30
  ## 2026-07-25 v1.56.0
4
31
 
5
32
  ### Changes
@@ -7,12 +7,13 @@ module Tins
7
7
  #
8
8
  # @param method_name [ Symbol ] the name of the method to invoke
9
9
  # @param args [ Array ] arguments to pass to the method
10
+ # @param kwargs [ Hash ] keyword arguments to pass to the method
10
11
  # @yield [ block ] optional block to pass to the method
11
12
  # @return [ Object, nil ] the result of the method call or nil if the
12
13
  # method doesn't exist
13
- def ask_and_send(method_name, *args, &block)
14
+ def ask_and_send(method_name, *args, **kwargs, &block)
14
15
  if respond_to?(method_name)
15
- __send__(method_name, *args, &block)
16
+ __send__(method_name, *args, **kwargs, &block)
16
17
  end
17
18
  end
18
19
 
@@ -21,13 +22,14 @@ module Tins
21
22
  #
22
23
  # @param method_name [ Symbol ] the name of the method to call
23
24
  # @param args [ Array ] arguments to pass to the method
25
+ # @param kwargs [ Hash ] keyword arguments to pass to the method
24
26
  # @param block [ Proc ] optional block to pass to the method
25
27
  #
26
28
  # @return [ Object, nil ] the result of the method call or nil if the
27
29
  # method doesn't exist
28
- def ask_and_send!(method_name, *args, &block)
30
+ def ask_and_send!(method_name, *args, **kwargs, &block)
29
31
  if respond_to?(method_name, true)
30
- __send__(method_name, *args, &block)
32
+ __send__(method_name, *args, **kwargs, &block)
31
33
  end
32
34
  end
33
35
 
@@ -38,13 +40,14 @@ module Tins
38
40
  #
39
41
  # @param method_name [ Symbol ] the name of the method to call
40
42
  # @param args [ Array ] the arguments to pass to the method
43
+ # @param kwargs [ Hash ] the keyword arguments to pass to the method
41
44
  # @param block [ Proc ] the block to pass to the method
42
45
  #
43
46
  # @return [ Object ] the result of the method call or self if the method
44
47
  # doesn't exist
45
- def ask_and_send_or_self(method_name, *args, &block)
48
+ def ask_and_send_or_self(method_name, *args, **kwargs, &block)
46
49
  if respond_to?(method_name)
47
- __send__(method_name, *args, &block)
50
+ __send__(method_name, *args, **kwargs, &block)
48
51
  else
49
52
  self
50
53
  end
@@ -57,13 +60,14 @@ module Tins
57
60
  #
58
61
  # @param method_name [ Symbol ] the name of the method to send
59
62
  # @param args [ Array ] the arguments to pass to the method
63
+ # @param kwargs [ Hash ] the keyword arguments to pass to the method
60
64
  # @param block [ Proc ] the block to pass to the method
61
65
  #
62
66
  # @return [ Object ] the result of the method call or the object itself if
63
67
  # the method is not found
64
- def ask_and_send_or_self!(method_name, *args, &block)
68
+ def ask_and_send_or_self!(method_name, *args, **kwargs, &block)
65
69
  if respond_to?(method_name, true)
66
- __send__(method_name, *args, &block)
70
+ __send__(method_name, *args, **kwargs, &block)
67
71
  else
68
72
  self
69
73
  end
data/lib/tins/expose.rb CHANGED
@@ -40,36 +40,42 @@ module Tins
40
40
  # This method provides three distinct usage patterns:
41
41
  #
42
42
  # 1. **Method Call**: When given a method name, directly calls that method
43
- # and returns its result.
43
+ # and returns its result. Positional arguments, keyword arguments, and
44
+ # a block can be forwarded to the called method.
44
45
  #
45
- # 2. **Block Execution**: When given a block, evaluates the block in the
46
- # context of the object, allowing access to private/protected methods.
46
+ # 2. **Block Execution**: When called without a method name but with a
47
+ # block, evaluates the block in the context of the object, allowing
48
+ # access to private/protected methods.
47
49
  #
48
- # 3. **Full Exposure**: When called without arguments, returns a duplicate
49
- # of the object with all private and protected methods exposed as public.
50
+ # 3. **Full Exposure**: When called without a method name and without a
51
+ # block, returns a duplicate of the object with all private and
52
+ # protected methods exposed as public.
50
53
  #
51
54
  # @param method_name [Symbol, String, nil] name of the method to call,
52
55
  # or nil for full exposure
53
56
  # @param args [Array] arguments to pass to the method when calling it
54
- # @param block [Proc] block to execute in the context of the object
57
+ # @param kwargs [Hash] keyword arguments to pass to the method when calling it
58
+ # @param block [Proc] block to execute in the context of the object or
59
+ # to forward to the called method
55
60
  #
56
61
  # @return [Object] result of the method call, block execution, or a new
57
62
  # object with exposed methods (when called without args)
58
63
  #
59
64
  # @raise [NoMethodError] if method_name is given but doesn't exist
60
- # @raise [ArgumentError] if both method_name and block are provided
61
- def expose(method_name = nil, *args, &block)
62
- if block
63
- instance_eval(&block)
64
- elsif method_name.nil?
65
- methods = private_methods(true) + protected_methods(true)
66
- o = dup
67
- o.singleton_class.class_eval do
68
- public(*methods)
65
+ def expose(method_name = nil, *args, **kwargs, &block)
66
+ if method_name.nil?
67
+ if block
68
+ instance_eval(&block)
69
+ else
70
+ methods = private_methods(true) + protected_methods(true)
71
+ o = dup
72
+ o.singleton_class.class_eval do
73
+ public(*methods)
74
+ end
75
+ o
69
76
  end
70
- o
71
77
  elsif method_name
72
- __send__(method_name, *args)
78
+ __send__(method_name, *args, **kwargs, &block)
73
79
  end
74
80
  end
75
81
  end
data/lib/tins/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Tins
2
2
  # Tins version
3
- VERSION = '1.56.0'
3
+ VERSION = '1.57.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/tins/xt/full.rb CHANGED
@@ -26,6 +26,7 @@ module Tins
26
26
  #
27
27
  # @param dispatch [Symbol, nil] The method to call on the object (optional)
28
28
  # @param args [Array] Arguments to pass to the dispatched method (optional)
29
+ # @param kwargs [Hash] Keyword arguments to pass to the dispatched method (optional)
29
30
  # @yield [Object] Optional block to execute with the result if result or
30
31
  # dispatched result not nil
31
32
  # @return [Object, nil] The object itself if not blank, or the result of
@@ -43,11 +44,11 @@ module Tins
43
44
  #
44
45
  # @example With block execution
45
46
  # user.full?(:name) { |name| "Hello #{name}" }
46
- def full?(dispatch = nil, *args)
47
+ def full?(dispatch = nil, *args, **kwargs)
47
48
  if blank?
48
49
  obj = nil
49
50
  elsif dispatch
50
- obj = __send__(dispatch, *args)
51
+ obj = __send__(dispatch, *args, **kwargs)
51
52
  obj = nil if obj.blank?
52
53
  else
53
54
  obj = self
@@ -10,11 +10,27 @@ module Tins
10
10
  :foo
11
11
  end
12
12
 
13
+ def foo_kw(x:)
14
+ [:foo_kw, x]
15
+ end
16
+
17
+ def foo_args(*args, &block)
18
+ [:foo_args, args, block&.call]
19
+ end
20
+
13
21
  private
14
22
 
15
23
  def bar
16
24
  :bar
17
25
  end
26
+
27
+ def bar_kw(x:)
28
+ [:bar_kw, x]
29
+ end
30
+
31
+ def bar_args(*args, &block)
32
+ [:bar_args, args, block&.call]
33
+ end
18
34
  end
19
35
 
20
36
  def test_asking_publicly
@@ -42,5 +58,51 @@ module Tins
42
58
  assert_equal :bar, a.ask_and_send_or_self!(:bar)
43
59
  assert_equal a, a.ask_and_send_or_self(:baz)
44
60
  end
61
+
62
+ def test_asking_publicly_with_kwargs
63
+ assert_equal [:foo_kw, 42], A.new.ask_and_send(:foo_kw, x: 42)
64
+ assert_nil A.new.ask_and_send(:bar_kw, x: 42)
65
+ end
66
+
67
+ def test_asking_privately_with_kwargs
68
+ assert_equal [:foo_kw, 42], A.new.ask_and_send!(:foo_kw, x: 42)
69
+ assert_equal [:bar_kw, 42], A.new.ask_and_send!(:bar_kw, x: 42)
70
+ end
71
+
72
+ def test_asking_selfy_publicly_with_kwargs
73
+ a = A.new
74
+ assert_equal [:foo_kw, 7], a.ask_and_send_or_self(:foo_kw, x: 7)
75
+ assert_equal a, a.ask_and_send_or_self(:bar_kw, x: 7)
76
+ end
77
+
78
+ def test_asking_selfy_privately_with_kwargs
79
+ a = A.new
80
+ assert_equal [:foo_kw, 7], a.ask_and_send_or_self!(:foo_kw, x: 7)
81
+ assert_equal [:bar_kw, 7], a.ask_and_send_or_self!(:bar_kw, x: 7)
82
+ end
83
+
84
+ def test_asking_publicly_with_args_and_block
85
+ a = A.new
86
+ assert_equal [:foo_args, [1, 2], :hello], a.ask_and_send(:foo_args, 1, 2) { :hello }
87
+ assert_nil a.ask_and_send(:bar_args, 1, 2) { :hello }
88
+ end
89
+
90
+ def test_asking_privately_with_args_and_block
91
+ a = A.new
92
+ assert_equal [:foo_args, [1, 2], :hello], a.ask_and_send!(:foo_args, 1, 2) { :hello }
93
+ assert_equal [:bar_args, [3, 4], :world], a.ask_and_send!(:bar_args, 3, 4) { :world }
94
+ end
95
+
96
+ def test_asking_selfy_publicly_with_args_and_block
97
+ a = A.new
98
+ assert_equal [:foo_args, [1], :ok], a.ask_and_send_or_self(:foo_args, 1) { :ok }
99
+ assert_equal a, a.ask_and_send_or_self(:bar_args, 1) { :ok }
100
+ end
101
+
102
+ def test_asking_selfy_privately_with_args_and_block
103
+ a = A.new
104
+ assert_equal [:foo_args, [1], :ok], a.ask_and_send_or_self!(:foo_args, 1) { :ok }
105
+ assert_equal [:bar_args, [2], :ok], a.ask_and_send_or_self!(:bar_args, 2) { :ok }
106
+ end
45
107
  end
46
108
  end
@@ -58,6 +58,15 @@ module Tins
58
58
  assert_equal 3, "foo".full?(:size)
59
59
  end
60
60
 
61
+ def test_full_with_kwargs
62
+ obj = Object.new
63
+ def obj.greet(name:)
64
+ "hello #{name}"
65
+ end
66
+ assert_equal 'hello world', obj.full?(:greet, name: 'world')
67
+ assert_nil ''.full?(:greet, name: 'world')
68
+ end
69
+
61
70
  def test_all_full
62
71
  assert_equal [1, 2], [1, 2].all_full?
63
72
  assert_nil [nil, 2].all_full?
data/tests/expose_test.rb CHANGED
@@ -13,6 +13,16 @@ module Tins
13
13
  :prot
14
14
  end
15
15
  protected :prot
16
+
17
+ def with_kw(x:)
18
+ [:with_kw, x]
19
+ end
20
+ private :with_kw
21
+
22
+ def with_block
23
+ yield :from_block
24
+ end
25
+ private :with_block
16
26
  end
17
27
 
18
28
  def setup
@@ -39,5 +49,17 @@ module Tins
39
49
  assert_equal :priv, @a.expose(:priv)
40
50
  assert_equal :prot, @a.expose(:prot, :any)
41
51
  end
52
+
53
+ def test_exposes_method_with_kwargs
54
+ assert_equal [:with_kw, 42], @a.expose(:with_kw, x: 42)
55
+ end
56
+
57
+ def test_exposes_method_with_block
58
+ assert_equal :from_block, @a.expose(:with_block) { |v| v }
59
+ end
60
+
61
+ def test_exposes_method_with_kwargs_and_block
62
+ assert_equal [:with_kw, 7], @a.expose(:with_kw, x: 7) { :ignored }
63
+ end
42
64
  end
43
65
  end
data/tins.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: tins 1.56.0 ruby lib
2
+ # stub: tins 1.57.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "tins".freeze
6
- s.version = "1.56.0".freeze
6
+ s.version = "1.57.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
 
24
24
  s.specification_version = 4
25
25
 
26
- s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.17.1".freeze])
26
+ s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.18.0".freeze])
27
27
  s.add_development_dependency(%q<all_images>.freeze, [">= 0".freeze])
28
28
  s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
29
29
  s.add_development_dependency(%q<simplecov>.freeze, [">= 0".freeze])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tins
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.56.0
4
+ version: 1.57.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 2.17.1
18
+ version: 2.18.0
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 2.17.1
25
+ version: 2.18.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: all_images
28
28
  requirement: !ruby/object:Gem::Requirement