each_line 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f1eaf44d03e2482b4ae470c4fce5f1131ddad39eaf30b77a47adef06f88c48fd
4
+ data.tar.gz: ab46c5dd059939e71c8d2b0187b8dae117038e44f1ece2685bb5d51b57b1236f
5
+ SHA512:
6
+ metadata.gz: 3f98034a942c4bde96d8b2b2945cb8ed06880f88bdbfd59653985ebcb9fb86b4a914e49b92c3fac26464879426e3558ac1558020ff638d579637e6a40081d20e
7
+ data.tar.gz: 17c181e81aa1bfda91f66b59d596a8fab72e1ca9fe9fd7ad3eb73e14edc78d24692c91977ff5624fa1b05ea1f854bcb6f8b513e612693b36cef5fc835516149e
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Josh Bodah
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,125 @@
1
+ # each_line
2
+
3
+ a text processing command-line tool that is driven by Ruby's `#each_line`
4
+
5
+ ## Why this project?
6
+
7
+ I've been juggling various command-line tools for a number of years.
8
+ Tools like `xargs`, `grep`, `awk`, and `sed` can certainly get the job done, but I found myself having to go
9
+ back to the documentation constantly for some of these.
10
+ If I ever needed to do anything more sophisticated that basic processing I found it more
11
+ productive pipe the text into `ruby` instead.
12
+ I use Ruby a lot so I'm much more comfortable with those APIs too.
13
+
14
+ e.g.
15
+
16
+ ```
17
+ $ (echo hello; echo world) | ruby -pe '$_ = $_[3]'
18
+ l
19
+ l
20
+
21
+ # Or
22
+ $ (echo hello; echo world; echo jello) | ruby -e 'puts $stdin.each_line.select { |line| line =~ /ello/ }'
23
+ hello
24
+ jello
25
+ ```
26
+
27
+ This worked better, but `ruby` still felt a bit cumbersome.
28
+ Sometimes I wanted to filter.
29
+ Sometimes I wanted to map.
30
+ Sometimes I wanted to reduce things into JSON.
31
+ I always forgot to `puts` my result and had to skip back to the beginning of iteration.
32
+ `ruby` had all the features, but again I found myself fighting the tools
33
+
34
+ Thus the goal of this project is to provide another interface for Ruby that I think strikes a better balance
35
+ for ad-hoc text processing on the command-line.
36
+
37
+ ## Installation
38
+
39
+ ```
40
+ gem install each_line
41
+ ```
42
+
43
+ ## Examples
44
+
45
+ ```rb
46
+ # Run a script directly against #each_line
47
+ $ (echo hello; echo world) | each_line 'to_a.map(&:strip).join(",")'
48
+ hello,world
49
+
50
+ # If your Ruby supports numbered parameters then you might find that this interface is all you really need
51
+ $ (echo hello; echo world; echo jello) | each_line 'select { _1 =~ /ello/ }'
52
+ hello
53
+ jello
54
+
55
+ # Run a block method (e.g. map, select, etc) on #each_line
56
+ # Use the -m option to specify the method to be run
57
+ # The first argument will be treated as the block body
58
+ # By default block args are positionally bound to $_1, $_2, etc
59
+ # If your version of Ruby supports numbered parameters (e.g. _1, _2, etc) you may find it easier do something along the lines of the example above
60
+ $ (echo hello; echo world; echo jello) | each_line -m select '$_1 =~ /ello/'
61
+ hello
62
+ jello
63
+
64
+ $ (echo hello; echo world; echo jello) | each_line -m reject '$_1 =~ /ello/'
65
+ world
66
+
67
+ # The -m option can also specify a chain of methods which can be useful in some situations
68
+ # Any block or args specified will be passed to the last method in the chain
69
+ $ (echo hello; echo world; echo jello) | each_line -m with_index.map '"#{$_2}\t#{$_1}"'
70
+ 0 hello
71
+ 1 world
72
+ 2 jello
73
+
74
+ # The chain of methods can also accept args and blocks
75
+ # The last method in the chain must use the -a and -b options
76
+ $ (echo hello; echo world; echo jello) | each_line -m 'each_slice(2).map' '$_1.inspect'
77
+ ["hello\n", "world\n"]
78
+ ["jello\n"]
79
+
80
+ # A more complicated example using #reduce
81
+ # The -a option can be used to specify args for reduce; args should be comma-separated
82
+ $ (echo hello; echo world; echo jello) | each_line -m reduce -a '{}' '$_1[$_2.strip] = $_2[3]; $_1'
83
+ {"hello"=>"l", "world"=>"l", "jello"=>"l"}
84
+
85
+ # We can customize the names of block args too to avoid mixing up the block args
86
+ # Use either -v or --block_vars and pass a comma-separated list of arg names
87
+ $ (echo hello; echo world; echo jello) | each_line -m reduce -a '{}' -v '$acc,$line' '$acc[$line.strip] = $line[3]; $acc'
88
+ {"hello"=>"l", "world"=>"l", "jello"=>"l"}
89
+
90
+ # A finalizer can be specified as well
91
+ # The -f option can accept a script to run
92
+ # Additionally the -r and -I options can be used to require libraries and modify the load-path similarly to how they do with the `ruby` executable
93
+ $ (echo hello; echo world; echo jello) | each_line -m reduce -a '{}' -v '$acc,$line' '$acc[$line.strip] = $line[3]; $acc' -f to_json -rjson
94
+ {"hello":"l","world":"l","jello":"l"}
95
+
96
+ # An initializer can be specified
97
+ # This is an arbitrary chunk of code that will be run once before any scripting is done
98
+ # You can use the -i option to specify an intializer
99
+ $ (echo hello; echo world; echo jello) | each_line -i '$lookup = %w(alpha beta charlie)' -m each_with_index.map -v '$el,$idx' '$lookup[$idx]'
100
+ alpha
101
+ beta
102
+ charlie
103
+
104
+ # The -d option can be used to specify a delimiter other than new-line
105
+ $ echo hello world jello | each_line -d ' ' -m map '$_1.gsub /e/, "q"'
106
+ hqllo
107
+ world
108
+ jqllo
109
+
110
+ $ echo hello,world,jello | each_line -d ',' -m map '$_1.gsub /e/, "q"'
111
+ hqllo,
112
+ world,
113
+ jqllo
114
+
115
+ # You can pass the --strip option which will strip off the delimiter before it is passed to your block
116
+ $ echo hello,world,jello | each_line --strip -d ',' -m map '$_1.inspect'
117
+ "hello"
118
+ "world"
119
+ "jello\n"
120
+
121
+ $ (echo hello; echo world; echo jello) | each_line --strip -m map '$_1.inspect'
122
+ "hello"
123
+ "world"
124
+ "jello"
125
+ ```
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "each_line"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["Josh Bodah"]
5
+ spec.email = ["joshuabodah@gmail.com"]
6
+
7
+ spec.summary = %q{a text processing command-line tool that is driven by Ruby's `#each_line`}
8
+ spec.homepage = "https://github.com/jbodah/each_line"
9
+ spec.license = "MIT"
10
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
11
+
12
+ spec.metadata["homepage_uri"] = spec.homepage
13
+
14
+ # Specify which files should be added to the gem when it is released.
15
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
16
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,98 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ options = {
6
+ method: nil,
7
+ block: nil,
8
+ args: [],
9
+ block_vars: nil,
10
+ finalizer: nil,
11
+ requires: [],
12
+ intializer: nil,
13
+ delimiter: $/,
14
+ strip: false,
15
+ }
16
+ OptionParser.new do |opts|
17
+ opts.banner = "Usage: each_line [options]"
18
+
19
+ opts.on("-m METHOD", "Specify the method to use") do |m|
20
+ options[:method] = m
21
+ end
22
+
23
+ opts.on("-b BLOCK_STR", "Specify the block to pass to the method") do |block_str|
24
+ options[:block] = block_str
25
+ end
26
+
27
+ opts.on("-a ARG_STR", "Specify the args to pass to the method") do |args_str|
28
+ options[:args] = eval("[" + args_str + "]")
29
+ end
30
+
31
+ opts.on("-v BLOCK_VARS", "--block_vars BLOCK_VARS", "Customize the names used for each block variable") do |block_vars|
32
+ options[:block_vars] = block_vars.split(',')
33
+ end
34
+
35
+ opts.on("-f STRING", "A finalizer string that we will eval against the final output before printing") do |finalizer|
36
+ options[:finalizer] = finalizer
37
+ end
38
+
39
+ opts.on("-r PATH", "Requires the given library. You can specify this multiple times") do |r|
40
+ options[:requires] << r
41
+ end
42
+
43
+ opts.on("-I DIRECTORY", "Adds the given directory to the load-path") do |dir|
44
+ $: << dir
45
+ end
46
+
47
+ opts.on("-i STRING", "An initializer string that we will eval before doing any other processing") do |initializer|
48
+ options[:initializer] = initializer
49
+ end
50
+
51
+ opts.on("-d DELIMITER", "Used to split on characters other than new-line") do |delimiter|
52
+ options[:delimiter] = delimiter
53
+ end
54
+
55
+ opts.on("--strip", "Strips off the delimiter before it is processed") do |strip|
56
+ options[:strip] = true
57
+ end
58
+ end.parse!
59
+
60
+ options[:requires].each { |r| require r }
61
+
62
+ eval(options[:initializer]) if options[:initializer]
63
+
64
+ target = $stdin.each_line(options[:delimiter])
65
+
66
+ target = target.lazy.map { |part| part.sub(/#{options[:delimiter]}$/, '') } if options[:strip]
67
+
68
+ if options[:method]
69
+ block_str = options[:block] || ARGV[0]
70
+ args = options[:args]
71
+ preamble, _, method = options[:method].rpartition('.')
72
+ if preamble.size > 0
73
+ target = target.instance_eval(preamble)
74
+ end
75
+
76
+ if block_str
77
+ block = proc do |*block_args|
78
+ block_args.each_with_index do |block_arg, idx|
79
+ block_var = options[:block_vars] ? options[:block_vars][idx] : "$_#{idx+1}"
80
+ eval("#{block_var} = block_arg")
81
+ end
82
+ eval(block_str)
83
+ end
84
+ result = target.public_send(method, *args, &block)
85
+ else
86
+ result = target.public_send(method, *args)
87
+ end
88
+ else
89
+ result = target.instance_eval(ARGV[0])
90
+ end
91
+
92
+ result = result.force if result.is_a?(Enumerator::Lazy)
93
+
94
+ if options[:finalizer]
95
+ result = result.instance_eval(options[:finalizer])
96
+ end
97
+
98
+ puts result
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: each_line
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Josh Bodah
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-05-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - joshuabodah@gmail.com
16
+ executables:
17
+ - each_line
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".gitignore"
22
+ - LICENSE.txt
23
+ - README.md
24
+ - Rakefile
25
+ - each_line.gemspec
26
+ - exe/each_line
27
+ homepage: https://github.com/jbodah/each_line
28
+ licenses:
29
+ - MIT
30
+ metadata:
31
+ homepage_uri: https://github.com/jbodah/each_line
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.3.0
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubygems_version: 3.1.2
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: a text processing command-line tool that is driven by Ruby's `#each_line`
51
+ test_files: []