rigortype 0.1.8 → 0.1.9
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 +186 -513
- data/lib/rigor/analysis/check_rules.rb +20 -0
- data/lib/rigor/cli/annotate_command.rb +224 -0
- data/lib/rigor/cli/baseline_command.rb +36 -16
- data/lib/rigor/cli/prism_colorizer.rb +111 -0
- data/lib/rigor/cli.rb +62 -4
- data/lib/rigor/environment.rb +9 -1
- data/lib/rigor/inference/builtins/method_catalog.rb +17 -1
- data/lib/rigor/inference/builtins/time_catalog.rb +10 -1
- data/lib/rigor/inference/expression_typer.rb +165 -6
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +109 -0
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +173 -10
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +53 -1
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +149 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +20 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +81 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +81 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +316 -2
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +126 -0
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +67 -0
- data/lib/rigor/inference/method_dispatcher.rb +148 -1
- data/lib/rigor/inference/method_parameter_binder.rb +67 -10
- data/lib/rigor/inference/narrowing.rb +29 -10
- data/lib/rigor/inference/statement_evaluator.rb +3 -1
- data/lib/rigor/plugin/base.rb +39 -0
- data/lib/rigor/plugin/loader.rb +22 -1
- data/lib/rigor/plugin/manifest.rb +73 -10
- data/lib/rigor/plugin/protocol_contract.rb +185 -0
- data/lib/rigor/plugin/registry.rb +66 -0
- data/lib/rigor/triage/catalogue.rb +2 -2
- data/lib/rigor/type/constant.rb +29 -2
- data/lib/rigor/version.rb +1 -1
- metadata +11 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Plugin
|
|
5
|
+
# ADR-28 declaration: "every instance/singleton method named
|
|
6
|
+
# `method_name`, defined in a source file matching `path_glob`,
|
|
7
|
+
# is implicitly required to satisfy the declared parameter +
|
|
8
|
+
# return-type protocol."
|
|
9
|
+
#
|
|
10
|
+
# Authored on a plugin manifest:
|
|
11
|
+
#
|
|
12
|
+
# manifest(
|
|
13
|
+
# id: "web",
|
|
14
|
+
# version: "0.1.0",
|
|
15
|
+
# protocol_contracts: [
|
|
16
|
+
# Rigor::Plugin::ProtocolContract.new(
|
|
17
|
+
# path_glob: "lib/controller/**/*.rb",
|
|
18
|
+
# method_name: :get,
|
|
19
|
+
# param_types: [{ index: 0, type_name: "Rack::Request" }],
|
|
20
|
+
# return_type_name: "Rack::Response"
|
|
21
|
+
# )
|
|
22
|
+
# ]
|
|
23
|
+
# )
|
|
24
|
+
#
|
|
25
|
+
# The contract drives two distinct engine behaviours (ADR-28
|
|
26
|
+
# § "provide-and-check"):
|
|
27
|
+
#
|
|
28
|
+
# - **provide** — when the inference engine binds the parameter
|
|
29
|
+
# list of a matching `def`, {Rigor::Inference::MethodParameterBinder}
|
|
30
|
+
# substitutes the declared `param_types` for the usual
|
|
31
|
+
# `Dynamic[Top]` fallback, so the method body is analysed as
|
|
32
|
+
# if the parameter carried its protocol type.
|
|
33
|
+
# - **check** — the contributing plugin's `#diagnostics_for_file`
|
|
34
|
+
# hook confirms the method exists and its inferred return type
|
|
35
|
+
# conforms to `return_type_name`.
|
|
36
|
+
#
|
|
37
|
+
# ## Fields
|
|
38
|
+
#
|
|
39
|
+
# - `path_glob` — `File.fnmatch` glob (String) selecting the
|
|
40
|
+
# source files the contract applies to, relative to the
|
|
41
|
+
# analysed project root (e.g. `"lib/controller/**/*.rb"`).
|
|
42
|
+
# - `method_name` — Symbol; the instance (or singleton) method
|
|
43
|
+
# the contract constrains.
|
|
44
|
+
# - `singleton` — Boolean; `true` constrains `def self.<name>`,
|
|
45
|
+
# `false` (default) constrains instance methods.
|
|
46
|
+
# - `param_types` — Array of `ParamType` (positional index →
|
|
47
|
+
# fully-qualified type name). The type names resolve against
|
|
48
|
+
# the analysed project's environment lazily, at consumption
|
|
49
|
+
# time, so the contract value object stays independent of
|
|
50
|
+
# environment construction order.
|
|
51
|
+
# - `return_type_name` — fully-qualified type name (String) the
|
|
52
|
+
# method's inferred return type must conform to.
|
|
53
|
+
# - `severity` — Symbol diagnostic severity for contract
|
|
54
|
+
# violations (`:error` default).
|
|
55
|
+
#
|
|
56
|
+
# ## Ractor-shareability
|
|
57
|
+
#
|
|
58
|
+
# Every field is frozen at construction (ADR-15 Phase 1); the
|
|
59
|
+
# nested `ParamType` is a frozen `Data`. `Ractor.shareable?`
|
|
60
|
+
# returns true after `#initialize`, so the contract survives
|
|
61
|
+
# `Plugin::Registry.materialize` into a worker Ractor.
|
|
62
|
+
class ProtocolContract
|
|
63
|
+
VALID_SEVERITIES = %i[error warning info].freeze
|
|
64
|
+
|
|
65
|
+
# One positional-parameter provision: the zero-based index of
|
|
66
|
+
# the parameter and the fully-qualified name of the type it
|
|
67
|
+
# carries under the protocol.
|
|
68
|
+
ParamType = Data.define(:index, :type_name)
|
|
69
|
+
|
|
70
|
+
attr_reader :path_glob, :method_name, :singleton, :param_types, :return_type_name, :severity
|
|
71
|
+
|
|
72
|
+
def initialize(path_glob:, method_name:, return_type_name: nil, param_types: [], singleton: false,
|
|
73
|
+
severity: :error)
|
|
74
|
+
validate_path_glob!(path_glob)
|
|
75
|
+
validate_method_name!(method_name)
|
|
76
|
+
validate_return_type_name!(return_type_name)
|
|
77
|
+
validate_severity!(severity)
|
|
78
|
+
|
|
79
|
+
@path_glob = path_glob.dup.freeze
|
|
80
|
+
@method_name = method_name.to_sym
|
|
81
|
+
@singleton = singleton ? true : false
|
|
82
|
+
@param_types = coerce_param_types(param_types)
|
|
83
|
+
@return_type_name = return_type_name.nil? ? nil : return_type_name.dup.freeze
|
|
84
|
+
@severity = severity.to_sym
|
|
85
|
+
freeze
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Returns a copy with `path_glob` replaced. Plugins use this to
|
|
89
|
+
# honour a per-project config override of the convention path
|
|
90
|
+
# without rebuilding the whole contract by hand.
|
|
91
|
+
def with_path_glob(glob)
|
|
92
|
+
ProtocolContract.new(
|
|
93
|
+
path_glob: glob,
|
|
94
|
+
method_name: method_name,
|
|
95
|
+
return_type_name: return_type_name,
|
|
96
|
+
param_types: param_types.map { |pt| { index: pt.index, type_name: pt.type_name } },
|
|
97
|
+
singleton: singleton,
|
|
98
|
+
severity: severity
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def to_h
|
|
103
|
+
{
|
|
104
|
+
"path_glob" => path_glob,
|
|
105
|
+
"method_name" => method_name.to_s,
|
|
106
|
+
"singleton" => singleton,
|
|
107
|
+
"param_types" => param_types.map { |pt| { "index" => pt.index, "type_name" => pt.type_name } },
|
|
108
|
+
"return_type_name" => return_type_name,
|
|
109
|
+
"severity" => severity.to_s
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def ==(other)
|
|
114
|
+
other.is_a?(ProtocolContract) && to_h == other.to_h
|
|
115
|
+
end
|
|
116
|
+
alias eql? ==
|
|
117
|
+
|
|
118
|
+
def hash
|
|
119
|
+
to_h.hash
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def validate_path_glob!(value)
|
|
125
|
+
return if value.is_a?(String) && !value.empty?
|
|
126
|
+
|
|
127
|
+
raise ArgumentError,
|
|
128
|
+
"Plugin::ProtocolContract#path_glob must be a non-empty String, got #{value.inspect}"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def validate_method_name!(value)
|
|
132
|
+
return if value.is_a?(Symbol) || (value.is_a?(String) && !value.empty?)
|
|
133
|
+
|
|
134
|
+
raise ArgumentError,
|
|
135
|
+
"Plugin::ProtocolContract#method_name must be a Symbol/non-empty String, got #{value.inspect}"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def validate_return_type_name!(value)
|
|
139
|
+
return if value.nil?
|
|
140
|
+
return if value.is_a?(String) && !value.empty?
|
|
141
|
+
|
|
142
|
+
raise ArgumentError,
|
|
143
|
+
"Plugin::ProtocolContract#return_type_name must be a non-empty String or nil, got #{value.inspect}"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def validate_severity!(value)
|
|
147
|
+
return if VALID_SEVERITIES.include?(value.to_sym)
|
|
148
|
+
|
|
149
|
+
raise ArgumentError,
|
|
150
|
+
"Plugin::ProtocolContract#severity must be one of #{VALID_SEVERITIES.inspect}, got #{value.inspect}"
|
|
151
|
+
rescue NoMethodError
|
|
152
|
+
raise ArgumentError,
|
|
153
|
+
"Plugin::ProtocolContract#severity must be one of #{VALID_SEVERITIES.inspect}, got #{value.inspect}"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def coerce_param_types(param_types)
|
|
157
|
+
unless param_types.is_a?(Array)
|
|
158
|
+
raise ArgumentError,
|
|
159
|
+
"Plugin::ProtocolContract#param_types must be an Array, got #{param_types.inspect}"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
param_types.map { |entry| coerce_param_type(entry) }.freeze
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def coerce_param_type(entry)
|
|
166
|
+
return entry if entry.is_a?(ParamType)
|
|
167
|
+
|
|
168
|
+
unless entry.is_a?(Hash)
|
|
169
|
+
raise ArgumentError,
|
|
170
|
+
"Plugin::ProtocolContract param_types entry must be a Hash or ParamType, got #{entry.inspect}"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
index = entry[:index] || entry["index"]
|
|
174
|
+
type_name = entry[:type_name] || entry["type_name"]
|
|
175
|
+
unless index.is_a?(Integer) && index >= 0 && type_name.is_a?(String) && !type_name.empty?
|
|
176
|
+
raise ArgumentError,
|
|
177
|
+
"Plugin::ProtocolContract param_types entry needs an Integer index >= 0 and a " \
|
|
178
|
+
"non-empty String type_name, got #{entry.inspect}"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
ParamType.new(index: index, type_name: type_name.dup.freeze)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -104,7 +104,73 @@ module Rigor
|
|
|
104
104
|
Inference::HktRegistry.new(registrations: registrations, definitions: definitions)
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
+
# ADR-25 — flat, ordered list of every loaded plugin's
|
|
108
|
+
# resolved RBS signature directories (absolute paths), in
|
|
109
|
+
# plugin registration order. `Environment.for_project`
|
|
110
|
+
# merges these into the signature-path set fed to
|
|
111
|
+
# `RbsLoader`, alongside the configuration's `signature_paths:`
|
|
112
|
+
# and the `bundler:` / `rbs_collection:` discovery output.
|
|
113
|
+
def signature_paths
|
|
114
|
+
plugins.flat_map(&:signature_paths)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# ADR-26 — the aggregate set of "open" receiver class names
|
|
118
|
+
# declared across loaded plugins (manifest `open_receivers:`).
|
|
119
|
+
# A class is open when a plugin vouches that it responds
|
|
120
|
+
# beyond its RBS-declared method surface. `open_receiver?`
|
|
121
|
+
# is the membership predicate `Analysis::CheckRules` consults
|
|
122
|
+
# to skip the `call.undefined-method` rule for such a class.
|
|
123
|
+
def open_receivers
|
|
124
|
+
plugins.flat_map { |plugin| plugin.manifest.open_receivers }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def open_receiver?(class_name)
|
|
128
|
+
return false if class_name.nil?
|
|
129
|
+
|
|
130
|
+
open_receivers.include?(class_name.to_s)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# ADR-28 — flat, ordered list of every loaded plugin's
|
|
134
|
+
# path-scoped method-protocol contracts, in plugin
|
|
135
|
+
# registration order. Read from each plugin's
|
|
136
|
+
# `#protocol_contracts` (which the manifest backs by default
|
|
137
|
+
# but a plugin MAY override to fold in per-project config).
|
|
138
|
+
# Consumed by `Inference::MethodParameterBinder` (the
|
|
139
|
+
# parameter-type provision) and by contributing plugins'
|
|
140
|
+
# `#diagnostics_for_file` hooks (the presence + return-type
|
|
141
|
+
# check).
|
|
142
|
+
def protocol_contracts
|
|
143
|
+
plugins.flat_map(&:protocol_contracts)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# ADR-28 — the subset of `protocol_contracts` whose
|
|
147
|
+
# `path_glob` matches `path`. Contract globs are authored
|
|
148
|
+
# project-root-relative (`lib/controller/**/*.rb`); the
|
|
149
|
+
# analyzer may hand this method either a project-relative
|
|
150
|
+
# path (`rigor check` run from the project root) or an
|
|
151
|
+
# absolute one (run from elsewhere, or a spec tmpdir), so the
|
|
152
|
+
# glob is matched both directly and as a `**/`-prefixed path
|
|
153
|
+
# suffix. `File::FNM_PATHNAME` keeps `*` from crossing `/`;
|
|
154
|
+
# `File::FNM_EXTGLOB` enables `{a,b}` groups. Returns `[]` for
|
|
155
|
+
# a nil path so the binder can call this unconditionally.
|
|
156
|
+
def contracts_for_path(path)
|
|
157
|
+
return [] if path.nil?
|
|
158
|
+
|
|
159
|
+
path_s = path.to_s
|
|
160
|
+
protocol_contracts.select { |contract| path_matches_glob?(contract.path_glob, path_s) }
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
FNMATCH_FLAGS = File::FNM_PATHNAME | File::FNM_EXTGLOB
|
|
164
|
+
private_constant :FNMATCH_FLAGS
|
|
165
|
+
|
|
107
166
|
EMPTY = new.freeze
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
def path_matches_glob?(glob, path)
|
|
171
|
+
File.fnmatch?(glob, path, FNMATCH_FLAGS) ||
|
|
172
|
+
File.fnmatch?(File.join("**", glob), path, FNMATCH_FLAGS)
|
|
173
|
+
end
|
|
108
174
|
end
|
|
109
175
|
end
|
|
110
176
|
end
|
|
@@ -122,8 +122,8 @@ module Rigor
|
|
|
122
122
|
diagnostic_count: matched.size,
|
|
123
123
|
summary: "undefined-method on core classes (#{top_methods(matched)}) — " \
|
|
124
124
|
"ActiveSupport monkey-patches these",
|
|
125
|
-
action: "
|
|
126
|
-
"
|
|
125
|
+
action: "Add rigor-activesupport-core-ext to `plugins:` in .rigor.yml " \
|
|
126
|
+
"(it is an RBS-bundle plugin — ADR-25)."
|
|
127
127
|
), matched]
|
|
128
128
|
end
|
|
129
129
|
|
data/lib/rigor/type/constant.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "date"
|
|
3
4
|
require_relative "../trinary"
|
|
4
5
|
|
|
5
6
|
module Rigor
|
|
@@ -24,6 +25,13 @@ module Rigor
|
|
|
24
25
|
Complex,
|
|
25
26
|
Regexp,
|
|
26
27
|
Pathname,
|
|
28
|
+
::Set,
|
|
29
|
+
# `Date` covers `DateTime` (a subclass). `Time` is core.
|
|
30
|
+
# Both arise only from deterministic constructor folding
|
|
31
|
+
# (`Date.new` / `Time.utc`) — there is no Date / Time
|
|
32
|
+
# literal node — so a `Constant` carrier is always sound.
|
|
33
|
+
Date,
|
|
34
|
+
Time,
|
|
27
35
|
TrueClass,
|
|
28
36
|
FalseClass,
|
|
29
37
|
NilClass
|
|
@@ -42,12 +50,31 @@ module Rigor
|
|
|
42
50
|
raise ArgumentError, "Rigor::Type::Constant only carries scalar literals; got #{value.class}"
|
|
43
51
|
end
|
|
44
52
|
|
|
45
|
-
@value =
|
|
53
|
+
@value = freezable_carrier?(value) ? value.dup.freeze : value
|
|
46
54
|
freeze
|
|
47
55
|
end
|
|
48
56
|
|
|
57
|
+
# Mutable-ish carriers are stored as a frozen copy so a later
|
|
58
|
+
# in-place mutation cannot rewrite the literal under us. `Time`
|
|
59
|
+
# joins `String` / `Set` here: `Time#localtime` mutates the
|
|
60
|
+
# receiver's zone in place, so the carrier holds a frozen copy
|
|
61
|
+
# (the catalog also blocklists the mutators). `Date` is already
|
|
62
|
+
# immutable, but is duped-and-frozen for symmetry.
|
|
63
|
+
def freezable_carrier?(value)
|
|
64
|
+
value.is_a?(String) || value.is_a?(::Set) ||
|
|
65
|
+
value.is_a?(Date) || value.is_a?(Time)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# `Date#inspect` / `DateTime#inspect` spell out the internal
|
|
69
|
+
# astronomical-Julian-day representation, which is unreadable
|
|
70
|
+
# in a diagnostic. ISO-8601 is the compact, deterministic
|
|
71
|
+
# form. `Time#inspect` is already compact (`2026-01-01
|
|
72
|
+
# 00:00:00 UTC`), so it keeps the default.
|
|
49
73
|
def describe(_verbosity = :short)
|
|
50
|
-
value
|
|
74
|
+
case value
|
|
75
|
+
when Date then value.iso8601
|
|
76
|
+
else value.inspect
|
|
77
|
+
end
|
|
51
78
|
end
|
|
52
79
|
|
|
53
80
|
# RBS supports `Literal` types for booleans, nil, integer
|
data/lib/rigor/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rigortype
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rigor contributors
|
|
@@ -261,10 +261,12 @@ files:
|
|
|
261
261
|
- lib/rigor/cache/rbs_known_class_names.rb
|
|
262
262
|
- lib/rigor/cache/store.rb
|
|
263
263
|
- lib/rigor/cli.rb
|
|
264
|
+
- lib/rigor/cli/annotate_command.rb
|
|
264
265
|
- lib/rigor/cli/baseline_command.rb
|
|
265
266
|
- lib/rigor/cli/diff_command.rb
|
|
266
267
|
- lib/rigor/cli/explain_command.rb
|
|
267
268
|
- lib/rigor/cli/lsp_command.rb
|
|
269
|
+
- lib/rigor/cli/prism_colorizer.rb
|
|
268
270
|
- lib/rigor/cli/sig_gen_command.rb
|
|
269
271
|
- lib/rigor/cli/triage_command.rb
|
|
270
272
|
- lib/rigor/cli/triage_renderer.rb
|
|
@@ -327,16 +329,23 @@ files:
|
|
|
327
329
|
- lib/rigor/inference/macro_block_self_type.rb
|
|
328
330
|
- lib/rigor/inference/method_dispatcher.rb
|
|
329
331
|
- lib/rigor/inference/method_dispatcher/block_folding.rb
|
|
332
|
+
- lib/rigor/inference/method_dispatcher/cgi_folding.rb
|
|
330
333
|
- lib/rigor/inference/method_dispatcher/constant_folding.rb
|
|
331
334
|
- lib/rigor/inference/method_dispatcher/file_folding.rb
|
|
332
335
|
- lib/rigor/inference/method_dispatcher/iterator_dispatch.rb
|
|
333
336
|
- lib/rigor/inference/method_dispatcher/kernel_dispatch.rb
|
|
334
337
|
- lib/rigor/inference/method_dispatcher/literal_string_folding.rb
|
|
338
|
+
- lib/rigor/inference/method_dispatcher/math_folding.rb
|
|
335
339
|
- lib/rigor/inference/method_dispatcher/method_folding.rb
|
|
336
340
|
- lib/rigor/inference/method_dispatcher/overload_selector.rb
|
|
337
341
|
- lib/rigor/inference/method_dispatcher/rbs_dispatch.rb
|
|
338
342
|
- lib/rigor/inference/method_dispatcher/receiver_affinity.rb
|
|
343
|
+
- lib/rigor/inference/method_dispatcher/regexp_folding.rb
|
|
344
|
+
- lib/rigor/inference/method_dispatcher/set_folding.rb
|
|
339
345
|
- lib/rigor/inference/method_dispatcher/shape_dispatch.rb
|
|
346
|
+
- lib/rigor/inference/method_dispatcher/shellwords_folding.rb
|
|
347
|
+
- lib/rigor/inference/method_dispatcher/time_folding.rb
|
|
348
|
+
- lib/rigor/inference/method_dispatcher/uri_folding.rb
|
|
340
349
|
- lib/rigor/inference/method_parameter_binder.rb
|
|
341
350
|
- lib/rigor/inference/multi_target_binder.rb
|
|
342
351
|
- lib/rigor/inference/narrowing.rb
|
|
@@ -378,6 +387,7 @@ files:
|
|
|
378
387
|
- lib/rigor/plugin/macro/heredoc_template.rb
|
|
379
388
|
- lib/rigor/plugin/macro/trait_registry.rb
|
|
380
389
|
- lib/rigor/plugin/manifest.rb
|
|
390
|
+
- lib/rigor/plugin/protocol_contract.rb
|
|
381
391
|
- lib/rigor/plugin/registry.rb
|
|
382
392
|
- lib/rigor/plugin/services.rb
|
|
383
393
|
- lib/rigor/plugin/trust_policy.rb
|