pipeable 0.5.0 → 0.6.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
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +62 -97
- data/lib/pipeable/steps/amap.rb +10 -0
- data/lib/pipeable/steps/container.rb +1 -0
- data/pipeable.gemspec +1 -1
- data.tar.gz.sig +0 -0
- metadata +3 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c03f09d3e8268f1786faa5907fe4f9dbc4beaf02c874bec73b683fd1e4a51de
|
4
|
+
data.tar.gz: 29943bc0fed70a2661cee558e5a4d23090af2fe216ba085ec1ff00e3da435ea3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebaeb186fb3c672501fa3b5414b2d4fe381a45fa22004ae2f128b80abc15d012f0ff70befb900ad75d82b760af33fa4a35c7db5d3113e7f3f261782f01e7dd24
|
7
|
+
data.tar.gz: 41fe4361d2a0226ceeb8796d1edc9e6fd0e19bc00539c3d3c4e87c57d09a871818d051d7a8d881b294c0f3ea8e73f2575a0ead5dcaaf3d44dbbb0dd53065d749
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.adoc
CHANGED
@@ -21,7 +21,7 @@ toc::[]
|
|
21
21
|
|
22
22
|
== Features
|
23
23
|
|
24
|
-
* Built atop
|
24
|
+
* Built atop native {function_composition_link}.
|
25
25
|
* Adheres to the {railway_pattern_link}.
|
26
26
|
* Provides built-in and customizable domain-specific steps.
|
27
27
|
* Provides chainable _pipes_ which can be used to build more complex workflows.
|
@@ -131,7 +131,7 @@ pipe(input, *steps)
|
|
131
131
|
|
132
132
|
The first argument is your input which can be a Ruby primitive or a monad. Regardless, the input will be automatically wrapped as a `Success` -- but only if not a `Result` to begin with -- before passing to the first step. From there, all steps are _required_ to answer a monad in order to adhere to the {railway_pattern_link}.
|
133
133
|
|
134
|
-
Behind the scenes, the `#pipe` method is syntactic sugar
|
134
|
+
Behind the scenes, the `#pipe` method is syntactic sugar built atop {function_composition_link} which means if this code were to be rewritten:
|
135
135
|
|
136
136
|
[source,ruby]
|
137
137
|
----
|
@@ -141,7 +141,7 @@ pipe csv,
|
|
141
141
|
map { |item| "#{item[:book]}: #{item[:price]}" }
|
142
142
|
----
|
143
143
|
|
144
|
-
|
144
|
+
...then the above would look like the following (as rewritten in native Ruby):
|
145
145
|
|
146
146
|
[source,ruby]
|
147
147
|
----
|
@@ -152,27 +152,28 @@ Then the above would look like this using native Ruby:
|
|
152
152
|
).call Success(csv)
|
153
153
|
----
|
154
154
|
|
155
|
+
Visually, the pipe can be diagramed as follows:
|
156
|
+
|
157
|
+
image::https://alchemists.io/images/projects/pipeable/diagrams/pipe.png[A diagram of pipe steps,width=591,height=734,role=focal_point]
|
158
|
+
|
155
159
|
The problem with native function composition is that it reads backwards by passing input at the end of all sequential steps. With the `#pipe` method, you have the benefit of allowing your eyes to read from top to bottom while not having to type multiple _forward composition_ operators.
|
156
160
|
|
157
161
|
=== Steps
|
158
162
|
|
159
|
-
There are several ways to compose steps for your pipe. As long as all steps succeed, you'll get a successful response. Otherwise, the first step to fail will pass the failure down by skipping all subsequent steps (unless you dynamically turn the failure into a success).
|
163
|
+
There are several ways to compose steps for your pipe. As long as all steps succeed, you'll get a successful response. Otherwise, the first step to fail will pass the failure down by skipping all subsequent steps (unless you dynamically turn the failure into a success). Each step can be initialized and called:
|
160
164
|
|
161
|
-
|
165
|
+
* `+#initialize+`: Arguments vary per step but can be positional, keyword, and/or block arguments. This is how you _customize_ the behavior of each step.
|
166
|
+
* `+#call+`: Expects a {dry_monads_link} `Result` object as input. The output is either the same or new `Result` object for consumption by the next step in the pipe. Additionally, each step will either unwrap the `Result` or pass the `Result` through depending on the step's implementation (as detailed below).
|
162
167
|
|
163
168
|
==== Basic
|
164
169
|
|
165
170
|
The following are the basic (default) steps for building custom pipes for which you can mix and match within your own implementation.
|
166
171
|
|
167
|
-
=====
|
172
|
+
===== alt
|
168
173
|
|
169
174
|
Allows you to operate on a failure and produce either a success or another failure. This is a convenience wrapper to native {dry_monads_link} `#or` functionality.
|
170
175
|
|
171
|
-
|
172
|
-
|
173
|
-
Processes a failure only while expecting you to answer a success or failure.
|
174
|
-
|
175
|
-
*Example*
|
176
|
+
Accepts a failure while answering either a success or failure. Example:
|
176
177
|
|
177
178
|
[source,ruby]
|
178
179
|
----
|
@@ -181,15 +182,23 @@ pipe Failure("Danger!"), alt { Success "Resolved" } # Success "Re
|
|
181
182
|
pipe Failure("Danger!"), alt { |object| Failure "Big #{object}" } # Failure "Big Danger!"
|
182
183
|
----
|
183
184
|
|
184
|
-
=====
|
185
|
+
===== amap
|
185
186
|
|
186
|
-
Allows you to
|
187
|
+
Allows you to unwrap a failure, make a modification, and wrap the modification as a new failure. This is a convenience wrapper to native {dry_monads_link} `#alt_map` functionality.
|
187
188
|
|
188
|
-
|
189
|
+
Accepts and answers a failure. Example:
|
189
190
|
|
190
|
-
|
191
|
+
[source,ruby]
|
192
|
+
----
|
193
|
+
pipe Failure("Danger"), amap { |object| "#{object}!" } # Failure "Danger!"
|
194
|
+
pipe Success("Pass"), amap { |object| "#{object}!" } # Success "Pass"
|
195
|
+
----
|
191
196
|
|
192
|
-
|
197
|
+
===== as
|
198
|
+
|
199
|
+
Allows you to message an object as a different result. The first argument is the method but additional positional and/or keyword arguments can be passed along if the method accepts them.
|
200
|
+
|
201
|
+
Accepts and answers a success. Example:
|
193
202
|
|
194
203
|
[source,ruby]
|
195
204
|
----
|
@@ -198,15 +207,11 @@ pipe %i[a b c], as(:dig, 1) # Success :b
|
|
198
207
|
pipe Failure("Danger!"), as(:inspect) # Failure "Danger!"
|
199
208
|
----
|
200
209
|
|
201
|
-
=====
|
210
|
+
===== bind
|
202
211
|
|
203
212
|
Allows you to perform operations upon success only. You are then responsible for answering a success or failure accordingly. This is a convenience wrapper to native {dry_monads_link} `#bind` functionality.
|
204
213
|
|
205
|
-
|
206
|
-
|
207
|
-
Processes a success only while expecting you to answer a success or failure in return.
|
208
|
-
|
209
|
-
*Example*
|
214
|
+
Accepts a success while answering either a success or failure. Example:
|
210
215
|
|
211
216
|
[source,ruby]
|
212
217
|
----
|
@@ -215,15 +220,11 @@ pipe %i[a b c], bind { |object| Failure object } # Failure [
|
|
215
220
|
pipe Failure("Danger!"), bind { |object| Success object.join("-") } # Failure "Danger!"
|
216
221
|
----
|
217
222
|
|
218
|
-
=====
|
223
|
+
===== check
|
219
224
|
|
220
225
|
Allows you to check if an object matches the proof (with message). The first argument is your proof while the second argument is the message to send to your proof. A check only passes if the messaged object evaluates to `true` or `Success`. When successful, the object is passed through as a `Success`. When false, the object is passed through as a `Failure`.
|
221
226
|
|
222
|
-
|
223
|
-
|
224
|
-
Processes a success only while answering a success or failure depending on whether unwrapped object checks against the proof.
|
225
|
-
|
226
|
-
*Example*
|
227
|
+
Accepts a success while answering a success or failure depending on whether unwrapped object checks against the proof. Example:
|
227
228
|
|
228
229
|
[source,ruby]
|
229
230
|
----
|
@@ -232,15 +233,11 @@ pipe :a, check(%i[b c], :include?) # Failure :a
|
|
232
233
|
pipe Failure("Danger!"), check(%i[a b], :include?) # Failure "Danger!"
|
233
234
|
----
|
234
235
|
|
235
|
-
=====
|
236
|
+
===== fmap
|
236
237
|
|
237
|
-
Allows you to unwrap a success, make a modification, and
|
238
|
+
Allows you to unwrap a success, make a modification, and wrap the modification as a new success. This is a convenience wrapper to native {dry_monads_link} `#fmap` functionality.
|
238
239
|
|
239
|
-
|
240
|
-
|
241
|
-
Processes and answers a success only.
|
242
|
-
|
243
|
-
*Example*
|
240
|
+
Accepts and answers a success. Example:
|
244
241
|
|
245
242
|
[source,ruby]
|
246
243
|
----
|
@@ -248,15 +245,11 @@ pipe %i[a b c], fmap { |object| object.join "-" } # Success "a-b-c"
|
|
248
245
|
pipe Failure("Danger!"), fmap { |object| object.join "-" } # Failure "Danger!"
|
249
246
|
----
|
250
247
|
|
251
|
-
=====
|
252
|
-
|
253
|
-
Allows you to insert an element after an object (default behavior). This step wraps native link:https://rubyapi.org/o/array#method-i-insert[Array#insert] functionality. If the object is not an array, it will be cast as one. You can use the `:at` key to specify where you want insertion to happen. This step is most useful when needing to assemble arguments for passing to a subsequent step.
|
254
|
-
|
255
|
-
*I/O*
|
248
|
+
===== insert
|
256
249
|
|
257
|
-
|
250
|
+
Allows you to insert an element after an object (default behavior) as a single array. This step wraps native link:https://rubyapi.org/o/array#method-i-insert[Array#insert] functionality. If the object is not an array, it will be cast as one. You can use the `:at` key to specify where you want insertion to happen. This step is most useful when needing to assemble _positional_ arguments for passing as an array to a subsequent step.
|
258
251
|
|
259
|
-
|
252
|
+
Accepts and answers a success. Example:
|
260
253
|
|
261
254
|
[source,ruby]
|
262
255
|
----
|
@@ -266,15 +259,11 @@ pipe %i[a c], insert(:b, at: 1) # Success [:a, :b, :c]
|
|
266
259
|
pipe Failure("Danger!"), insert(:b) # Failure "Danger!"
|
267
260
|
----
|
268
261
|
|
269
|
-
=====
|
262
|
+
===== map
|
270
263
|
|
271
264
|
Allows you to map over an object (enumerable) by wrapping native link:https://rubyapi.org/o/enumerable#method-i-map[Enumerable#map] functionality.
|
272
265
|
|
273
|
-
|
274
|
-
|
275
|
-
Processes and answers a success only.
|
276
|
-
|
277
|
-
*Example*
|
266
|
+
Accepts and answers a success. Example:
|
278
267
|
|
279
268
|
[source,ruby]
|
280
269
|
----
|
@@ -282,15 +271,11 @@ pipe %i[a b c], map(&:inspect) # Success [":a", ":b", ":c"]
|
|
282
271
|
pipe Failure("Danger!"), map(&:inspect) # Failure "Danger!"
|
283
272
|
----
|
284
273
|
|
285
|
-
=====
|
286
|
-
|
287
|
-
Allows you to merge an object with additional attributes as a single hash. If the input is not a hash, then the object will be merged with `step` as the key. The default `step` key can be renamed to a different key by using the `:as` key. Like the _Insert_ step, this is most useful when assembling arguments and/or data for consumption by subsequent steps
|
274
|
+
===== merge
|
288
275
|
|
289
|
-
|
276
|
+
Allows you to merge an object with additional attributes as a single hash. This step wraps native link:https://rubyapi.org/o/hash#method-i-merge[Hash#merge] functionality. If the input is not a hash, then the object will be merged with `step` as the key. The default `step` key can be renamed to a different key by using the `:as` key. Like the _insert_ step, this step is most useful when assembling _keyword_ arguments and/or a hash for a subsequent steps.
|
290
277
|
|
291
|
-
|
292
|
-
|
293
|
-
*Example*
|
278
|
+
Accepts and answers a success. Example:
|
294
279
|
|
295
280
|
[source,ruby]
|
296
281
|
----
|
@@ -300,15 +285,11 @@ pipe "test", merge(as: :a, b: 2) # Success {a: "test", b: 2}
|
|
300
285
|
pipe Failure("Danger!"), merge(b: 2) # Failure "Danger!"
|
301
286
|
----
|
302
287
|
|
303
|
-
=====
|
288
|
+
===== tee
|
304
289
|
|
305
290
|
Allows you to run an operation and ignore the response while input is passed through as output. This behavior is similar in nature to the link:https://www.gnu.org/savannah-checkouts/gnu/gawk/manual/html_node/Tee-Program.html[tee] program in Bash.
|
306
291
|
|
307
|
-
|
308
|
-
|
309
|
-
Passes the result through while allowing you to execute arbitrary behavior.
|
310
|
-
|
311
|
-
*Example*
|
292
|
+
Accepts either a success or failure and passes the result through while allowing you to execute arbitrary behavior. Example:
|
312
293
|
|
313
294
|
[source,ruby]
|
314
295
|
----
|
@@ -323,15 +304,11 @@ pipe Failure("Danger!"), tee(Kernel, :puts, "Example.")
|
|
323
304
|
# Failure "Danger!"
|
324
305
|
----
|
325
306
|
|
326
|
-
=====
|
307
|
+
===== to
|
327
308
|
|
328
309
|
Allows you to delegate to an object which doesn't have a callable interface and may or may not answer a result. If the response is not a monad, it'll be automatically wrapped as a `Success`.
|
329
310
|
|
330
|
-
|
331
|
-
|
332
|
-
Processes a success only while sending the unwrapped object to the given object's corresponding method. The object is expected to answer either a plain Ruby object which will be automatically wrapped as a success or a {dry_monads_link} `Result`.
|
333
|
-
|
334
|
-
*Example*
|
311
|
+
Accepts a success while sending the unwrapped object to the given object's corresponding method. The object is expected to answer either a plain Ruby object which will be automatically wrapped as a success or a {dry_monads_link} `Result`. Example:
|
335
312
|
|
336
313
|
[source,ruby]
|
337
314
|
----
|
@@ -345,15 +322,11 @@ pipe({label: "Test"}, to(Model, :for)) # Success #<struct Model label="Test">
|
|
345
322
|
pipe Failure("Danger!"), to(Model, :for) # Failure "Danger!"
|
346
323
|
----
|
347
324
|
|
348
|
-
=====
|
325
|
+
===== try
|
349
326
|
|
350
327
|
Allows you to try an operation which may fail while catching any exceptions as a failure for further processing. You can catch a single exception by providing the exception as a single value or multiple exceptions as an array of values.
|
351
328
|
|
352
|
-
|
353
|
-
|
354
|
-
Processes and answers a success only if there are no exceptions. Otherwise, captures any error as a failure.
|
355
|
-
|
356
|
-
*Example*
|
329
|
+
Accepts and answers a success if there are no exceptions. Otherwise, captures any error as a failure. Example:
|
357
330
|
|
358
331
|
[source,ruby]
|
359
332
|
----
|
@@ -370,15 +343,11 @@ pipe Failure("Danger!"), try(:to_json, catch: JSON::ParserError)
|
|
370
343
|
# Failure "Danger!"
|
371
344
|
----
|
372
345
|
|
373
|
-
=====
|
346
|
+
===== use
|
374
347
|
|
375
348
|
Allows you to use another pipe to build a superpipe, use an object that adheres to the {command_pattern_link}, or any function which answers a {dry_monads_link} `Result` object. In other words, you can use _use_ any object which responds to `#call` that answers a {dry_monads_link} `Result` object. This is great for chaining multiple pipes together (i.e. superpipes).
|
376
349
|
|
377
|
-
|
378
|
-
|
379
|
-
Processes a success only while sending the unwrapped object to the command (or pipe) for further processing. A {dry_monads_link} `Result` is expected to be answered by the command.
|
380
|
-
|
381
|
-
*Example*
|
350
|
+
Accepts a success while sending the unwrapped object to the command (or pipe) for further processing. A {dry_monads_link} `Result` is expected to be answered by the command. Example:
|
382
351
|
|
383
352
|
[source,ruby]
|
384
353
|
----
|
@@ -388,19 +357,13 @@ pipe 3, use(function) # Success 9
|
|
388
357
|
pipe Failure("Danger!"), use(function) # Failure "Danger!"
|
389
358
|
----
|
390
359
|
|
391
|
-
=====
|
360
|
+
===== validate
|
392
361
|
|
393
362
|
Allows you to use an contract for validating an object. This is especially useful when using {dry_schema_link}, {dry_validation_link}, or any contract that responds to `#call` and answers a `Result`.
|
394
363
|
|
395
|
-
|
396
|
-
|
397
|
-
By default, the `:as` key's value is `nil``. Use `:to_h`, for example, as the value for automatic casting to a `Hash`. You can also pass in any value to the `:as` key which is a valid method that the contract's result will respond to.
|
364
|
+
By default, the `:as` key's value is `nil`. Use `:to_h`, for example, as the value for automatic casting to a `Hash`. You can also pass in any value to the `:as` key which is a valid method that the contract's result will respond to.
|
398
365
|
|
399
|
-
|
400
|
-
|
401
|
-
Processes a success only. A success will be rewrapped as a success if the `:as` keyword is supplied. Otherwise, any failure is immediately passed through.
|
402
|
-
|
403
|
-
*Example*
|
366
|
+
Accepts a success and rewraps as a success if the `:as` keyword is supplied. Otherwise, any failure is immediately passed through. Example:
|
404
367
|
|
405
368
|
[source,ruby]
|
406
369
|
----
|
@@ -416,6 +379,8 @@ pipe Failure("Danger!"), validate(schema)
|
|
416
379
|
# Failure "Danger!"
|
417
380
|
----
|
418
381
|
|
382
|
+
💡 Ensure you enable the {dry_monads_link} extension for {dry_schema_link} and/or {dry_validation_link} when using this step since this step expects the contract to respond to the `#to_monad` message.
|
383
|
+
|
419
384
|
==== Advanced
|
420
385
|
|
421
386
|
Several options are available should you need to advance beyond the basic steps. Each is described in detail below.
|
@@ -577,13 +542,13 @@ class Three
|
|
577
542
|
end
|
578
543
|
----
|
579
544
|
|
580
|
-
Notice, `One` and `Two` are
|
545
|
+
Notice, `One` and `Two` are normal pipeable objects with individual steps while `Three` injects both `One` and `Two` as dependencies and then subsequently pipes them together in the `#call` method via the `use` step. This is the power of a superpipe. ...and, yes, a superpipe can be an individual step in some other object. Turtles all the way down (or up). 😉
|
581
546
|
|
582
|
-
Again, the above is contrived but hopefully
|
547
|
+
Again, the above is contrived but hopefully illustrates how you can build more complex architectures from smaller pipes.
|
583
548
|
|
584
549
|
=== Containers
|
585
550
|
|
586
|
-
Should you not want the basic steps, need custom steps, or a hybrid of default and custom steps, you can define your own container and provide
|
551
|
+
Should you not want the basic steps, need custom steps, or a hybrid of default and custom steps, you can define your own container -- using the {containable_link} gem -- and provide the container as an argument to `.[]` when including pipeable behavior. Example:
|
587
552
|
|
588
553
|
[source,ruby]
|
589
554
|
----
|
@@ -636,7 +601,7 @@ The architecture of this gem is built on top of the following concepts and gems:
|
|
636
601
|
* {function_composition_link}: Made possible through the use of the `\#>>` and `#<<` methods on the link:https://rubyapi.org/3.1/o/method[Method] and link:https://rubyapi.org/3.1/o/proc[Proc] objects.
|
637
602
|
* {containable_link}: Allows related dependencies to be grouped together for injection as desired.
|
638
603
|
* {dry_monads_link}: Critical to ensuring the entire pipeline of steps adhere to the {railway_pattern_link} and leans heavily on the `Result` object.
|
639
|
-
* link:https://alchemists.io/projects/marameters[Marameters]: Through the use of the `.categorize` method, dynamic message passing is possible by inspecting the
|
604
|
+
* link:https://alchemists.io/projects/marameters[Marameters]: Through the use of the `.categorize` method, dynamic message passing is possible by inspecting the object's method parameters.
|
640
605
|
|
641
606
|
=== Style Guide
|
642
607
|
|
@@ -657,7 +622,7 @@ If you need to debug (i.e. {debug_link}) your pipe, use a lambda. Example:
|
|
657
622
|
----
|
658
623
|
pipe data,
|
659
624
|
check(/Book.+Price/, :match?),
|
660
|
-
-> result { binding.break },
|
625
|
+
-> result { binding.break; result }, # Breakpoint
|
661
626
|
:parse
|
662
627
|
----
|
663
628
|
|
@@ -671,12 +636,12 @@ The following might be of aid to as you implement your own pipes.
|
|
671
636
|
|
672
637
|
If you get a `TypeError: Step must be functionally composable and answer a monad`, it means:
|
673
638
|
|
674
|
-
. The step must be a `Proc`, `Method`, or
|
675
|
-
. The step doesn't answer a result monad (i.e. `Success
|
639
|
+
. The step must be a `Proc`, `Method`, or any object which responds to `\#>>`, `#<<`, and `#call`.
|
640
|
+
. The step doesn't answer a result monad (i.e. `Success object` or `Failure object`).
|
676
641
|
|
677
642
|
==== No Method Errors
|
678
643
|
|
679
|
-
If you get a `NoMethodError: undefined method
|
644
|
+
If you get a `NoMethodError: undefined method success?` exception, this might mean that you forgot to add a comma after one of your steps. Example:
|
680
645
|
|
681
646
|
[source,ruby]
|
682
647
|
----
|
@@ -687,7 +652,7 @@ pipe "https://www.wikipedia.org",
|
|
687
652
|
|
688
653
|
# Invalid
|
689
654
|
pipe "https://www.wikipedia.org",
|
690
|
-
to(client, :get)
|
655
|
+
to(client, :get) # Missing comma.
|
691
656
|
try(:parse, catch: HTTP::Error)
|
692
657
|
----
|
693
658
|
|
data/pipeable.gemspec
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pipeable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brooke Kuhlmann
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
|
36
36
|
gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2024-05-
|
38
|
+
date: 2024-05-12 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: containable
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- lib/pipeable/composable.rb
|
124
124
|
- lib/pipeable/pipe.rb
|
125
125
|
- lib/pipeable/steps/abstract.rb
|
126
|
+
- lib/pipeable/steps/amap.rb
|
126
127
|
- lib/pipeable/steps/as.rb
|
127
128
|
- lib/pipeable/steps/bind.rb
|
128
129
|
- lib/pipeable/steps/check.rb
|
metadata.gz.sig
CHANGED
Binary file
|