ned 0.0.1 → 0.0.2
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +95 -20
- data/bin/ned +1 -1
- data/lib/ned/command.rb +131 -8
- data/lib/ned/command_registry.rb +27 -0
- data/lib/ned/commands/append.rb +27 -13
- data/lib/ned/commands/backward.rb +21 -14
- data/lib/ned/commands/head.rb +33 -18
- data/lib/ned/commands/index.rb +34 -25
- data/lib/ned/commands/join.rb +41 -14
- data/lib/ned/commands/prepend.rb +27 -13
- data/lib/ned/commands/print.rb +13 -0
- data/lib/ned/commands/quote.rb +29 -13
- data/lib/ned/commands/read.rb +40 -0
- data/lib/ned/commands/sort.rb +45 -31
- data/lib/ned/commands/tail.rb +29 -20
- data/lib/ned/commands/uniq.rb +53 -18
- data/lib/ned/string.rb +14 -0
- data/lib/ned/strings.rb +1 -1
- data/lib/ned/version.rb +1 -3
- data/lib/ned.rb +181 -138
- data/lib/{ned → ned_old}/commands/grep.rb +0 -0
- data/lib/{ned → ned_old}/commands/only.rb +0 -0
- data/lib/{ned → ned_old}/commands/replace.rb +0 -0
- data/lib/{ned → ned_old}/commands/visual.rb +0 -0
- data/lib/ned_old.rb +193 -0
- data/ned.gemspec +2 -2
- data/scripts/generate_readme +6 -0
- data/spec_old/file_spec.rb +29 -0
- metadata +14 -12
- data/lib/ned/config.rb +0 -73
- data/lib/ned/context.rb +0 -10
- data/lib/ned/validators.rb +0 -19
- data/todo +0 -15
data/lib/ned_old.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ned/command'
|
4
|
+
require 'ned/config'
|
5
|
+
require 'ned/context'
|
6
|
+
require 'ned/strings'
|
7
|
+
require 'ned/validators'
|
8
|
+
require 'ned/version'
|
9
|
+
|
10
|
+
Dir["#{__dir__}/ned/commands/**/*.rb"].sort.each { |f| require f }
|
11
|
+
|
12
|
+
module Ned
|
13
|
+
def self.help(error_output)
|
14
|
+
error_output.puts <<~EOF
|
15
|
+
A stream editor.
|
16
|
+
|
17
|
+
Usage: ned [file] [options ...]
|
18
|
+
|
19
|
+
Options:
|
20
|
+
EOF
|
21
|
+
|
22
|
+
lines = [
|
23
|
+
[' --help', 'Print this message.'],
|
24
|
+
[' --version', 'Print version.']
|
25
|
+
]
|
26
|
+
max = lines[0][0].length
|
27
|
+
Ned::Config.all.each do |config|
|
28
|
+
next if config.hidden?
|
29
|
+
|
30
|
+
line = "#{config.short}, #{config.long} #{config.params}"
|
31
|
+
lines << [line, config.description]
|
32
|
+
max = [max, line.length].max
|
33
|
+
end
|
34
|
+
|
35
|
+
lines.each do |line|
|
36
|
+
error_output.puts " #{line[0].ljust(max)} #{line[1]}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.failure(error_output, message)
|
41
|
+
error_output.puts "fatal: #{message}\n\n"
|
42
|
+
help(error_output)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.run(input: $stdin, output: $stdout, error_output: $stderr, args: ARGV)
|
46
|
+
args = args.map do |arg|
|
47
|
+
Ned::Strings.unescape!(arg.dup)
|
48
|
+
end
|
49
|
+
|
50
|
+
if args.include?('--help')
|
51
|
+
help(error_output)
|
52
|
+
return 0
|
53
|
+
end
|
54
|
+
|
55
|
+
if args.include?('--version')
|
56
|
+
output.puts("Ned version #{Ned::VERSION}")
|
57
|
+
return 0
|
58
|
+
end
|
59
|
+
|
60
|
+
inputs = []
|
61
|
+
while args.first && !args.first.match(/^-./)
|
62
|
+
arg = args.shift
|
63
|
+
|
64
|
+
if arg == '-'
|
65
|
+
inputs << input
|
66
|
+
else
|
67
|
+
unless File.exist?(arg)
|
68
|
+
failure(error_output, "no such file: #{arg}")
|
69
|
+
return 1
|
70
|
+
end
|
71
|
+
inputs << arg
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
if input.tty? && (inputs.empty? || (inputs.size == 1 && inputs[0] == input))
|
76
|
+
failure(error_output, 'no input')
|
77
|
+
return 1
|
78
|
+
end
|
79
|
+
|
80
|
+
inputs = inputs.unshift(input) if !input.tty? && !inputs.index(input)
|
81
|
+
|
82
|
+
if inputs.count(input) > 1
|
83
|
+
failure(error_output, "can't read from standard in twice, silly")
|
84
|
+
return 1
|
85
|
+
end
|
86
|
+
|
87
|
+
if inputs.size > 1
|
88
|
+
failure(error_output, "more than one input not yet supported")
|
89
|
+
return 1
|
90
|
+
end
|
91
|
+
|
92
|
+
commands = []
|
93
|
+
|
94
|
+
while arg = args.shift
|
95
|
+
config = Ned::Config.all.find do |config|
|
96
|
+
arg.start_with?(config.short) || arg == config.long || arg.start_with?("#{config.long}=")
|
97
|
+
end
|
98
|
+
|
99
|
+
unless config
|
100
|
+
failure(error_output, "invalid option: #{arg}")
|
101
|
+
return 1
|
102
|
+
end
|
103
|
+
|
104
|
+
params = []
|
105
|
+
|
106
|
+
if arg.start_with?("#{config.long}=")
|
107
|
+
params << arg["#{config.long}=".size..-1]
|
108
|
+
elsif arg.start_with?(config.short) && arg != config.short
|
109
|
+
params << arg[config.short.size..-1]
|
110
|
+
else
|
111
|
+
while !args.empty? && !args.first.start_with?('-')
|
112
|
+
arg = args.shift
|
113
|
+
if arg.start_with? '\\-'
|
114
|
+
arg = arg[1..-1]
|
115
|
+
end
|
116
|
+
params << arg
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
valid = config.validate(*params)
|
121
|
+
if valid.nil?
|
122
|
+
if config.params.nil?
|
123
|
+
failure(error_output, "invalid param for #{config.name}. found: #{params}, expected none")
|
124
|
+
return 1
|
125
|
+
else
|
126
|
+
failure(error_output, "invalid param for #{config.name}. found: #{params}, expected: #{config.params}")
|
127
|
+
return 1
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
commands << Ned::Command.new(config, valid)
|
132
|
+
end
|
133
|
+
|
134
|
+
if commands.any?(&:all?)
|
135
|
+
lines = inputs.flat_map do |i|
|
136
|
+
if i.is_a? String
|
137
|
+
IO.readlines(i, sep="\n")
|
138
|
+
else
|
139
|
+
i.readlines(sep="\n")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
process_all(commands, lines, output)
|
143
|
+
else
|
144
|
+
process_each(commands, inputs, output)
|
145
|
+
end
|
146
|
+
|
147
|
+
0
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.process_all(commands, lines, output)
|
151
|
+
final_newline = lines[-1]&.[](-1) == "\n" ? "\n" : ''
|
152
|
+
|
153
|
+
lines = lines.map { |line| line.chomp("\n") }
|
154
|
+
context = Context.new(lines, 0)
|
155
|
+
commands.each do |command|
|
156
|
+
command.execute(context)
|
157
|
+
end
|
158
|
+
last = context.lines.length - 1
|
159
|
+
context.lines.each_with_index do |line, index|
|
160
|
+
output.print "#{line}#{index == last ? final_newline : "\n"}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.process_each(commands, inputs, output)
|
165
|
+
input = inputs[0]
|
166
|
+
|
167
|
+
if input.is_a? String
|
168
|
+
input = File.open(input)
|
169
|
+
end
|
170
|
+
|
171
|
+
current = input.gets(sep="\n")
|
172
|
+
next_line = input.gets(sep="\n")
|
173
|
+
index = 0
|
174
|
+
|
175
|
+
while current
|
176
|
+
final_newline = current[-1]&.[](-1) == "\n" ? "\n" : ''
|
177
|
+
context = Context.new([current.chomp("\n")], index)
|
178
|
+
commands.each do |command|
|
179
|
+
command.execute(context)
|
180
|
+
end
|
181
|
+
index = context.start_index + context.lines.size
|
182
|
+
last = context.lines.length - 1
|
183
|
+
context.lines.each_with_index do |line, index|
|
184
|
+
output.print "#{line}#{index == last && next_line.nil? ? final_newline : "\n"}"
|
185
|
+
end
|
186
|
+
|
187
|
+
current = next_line
|
188
|
+
next_line = input.gets(sep="\n")
|
189
|
+
end
|
190
|
+
|
191
|
+
input.close
|
192
|
+
end
|
193
|
+
end
|
data/ned.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Nick Dower"]
|
9
9
|
spec.email = ["nicholasdower@gmail.com"]
|
10
10
|
|
11
|
-
spec.summary = "A
|
12
|
-
spec.description = "A
|
11
|
+
spec.summary = "A stream editor."
|
12
|
+
spec.description = "A stream editor"
|
13
13
|
spec.homepage = "https://github.com/nicholasdower/ned"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
data/scripts/generate_readme
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'files' do
|
4
|
+
test_failure 'no input', args: '-s', stdin: nil, stderr: 'fatal: no input'
|
5
|
+
|
6
|
+
test_failure 'no such file', args: 'foo -s', stdin: nil, stderr: 'fatal: no such file: foo'
|
7
|
+
|
8
|
+
test_failure 'multiple files', args: 'spec/support/file spec/support/file -s', stdin: nil, stderr: 'fatal: more than one input not yet supported'
|
9
|
+
|
10
|
+
test_failure 'no input, standard in as file arg', args: '- -s', stdin: nil, stderr: 'fatal: no input'
|
11
|
+
|
12
|
+
test_failure 'standard in as file arg multiple times', args: '- - -s', stdin: '', stderr: "fatal: can't read from standard in twice, silly"
|
13
|
+
|
14
|
+
context 'all lines read' do
|
15
|
+
test_success 'standard in', stdin: "two\none\n", args: '-s', stdout: "one\ntwo\n"
|
16
|
+
|
17
|
+
test_success 'standard in as file arg', stdin: "two\none\n", args: '- -s', stdout: "one\ntwo\n"
|
18
|
+
|
19
|
+
test_success 'single file', stdin: nil, args: 'spec/support/file -s', stdout: "one\nthree\ntwo\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'lines read one at a time' do
|
23
|
+
test_success 'standard in', stdin: "two\none\n", args: '-a 1', stdout: "two1\none1\n"
|
24
|
+
|
25
|
+
test_success 'standard in as file arg', stdin: "two\none\n", args: '- -a 1', stdout: "two1\none1\n"
|
26
|
+
|
27
|
+
test_success 'single file', stdin: nil, args: 'spec/support/file -a 1', stdout: "one1\ntwo1\nthree1\n"
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ned
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Dower
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: A
|
13
|
+
description: A stream editor
|
14
14
|
email:
|
15
15
|
- nicholasdower@gmail.com
|
16
16
|
executables:
|
@@ -25,30 +25,32 @@ files:
|
|
25
25
|
- bin/ned
|
26
26
|
- lib/ned.rb
|
27
27
|
- lib/ned/command.rb
|
28
|
+
- lib/ned/command_registry.rb
|
28
29
|
- lib/ned/commands/append.rb
|
29
30
|
- lib/ned/commands/backward.rb
|
30
|
-
- lib/ned/commands/grep.rb
|
31
31
|
- lib/ned/commands/head.rb
|
32
32
|
- lib/ned/commands/index.rb
|
33
33
|
- lib/ned/commands/join.rb
|
34
|
-
- lib/ned/commands/only.rb
|
35
34
|
- lib/ned/commands/prepend.rb
|
35
|
+
- lib/ned/commands/print.rb
|
36
36
|
- lib/ned/commands/quote.rb
|
37
|
-
- lib/ned/commands/
|
37
|
+
- lib/ned/commands/read.rb
|
38
38
|
- lib/ned/commands/sort.rb
|
39
39
|
- lib/ned/commands/tail.rb
|
40
40
|
- lib/ned/commands/uniq.rb
|
41
|
-
- lib/ned/
|
42
|
-
- lib/ned/config.rb
|
43
|
-
- lib/ned/context.rb
|
41
|
+
- lib/ned/string.rb
|
44
42
|
- lib/ned/strings.rb
|
45
|
-
- lib/ned/validators.rb
|
46
43
|
- lib/ned/version.rb
|
44
|
+
- lib/ned_old.rb
|
45
|
+
- lib/ned_old/commands/grep.rb
|
46
|
+
- lib/ned_old/commands/only.rb
|
47
|
+
- lib/ned_old/commands/replace.rb
|
48
|
+
- lib/ned_old/commands/visual.rb
|
47
49
|
- ned.gemspec
|
48
50
|
- scripts/generate_readme
|
49
51
|
- scripts/release
|
50
52
|
- scripts/test
|
51
|
-
-
|
53
|
+
- spec_old/file_spec.rb
|
52
54
|
homepage: https://github.com/nicholasdower/ned
|
53
55
|
licenses:
|
54
56
|
- MIT
|
@@ -74,5 +76,5 @@ requirements: []
|
|
74
76
|
rubygems_version: 3.3.3
|
75
77
|
signing_key:
|
76
78
|
specification_version: 4
|
77
|
-
summary: A
|
79
|
+
summary: A stream editor.
|
78
80
|
test_files: []
|
data/lib/ned/config.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Ned
|
4
|
-
class Config
|
5
|
-
class << self
|
6
|
-
attr_reader :all
|
7
|
-
end
|
8
|
-
|
9
|
-
@all = []
|
10
|
-
|
11
|
-
def self.add(name:, description:, short:, long:, params:, validator:, execute:, all: nil, hidden: false)
|
12
|
-
@all.each do |config|
|
13
|
-
if config.short.start_with?(short) || short.start_with?(config.short)
|
14
|
-
raise "Cannot add command #{name}. Flag conflicts with #{config.name}."
|
15
|
-
end
|
16
|
-
|
17
|
-
if config.long.start_with?(long) || long.start_with?(config.long)
|
18
|
-
raise "Cannot add command #{name}. Flag conflicts with #{config.name}."
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
@all << Config.new(
|
23
|
-
name: name,
|
24
|
-
description: description,
|
25
|
-
short: short,
|
26
|
-
long: long,
|
27
|
-
params: params,
|
28
|
-
validator: validator,
|
29
|
-
execute: execute,
|
30
|
-
all: all,
|
31
|
-
hidden: hidden
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
attr_reader :name, :description, :short, :long, :params
|
36
|
-
|
37
|
-
def initialize(name:, description:, short:, long:, params:, validator:, execute:, all: nil, hidden: false)
|
38
|
-
@name = name
|
39
|
-
@description = description
|
40
|
-
@short = short
|
41
|
-
@long = long
|
42
|
-
@params = params
|
43
|
-
@validator = validator
|
44
|
-
@execute = execute
|
45
|
-
@hidden = hidden
|
46
|
-
|
47
|
-
all = all || false
|
48
|
-
if [true, false].include? all
|
49
|
-
@all = lambda { |*params| all }
|
50
|
-
elsif all.is_a? Proc
|
51
|
-
@all = all
|
52
|
-
else
|
53
|
-
raise "Invalid all type for #{name}: #{all.class}"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def validate(*args)
|
58
|
-
@validator.call(*args)
|
59
|
-
end
|
60
|
-
|
61
|
-
def all?(params)
|
62
|
-
@all.call(*params)
|
63
|
-
end
|
64
|
-
|
65
|
-
def hidden?
|
66
|
-
@hidden
|
67
|
-
end
|
68
|
-
|
69
|
-
def execute(*args)
|
70
|
-
@execute.call(*args)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
data/lib/ned/context.rb
DELETED
data/lib/ned/validators.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Ned
|
4
|
-
class Validators
|
5
|
-
def self.none
|
6
|
-
lambda { |*params| params.length == 0 ? [] : nil }
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.num(min, max = nil, &block)
|
10
|
-
lambda do |*params|
|
11
|
-
max = min unless max
|
12
|
-
|
13
|
-
return nil if params.length < min || params.length > max
|
14
|
-
|
15
|
-
block.nil? ? params : yield(*params)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/todo
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
add support for a ~/.ned/ dir
|
2
|
-
implement highlight
|
3
|
-
add color
|
4
|
-
add support for more escape sequences, see https://github.com/ruby/ruby/blob/master/doc/syntax/literals.rdoc#label-Strings
|
5
|
-
add support for operating on one or more files
|
6
|
-
add support for editing files in place
|
7
|
-
handle --
|
8
|
-
add ljust
|
9
|
-
maybe add ability to highlight columns, not just full lines
|
10
|
-
write readme
|
11
|
-
add support for to_set
|
12
|
-
add support for overriding existing commands
|
13
|
-
add support for ommitting short or long flags
|
14
|
-
add support for uniq with count?
|
15
|
-
consider giving commands a way to operate on entire line with newline. currently can't replicate tr.
|