blackwinter-pru 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +7 -0
- data/Gemfile.lock +26 -0
- data/Rakefile +22 -0
- data/Readme.md +71 -0
- data/VERSION +1 -0
- data/bin/pru +80 -0
- data/lib/pru.rb +26 -0
- data/lib/pru/core_ext.rb +2 -0
- data/lib/pru/core_ext/array.rb +29 -0
- data/lib/pru/core_ext/symbol.rb +7 -0
- data/lib/pru/helper.rb +41 -0
- data/pru.gemspec +48 -0
- data/spec/pru_spec.rb +79 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/test.txt +5 -0
- metadata +71 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.5.2)
|
7
|
+
bundler (~> 1.0.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rake (0.8.7)
|
11
|
+
rspec (2.4.0)
|
12
|
+
rspec-core (~> 2.4.0)
|
13
|
+
rspec-expectations (~> 2.4.0)
|
14
|
+
rspec-mocks (~> 2.4.0)
|
15
|
+
rspec-core (2.4.0)
|
16
|
+
rspec-expectations (2.4.0)
|
17
|
+
diff-lcs (~> 1.1.2)
|
18
|
+
rspec-mocks (2.4.0)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
jeweler
|
25
|
+
rake
|
26
|
+
rspec (~> 2)
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
|
4
|
+
Jeweler::Tasks.new { |gem|
|
5
|
+
gem.name = 'blackwinter-pru'
|
6
|
+
gem.summary = 'Pipeable Ruby - forget about grep/sed/awk/wc... use pure, readable Ruby!'
|
7
|
+
gem.email = 'michael@grosser.it'
|
8
|
+
gem.homepage = "http://github.com/grosser/#{gem.name}"
|
9
|
+
gem.authors = ['Michael Grosser']
|
10
|
+
}
|
11
|
+
|
12
|
+
Jeweler::GemcutterTasks.new
|
13
|
+
rescue LoadError
|
14
|
+
puts 'Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run specs'
|
18
|
+
task :spec do
|
19
|
+
sh 'rspec spec/'
|
20
|
+
end
|
21
|
+
|
22
|
+
task :default => :spec
|
data/Readme.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
Pipeable Ruby - forget about grep / sed / awk / wc ... use pure, readable Ruby!
|
2
|
+
|
3
|
+
Install
|
4
|
+
=======
|
5
|
+
sudo gem install pru
|
6
|
+
|
7
|
+
Working with rvm / many gemsets -> only install once (1.9 recommended)
|
8
|
+
|
9
|
+
rvm 1.9.2 exec gem install pru
|
10
|
+
echo 'alias pru="rvm 1.9.2 exec pru"' >> ~/.bash_profile
|
11
|
+
|
12
|
+
Usage
|
13
|
+
=====
|
14
|
+
pru supports mapping and reducing.<br/><br/>
|
15
|
+
Map works on each line as String<br/>
|
16
|
+
Reduce works on all lines as Array<br/>
|
17
|
+
|
18
|
+
something | pru 'map' ['reduce']
|
19
|
+
something | pru -r 'reduce'
|
20
|
+
|
21
|
+
### Examples
|
22
|
+
|
23
|
+
# grep --- all lines including foo
|
24
|
+
ls -al | grep foo
|
25
|
+
ls -al | pru /foo/
|
26
|
+
|
27
|
+
# grep --- all lines including current date
|
28
|
+
ls -al | grep $(date +"%Y-%m-%d")
|
29
|
+
ls -al | pru 'include?(Time.now.strftime("%Y-%m-%d"))'
|
30
|
+
|
31
|
+
# grep --- all lines including foo but not self
|
32
|
+
ps -ef | grep foo | grep -v grep
|
33
|
+
ps -ef | pru 'include?("foo") and not include?("pru")'
|
34
|
+
|
35
|
+
# awk --- return second item
|
36
|
+
ls -al | awk '{print $2}'
|
37
|
+
ls -al | pru 'split(" ")[1]'
|
38
|
+
|
39
|
+
# awk --- count and average of all integers on second position
|
40
|
+
ls -al | awk '{ s += $2; } END {print "average" ,int(s/NR);print "count ",int(NR)}'
|
41
|
+
ls -al | pru 'split(" ")[1]' '"average #{mean(&:to_i)}\ncount #{size}"'
|
42
|
+
|
43
|
+
# wc --- count lines
|
44
|
+
ls -al | wc -l
|
45
|
+
ls -al | pru -r 'size'
|
46
|
+
|
47
|
+
# sed -- replace a 5 with five
|
48
|
+
ls -al | sed 's/5/five/'
|
49
|
+
ls -al | pru 'gsub(/5/,"five")'
|
50
|
+
|
51
|
+
# every second line
|
52
|
+
ls -al | pru 'i % 2 == 0'
|
53
|
+
|
54
|
+
# paste-friendly mime-types
|
55
|
+
curl https://github.com/mattetti/mimetype-fu/raw/master/lib/mime_types.yml | grep image | pru 'gsub(/(.*): (.*)/, %{"\\1" => "\\2",})'
|
56
|
+
|
57
|
+
# number of files by date:
|
58
|
+
ls -al | pru 'split(" ")[5]' 'grouped.map{|d, f| "#{d} : #{f.size}" }'
|
59
|
+
|
60
|
+
# quotes inside a string
|
61
|
+
something | pru 'include?(%{"string"})'
|
62
|
+
|
63
|
+
Authors
|
64
|
+
=======
|
65
|
+
### [Contributors](http://github.com/grosser/pru/contributors)
|
66
|
+
- [John Hobbs](http://github.com/jmhobbs)
|
67
|
+
- [Vasiliy Ermolovich](http://github.com/nashby)
|
68
|
+
|
69
|
+
[Michael Grosser](http://grosser.it)<br/>
|
70
|
+
michael@grosser.it<br/>
|
71
|
+
Hereby placed under public domain, do what you want, just do not hold me accountable...
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.4
|
data/bin/pru
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
autoload :Pru, 'pru'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
usage = <<-EOS
|
7
|
+
Pipeable Ruby
|
8
|
+
|
9
|
+
Use ruby in your pipes, forget about grep/sed/awk/wc...
|
10
|
+
|
11
|
+
Map works on each line as String.
|
12
|
+
Reduce works on all lines as Array (optional or via -e/-f).
|
13
|
+
|
14
|
+
Usage:
|
15
|
+
something | pru 'map' ['reduce']
|
16
|
+
something | pru -e 'reduce'
|
17
|
+
EOS
|
18
|
+
|
19
|
+
options = {}
|
20
|
+
|
21
|
+
OptionParser.new { |opts|
|
22
|
+
opts.banner = usage
|
23
|
+
|
24
|
+
opts.separator ''
|
25
|
+
opts.separator 'Options:'
|
26
|
+
|
27
|
+
opts.on('-m', '--map-file FILE', 'Map via FILE') { |file|
|
28
|
+
options[:map] = Pru::Helper.load_file(file, :map)
|
29
|
+
}
|
30
|
+
|
31
|
+
opts.separator ''
|
32
|
+
|
33
|
+
opts.on('-e', '--execute CODE', 'Reduce via CODE') { |code|
|
34
|
+
options[:reduce] = code
|
35
|
+
}
|
36
|
+
|
37
|
+
opts.on('-f', '--reduce-file FILE', 'Reduce via FILE') { |file|
|
38
|
+
options[:reduce] = Pru::Helper.load_file(file, :reduce)
|
39
|
+
}
|
40
|
+
|
41
|
+
opts.separator ''
|
42
|
+
opts.separator 'Load options:'
|
43
|
+
|
44
|
+
opts.on('-I', '--libdir LIBDIR', 'Include LIBDIR in the search path for required modules') { |dir|
|
45
|
+
$LOAD_PATH << dir
|
46
|
+
}
|
47
|
+
|
48
|
+
opts.on('-r', '--require MODULE', 'Require MODULE before executing any code') { |mod|
|
49
|
+
require mod
|
50
|
+
}
|
51
|
+
|
52
|
+
opts.separator ''
|
53
|
+
opts.separator 'Generic options:'
|
54
|
+
|
55
|
+
opts.on('-h', '--help', 'Print this help message and exit') {
|
56
|
+
puts opts
|
57
|
+
exit
|
58
|
+
}
|
59
|
+
|
60
|
+
opts.on('--version', 'Print program version and exit') {
|
61
|
+
puts "#{File.basename($0)} v#{Pru::VERSION}"
|
62
|
+
exit
|
63
|
+
}
|
64
|
+
}.parse!
|
65
|
+
|
66
|
+
abort usage if ARGV.size > 2
|
67
|
+
map, reduce = ARGV
|
68
|
+
|
69
|
+
map ||= options[:map]
|
70
|
+
reduce ||= options[:reduce]
|
71
|
+
|
72
|
+
map = 'true' if map.nil? || map.strip.empty?
|
73
|
+
|
74
|
+
if reduce
|
75
|
+
results = []
|
76
|
+
Pru.map($stdin, map) { |x| results << x }
|
77
|
+
puts Pru.reduce(results, reduce)
|
78
|
+
else
|
79
|
+
Pru.map($stdin, map) { |x| puts x }
|
80
|
+
end
|
data/lib/pru.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'pru/helper'
|
2
|
+
require 'pru/core_ext'
|
3
|
+
|
4
|
+
module Pru
|
5
|
+
|
6
|
+
extend self
|
7
|
+
|
8
|
+
VERSION = File.read(File.join(File.dirname(__FILE__), '..', 'VERSION')).strip
|
9
|
+
|
10
|
+
def map(io, code)
|
11
|
+
io.each_line { |line|
|
12
|
+
line.chomp!
|
13
|
+
|
14
|
+
case result = line.instance_eval(code) or next
|
15
|
+
when true then yield line
|
16
|
+
when Regexp then yield line if line =~ result
|
17
|
+
else yield result
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def reduce(array, code)
|
23
|
+
array.instance_eval(code)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/pru/core_ext.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
class Array
|
2
|
+
|
3
|
+
# http://madeofcode.com/posts/74-ruby-core-extension-array-sum
|
4
|
+
def sum(method = nil)
|
5
|
+
if block_given?
|
6
|
+
raise ArgumentError, 'You cannot pass both a block and a method' if method
|
7
|
+
inject(0) { |s, x| s + yield(x) }
|
8
|
+
elsif method
|
9
|
+
inject(0) { |s, x| s + x.send(method) }
|
10
|
+
else
|
11
|
+
inject(0) { |s, x| s + x }
|
12
|
+
end
|
13
|
+
end unless method_defined?(:sum)
|
14
|
+
|
15
|
+
def mean(method = nil, &block)
|
16
|
+
sum(method, &block) / size.to_f
|
17
|
+
end unless method_defined?(:mean)
|
18
|
+
|
19
|
+
def grouped
|
20
|
+
group_by { |x| x }
|
21
|
+
end unless method_defined?(:grouped)
|
22
|
+
|
23
|
+
def group_by
|
24
|
+
hash = {}
|
25
|
+
each { |x| hash[yield(x)] = x }
|
26
|
+
hash
|
27
|
+
end unless method_defined?(:group_by)
|
28
|
+
|
29
|
+
end
|
data/lib/pru/helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Pru
|
2
|
+
|
3
|
+
module Helper
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
EXTENSIONS = ['', '.pru', '.rb']
|
8
|
+
|
9
|
+
def load_file(file, type)
|
10
|
+
if _file = find_file(file)
|
11
|
+
file = _file
|
12
|
+
else
|
13
|
+
home = begin
|
14
|
+
require 'nuggets/env/user_home'
|
15
|
+
ENV.user_home
|
16
|
+
rescue LoadError
|
17
|
+
File.expand_path('~')
|
18
|
+
end
|
19
|
+
|
20
|
+
if _file = find_file(File.join(home, '.pru', type.to_s, file))
|
21
|
+
file = _file
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
File.read(file)
|
27
|
+
rescue => err
|
28
|
+
abort "#{$0}: #{err}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_file(file, extensions = EXTENSIONS)
|
33
|
+
extensions.find { |extension|
|
34
|
+
_file = file + extension
|
35
|
+
return _file if File.exist?(_file)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/pru.gemspec
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{pru}
|
8
|
+
s.version = "0.1.4"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Michael Grosser"]
|
12
|
+
s.date = %q{2011-04-21}
|
13
|
+
s.default_executable = %q{pru}
|
14
|
+
s.email = %q{michael@grosser.it}
|
15
|
+
s.executables = ["pru"]
|
16
|
+
s.files = [
|
17
|
+
"Gemfile",
|
18
|
+
"Gemfile.lock",
|
19
|
+
"Rakefile",
|
20
|
+
"Readme.md",
|
21
|
+
"VERSION",
|
22
|
+
"bin/pru",
|
23
|
+
"lib/pru.rb",
|
24
|
+
"lib/pru/core_ext.rb",
|
25
|
+
"pru.gemspec",
|
26
|
+
"spec/pru_spec.rb",
|
27
|
+
"spec/spec_helper.rb",
|
28
|
+
"spec/test.txt"
|
29
|
+
]
|
30
|
+
s.homepage = %q{http://github.com/grosser/pru}
|
31
|
+
s.require_paths = ["lib"]
|
32
|
+
s.rubygems_version = %q{1.4.2}
|
33
|
+
s.summary = %q{Pipeable Ruby - forget about grep / sed / awk / wc ... use pure, readable Ruby!}
|
34
|
+
s.test_files = [
|
35
|
+
"spec/pru_spec.rb",
|
36
|
+
"spec/spec_helper.rb"
|
37
|
+
]
|
38
|
+
|
39
|
+
if s.respond_to? :specification_version then
|
40
|
+
s.specification_version = 3
|
41
|
+
|
42
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
43
|
+
else
|
44
|
+
end
|
45
|
+
else
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
data/spec/pru_spec.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Pru do
|
4
|
+
|
5
|
+
it 'has a VERSION' do
|
6
|
+
Pru::VERSION.should =~ /\A\d+\.\d+\.\d+\z/
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'map' do
|
10
|
+
|
11
|
+
it 'selects' do
|
12
|
+
%x{ls -l | #{PRU_CMD} 'include?("G")'}.split($/).size.should == 2
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'selects via regex' do
|
16
|
+
%x{ls -l | #{PRU_CMD} /G/}.split($/).size.should == 2
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'selects via $.' do
|
20
|
+
%x{cat spec/test.txt | #{PRU_CMD} '$.'}.split($/)[0...3].should == %w[1 2 3]
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'maps' do
|
24
|
+
%x{echo abc | #{PRU_CMD} 'gsub(/a/, "b")'}.should == "bbc\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'selects and reduces' do
|
28
|
+
%x{cat spec/test.txt | #{PRU_CMD} 'include?("abc")' 'size'}.should == "3\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'opens files' do
|
32
|
+
%x{echo spec/test.txt | #{PRU_CMD} 'File.read(self)'}.should == File.read('spec/test.txt')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'open preserves whitespaces' do
|
36
|
+
%x{echo ' ab\tcd ' | #{PRU_CMD} 'self'}.should == " ab\tcd \n"
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'works with continuous input' do
|
40
|
+
results = %x{ruby -e 'STDOUT.sync = true; puts 1; sleep 2; puts 1' | #{PRU_CMD} 'Time.now.to_i'}.split($/)
|
41
|
+
results.size.should == 2
|
42
|
+
results.uniq.size.should == 2 # called at a different time -> parses as you go
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'reduce' do
|
48
|
+
|
49
|
+
it 'reduces' do
|
50
|
+
%x{cat spec/test.txt | #{PRU_CMD} -e 'size'}.should == "5\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'prints arrays as newlines' do
|
54
|
+
%x{cat spec/test.txt | #{PRU_CMD} -e 'self'}.should == File.read('spec/test.txt')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'can sum' do
|
58
|
+
%x{cat spec/test.txt | #{PRU_CMD} -e 'sum(&:to_i)'}.should == "1212\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'can mean' do
|
62
|
+
%x{cat spec/test.txt | #{PRU_CMD} -e 'mean(&:to_i)'}.should == "242.4\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'can grouped' do
|
66
|
+
%x{cat spec/test.txt | #{PRU_CMD} -e 'grouped.map { |a, b| b.size }'}.should include("2\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'map and reduce' do
|
72
|
+
|
73
|
+
it 'selects with empty string and reduces' do
|
74
|
+
%x{cat spec/test.txt | #{PRU_CMD} '' 'size'}.should == "5\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: blackwinter-pru
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.4
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Grosser
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-04-21 00:00:00 +02:00
|
14
|
+
default_executable: pru
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description:
|
18
|
+
email: michael@grosser.it
|
19
|
+
executables:
|
20
|
+
- pru
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- Gemfile
|
27
|
+
- Gemfile.lock
|
28
|
+
- Rakefile
|
29
|
+
- Readme.md
|
30
|
+
- VERSION
|
31
|
+
- bin/pru
|
32
|
+
- lib/pru.rb
|
33
|
+
- lib/pru/core_ext.rb
|
34
|
+
- lib/pru/core_ext/array.rb
|
35
|
+
- lib/pru/core_ext/symbol.rb
|
36
|
+
- lib/pru/helper.rb
|
37
|
+
- pru.gemspec
|
38
|
+
- spec/pru_spec.rb
|
39
|
+
- spec/spec_helper.rb
|
40
|
+
- spec/test.txt
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/grosser/blackwinter-pru
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.4.2
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Pipeable Ruby - forget about grep/sed/awk/wc... use pure, readable Ruby!
|
69
|
+
test_files:
|
70
|
+
- spec/pru_spec.rb
|
71
|
+
- spec/spec_helper.rb
|