kube_schema 1.11.0 → 2.0.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/.envrc +1 -0
- data/.github/FUNDING.yml +3 -0
- data/.rubocop.yml +226 -5984
- data/CHANGELOG.md +127 -2
- data/DEPRECATIONS.md +172 -0
- data/Gemfile +13 -3
- data/Gemfile.lock +41 -31
- data/RELEASE.md +161 -0
- data/Rakefile +1 -1
- data/bin/rubocop +3 -0
- data/bin/test +2 -9
- data/cops/begin_block_assignment.rb +34 -0
- data/cops/comment_structure.rb +307 -0
- data/cops/constant_matches_path.rb +142 -0
- data/cops/multiline_method_arguments.rb +89 -0
- data/cops/no_conditional_assignment.rb +186 -0
- data/cops/no_console_logging.rb +62 -0
- data/cops/no_modifier_if.rb +74 -0
- data/cops/no_return.rb +152 -0
- data/cops/support/prism_source.rb +234 -0
- data/cops/use_tap.rb +100 -0
- data/flake.lock +42 -5
- data/flake.nix +28 -21
- data/gemset.nix +983 -0
- data/kube_schema.gemspec +4 -2
- data/lib/kube/errors.rb +652 -645
- data/lib/kube/monkey_patches.rb +5 -6
- data/lib/kube/schema/instance.rb +344 -363
- data/lib/kube/schema/lazy.rb +370 -0
- data/lib/kube/schema/manifest.rb +289 -310
- data/lib/kube/schema/resource.rb +352 -356
- data/lib/kube/schema/sub_spec.rb +261 -293
- data/lib/kube/schema.rb +173 -172
- data/lib/{kube/schema → kube_schema}/version.rb +1 -1
- data/lib/kube_schema.rb +6 -0
- data/readme.md +5 -0
- metadata +50 -9
- data/bin/increment-version +0 -45
- data/bin/release-gem +0 -32
- data/bin/tag-version +0 -19
- data/lib/kube/schema/version.rb.erb +0 -7
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the Apache License, Version 2.0.
|
|
4
|
+
# Copyright, 2026, by General Intelligence Systems.
|
|
5
|
+
|
|
6
|
+
# Reads the file under inspection with Prism, which ships with Ruby, instead of through the parser gem syntax tree RuboCop hands a cop.
|
|
7
|
+
#
|
|
8
|
+
# A cop which includes this does not use the `on_<type>` callbacks: those are driven by the parser gem tree, so a cop which reads a different tree walks it itself from `on_new_investigation`. What it gains is one parse of the file by the same Prism which runs the program, and a uniform walk over every node.
|
|
9
|
+
#
|
|
10
|
+
# Offences are still reported against `Parser::Source::Range`, because that is what RuboCop and its correctors take. THE TWO DO NOT MEASURE THE SAME WAY: a Prism location counts BYTES and a `Parser::Source::Range` counts CHARACTERS, so a range built from `start_offset` is correct only until the first multibyte character in the file and silently wrong after it. Prism gives both, and `prism_range` takes the character pair.
|
|
11
|
+
#
|
|
12
|
+
# Prism does not track parentage - a node does not name the node it is written inside - so the walk records the parent of each node as it descends.
|
|
13
|
+
|
|
14
|
+
require "prism"
|
|
15
|
+
|
|
16
|
+
module RuboCop
|
|
17
|
+
module Cop
|
|
18
|
+
module PrismSource
|
|
19
|
+
# @returns [Prism::ParseResult] the file, parsed once however many times this is called.
|
|
20
|
+
def prism_result
|
|
21
|
+
self.prism_state.fetch(:result)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Every node in the file, outermost first, in source order.
|
|
25
|
+
#
|
|
26
|
+
# @returns [Array(Prism::Node)] the nodes.
|
|
27
|
+
def prism_nodes
|
|
28
|
+
self.prism_state.fetch(:nodes)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @parameter classes [Array(Class)] the Prism node classes wanted.
|
|
32
|
+
# @returns [Array(Prism::Node)] the nodes which are one of them.
|
|
33
|
+
def prism_each(*classes)
|
|
34
|
+
if classes.empty?
|
|
35
|
+
self.prism_nodes
|
|
36
|
+
else
|
|
37
|
+
self.prism_nodes.select{|node| classes.any?{|klass| node.is_a?(klass)}}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @parameter node [Prism::Node] the node whose parent is wanted.
|
|
42
|
+
# @returns [Prism::Node | nil] the node it is written inside, or nil at the root.
|
|
43
|
+
def prism_parent(node)
|
|
44
|
+
self.prism_state.fetch(:parents)[node]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The nodes a node is written inside, innermost first.
|
|
48
|
+
#
|
|
49
|
+
# @returns [Array(Prism::Node)] the ancestors.
|
|
50
|
+
def prism_ancestors(node)
|
|
51
|
+
[].tap do |found|
|
|
52
|
+
current = self.prism_parent(node)
|
|
53
|
+
|
|
54
|
+
while current
|
|
55
|
+
found << current
|
|
56
|
+
current = self.prism_parent(current)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @returns [Array(Prism::Node)] the nodes written directly inside the given node.
|
|
62
|
+
def prism_children(node)
|
|
63
|
+
node.compact_child_nodes
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Everything written inside the given node, at any depth, outermost first.
|
|
67
|
+
#
|
|
68
|
+
# @parameter classes [Array(Class)] the Prism node classes wanted, or none for all of them.
|
|
69
|
+
# @returns [Array(Prism::Node)] the nodes.
|
|
70
|
+
def prism_descendants(node, *classes)
|
|
71
|
+
[].tap do |found|
|
|
72
|
+
pending = node.compact_child_nodes.dup
|
|
73
|
+
|
|
74
|
+
until pending.empty?
|
|
75
|
+
current = pending.shift
|
|
76
|
+
|
|
77
|
+
if classes.empty? or classes.any?{|klass| current.is_a?(klass)}
|
|
78
|
+
found << current
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
pending.concat(current.compact_child_nodes)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Whether the given node contains a heredoc, whose content lives below the line it opens on.
|
|
87
|
+
def prism_heredoc?(node)
|
|
88
|
+
[node].concat(self.prism_descendants(node)).any? do |current|
|
|
89
|
+
case current
|
|
90
|
+
when ::Prism::StringNode, ::Prism::InterpolatedStringNode,
|
|
91
|
+
::Prism::XStringNode, ::Prism::InterpolatedXStringNode
|
|
92
|
+
current.heredoc?
|
|
93
|
+
else
|
|
94
|
+
false
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# The statements of a body, whether it holds one or many.
|
|
100
|
+
#
|
|
101
|
+
# @parameter body [Prism::StatementsNode | nil] the body of a method, module, or block.
|
|
102
|
+
# @returns [Array(Prism::Node)] its statements, which is empty when there is no body.
|
|
103
|
+
def prism_statements(body)
|
|
104
|
+
if body.nil?
|
|
105
|
+
[]
|
|
106
|
+
else
|
|
107
|
+
body.body
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# A Prism location as the range RuboCop reports an offence against.
|
|
112
|
+
#
|
|
113
|
+
# @parameter location [Prism::Location] where the offence is.
|
|
114
|
+
# @returns [Parser::Source::Range] the same place, measured for RuboCop.
|
|
115
|
+
def prism_range(location)
|
|
116
|
+
# CHARACTER OFFSETS, NOT `start_offset`. A `Parser::Source::Range` indexes the buffer by character and a Prism location counts bytes, so a range built from the byte pair lands further and further past where it should as the multibyte characters above it accumulate. A corrector handed such a range replaces the wrong text and writes a file which no longer parses.
|
|
117
|
+
::Parser::Source::Range.new(
|
|
118
|
+
processed_source.buffer,
|
|
119
|
+
location.start_character_offset,
|
|
120
|
+
location.end_character_offset,
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# One range reaching from the start of the first location to the end of the last, for an offence over a run of statements rather than a single node.
|
|
125
|
+
#
|
|
126
|
+
# @returns [Parser::Source::Range] the span.
|
|
127
|
+
def prism_span(first, last)
|
|
128
|
+
::Parser::Source::Range.new(
|
|
129
|
+
processed_source.buffer,
|
|
130
|
+
first.start_character_offset,
|
|
131
|
+
last.end_character_offset,
|
|
132
|
+
)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @returns [Parser::Source::Range] the whole of the given node.
|
|
136
|
+
def prism_node_range(node)
|
|
137
|
+
self.prism_range(node.location)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# The column a node starts at, counted the way a Ruby String is indexed.
|
|
141
|
+
#
|
|
142
|
+
# @returns [Integer] the character column.
|
|
143
|
+
def prism_column(node)
|
|
144
|
+
# `Prism::Location#start_column` counts bytes, so indexing a line from `processed_source.lines` with it cuts in the wrong place once anything above or before it on that line is multibyte.
|
|
145
|
+
node.location.start_character_column
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# @returns [String] the source of the given node.
|
|
149
|
+
def prism_source(node)
|
|
150
|
+
node.location.slice
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @returns [Array(Prism::InlineComment)] every comment in the file, in source order.
|
|
154
|
+
def prism_comments
|
|
155
|
+
self.prism_result.comments
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# The run of comment lines written directly above a declaration, which is what documents it.
|
|
159
|
+
#
|
|
160
|
+
# @returns [Array(Prism::InlineComment)] the comments, in source order.
|
|
161
|
+
def prism_leading_comments(node)
|
|
162
|
+
self.prism_state.fetch(:leading)[node] ||= self.contiguous_above(node)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Every comment a declaration owns, which is the same run: a comment belongs to whatever it is written above.
|
|
166
|
+
#
|
|
167
|
+
# @returns [Array(Prism::InlineComment)] the comments, in source order.
|
|
168
|
+
def prism_owned_comments(node)
|
|
169
|
+
self.prism_leading_comments(node)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private
|
|
173
|
+
|
|
174
|
+
# Everything read from the file, discarded when RuboCop moves to the next one.
|
|
175
|
+
def prism_state
|
|
176
|
+
source = processed_source
|
|
177
|
+
|
|
178
|
+
unless @prism_state and @prism_source.equal?(source)
|
|
179
|
+
@prism_source = source
|
|
180
|
+
@prism_state = self.read(source)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
@prism_state
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def read(source)
|
|
187
|
+
result = ::Prism.parse(source.buffer.source)
|
|
188
|
+
|
|
189
|
+
nodes = []
|
|
190
|
+
parents = {}.compare_by_identity
|
|
191
|
+
|
|
192
|
+
self.descend(result.value, nil, nodes, parents)
|
|
193
|
+
|
|
194
|
+
by_line = {}
|
|
195
|
+
|
|
196
|
+
result.comments.each do |comment|
|
|
197
|
+
by_line[comment.location.start_line] = comment
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
{
|
|
201
|
+
result: result,
|
|
202
|
+
nodes: nodes,
|
|
203
|
+
parents: parents,
|
|
204
|
+
by_line: by_line,
|
|
205
|
+
leading: {}.compare_by_identity,
|
|
206
|
+
}
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# The tree, recorded flat with the parent of each node, since Prism does not say.
|
|
210
|
+
def descend(node, parent, nodes, parents)
|
|
211
|
+
nodes << node
|
|
212
|
+
parents[node] = parent
|
|
213
|
+
|
|
214
|
+
node.compact_child_nodes.each do |child|
|
|
215
|
+
self.descend(child, node, nodes, parents)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# The run of comment lines ending on the line above the node, stopping at the first gap.
|
|
220
|
+
def contiguous_above(node)
|
|
221
|
+
by_line = self.prism_state.fetch(:by_line)
|
|
222
|
+
found = []
|
|
223
|
+
line = node.location.start_line - 1
|
|
224
|
+
|
|
225
|
+
while comment = by_line[line]
|
|
226
|
+
found.unshift(comment)
|
|
227
|
+
line -= 1
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
found
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
data/cops/use_tap.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Requires `tap` when a method opens by assigning a local variable and closes by
|
|
4
|
+
# returning that same variable:
|
|
5
|
+
#
|
|
6
|
+
# def require_existing_column! # NO
|
|
7
|
+
# column = params[:id].to_s
|
|
8
|
+
# unless connection.columns(@table).any? { |c| c.name == column }
|
|
9
|
+
# render json: { error: "unknown column" }, status: :not_found
|
|
10
|
+
# end
|
|
11
|
+
# column
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# def require_existing_column! # YES
|
|
15
|
+
# params[:id].to_s.tap do |column|
|
|
16
|
+
# unless connection.columns(@table).any? { |c| c.name == column }
|
|
17
|
+
# render json: { error: "unknown column" }, status: :not_found
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# The assign-work-return shape states the return value twice — once as the
|
|
23
|
+
# assignment target, once as a bare mention on the last line — and puts the two
|
|
24
|
+
# far enough apart that the trailing `column` reads as a stray expression.
|
|
25
|
+
# `tap` names the value once, scopes it to the block that works on it, and makes
|
|
26
|
+
# "the value flows through unchanged" structural rather than something you check
|
|
27
|
+
# by comparing the first and last lines.
|
|
28
|
+
#
|
|
29
|
+
# A body that REASSIGNS the variable is left alone: `tap` yields the original
|
|
30
|
+
# object and returns it, so that rewrite would change the result.
|
|
31
|
+
module RuboCop
|
|
32
|
+
module Cop
|
|
33
|
+
module Local
|
|
34
|
+
class UseTap < Base
|
|
35
|
+
MSG = "Assigning `%<name>s` and returning it at the end is `tap`; " \
|
|
36
|
+
"write `<expression>.tap do |%<name>s| ... end`."
|
|
37
|
+
|
|
38
|
+
# Every way a local can be written to after the opening assignment.
|
|
39
|
+
REASSIGNMENTS = %i[lvasgn op_asgn or_asgn and_asgn masgn].freeze
|
|
40
|
+
|
|
41
|
+
def on_def(node)
|
|
42
|
+
check(node.body)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def on_defs(node)
|
|
46
|
+
check(node.body)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def check(body)
|
|
52
|
+
if tap_shaped?(body)
|
|
53
|
+
add_offense(body, message: format(MSG, name: assigned_name(body)))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# First statement assigns a local; last statement is that same local,
|
|
58
|
+
# read and nothing else.
|
|
59
|
+
def tap_shaped?(body)
|
|
60
|
+
body&.begin_type? &&
|
|
61
|
+
body.children.size >= 2 &&
|
|
62
|
+
body.children.first.lvasgn_type? &&
|
|
63
|
+
returns_assigned?(body) &&
|
|
64
|
+
!reassigned?(body)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def assigned_name(body)
|
|
68
|
+
body.children.first.name
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def returns_assigned?(body)
|
|
72
|
+
last = body.children.last
|
|
73
|
+
|
|
74
|
+
last.lvar_type? && last.children.first == assigned_name(body)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# `tap` yields the object the receiver evaluated to, so a body that
|
|
78
|
+
# points the name at something else partway through is a different
|
|
79
|
+
# program and must not be flagged.
|
|
80
|
+
def reassigned?(body)
|
|
81
|
+
name = assigned_name(body)
|
|
82
|
+
|
|
83
|
+
body.children[1..-2].any? do |statement|
|
|
84
|
+
statement.each_node(*REASSIGNMENTS).any? do |write|
|
|
85
|
+
writes_name?(write, name)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def writes_name?(node, name)
|
|
91
|
+
if node.masgn_type?
|
|
92
|
+
node.assignments.any? { |target| target == name }
|
|
93
|
+
else
|
|
94
|
+
node.children.first == name
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
data/flake.lock
CHANGED
|
@@ -1,23 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"nodes": {
|
|
3
|
+
"mine": {
|
|
4
|
+
"inputs": {
|
|
5
|
+
"nixpkgs": [
|
|
6
|
+
"nixpkgs"
|
|
7
|
+
],
|
|
8
|
+
"systems": "systems"
|
|
9
|
+
},
|
|
10
|
+
"locked": {
|
|
11
|
+
"lastModified": 1790610895,
|
|
12
|
+
"narHash": "sha256-sansiZlrb60MrGFzTXNCVVMTU5EsGM6KWvZkA/aNp14=",
|
|
13
|
+
"owner": "n-at-han-k",
|
|
14
|
+
"repo": "flake.nix",
|
|
15
|
+
"rev": "0f3388742debac3e78751796f4568f441c0dee57",
|
|
16
|
+
"type": "github"
|
|
17
|
+
},
|
|
18
|
+
"original": {
|
|
19
|
+
"owner": "n-at-han-k",
|
|
20
|
+
"repo": "flake.nix",
|
|
21
|
+
"type": "github"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
3
24
|
"nixpkgs": {
|
|
4
25
|
"locked": {
|
|
5
|
-
"lastModified":
|
|
6
|
-
"narHash": "sha256-
|
|
26
|
+
"lastModified": 1780902259,
|
|
27
|
+
"narHash": "sha256-q8yYEC5f1mFlQO9RGna4LTc9QrcvWunX6FYp83munkQ=",
|
|
7
28
|
"owner": "NixOS",
|
|
8
29
|
"repo": "nixpkgs",
|
|
9
|
-
"rev": "
|
|
30
|
+
"rev": "bd0ff2d3eac24699c3664d5966b9ef36f388e2ca",
|
|
10
31
|
"type": "github"
|
|
11
32
|
},
|
|
12
33
|
"original": {
|
|
13
34
|
"owner": "NixOS",
|
|
14
|
-
"ref": "nixos-unstable",
|
|
15
35
|
"repo": "nixpkgs",
|
|
36
|
+
"rev": "bd0ff2d3eac24699c3664d5966b9ef36f388e2ca",
|
|
16
37
|
"type": "github"
|
|
17
38
|
}
|
|
18
39
|
},
|
|
19
40
|
"root": {
|
|
20
41
|
"inputs": {
|
|
42
|
+
"mine": "mine",
|
|
21
43
|
"nixpkgs": "nixpkgs",
|
|
22
44
|
"utils": "utils"
|
|
23
45
|
}
|
|
@@ -37,9 +59,24 @@
|
|
|
37
59
|
"type": "github"
|
|
38
60
|
}
|
|
39
61
|
},
|
|
62
|
+
"systems_2": {
|
|
63
|
+
"locked": {
|
|
64
|
+
"lastModified": 1681028828,
|
|
65
|
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
66
|
+
"owner": "nix-systems",
|
|
67
|
+
"repo": "default",
|
|
68
|
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
69
|
+
"type": "github"
|
|
70
|
+
},
|
|
71
|
+
"original": {
|
|
72
|
+
"owner": "nix-systems",
|
|
73
|
+
"repo": "default",
|
|
74
|
+
"type": "github"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
40
77
|
"utils": {
|
|
41
78
|
"inputs": {
|
|
42
|
-
"systems": "
|
|
79
|
+
"systems": "systems_2"
|
|
43
80
|
},
|
|
44
81
|
"locked": {
|
|
45
82
|
"lastModified": 1731533236,
|
data/flake.nix
CHANGED
|
@@ -2,38 +2,45 @@
|
|
|
2
2
|
description = "Ruby gem flake";
|
|
3
3
|
|
|
4
4
|
inputs = {
|
|
5
|
-
nixpkgs.url = "github:NixOS/nixpkgs/
|
|
5
|
+
nixpkgs.url = "github:NixOS/nixpkgs/bd0ff2d3eac24699c3664d5966b9ef36f388e2ca"; # == this machine's system nixpkgs
|
|
6
6
|
utils.url = "github:numtide/flake-utils";
|
|
7
|
+
mine.url = "github:n-at-han-k/flake.nix";
|
|
8
|
+
mine.inputs.nixpkgs.follows = "nixpkgs";
|
|
7
9
|
};
|
|
8
|
-
outputs = { self, nixpkgs, utils }:
|
|
10
|
+
outputs = { self, nixpkgs, utils, mine }:
|
|
9
11
|
utils.lib.eachDefaultSystem (system:
|
|
10
12
|
let
|
|
11
13
|
pkgs = nixpkgs.legacyPackages.${system};
|
|
12
|
-
|
|
14
|
+
lib = mine.lib.${system};
|
|
15
|
+
|
|
16
|
+
gems = pkgs.bundlerEnv {
|
|
17
|
+
name = "kube_schema-gems";
|
|
18
|
+
ruby = pkgs.ruby_3_4;
|
|
19
|
+
gemfile = ./Gemfile;
|
|
20
|
+
lockfile = ./Gemfile.lock;
|
|
21
|
+
gemset = ./gemset.nix;
|
|
22
|
+
};
|
|
13
23
|
in
|
|
14
24
|
{
|
|
15
|
-
devShells.default =
|
|
16
|
-
nativeBuildInputs = [
|
|
17
|
-
pkgs.pkg-config # native extension discovery
|
|
18
|
-
];
|
|
19
|
-
|
|
25
|
+
devShells.default = lib.mkRubyShell {
|
|
20
26
|
buildInputs = [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
pkgs.
|
|
24
|
-
pkgs.openssl # openssl gem
|
|
27
|
+
gems
|
|
28
|
+
gems.wrappedRuby
|
|
29
|
+
pkgs.ripgrep # scampi shells out to `rg` to discover __END__ spec sections
|
|
25
30
|
];
|
|
26
31
|
|
|
27
|
-
shellHook = ''
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
shellHook = /* bash */ ''
|
|
33
|
+
unset RUBYOPT
|
|
34
|
+
export BUNDLE_FORCE_RUBY_PLATFORM=false
|
|
35
|
+
export BUNDLE_GEMFILE="$PWD/Gemfile"
|
|
36
|
+
export BUNDLE_FROZEN=false
|
|
37
|
+
|
|
38
|
+
export LANG="''${LANG:-C.UTF-8}"
|
|
39
|
+
export LC_ALL="''${LC_ALL:-$LANG}"
|
|
40
|
+
|
|
41
|
+
export RUBYLIB="$PWD/lib''${RUBYLIB:+:$RUBYLIB}"
|
|
42
|
+
'';
|
|
35
43
|
};
|
|
36
44
|
}
|
|
37
45
|
);
|
|
38
46
|
}
|
|
39
|
-
|