callable-mixin 0.1.1 → 0.2.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 +4 -4
- data/README.md +56 -21
- data/lib/callable/mixin.rb +45 -19
- data/lib/callable/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c4ab883eaeb5a2633c55642e2ad8aef2c97fc836d8eeb9a037e55d7e93bca84
|
|
4
|
+
data.tar.gz: b5b8203b5653d12f6d40730a734dd29febf78fd8e6db065cc651dced0b6ec248
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2726c5f636c2ab6502db98a40afce7d237ae811d7a1b3c177c745b3926441ba2dd918b7a9dcb56800271e91b2ea624ade06de9e4da5233a07cdab20092eed547
|
|
7
|
+
data.tar.gz: c46915a2fb9687b707aaea865bd4c002ae197a0ed2f84355a9a924bf380240d8b8a26170c5175d8a338337e25cee66db60f7a87c1fefe1da3c1c1c90546b1a50
|
data/README.md
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
|
+
[](https://badge.fury.io/rb/callable-mixin)
|
|
2
|
+
[](https://github.com/dbongo/callable-mixin/actions)
|
|
3
|
+
|
|
1
4
|
# Callable
|
|
2
5
|
|
|
3
|
-
Callable is a minimal Ruby mix-in that provides your classes with a simple `.call` class method. It allows you to instantiate and immediately invoke an instance method (`call`) without boilerplate or additional dependencies. Perfect for clean, readable, and concise service objects.
|
|
6
|
+
Callable is a minimal Ruby mix-in that provides your classes with a simple `.call` class method (plus `to_proc`). It allows you to instantiate and immediately invoke an instance method (`call`) without boilerplate or additional dependencies. Perfect for clean, readable, and concise service objects.
|
|
7
|
+
|
|
8
|
+
Learn more at https://rubydoc.info/gems/callable-mixin
|
|
4
9
|
|
|
5
10
|
## Features
|
|
6
11
|
|
|
7
12
|
- Provides a `.call` class method to any Ruby class.
|
|
8
|
-
-
|
|
9
|
-
-
|
|
13
|
+
- Supports `Class#to_proc`, letting you use `&YourService` in `Enumerable` methods.
|
|
14
|
+
- Transparently forwards positional args, keyword args, and blocks to `#call`.
|
|
15
|
+
- Raises `ConstructionError` (subclass of `ArgumentError`) for constructor arity/kwarg mismatches.
|
|
16
|
+
- Raises `NotImplementedError` when the class does not define an instance `#call`.
|
|
10
17
|
- Zero external runtime dependencies.
|
|
11
18
|
- Compatible with MRI Ruby 2.3 through Ruby 3.x.
|
|
12
19
|
|
|
13
20
|
## Installation
|
|
14
21
|
|
|
15
|
-
Add this to your application's Gemfile:
|
|
22
|
+
Add this to your application's Gemfile (version 0.2.0 or later):
|
|
16
23
|
|
|
17
24
|
```ruby
|
|
18
|
-
gem 'callable-mixin'
|
|
25
|
+
gem 'callable-mixin', '~> 0.2.0'
|
|
19
26
|
```
|
|
20
27
|
|
|
21
28
|
Then execute:
|
|
@@ -32,9 +39,7 @@ gem install callable-mixin
|
|
|
32
39
|
|
|
33
40
|
## Usage
|
|
34
41
|
|
|
35
|
-
###
|
|
36
|
-
|
|
37
|
-
Simply include `Callable` in your class and implement an instance method named `call`:
|
|
42
|
+
### Example Service with Multiple Arguments
|
|
38
43
|
|
|
39
44
|
```ruby
|
|
40
45
|
class SendNotification
|
|
@@ -51,36 +56,66 @@ class SendNotification
|
|
|
51
56
|
end
|
|
52
57
|
```
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
- **Explicit invocation** when you need multiple constructor args:
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
```ruby
|
|
62
|
+
users.each do |user|
|
|
63
|
+
SendNotification.call(user, "Your message here")
|
|
64
|
+
end
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
# You can also call via the `.()` alias:
|
|
67
|
+
SendNotification.(user, "Your message here")
|
|
68
|
+
```
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
### Example Service with Single Argument (to_proc Shorthand)
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
class WelcomeUser
|
|
62
74
|
include Callable
|
|
63
75
|
|
|
64
|
-
def initialize(user
|
|
76
|
+
def initialize(user)
|
|
65
77
|
@user = user
|
|
66
|
-
@message = message
|
|
67
78
|
end
|
|
68
79
|
|
|
69
80
|
def call
|
|
70
|
-
NotificationMailer.
|
|
81
|
+
NotificationMailer.welcome(@user).deliver_now
|
|
71
82
|
end
|
|
72
83
|
end
|
|
73
84
|
```
|
|
74
85
|
|
|
75
|
-
|
|
86
|
+
- **Proc shorthand** for one-arg services:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
users.each(&WelcomeUser)
|
|
90
|
+
|
|
91
|
+
# Or invoke with the `.()` alias:
|
|
92
|
+
WelcomeUser.(current_user)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Using in a Plain Ruby Script
|
|
76
96
|
|
|
77
97
|
```ruby
|
|
78
|
-
|
|
98
|
+
require 'callable-mixin'
|
|
79
99
|
|
|
80
|
-
#
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
# Define your service with Callable
|
|
101
|
+
class MyService
|
|
102
|
+
include Callable
|
|
103
|
+
|
|
104
|
+
def initialize(value)
|
|
105
|
+
@value = value
|
|
106
|
+
end
|
|
83
107
|
|
|
108
|
+
def call
|
|
109
|
+
puts "Processing #{@value}"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Invoke the service
|
|
114
|
+
MyService.call("some data")
|
|
115
|
+
|
|
116
|
+
# Or use the `.()` alias:
|
|
117
|
+
MyService.("more data")
|
|
118
|
+
```
|
|
84
119
|
|
|
85
120
|
## Development
|
|
86
121
|
|
data/lib/callable/mixin.rb
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
##
|
|
4
|
+
# Callable
|
|
5
|
+
#
|
|
6
|
+
# A lightweight mix‑in that gives any class a convenient class‑level `.call` helper.
|
|
7
|
+
#
|
|
8
|
+
# class SendEmail
|
|
9
|
+
# include Callable
|
|
10
|
+
#
|
|
11
|
+
# def initialize(user)
|
|
12
|
+
# @user = user
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# def call
|
|
16
|
+
# Mailer.welcome(@user).deliver_now
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# SendEmail.call(User.first) # => delivers email
|
|
21
|
+
# users.each(&SendEmail) # => thanks to #to_proc
|
|
22
|
+
#
|
|
23
|
+
# Compatible with Ruby 2.3+ and works the same on 3.x.
|
|
3
24
|
module Callable
|
|
4
|
-
# Raised when
|
|
25
|
+
# Raised when `.call` cannot build the instance (arity/keyword mismatch).
|
|
5
26
|
class ConstructionError < ArgumentError; end
|
|
6
27
|
|
|
7
28
|
def self.included(base)
|
|
@@ -10,27 +31,32 @@ module Callable
|
|
|
10
31
|
|
|
11
32
|
module ClassMethods
|
|
12
33
|
##
|
|
13
|
-
# Instantiate and immediately invoke
|
|
14
|
-
#
|
|
15
|
-
# @param
|
|
16
|
-
# @
|
|
17
|
-
# @
|
|
18
|
-
# @
|
|
34
|
+
# Instantiate the class and immediately invoke its instance `#call`.
|
|
35
|
+
#
|
|
36
|
+
# @param args [Array] positional arguments for `initialize`.
|
|
37
|
+
# @param kwargs [Hash] keyword arguments for `initialize`.
|
|
38
|
+
# @yield [optional] block passed directly to the instance method `#call`; ignored if not yielded.
|
|
39
|
+
# @return anything returned by the instance `#call`.
|
|
40
|
+
# @raise [ConstructionError] if construction fails (plain `ArgumentError`).
|
|
41
|
+
# @raise [NotImplementedError] if the instance does not implement `#call`.
|
|
19
42
|
def call(*args, **kwargs, &block)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
# Ruby versions earlier than 2.7 can't reliably handle splatting empty kwargs, so branch for compatibility
|
|
44
|
+
inst = kwargs.empty? ? new(*args) : new(*args, **kwargs)
|
|
45
|
+
rescue ArgumentError => e
|
|
46
|
+
# Bubble up anything that isn't exactly ArgumentError (e.g., subclasses)
|
|
47
|
+
raise unless e.instance_of?(ArgumentError)
|
|
48
|
+
raise ConstructionError, "Cannot instantiate #{name}: #{e.message}", e.backtrace
|
|
49
|
+
else
|
|
50
|
+
# Ensure the instance defines `#call`
|
|
51
|
+
unless inst.respond_to?(:call)
|
|
52
|
+
raise NotImplementedError, "#{name} must implement #call"
|
|
27
53
|
end
|
|
54
|
+
inst.call(&block)
|
|
55
|
+
end
|
|
28
56
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
inst.call
|
|
33
|
-
end
|
|
57
|
+
# @return [Proc] a proc that delegates to `.call`, enabling `&MyService` shorthand.
|
|
58
|
+
def to_proc
|
|
59
|
+
method(:call).to_proc
|
|
34
60
|
end
|
|
35
61
|
end
|
|
36
62
|
end
|
data/lib/callable/version.rb
CHANGED