Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

method-pipeline

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

method-pipeline

  • 1.0.3
  • Rubygems
  • Socket score

Version published
Maintainers
1
Created
Source

The Pipeline Refinement module bundles a method duo that builds a clean and clever pure-Ruby solution to rightward method piping.

A reminder that Refinement modules are activated with using and last only for that module/class block or file (if top-level). See: refinements.rdoc (on docs.ruby-lang.org)

Synopsis Example

Here’s the example from Kernel#then straight off the Ruby 3.2 docs:

require 'open-uri'
require 'json'

construct_url(arguments).
  then {|url| URI(url).read }.
  then {|response| JSON.parse(response) }

With the new Refinement active: (Oh gosh, this looks like a brand-new language!)

using Pipeline

arguments.then_pipe(
  `construct_url`,
  `URI`,
  :read,
  JSON.`:parse
)

Walkthrough Introduction

We traditionally pipe methods leftwards as nesting arguments:

def parse(string) = …
do_stuff = ->(a){ … }

# This is even more incomprehensible if omitting round parentheses (poetry mode)
STDOUT.puts(     # different-scope method
  do_stuff.call( # Proc
    parse(       # same-scope method
      input
    )
  )
)

The trending Rightward Operations improve readability – especially for wordy expressions like the above – by matching English’s left-to-right writing direction. We currently accomplish this with Object#then and light-weight Procs:

input
  .then { parse _1 }
  .then { do_stuff.call _1 }
  .then { STDOUT.puts _1 }

We alternatively can deconstruct the corresponding #to_proc objects with &:

# heck, these `method` calls can't even go poetry mode
input
  .then(&method(:parse))
  .then(&do_stuff)
  .then(&STDOUT.method(:puts))

The Refinement module Pipeline introduces Object#then_pipe to eliminate repeating then(&…). It gives a beautiful vibe similar to that of the Pipe Operator |> in some other languages (namely Elixir).

using Pipeline

input.then_pipe(
  method(:parse),
  do_stuff,
  STDOUT.method(:puts)
)

However, unlike Lisp-1 languages like Python or JavaScript, Lisp-2s like Ruby face the additional challenge of namespace disambiguation. Ruby solves it with the reflection methods method & co., but, as seen above, their verbosity makes them eyesores inside otherwise elegant syntax. Therefore, Pipeline further improves the grammar by replacing the `…` syntax (powered by Kernel#`) with an alias of the bulky Object#method:

using Pipeline

input.then_pipe(
  `parse`,
  do_stuff,
  STDOUT.`:puts
)

Why #`?

  • It is the backend of both `…` and %x{…} syntaxes – self.`:meth can instead be %x:meth: or `meth`.
  • A Ruby script is not (strictly) a Shell script. User system differences aside, summoning subshells should be the last resort when there are no Ruby/Gem APIs. Dedicating the ` char to subshells is a waste; e.g., you typically see $(…) in bash rather than `…`. Pipeline assigns #` a new and recurrent purpose; it also aliases the original Kernel#` to Object#sys in the event of its preference.

Limitations

  • The new #` ignores method visibilities (private or protected).
    • This is a Ruby limitation – one can bypass visibilities with Object#method and Method#call regardless of this Refinement. A security engineer would love reflection APIs that respect visibilities.
    • The original design for the new #` was to match Object#public_method, but it couldn’t retrieve oneself’s own private and protected methods.
  • #then_pipe cannot pass additional arguments at each step.
    • The current Object#then-based solution is as good as it can get – There are no syntactical benefits to avoid a block while calling rightwards. Hey, unlike #then_pipe, it welcomes (inner) blocks.
      # a lambda – a Proc with fixed arities, unlike regula-o’ procs (or blocks)
      do_stuff = ->(a, o, z){ … }
      
      # This essentially wraps `do_stuff` in a one-arg block (as in F#).
      # The `_1` resembles Hack’s special pipe variable `$$`.
      o.then { do_stuff.(a, _1, z) }
      # The previous, adapted for `then_pipe`
      o.then_pipe ->{ do_stuff.(a, _1, z) }
      # Pure-rightward solution
      [a, o, b].then { do_stuff.(*_1) }
      

Miniblog: My insights on a Pipeline Operator for Ruby

https://gist.github.com/ParadoxV5/4f563e609decbdac07d40e5f2dead751

License

Copyright (c) 2023 ParadoxV5

Licensed under the Universal Permissive License v 1.0

FAQs

Package last updated on 26 Jul 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc