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.

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.



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

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

#any_no_render_pipes?(global_opt) ⇒ Boolean

Returns:

  • (Boolean)


127
128
129
130
# File 'lib/boson/pipe.rb', line 127

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



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

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:



89
90
91
92
93
# File 'lib/boson/pipe.rb', line 89

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



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

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

#pipe_optionsObject



95
96
97
# File 'lib/boson/pipe.rb', line 95

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

#pipes_to_process(global_opt) ⇒ Object



132
133
134
135
# File 'lib/boson/pipe.rb', line 132

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.



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

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



108
109
110
111
112
113
114
115
116
117
# File 'lib/boson/pipe.rb', line 108

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



68
69
70
71
72
# File 'lib/boson/pipe.rb', line 68

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



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

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