ru2 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|