Skip to content

Commit 08246b6

Browse files
committed
Initial Commit
0 parents  commit 08246b6

22 files changed

+523
-0
lines changed

.github/workflows/main.yml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Ruby
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
pull_request:
9+
10+
jobs:
11+
build:
12+
runs-on: ubuntu-latest
13+
name: Ruby ${{ matrix.ruby }}
14+
strategy:
15+
matrix:
16+
ruby:
17+
- '3.2.1'
18+
19+
steps:
20+
- uses: actions/checkout@v3
21+
- name: Set up Ruby
22+
uses: ruby/setup-ruby@v1
23+
with:
24+
ruby-version: ${{ matrix.ruby }}
25+
bundler-cache: true
26+
- name: Run the default task
27+
run: bundle exec rake

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/.bundle/
2+
/.yardoc
3+
/_yardoc/
4+
/coverage/
5+
/doc/
6+
/pkg/
7+
/spec/reports/
8+
/tmp/

.standard.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# For available configuration options, see:
2+
# https://github.com/testdouble/standard
3+
ruby_version: 2.6

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## [Unreleased]
2+
3+
## [1.0.0]
4+
5+
- Initial release

Gemfile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
source "https://rubygems.org"
2+
3+
# Specify your gem's dependencies in lint_roller.gemspec
4+
gemspec
5+
6+
gem "rake"
7+
gem "minitest"
8+
gem "standard"
9+
gem "m"

Gemfile.lock

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
PATH
2+
remote: .
3+
specs:
4+
lint_roller (1.0.0)
5+
6+
GEM
7+
remote: https://rubygems.org/
8+
specs:
9+
ast (2.4.2)
10+
json (2.6.3)
11+
language_server-protocol (3.17.0.3)
12+
m (1.6.1)
13+
method_source (>= 0.6.7)
14+
rake (>= 0.9.2.2)
15+
method_source (1.0.0)
16+
minitest (5.18.0)
17+
parallel (1.22.1)
18+
parser (3.2.2.0)
19+
ast (~> 2.4.1)
20+
rainbow (3.1.1)
21+
rake (13.0.6)
22+
regexp_parser (2.7.0)
23+
rexml (3.2.5)
24+
rubocop (1.48.1)
25+
json (~> 2.3)
26+
parallel (~> 1.10)
27+
parser (>= 3.2.0.0)
28+
rainbow (>= 2.2.2, < 4.0)
29+
regexp_parser (>= 1.8, < 3.0)
30+
rexml (>= 3.2.5, < 4.0)
31+
rubocop-ast (>= 1.26.0, < 2.0)
32+
ruby-progressbar (~> 1.7)
33+
unicode-display_width (>= 2.4.0, < 3.0)
34+
rubocop-ast (1.28.0)
35+
parser (>= 3.2.1.0)
36+
rubocop-performance (1.16.0)
37+
rubocop (>= 1.7.0, < 2.0)
38+
rubocop-ast (>= 0.4.0)
39+
ruby-progressbar (1.13.0)
40+
standard (1.26.0)
41+
language_server-protocol (~> 3.17.0.2)
42+
rubocop (~> 1.48.1)
43+
rubocop-performance (~> 1.16.0)
44+
unicode-display_width (2.4.2)
45+
46+
PLATFORMS
47+
arm64-darwin-22
48+
49+
DEPENDENCIES
50+
lint_roller!
51+
m
52+
minitest
53+
rake
54+
standard
55+
56+
BUNDLED WITH
57+
2.4.10

LICENSE.txt

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2023 Test Double, Inc.
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

