ru2 2.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +7 -0
- data/Appraisals +11 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +324 -0
- data/Rakefile +11 -0
- data/bin/ru +13 -0
- data/doc/help.erb +33 -0
- data/doc/logo.png +0 -0
- data/gemfiles/activesupport_3.gemfile +7 -0
- data/gemfiles/activesupport_3.gemfile.lock +46 -0
- data/gemfiles/activesupport_4.gemfile +7 -0
- data/gemfiles/activesupport_4.gemfile.lock +53 -0
- data/gemfiles/activesupport_5.gemfile +7 -0
- data/gemfiles/activesupport_5.gemfile.lock +52 -0
- data/lib/ru/array.rb +88 -0
- data/lib/ru/file.rb +94 -0
- data/lib/ru/iterator.rb +56 -0
- data/lib/ru/option_printer.rb +33 -0
- data/lib/ru/process.rb +121 -0
- data/lib/ru/stream.rb +126 -0
- data/lib/ru/version.rb +3 -0
- data/lib/ru.rb +7 -0
- data/ru.gemspec +20 -0
- data/spec/examples/misc_examples_spec.rb +40 -0
- data/spec/examples/sed_examples_spec.rb +95 -0
- data/spec/examples/stream_examples_spec.rb +136 -0
- data/spec/fixtures/files/access.log +5 -0
- data/spec/fixtures/files/bar.txt +1 -0
- data/spec/fixtures/files/foo.txt +3 -0
- data/spec/lib/array_spec.rb +38 -0
- data/spec/lib/iterator_spec.rb +72 -0
- data/spec/lib/process_spec.rb +126 -0
- data/spec/lib/stream_spec.rb +41 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/fixtures_helper.rb +6 -0
- data/spec/support/process_helper.rb +30 -0
- metadata +127 -0
data/lib/ru/array.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module Ru
|
2
|
+
class Array
|
3
|
+
def initialize(array)
|
4
|
+
@data = array.to_a
|
5
|
+
end
|
6
|
+
|
7
|
+
def each_line
|
8
|
+
Ru::Iterator.new(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def files
|
12
|
+
@data.map! do |line|
|
13
|
+
Ru::File.new(line)
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def format(format='l')
|
19
|
+
@data.map! do |item|
|
20
|
+
item.format(format)
|
21
|
+
end
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def grep(pattern)
|
26
|
+
if pattern.kind_of?(String)
|
27
|
+
pattern = Regexp.new(pattern)
|
28
|
+
end
|
29
|
+
select! do |item|
|
30
|
+
item.to_s =~ pattern
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def map(method=nil, *args, &block)
|
36
|
+
if method.nil? && !block_given?
|
37
|
+
to_a.map
|
38
|
+
elsif method.nil?
|
39
|
+
array = to_a.map(&block)
|
40
|
+
self.class.new(array)
|
41
|
+
else
|
42
|
+
array = to_a.map { |item| item.send(method, *args) }
|
43
|
+
self.class.new(array)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def select(*args, &block)
|
48
|
+
delegate_to_array(:select, *args, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_a
|
52
|
+
@data
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_ary
|
56
|
+
to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
to_a.join("\n")
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_self
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def ==(other)
|
68
|
+
self.to_a == other.to_a
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def method_missing(method, *args, &block)
|
74
|
+
delegate_to_array(method, *args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
def delegate_to_array(method, *args, &block)
|
78
|
+
result = @data.send(method, *args, &block)
|
79
|
+
if result.kind_of? Enumerator::Lazy
|
80
|
+
Ru::Stream.new(result)
|
81
|
+
elsif result.kind_of? ::Array
|
82
|
+
self.class.new(result)
|
83
|
+
else
|
84
|
+
result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/ru/file.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'etc'
|
2
|
+
|
3
|
+
module Ru
|
4
|
+
class File
|
5
|
+
def initialize(path)
|
6
|
+
@path = path
|
7
|
+
end
|
8
|
+
|
9
|
+
def basename
|
10
|
+
delegate_to_file(:basename)
|
11
|
+
end
|
12
|
+
|
13
|
+
def ctime
|
14
|
+
delegate_to_file(:ctime)
|
15
|
+
end
|
16
|
+
|
17
|
+
def extname
|
18
|
+
delegate_to_file(:extname)
|
19
|
+
end
|
20
|
+
|
21
|
+
def format(format='l')
|
22
|
+
separator = "\t"
|
23
|
+
case format
|
24
|
+
when 'l'
|
25
|
+
datetime = ctime.strftime(%w{%Y-%m-%d %H:%M}.join(separator))
|
26
|
+
return [omode, owner, group, size, datetime, name].join(separator)
|
27
|
+
else
|
28
|
+
raise 'format not supported'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def ftype
|
33
|
+
delegate_to_file(:ftype)
|
34
|
+
end
|
35
|
+
|
36
|
+
def gid
|
37
|
+
delegate_to_stat(:gid)
|
38
|
+
end
|
39
|
+
|
40
|
+
def group
|
41
|
+
Etc.getgrgid(gid).name
|
42
|
+
end
|
43
|
+
|
44
|
+
def mode
|
45
|
+
delegate_to_stat(:mode)
|
46
|
+
end
|
47
|
+
|
48
|
+
def mtime
|
49
|
+
delegate_to_file(:mtime)
|
50
|
+
end
|
51
|
+
|
52
|
+
def omode
|
53
|
+
'%o' % world_readable?
|
54
|
+
end
|
55
|
+
|
56
|
+
def owner
|
57
|
+
Etc.getpwuid(uid).name
|
58
|
+
end
|
59
|
+
|
60
|
+
def size
|
61
|
+
delegate_to_file(:size)
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
name
|
66
|
+
end
|
67
|
+
|
68
|
+
def uid
|
69
|
+
delegate_to_stat(:uid)
|
70
|
+
end
|
71
|
+
|
72
|
+
def world_readable?
|
73
|
+
delegate_to_stat(:world_readable?)
|
74
|
+
end
|
75
|
+
|
76
|
+
def <=>(other)
|
77
|
+
name <=> other.name
|
78
|
+
end
|
79
|
+
|
80
|
+
alias_method :name, :basename
|
81
|
+
alias_method :created_at, :ctime
|
82
|
+
alias_method :updated_at, :mtime
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def delegate_to_file(method)
|
87
|
+
::File.send(method, @path)
|
88
|
+
end
|
89
|
+
|
90
|
+
def delegate_to_stat(method)
|
91
|
+
::File.stat(@path).send(method)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/ru/iterator.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Ru
|
2
|
+
class Iterator
|
3
|
+
class << self
|
4
|
+
def redefined_methods
|
5
|
+
@redefined_methods ||= begin
|
6
|
+
preserved_methods = %{initialize method_missing respond_to? to_a}
|
7
|
+
[].public_methods.select do |method|
|
8
|
+
method = method.to_s
|
9
|
+
method =~ /^[a-z]/ && !preserved_methods.include?(method)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(enum)
|
16
|
+
@enum = enum
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_a
|
20
|
+
case @enum
|
21
|
+
when ::Array
|
22
|
+
Ru::Array.new(@enum)
|
23
|
+
when Ru::Array
|
24
|
+
@enum
|
25
|
+
when Ru::Stream
|
26
|
+
@enum.to_a
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_stdout
|
31
|
+
case @enum
|
32
|
+
when ::Array
|
33
|
+
@enum.join("\n")
|
34
|
+
else
|
35
|
+
@enum.to_s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def method_missing(method, *args, &block)
|
42
|
+
map_method(method, *args, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def map_method(method, *args, &block)
|
46
|
+
@enum = @enum.map { |item| item.send(method, *args, &block) }
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
redefined_methods.each do |method|
|
51
|
+
define_method(method) do |*args|
|
52
|
+
map_method(method, *args)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Ru
|
4
|
+
class OptionPrinter
|
5
|
+
def exists?(option_key)
|
6
|
+
options[option_key].present?
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(option_key, option_value=nil)
|
10
|
+
send(options[option_key], *option_value)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def options
|
16
|
+
{
|
17
|
+
help: :get_help,
|
18
|
+
version: :get_version
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_help
|
23
|
+
namespace = OpenStruct.new(version: Ru::VERSION)
|
24
|
+
template_path = ::File.expand_path("../../../doc/help.erb", __FILE__)
|
25
|
+
template = ::File.open(template_path).read
|
26
|
+
ERB.new(template).result(namespace.instance_eval { binding })
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_version
|
30
|
+
Ru::VERSION
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/ru/process.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Ru
|
4
|
+
class Process
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@option_printer = OptionPrinter.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
output = process_options
|
12
|
+
return output if output
|
13
|
+
|
14
|
+
args = ARGV.dup
|
15
|
+
@code = args.shift
|
16
|
+
|
17
|
+
if @code.blank?
|
18
|
+
$stderr.puts @option_printer.run(:help)
|
19
|
+
return
|
20
|
+
end
|
21
|
+
|
22
|
+
@stdin = get_stdin(args, @options[:stream]) unless @code.start_with?('! ')
|
23
|
+
@code = prepare_code(@code)
|
24
|
+
|
25
|
+
context =
|
26
|
+
if @stdin.nil?
|
27
|
+
Ru::Array.new([])
|
28
|
+
else
|
29
|
+
if @options[:stream]
|
30
|
+
if @options[:binary]
|
31
|
+
Ru::Stream.new(@stdin.each_byte.lazy)
|
32
|
+
else
|
33
|
+
Ru::Stream.new(@stdin.each_line.lazy.map { |line| line.chomp("\n".freeze) })
|
34
|
+
end
|
35
|
+
else
|
36
|
+
if @options[:binary]
|
37
|
+
Ru::Array.new(@stdin.bytes)
|
38
|
+
else
|
39
|
+
# Prevent 'invalid byte sequence in UTF-8'
|
40
|
+
@stdin.encode!('UTF-8', 'UTF-8', invalid: :replace)
|
41
|
+
Ru::Array.new(@stdin.split("\n"))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
output = context.instance_eval(@code) || @stdin
|
46
|
+
|
47
|
+
prepare_output(output)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def prepare_code(code)
|
53
|
+
if code.kind_of?(String)
|
54
|
+
if code.start_with?('[')
|
55
|
+
code = 'to_self' + code
|
56
|
+
elsif code.start_with?('! ')
|
57
|
+
code = code[2..-1]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
code
|
61
|
+
end
|
62
|
+
|
63
|
+
def prepare_output(output)
|
64
|
+
if output.respond_to?(:to_stdout)
|
65
|
+
output = output.to_stdout
|
66
|
+
end
|
67
|
+
if output.kind_of?(::Array)
|
68
|
+
output = output.join("\n")
|
69
|
+
end
|
70
|
+
output.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def process_options
|
74
|
+
@options = get_options
|
75
|
+
@options.each do |option, value|
|
76
|
+
if @option_printer.exists?(option)
|
77
|
+
return @option_printer.run(option)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_options
|
84
|
+
options = {}
|
85
|
+
OptionParser.new do |opts|
|
86
|
+
opts.on("-h", "--help", "Print help") do
|
87
|
+
options[:help] = true
|
88
|
+
end
|
89
|
+
|
90
|
+
opts.on("-v", "--version", "Print version") do
|
91
|
+
options[:version] = true
|
92
|
+
end
|
93
|
+
|
94
|
+
opts.on('-s', '--stream', 'Stream mode') do
|
95
|
+
options[:stream] = true
|
96
|
+
end
|
97
|
+
|
98
|
+
opts.on('-b', '--binary', 'Binary mode') do
|
99
|
+
options[:binary] = true
|
100
|
+
end
|
101
|
+
end.parse!
|
102
|
+
options
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_stdin(paths, stream)
|
106
|
+
if paths.present?
|
107
|
+
if stream
|
108
|
+
::File.open(paths[0])
|
109
|
+
else
|
110
|
+
paths.map { |path| ::File.read(path) }.join("\n")
|
111
|
+
end
|
112
|
+
else
|
113
|
+
if stream
|
114
|
+
$stdin
|
115
|
+
else
|
116
|
+
$stdin.read
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/ru/stream.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
class Enumerator::Lazy
|
2
|
+
def [](number_or_range, length=1)
|
3
|
+
if number_or_range.kind_of? Range
|
4
|
+
range = number_or_range
|
5
|
+
if range.begin < 0 || range.end < -1 || (range.exclude_end? && range.end == -1)
|
6
|
+
raise ArgumentError, "Stream doesn't support negative indexes, except x..-1"
|
7
|
+
end
|
8
|
+
if range.end == -1
|
9
|
+
drop(range.begin)
|
10
|
+
else
|
11
|
+
each_with_index.select { |_, index|
|
12
|
+
range.cover?(index)
|
13
|
+
}
|
14
|
+
end
|
15
|
+
else
|
16
|
+
number = number_or_range
|
17
|
+
if number >= 0
|
18
|
+
result = drop(number)
|
19
|
+
if length >= 0
|
20
|
+
result.take(length)
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
else
|
25
|
+
raise ArgumentError, "Stream doesn't support negative indexes"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def length
|
31
|
+
count
|
32
|
+
end
|
33
|
+
|
34
|
+
def uniq
|
35
|
+
seen = Set.new
|
36
|
+
select { |item|
|
37
|
+
seen.add?(item)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module Ru
|
43
|
+
class Stream
|
44
|
+
|
45
|
+
attr :stream
|
46
|
+
|
47
|
+
# @param [Enumerator::Lazy] stream
|
48
|
+
def initialize(stream)
|
49
|
+
raise ArgumentError unless stream.kind_of? Enumerator::Lazy
|
50
|
+
@stream = stream
|
51
|
+
end
|
52
|
+
|
53
|
+
def each_line
|
54
|
+
Ru::Iterator.new(self)
|
55
|
+
end
|
56
|
+
|
57
|
+
def files
|
58
|
+
self.class.new @stream.map { |line| Ru::File.new(line) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def format(format='l')
|
62
|
+
self.class.new @stream.map { |item| item.format(format) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def grep(pattern)
|
66
|
+
if pattern.kind_of? String
|
67
|
+
pattern = Regexp.new(pattern)
|
68
|
+
end
|
69
|
+
self.class.new @stream.select { |item| item.to_s =~ pattern }
|
70
|
+
end
|
71
|
+
|
72
|
+
def map(method=nil, *args, &block)
|
73
|
+
if method.nil? && !block_given?
|
74
|
+
each_line
|
75
|
+
elsif method.nil?
|
76
|
+
self.class.new @stream.map(&block)
|
77
|
+
else
|
78
|
+
self.class.new @stream.map { |item| item.send(method, *args) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def select(*args, &block)
|
83
|
+
self.class.new @stream.select(*args, &block)
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_a
|
87
|
+
Ru::Array.new(@stream.to_a)
|
88
|
+
end
|
89
|
+
|
90
|
+
alias_method :to_ary, :to_a
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
result = ''
|
94
|
+
result.concat @stream.next.to_s
|
95
|
+
loop do
|
96
|
+
item = @stream.next.to_s
|
97
|
+
result.concat "\n".freeze
|
98
|
+
result.concat item
|
99
|
+
end
|
100
|
+
result
|
101
|
+
rescue StopIteration
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_self
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
def ==(other)
|
110
|
+
other.is_a?(self.class) && self.stream == other.stream
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def method_missing(method, *args, &block)
|
116
|
+
result = @stream.send(method, *args, &block)
|
117
|
+
if result.kind_of? Enumerator::Lazy
|
118
|
+
self.class.new(result)
|
119
|
+
elsif result.kind_of? ::Array
|
120
|
+
Ru::Array.new(result)
|
121
|
+
else
|
122
|
+
result
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/ru/version.rb
ADDED
data/lib/ru.rb
ADDED
data/ru.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path('../lib/ru/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.authors = ['Tom Benner', 'Alexander Pavlenko']
|
5
|
+
s.email = ['tombenner@gmail.com', 'alerticus@gmail.com']
|
6
|
+
s.description = s.summary = %q{Ruby in your shell!}
|
7
|
+
s.homepage = 'https://github.com/AlexanderPavlenko/ru'
|
8
|
+
|
9
|
+
s.files = `git ls-files`.split($\)
|
10
|
+
s.name = 'ru2'
|
11
|
+
s.executables = ['ru']
|
12
|
+
s.require_paths = ['lib']
|
13
|
+
s.version = Ru::VERSION
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.add_dependency 'activesupport', '>= 3.2.0'
|
17
|
+
|
18
|
+
s.add_development_dependency 'appraisal', '~> 1.0'
|
19
|
+
s.add_development_dependency 'rspec', '~> 3.1'
|
20
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'misc examples' do
|
4
|
+
include FixturesHelper
|
5
|
+
include ProcessHelper
|
6
|
+
|
7
|
+
# http://stackoverflow.com/questions/450799/shell-command-to-sum-integers-one-per-line
|
8
|
+
context "summing integers" do
|
9
|
+
it "sums" do
|
10
|
+
lines = (1..10).to_a.map(&:to_s)
|
11
|
+
out = run('map(:to_i).sum', lines)
|
12
|
+
expect(out).to eq('55')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# http://stackoverflow.com/questions/6022384/bash-tool-to-get-nth-line-from-a-file
|
17
|
+
context "printing the nth line" do
|
18
|
+
it "prints" do
|
19
|
+
lines = (1..10).to_a.map(&:to_s)
|
20
|
+
out = run('[4]', lines)
|
21
|
+
expect(out).to eq('5')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# https://coderwall.com/p/ueazhw
|
26
|
+
context "sorting an Apache access log by response time" do
|
27
|
+
it "sorts" do
|
28
|
+
file = fixture_path('files', 'access.log')
|
29
|
+
out = run(['map { |line| [line[/(\d+)( ".+"){2}$/, 1].to_i, line] }.sort.reverse.map(:join, " ")', file])
|
30
|
+
expect(out).to eq(<<-EOF.strip
|
31
|
+
584912 66.249.64.14 - - [18/Sep/2004:11:07:48 +1000] "GET /file.txt HTTP/1.0" 200 584912 "-" "Googlebot/2.1"
|
32
|
+
6433 66.249.64.14 - - [18/Sep/2004:11:07:48 +1000] "GET / HTTP/1.0" 200 6433 "-" "Googlebot/2.1"
|
33
|
+
6433 66.249.64.13 - - [18/Sep/2004:11:07:48 +1000] "GET / HTTP/1.0" 200 6433 "-" "Googlebot/2.1"
|
34
|
+
468 66.249.64.14 - - [18/Sep/2004:11:07:48 +1000] "GET /robots.txt HTTP/1.0" 200 468 "-" "Googlebot/2.1"
|
35
|
+
468 66.249.64.13 - - [18/Sep/2004:11:07:48 +1000] "GET /robots.txt HTTP/1.0" 200 468 "-" "Googlebot/2.1"
|
36
|
+
EOF
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# https://www.gnu.org/software/sed/manual/sed.html#Examples
|
4
|
+
describe 'sed examples' do
|
5
|
+
include FixturesHelper
|
6
|
+
include ProcessHelper
|
7
|
+
|
8
|
+
context "centering lines" do
|
9
|
+
it "centers" do
|
10
|
+
lines = %w{john paul george} + [' ringo ']
|
11
|
+
out = run('each_line.strip.center(10)', lines)
|
12
|
+
expect(out).to eq(" john \n paul \n george \n ringo ")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "increment a number" do
|
17
|
+
it "increments" do
|
18
|
+
lines = ('5'..'10').to_a
|
19
|
+
out = run('(each_line.to_i+1)', lines)
|
20
|
+
expect(out).to eq(('6'..'11').to_a.join("\n"))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "reverse characters of lines" do
|
25
|
+
it "reverses" do
|
26
|
+
lines = %w{john paul george ringo}
|
27
|
+
out = run('each_line.reverse', lines)
|
28
|
+
expect(out).to eq("nhoj\nluap\negroeg\nognir")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "numbering lines" do
|
33
|
+
it "numbers" do
|
34
|
+
lines = %w{john paul george ringo}
|
35
|
+
out = run('map.with_index { |line, index| "#{(index+1).to_s.rjust(6)} #{line}" }', lines)
|
36
|
+
expect(out).to eq(" 1 john\n 2 paul\n 3 george\n 4 ringo")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "counting lines" do
|
41
|
+
it "counts" do
|
42
|
+
lines = %w{john paul george ringo}
|
43
|
+
out = run('length', lines)
|
44
|
+
expect(out).to eq("4")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "printing the first lines" do
|
49
|
+
it "prints" do
|
50
|
+
lines = %w{john paul george ringo}
|
51
|
+
out = run('[0,2]', lines)
|
52
|
+
expect(out).to eq("john\npaul")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "printing the last lines" do
|
57
|
+
it "prints" do
|
58
|
+
lines = %w{john paul george ringo}
|
59
|
+
out = run('[2..-1]', lines)
|
60
|
+
expect(out).to eq("george\nringo")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "make duplicate lines unique" do
|
65
|
+
it "dedupes" do
|
66
|
+
lines = %w{john john paul george george george ringo}
|
67
|
+
out = run('uniq', lines)
|
68
|
+
expect(out).to eq("john\npaul\ngeorge\nringo")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "print duplicated lines of input" do
|
73
|
+
it "prints" do
|
74
|
+
lines = %w{john john paul george george george ringo}
|
75
|
+
out = run('select { |line| self.count(line) > 1 }', lines)
|
76
|
+
expect(out).to eq("john\njohn\ngeorge\ngeorge\ngeorge")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "remove all duplicated lines" do
|
81
|
+
it "removes" do
|
82
|
+
lines = %w{john john paul george george george ringo}
|
83
|
+
out = run('select { |line| self.count(line) == 1 }', lines)
|
84
|
+
expect(out).to eq("paul\nringo")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "squeezing blank lines" do
|
89
|
+
it "squeezes" do
|
90
|
+
lines = "john\n\npaul\ngeorge\n\n\nringo"
|
91
|
+
out = run('to_s.squeeze("\n")', lines)
|
92
|
+
expect(out).to eq("john\npaul\ngeorge\nringo")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|