Skip to content

Commit 48a4b48

Browse files
committed
Initial scaffold: gemspec, lib, tests, CI matrix, scripts, and docs
0 parents  commit 48a4b48

File tree

15 files changed

+608
-0
lines changed

15 files changed

+608
-0
lines changed

.github/workflows/ci.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
jobs:
8+
test:
9+
runs-on: ubuntu-22.04
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
include:
14+
# ---- Ruby ≤ 2.2 need Bundler 1.17.x ------------------------
15+
- ruby: "2.0.0-p648"
16+
bundler: "1.17.3"
17+
- ruby: "2.1.10"
18+
bundler: "1.17.3"
19+
- ruby: "2.2.10"
20+
bundler: "1.17.3"
21+
# ---- Normal modern combo -----------------------------------
22+
- ruby: "2.3.8"
23+
- ruby: "2.4.10"
24+
- ruby: "2.5.9"
25+
- ruby: "2.6.7"
26+
- ruby: "2.7.8"
27+
- ruby: "3.0.6"
28+
- ruby: "3.1.4"
29+
- ruby: "3.2.3"
30+
- ruby: "3.3.0"
31+
steps:
32+
- uses: actions/checkout@v4
33+
34+
- name: Set up Ruby
35+
uses: ruby/setup-ruby@v1
36+
with:
37+
ruby-version: ${{ matrix.ruby }}
38+
bundler: ${{ matrix.bundler || 'latest' }}
39+
bundler-cache: true # caches Gem/ bundler dir
40+
41+
# For 2.0–2.2, force-install bundler 1.17 (setup-ruby can’t)
42+
- name: Install Bundler 1.x on very old Rubies
43+
if: matrix.bundler
44+
run: gem install bundler -v "$BUNDLER_VERSION"
45+
env:
46+
BUNDLER_VERSION: ${{ matrix.bundler }}
47+
48+
- name: Install dependencies
49+
run: bundle install --jobs 3 --retry 3
50+
51+
- name: Run specs
52+
run: bundle exec rspec

.gitignore

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# macOS
2+
.DS_Store
3+
4+
# editor
5+
*.swp
6+
.idea/
7+
.vscode/
8+
9+
# ruby
10+
.ruby-version
11+
.rvmrc
12+
/.bundle/
13+
/vendor/bundle/
14+
/Gemfile.lock
15+
16+
# gems and packages
17+
*.gem
18+
/pkg/
19+
20+
# docs and coverage
21+
/doc/
22+
/rdoc/
23+
/_yardoc/
24+
/.yardoc
25+
/coverage/
26+
/spec/reports/
27+
28+
# logs and temp
29+
/log/
30+
/tmp/
31+
32+
# test
33+
.rspec_status
34+
35+
# misc
36+
tags
37+
.loadpath
38+
.project

.rspec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
--format documentation
2+
--color
3+
--require spec_helper

Gemfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
source "https://rubygems.org"
2+
3+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4+
5+
# Specify your gem's dependencies in callable.gemspec
6+
gemspec

LICENSE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2025 Michael Crowther
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Callable
2+
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.
4+
5+
## Features
6+
7+
- Provides a `.call` class method to any Ruby class.
8+
- Transparently forwards positional arguments, keyword arguments, and blocks.
9+
- Handles argument errors gracefully, raising clear exceptions.
10+
- Zero external runtime dependencies.
11+
- Compatible with MRI Ruby 2.0 through Ruby 3.x.
12+
13+
## Installation
14+
15+
Add this to your application's Gemfile:
16+
17+
```ruby
18+
gem 'callable'
19+
```
20+
21+
Then execute:
22+
23+
```bash
24+
bundle install
25+
```
26+
27+
Or install directly:
28+
29+
```bash
30+
gem install callable
31+
```
32+
33+
## Usage
34+
35+
Simply include Callable in your class and implement an instance method named `call`:
36+
37+
```ruby
38+
class SendNotification
39+
include Callable
40+
41+
def initialize(user, message)
42+
@user = user
43+
@message = message
44+
end
45+
46+
def call
47+
NotificationMailer.notify(@user, @message).deliver_now
48+
end
49+
end
50+
51+
SendNotification.call(current_user, "Hello from Callable!")
52+
```
53+
54+
Then run your class using the `.call` class method:
55+
56+
```ruby
57+
SendNotification.call(current_user, "Hello from Callable!")
58+
59+
# or use .() (syntactic sugar for .call)
60+
SendNotification.(current_user, "Hello from Callable!")
61+
```
62+
63+
64+
## Development
65+
66+
After cloning the repo, install dependencies with `bundle install`, then run tests with `bundle exec rspec`.
67+
68+
## Contributing
69+
70+
Bug reports and pull requests are welcome on GitHub at https://github.com/dbongo/callable.
71+
72+
## License
73+
74+
The gem is available under the MIT License.

Rakefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
require "bundler/gem_tasks"
2+
require "rspec/core/rake_task"
3+
4+
desc "Run specs"
5+
RSpec::Core::RakeTask.new(:spec)
6+
7+
# Run the suite under every ruby installed via rbenv/rvm
8+
namespace :multi do
9+
task :spec do
10+
rubies = %w[
11+
2.0.0-p648 2.1.10 2.2.10 2.3.8 2.4.10 2.5.9
12+
2.6.7 2.7.8 3.0.6 3.1.4 3.2.3 3.3.0
13+
]
14+
rubies.each do |v|
15+
puts "\n=== Ruby #{v} ==="
16+
cmd = "RBENV_VERSION=#{v} bundle _#{v < '2.3' ? '1.17.3' : '2'}_ exec rspec"
17+
system(cmd) || abort("Failed on #{v}")
18+
end
19+
end
20+
end

bin/console

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env ruby
2+
3+
require "bundler/setup"
4+
require "callable"
5+
6+
# You can add fixtures and/or initialization code here to make experimenting
7+
# with your gem easier. You can also use a different console, if you like.
8+
9+
# (If you use this, don't forget to add pry to your Gemfile!)
10+
# require "pry"
11+
# Pry.start
12+
13+
require "irb"
14+
IRB.start(__FILE__)

bin/setup

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
IFS=$'\n\t'
4+
set -vx
5+
6+
bundle install
7+
8+
# Do any other automated setup that you need to do here

callable.gemspec

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "lib/callable/version"
4+
5+
Gem::Specification.new do |spec|
6+
spec.name = "callable"
7+
spec.version = Callable::VERSION
8+
spec.authors = ["Michael Crowther"]
9+
spec.email = ["[email protected]"]
10+
11+
spec.summary = "Lightweight .call mix-in for service objects"
12+
spec.description = "Callable provides Ruby classes with a convenient `.call` method, "\
13+
"simplifying instantiation and method invocation."
14+
spec.homepage = "https://github.com/dbongo/callable"
15+
spec.license = "MIT"
16+
spec.required_ruby_version = ">= 2.0.0"
17+
18+
spec.metadata = {
19+
"homepage_uri" => spec.homepage,
20+
"source_code_uri" => spec.homepage,
21+
"changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md"
22+
}
23+
24+
spec.files = Dir["lib/**/*.rb", "LICENSE", "README.md"]
25+
spec.require_paths = ["lib"]
26+
27+
spec.add_development_dependency "bundler", ">= 1.17"
28+
spec.add_development_dependency "rake", "~> 13.0"
29+
spec.add_development_dependency "rspec", "~> 3.0"
30+
end

0 commit comments

Comments
 (0)