Module: Boson::Pipe

Extended by:
Pipe
Included in:
Pipe
Defined in:
lib/boson/pipe.rb

Overview

This module passes an original command’s return value through methods/commands specified as pipe options. Pipe options are processed in this order:

  • A :query option searches an array of objects or hashes using Pipes.query_pipe.

  • A :sort option sorts an array of objects or hashes using Pipes.sort_pipe.

  • A :reverse_sort pipe option reverses an array.

  • A :pipes option takes an array of commands that modify the return value using Pipes.pipes_pipe.

  • All user-defined pipe options (:pipe_options key in Repo.config) are processed in random order.

Some points:

  • User-defined pipes call a command (the option’s name by default). It’s the user’s responsibility to have this command loaded when used. The easiest way to do this is by adding the pipe command’s library to :defaults in main config.

  • By default, pipe commands do not modify the value their given. This means you can activate multiple pipes using a method’s original return value.

  • A pipe command expects a command’s return value as its first argument. If the pipe option takes an argument, it’s passed on as a second argument.

  • When piping occurs in relation to rendering depends on the Hirb view. With the default Hirb view, piping occurs occurs in the middle of the rendering, after Hirb has converted the return value into an array of hashes. If using a custom Hirb view, piping occurs before rendering.

  • What the pipe command should expect as a return value depends on the type of command. If it’s a command rendered with hirb’s tables, the return value is a an array of hashes. For everything else, it’s the method’s original return value.

User Pipes

User pipes have the following attributes which alter their behavior:

:pipe

Pipe command the pipe executes when called. Default is the pipe’s name.

:env

Boolean which enables passing an additional hash to the pipe command. This hash contains information from the first command’s input with the following keys: :args (command’s arguments), :options (command’s options), :global_options (command’s global options) and :config (a command’s configuration hash). Default is false.

:filter

Boolean which has the pipe command modify the original command’s output with the value it returns. Default is false.

:no_render

Boolean to turn off auto-rendering of the original command’s final output. Only applicable to :filter enabled pipes. Default is false.

:solo

Boolean to indicate this pipe can’t run with other user pipes or pipes from :pipes option. If a user calls multiple solo pipes, only the first one detected is called.

Repo Config

This class adds the following key to the main repo config:

:pipe_options

Hash of options available to all option commands for piping (see Pipe). A pipe option has the normal option attributes and these:

  • :pipe: Specifies the command to call when piping. Defaults to the pipe’s option name.

  • :filter: Boolean which indicates that the pipe command will modify its input with what it returns. Default is false.

User Pipes Example

Let’s say you want to have two commands, browser and copy, you want to make available as pipe options:

# Opens url in browser. This command already ships with Boson.
def browser(url)
  system('open', url)
end

# Copy to clipboard
def copy(str)
  IO.popen('pbcopy', 'w+') {|clipboard| clipboard.write(str)}
end

To configure them, drop the following config in ~/.boson/config/boson.yml:

:pipe_options:
  :browser:
    :type: :boolean
    :desc: Open in browser
  :copy:
    :type: :boolean
    :desc: Copy to clipboard

Now for any command that returns a url string, these pipe options can be turned on to execute the url.

Some examples of these options using commands from my libraries:

# Creates a gist and then opens url in browser and copies it.
$ cat some_file | boson gist -bC        # or cat some_file | boson gist --browser --copy

# Generates rdoc in current directory and then opens it in browser
irb>> rdoc '-b'    # or rdoc '--browser'

Defined Under Namespace

Modules: TableCallbacks

Instance Method Summary collapse

Instance Method Details

#add_pipes(hash) ⇒ Object

A hash that defines user pipes in the same way as the :pipe_options key in Repo.config. This method should be called when a pipe’s library is loading.



93
94
95
# File 'lib/boson/pipe.rb', line 93

def add_pipes(hash)
  pipe_options.merge! setup_pipes(hash)
end

#any_no_render_pipes?(global_opt) ⇒ Boolean

Returns:

  • (Boolean)


136
137
138
139
# File 'lib/boson/pipe.rb', line 136

def any_no_render_pipes?(global_opt)
  !(pipes = pipes_to_process(global_opt)).empty? &&
    pipes.any? {|e| pipe(e)[:no_render] }
end

#get_env(key, global_opt) ⇒ Object



128
129
130
131
132
133
134
# File 'lib/boson/pipe.rb', line 128

def get_env(key, global_opt)
  { :global_options=>global_opt.merge(:delete_callbacks=>[:z_boson_pipes]),
    :config=>(@env[:config].dup[key] || {}),
    :args=>@env[:args],
    :options=>@env[:options] || {}
  }
end

#internal_pipes(global_opt) ⇒ Object

:stopdoc:



98
99
100
101
102
# File 'lib/boson/pipe.rb', line 98

def internal_pipes(global_opt)
  internals = [:query, :sort, :reverse_sort, :pipes]
  internals.delete(:pipes) if pipes_to_process(global_opt).any? {|e| pipe(e)[:solo] }
  internals
end

#pipe(key) ⇒ Object



112
113
114
# File 'lib/boson/pipe.rb', line 112

def pipe(key)
  pipe_options[key] || {}
end

#pipe_optionsObject



104
105
106
# File 'lib/boson/pipe.rb', line 104

def pipe_options
  @pipe_options ||= setup_pipes(Boson.repo.config[:pipe_options] || {})
end

#pipes_to_process(global_opt) ⇒ Object



141
142
143
144
# File 'lib/boson/pipe.rb', line 141

def pipes_to_process(global_opt)
  pipes = (global_opt.keys & pipe_options.keys)
  (solo_pipe = pipes.find {|e| pipe(e)[:solo] }) ? [solo_pipe] : pipes
end

#process_pipes(obj, options) ⇒ Object

Main method which processes all pipe commands, both default and user-defined ones.



84
85
86
87
88
89
# File 'lib/boson/pipe.rb', line 84

def process_pipes(obj, options)
  internal_pipes(options).each {|pipe|
    obj = Pipes.send("#{pipe}_pipe", obj, options[pipe]) if options[pipe]
  }
  process_user_pipes(obj, options)
end

#process_user_pipes(result, global_opt) ⇒ Object

global_opt can come from Hirb callback or Scientist



117
118
119
120
121
122
123
124
125
126
# File 'lib/boson/pipe.rb', line 117

def process_user_pipes(result, global_opt)
  pipes_to_process(global_opt).each {|e|
    args = [pipe(e)[:pipe], result]
    args << global_opt[e] unless pipe(e)[:type] == :boolean
    args << get_env(e, global_opt) if pipe(e)[:env]
    pipe_result = Boson.invoke(*args)
    result = pipe_result if pipe(e)[:filter]
  }
  result
end

#scientist_process(object, global_opt, env = {}) ⇒ Object

Process pipes for Scientist



77
78
79
80
81
# File 'lib/boson/pipe.rb', line 77

def scientist_process(object, global_opt, env={})
  @env = env
  [:query, :sort, :reverse_sort].each {|e| global_opt.delete(e) } unless object.is_a?(Array)
  process_pipes(object, global_opt)
end

#setup_pipes(hash) ⇒ Object



108
109
110
# File 'lib/boson/pipe.rb', line 108

def setup_pipes(hash)
  hash.each {|k,v| v[:pipe] ||= k }
end