+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# lint_roller - A plugin specification for linters
2+
3+
`lint_roller` is an itty-bitty plugin API for code analysis tools like linters
4+
and formatters. It provides plugins for those tools to load extensions and
5+
specify custom rulesets.
6+
7+
(As of this release, only [Standard
8+
Ruby](https://github.com/standardrb/standard) supports `lint_roller` plugins,
9+
but we think [RuboCop](https://github.com/rubocop/rubocop) could add support and
10+
most plugins would be compatible with both `rubocop` and `standardrb`.
11+
Additionally, there's nothing that would prevent other tools like
12+
[rufo](https://github.com/ruby-formatter/rufo) from adopting it.)
13+
14+
## How to make a plugin
15+
16+
If you want to make a plugin, the first thing you should do is extend
17+
[LintRoller::Plugin](/lib/lint_roller/plugin.rb) with a custom class. Let's take
18+
this example plugin for banana-related static analysis:
19+
20+
```ruby
21+
module BananaRoller
22+
class Plugin
23+
# `config' is a Hash of options passed to the plugin by the user
24+
def initialize(config = {})
25+
@alternative = config["alternative"] ||= "chocolate"
26+
end
27+
28+
def about
29+
LintRoller::About.new(
30+
name: "banana_roller",
31+
version: "1.0", # or, in a gem, probably BananaRoller::VERSION
32+
homepage: "https://github.com/example/banana_roller",
33+
description: "Configuration of banana-related code"
34+
)
35+
end
36+
37+
# `context' is an instance of LintRoller::Context provided by the runner
38+
def supported?(context)
39+
if context.engine == :rubocop
40+
true
41+
else
42+
false
43+
end
44+
end
45+
46+
# `context' is an instance of LintRoller::Context provided by the runner
47+
def rules(context)
48+
LintRoller::Rules.new(
49+
type: :path,
50+
config_format: :rubocop,
51+
value: Pathname.new(__dir__).join("../../config/default.yml")
52+
)
53+
end
54+
end
55+
end
56+
```
57+
58+
And that's pretty much it. Just a declarative way to identify your plugin,
59+
detect whether it supports the given context (e.g. the current `runner` and
60+
`engine` and their respective `_version`s), and then provides your custom
61+
configuration as a [LintRoller::Rules](lib/lint_roller/rules.rb) object.
62+
63+
## Packaging a plugin in a gem
64+
65+
In order for a formatter to use your plugin, it needs to know where to what path
66+
to require and the name of your plugin class to instantiate and invoke.
67+
68+
To make this work seamlessly for your users without additional configuration of
69+
their own, all you need to do is specify a metadata attribute called
70+
`default_lint_roller_plugin` in your gemspec.
71+
72+
Taking [standard-custom](https://github.com/standardrb/standard-custom) as an
73+
example, its gemspec contains:
74+
75+
```ruby
76+
Gem::Specification.new do |spec|
77+
#
78+
spec.metadata["default_lint_roller_plugin"] = "Standard::Custom::Plugin"
79+
#
80+
end
81+
```
82+
83+
Because gem specs are loaded by RubyGems and Bundler very early, remember to
84+
specify the plugin as a string representation of the constant, as load order
85+
usually matters, and most tools will need to be loaded before any custom
86+
extensions. Hence, `"Standard::Custom::Plugin"` instead of
87+
`Standard::Custom::Plugin`.
88+
89+
## Using your plugin
90+
91+
Once you've made your plugin, here's how it's configured from a Standard Ruby
92+
`.standard.yml` file.
93+
94+
### If your plugin is packaged as a gem
95+
96+
Packaging your plugin in a gem is the golden path, both because distributing
97+
code via [RubyGems.org](https://rubygems.org) is very neat, but also because it
98+
makes the least work for your users.
99+
100+
If your gem name is `banana_roller` and you've set
101+
`spec.metadata["default_lint_roller_plugin"]` to `"BananaRoller::Plugin"`, then
102+
your users could just add this to their `.standard.yml` file:
103+
104+
```yaml
105+
plugins:
106+
- banana_roller
107+
```
108+
109+
And that's it! During initialization, `standardrb` will `require
110+
"banana_roller"` and know to call `BananaRoller::Plugin.new(config)` to
111+
instantiate it.
112+
113+
### If your plugin ISN'T in a gem
114+
115+
If you're developing a plugin for internal use or in conjunction with a single
116+
project, you may want it to live in the same repo as opposed to packaging it in
117+
a gem.
118+
119+
To do this, then—in lieu of a gem name—provide the path you want to be required
120+
as its name, and (since there is no `spec.metadata` to learn of your plugin's
121+
class name), specify it as an option on the plugin:
122+
123+
```yaml
124+
plugins:
125+
- lib/banana_roller/plugin:
126+
plugin_class_name: BananaRoller::Plugin
127+
```
128+
129+
(Be careful with the indentation here! Any configuration under a plugin must be
130+
indented in order for it to be parsed as a hash under the
131+
`"lib/banana_roller/plugin"` key.)
132+
133+
Additionally, if you want the plugin's name to make more sense, you can give
134+
it whatever name you like in the configuration and specify the `require_path`
135+
explicitly:
136+
137+
```yaml
138+
plugins:
139+
- banana_roller:
140+
require_path: lib/banana_roller/plugin
141+
plugin_class_name: BananaRoller::Plugin
142+
```
143+
144+
### Passing user configuration to the plugin
145+
146+
When a `LintRoller::Plugin` is instantiated, users can pass a configuration hash
147+
that tells your plugin how to behave.
148+
149+
To illustrate how this works in Standard Ruby, anything passed as a hash beneath
150+
a plugin will be passed to the class's `initialize` method:
151+
152+
```yaml
153+
plugins:
154+
- apple_roller
155+
- banana_roller:
156+
require_path: lib/banana_roller/plugin
157+
plugin_class_name: BananaRoller::Plugin
158+
alternative: "apples"
159+
- orange_roller:
160+
rind: false
161+
```
162+
163+
In the above case, `apple_roller`'s plugin class will be instantiated with
164+
`new({})`, `banana_roller` will get all 3 of those parameters passed
165+
`BananaRoller::Plugin.new({require_path…})`, and `orange_roller`'s class will be
166+
called with `new({rind: false})`.
167+
168+
## Code of Conduct
169+
170+
This project follows Test Double's [code of
171+
conduct](https://testdouble.com/code-of-conduct) for all community interactions,
172+
including (but not limited to) one-on-one communications, public posts/comments,
173+
code reviews, pull requests, and GitHub issues. If violations occur, Test Double
174+
will take any action they deem appropriate for the infraction, up to and
175+
including blocking a user from the organization's repositories.
176+

Rakefile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
require "bundler/gem_tasks"
2+
require "rake/testtask"
3+
4+
Rake::TestTask.new(:test) do |t|
5+
t.libs << "test"
6+
t.libs << "lib"
7+
t.test_files = FileList["test/**/*_test.rb"]
8+
end
9+
10+
require "standard/rake"
11+
12+
task default: %i[test standard:fix]

bin/console

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env ruby
2+
3+
require "bundler/setup"
4+
require "lint_roller"
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+
require "irb"
10+
IRB.start(__FILE__)

bin/setup

+8
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

lib/lint_roller.rb

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require_relative "lint_roller/version"
2+
3+
require_relative "lint_roller/about"
4+
require_relative "lint_roller/context"
5+
require_relative "lint_roller/rules"
6+
7+
require_relative "lint_roller/plugin"
8+
require_relative "lint_roller/error"
9+
10+
module LintRoller
11+
end

lib/lint_roller/about.rb

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module LintRoller
2+
About = Struct.new(
3+
:name, # "standard-performance"
4+
:version, # "1.2.3"
5+
:homepage, # "https://github.com/testdouble/standard-performance"
6+
:description, # "A configuration of rubocop-performance rules to make Ruby go faster"
7+
keyword_init: true
8+
)
9+
end

lib/lint_roller/context.rb

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module LintRoller
2+
Context = Struct.new(
3+
:runner, # :standard, :rubocop
4+
:runner_version, # "1.2.3"
5+
:engine, # :rubocop
6+
:engine_version, # "2.3.4",
7+
:rule_format, # :rubocop
8+
:target_ruby_version, # Gem::Version.new("2.7.0")
9+
keyword_init: true
10+
)
11+
end

lib/lint_roller/error.rb

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module LintRoller
2+
class Error < StandardError
3+
end
4+
end

0 commit comments

Comments
 (0)