cielli 4.2.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a879b0879f37e07178e19a7a5c2bd444ba2b0e52816ee65447fd20e889ffa620
4
+ data.tar.gz: 9dae86ada4ae248e61156b8d5b32da04411656b775e9ea767d04c058038c1484
5
+ SHA512:
6
+ metadata.gz: c5c19a68907b8e0c4f00d90edb0255f87bc68dc583bc9f629e6da3f01a3a3d47e8256583e56e50a09d6812d7a7faf9aa6e47b0a22f89547ccb3b203b8eb4be8c
7
+ data.tar.gz: 649d20e2a90c9762da2d5c276a20a65d2481e9793982855a5ed343d3dd9604111dcbe298147ab5546343640b0c568c7846c1ce1dba3c4cca4dd5c9955915411b
@@ -0,0 +1,40 @@
1
+ NAME
2
+ ====
3
+ cielli
4
+
5
+ SYNOPSIS
6
+ ========
7
+ a minimalist's toolkit for quickly writing well behaved CLI/cee-el-ahy programs
8
+
9
+ DESCRIPTION
10
+ ===========
11
+
12
+ cielli is the command line tool your mother wanted you to use. i learned this [the hard way](https://github.com/ahoward/main].
13
+
14
+
15
+ SAMPLES
16
+ =======
17
+
18
+ <========< samples/a.rb >========>
19
+
20
+ ~ > cat samples/a.rb
21
+
22
+ #! /usr/bin/env ruby
23
+
24
+ require 'cielli'
25
+
26
+ cli do
27
+ run do
28
+ p [@argv, @options]
29
+ end
30
+ end
31
+
32
+ ~ > ruby samples/a.rb
33
+
34
+ [[], {}]
35
+
36
+
37
+
38
+ INSTALL
39
+ =======
40
+ gem install cielli -v 0.4.2
@@ -0,0 +1,21 @@
1
+ NAME
2
+ ====
3
+ <%= This.lib %>
4
+
5
+ SYNOPSIS
6
+ ========
7
+ <%= This.summary %>
8
+
9
+ DESCRIPTION
10
+ ===========
11
+
12
+ cielli is the command line tool your mother wanted you to use. i learned this [the hard way](https://github.com/ahoward/main].
13
+
14
+
15
+ SAMPLES
16
+ =======
17
+ <%= samples %>
18
+
19
+ INSTALL
20
+ =======
21
+ gem install <%= lib %> -v <%= version %>
@@ -0,0 +1,389 @@
1
+ This.author = "Ara T. Howard"
2
+ This.email = "ara.t.howard@gmail.com"
3
+ This.homepage = "https://github.com/ahoward/#{ This.lib }"
4
+
5
+ task :license do
6
+ open('LICENSE', 'w'){|fd| fd.puts "Ruby"}
7
+ end
8
+
9
+ task :default do
10
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
11
+ end
12
+
13
+ task :test do
14
+ run_tests!
15
+ end
16
+
17
+ namespace :test do
18
+ task(:unit){ run_tests!(:unit) }
19
+ task(:functional){ run_tests!(:functional) }
20
+ task(:integration){ run_tests!(:integration) }
21
+ end
22
+
23
+ def run_tests!(which = nil)
24
+ which ||= '**'
25
+ test_dir = File.join(This.dir, "test")
26
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
27
+ test_rbs = Dir.glob(test_glob).sort
28
+
29
+ div = ('=' * 119)
30
+ line = ('-' * 119)
31
+
32
+ test_rbs.each_with_index do |test_rb, index|
33
+ testno = index + 1
34
+ command = "#{ This.ruby } -w -I ./lib -I ./test/lib #{ test_rb }"
35
+
36
+ puts
37
+ say(div, :color => :cyan, :bold => true)
38
+ say("@#{ testno } => ", :bold => true, :method => :print)
39
+ say(command, :color => :cyan, :bold => true)
40
+ say(line, :color => :cyan, :bold => true)
41
+
42
+ system(command)
43
+
44
+ say(line, :color => :cyan, :bold => true)
45
+
46
+ status = $?.exitstatus
47
+
48
+ if status.zero?
49
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
50
+ say("SUCCESS", :color => :green, :bold => true)
51
+ else
52
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
53
+ say("FAILURE", :color => :red, :bold => true)
54
+ end
55
+ say(line, :color => :cyan, :bold => true)
56
+
57
+ exit(status) unless status.zero?
58
+ end
59
+ end
60
+
61
+
62
+ task :gemspec do
63
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
64
+ ignore_directories = ['pkg']
65
+ ignore_files = ['test/log']
66
+
67
+ shiteless =
68
+ lambda do |list|
69
+ list.delete_if do |entry|
70
+ next unless test(?e, entry)
71
+ extension = File.basename(entry).split(%r/[.]/).last
72
+ ignore_extensions.any?{|ext| ext === extension}
73
+ end
74
+ list.delete_if do |entry|
75
+ next unless test(?d, entry)
76
+ dirname = File.expand_path(entry)
77
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
78
+ end
79
+ list.delete_if do |entry|
80
+ next unless test(?f, entry)
81
+ filename = File.expand_path(entry)
82
+ ignore_files.any?{|file| File.expand_path(file) == filename}
83
+ end
84
+ end
85
+
86
+ lib = This.lib
87
+ object = This.object
88
+ version = This.version
89
+ files = shiteless[Dir::glob("**/**")]
90
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
91
+ #has_rdoc = true #File.exist?('doc')
92
+ test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
93
+ summary = object.respond_to?(:summary) ? object.summary : "summary: #{ lib } kicks the ass"
94
+ description = object.respond_to?(:description) ? object.description : "description: #{ lib } kicks the ass"
95
+ license = object.respond_to?(:license) ? object.license : "Ruby"
96
+
97
+ if This.extensions.nil?
98
+ This.extensions = []
99
+ extensions = This.extensions
100
+ %w( Makefile configure extconf.rb ).each do |ext|
101
+ extensions << ext if File.exists?(ext)
102
+ end
103
+ end
104
+ extensions = [extensions].flatten.compact
105
+
106
+ if This.dependencies.nil?
107
+ dependencies = []
108
+ else
109
+ case This.dependencies
110
+ when Hash
111
+ dependencies = This.dependencies.values
112
+ when Array
113
+ dependencies = This.dependencies
114
+ end
115
+ end
116
+
117
+ template =
118
+ if test(?e, 'gemspec.erb')
119
+ Template{ IO.read('gemspec.erb') }
120
+ else
121
+ Template {
122
+ <<-__
123
+ ## <%= lib %>.gemspec
124
+ #
125
+
126
+ Gem::Specification::new do |spec|
127
+ spec.name = <%= lib.inspect %>
128
+ spec.version = <%= version.inspect %>
129
+ spec.platform = Gem::Platform::RUBY
130
+ spec.summary = <%= lib.inspect %>
131
+ spec.description = <%= description.inspect %>
132
+ spec.license = <%= license.inspect %>
133
+
134
+ spec.files =\n<%= files.sort.pretty_inspect %>
135
+ spec.executables = <%= executables.inspect %>
136
+
137
+ spec.require_path = "lib"
138
+
139
+ spec.test_files = <%= test_files.inspect %>
140
+
141
+ <% dependencies.each do |lib_version| %>
142
+ spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
143
+ <% end %>
144
+
145
+ spec.extensions.push(*<%= extensions.inspect %>)
146
+
147
+ spec.author = <%= This.author.inspect %>
148
+ spec.email = <%= This.email.inspect %>
149
+ spec.homepage = <%= This.homepage.inspect %>
150
+ end
151
+ __
152
+ }
153
+ end
154
+
155
+ Fu.mkdir_p(This.pkgdir)
156
+ gemspec = "#{ lib }.gemspec"
157
+ open(gemspec, "w"){|fd| fd.puts(template)}
158
+ This.gemspec = gemspec
159
+ end
160
+
161
+ task :gem => [:clean, :gemspec] do
162
+ Fu.mkdir_p(This.pkgdir)
163
+ before = Dir['*.gem']
164
+ cmd = "gem build #{ This.gemspec }"
165
+ `#{ cmd }`
166
+ after = Dir['*.gem']
167
+ gem = ((after - before).first || after.first) or abort('no gem!')
168
+ Fu.mv(gem, This.pkgdir)
169
+ This.gem = File.join(This.pkgdir, File.basename(gem))
170
+ end
171
+
172
+ task :readme do
173
+ lib = This.lib
174
+ version = This.version
175
+
176
+ samples = nil
177
+ prompt = '~ > '
178
+
179
+ Dir['sample*/*'].sort.each do |sample|
180
+ samples ||= ''
181
+
182
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
183
+
184
+ cmd = "cat #{ sample }"
185
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
186
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
187
+
188
+ cmd = "ruby #{ sample }"
189
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
190
+
191
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
192
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
193
+ end
194
+
195
+ template =
196
+ if test(?e, 'README.md.erb')
197
+ Template{ IO.read('README.md.erb') }
198
+ else
199
+ IO.binread('README.md')
200
+ end
201
+
202
+ open("README.md", "w"){|fd| fd.puts template}
203
+
204
+ puts IO.binread("README.md")
205
+ end
206
+
207
+ task :clean do
208
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
209
+ end
210
+
211
+ task :release => [:clean, :readme, :gemspec, :gem] do
212
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
213
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
214
+ raise "no gems?" if gems.size < 1
215
+
216
+ cmd = "gem push #{ This.gem }"
217
+ puts cmd
218
+ puts
219
+ system(cmd)
220
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
221
+ end
222
+
223
+
224
+
225
+
226
+
227
+ BEGIN {
228
+ # support for this rakefile
229
+ #
230
+ $VERBOSE = nil
231
+
232
+ require 'ostruct'
233
+ require 'erb'
234
+ require 'fileutils'
235
+ require 'rbconfig'
236
+ require 'pp'
237
+
238
+ # fu shortcut
239
+ #
240
+ Fu = FileUtils
241
+
242
+ # cache a bunch of stuff about this rakefile/environment
243
+ #
244
+ This = OpenStruct.new
245
+
246
+ This.file = File.expand_path(__FILE__)
247
+ This.dir = File.dirname(This.file)
248
+ This.pkgdir = File.join(This.dir, 'pkg')
249
+ This.lib = File.basename(Dir.pwd).sub(/[-].*$/, '')
250
+
251
+ # load _lib
252
+ #
253
+ _lib = ["./lib/#{ This.lib }/_lib.rb", "./lib/#{ This.lib }.rb"].detect{|l| test(?s, l)}
254
+ unless _lib
255
+ abort "could not find a _lib in ./lib!?"
256
+ end
257
+ This._lib = _lib
258
+ require This._lib
259
+
260
+
261
+ # extract name from _lib
262
+ #
263
+ lines = IO.binread(This._lib).split("\n")
264
+ re = %r`\A \s* (module|class) \s+ ([^\s]+) \s* \z`iomx
265
+ name = nil
266
+ lines.each do |line|
267
+ match = line.match(re)
268
+ if match
269
+ name = match.to_a.last
270
+ break
271
+ end
272
+ end
273
+ unless name
274
+ abort "could not extract `name` from #{ This._lib }"
275
+ end
276
+ This.name = name
277
+
278
+ # now, fully grok This
279
+ #
280
+ This.object = eval(This.name)
281
+
282
+ version = This.object.send(:version)
283
+ This.version = version
284
+
285
+ if This.object.respond_to?(:dependencies)
286
+ This.dependencies = This.object.dependencies
287
+ end
288
+
289
+ if This.object.respond_to?(:summary)
290
+ This.summary = This.object.summary
291
+ end
292
+
293
+ # discover full path to this ruby executable
294
+ #
295
+ c = RbConfig::CONFIG
296
+ bindir = c["bindir"] || c['BINDIR']
297
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
298
+ ruby_ext = c['EXEEXT'] || ''
299
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
300
+ This.ruby = ruby
301
+
302
+ # some utils
303
+ #
304
+ module Util
305
+ def indent(s, n = 2)
306
+ s = unindent(s)
307
+ ws = ' ' * n
308
+ s.gsub(%r/^/, ws)
309
+ end
310
+
311
+ def unindent(s)
312
+ indent = nil
313
+ s.each_line do |line|
314
+ next if line =~ %r/^\s*$/
315
+ indent = line[%r/^\s*/] and break
316
+ end
317
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
318
+ end
319
+ extend self
320
+ end
321
+
322
+ # template support
323
+ #
324
+ class Template
325
+ def initialize(&block)
326
+ @block = block
327
+ @template = block.call.to_s
328
+ end
329
+ def expand(b=nil)
330
+ ERB.new(Util.unindent(@template)).result((b||@block).binding)
331
+ end
332
+ alias_method 'to_s', 'expand'
333
+ end
334
+ def Template(*args, &block) Template.new(*args, &block) end
335
+
336
+ # colored console output support
337
+ #
338
+ This.ansi = {
339
+ :clear => "\e[0m",
340
+ :reset => "\e[0m",
341
+ :erase_line => "\e[K",
342
+ :erase_char => "\e[P",
343
+ :bold => "\e[1m",
344
+ :dark => "\e[2m",
345
+ :underline => "\e[4m",
346
+ :underscore => "\e[4m",
347
+ :blink => "\e[5m",
348
+ :reverse => "\e[7m",
349
+ :concealed => "\e[8m",
350
+ :black => "\e[30m",
351
+ :red => "\e[31m",
352
+ :green => "\e[32m",
353
+ :yellow => "\e[33m",
354
+ :blue => "\e[34m",
355
+ :magenta => "\e[35m",
356
+ :cyan => "\e[36m",
357
+ :white => "\e[37m",
358
+ :on_black => "\e[40m",
359
+ :on_red => "\e[41m",
360
+ :on_green => "\e[42m",
361
+ :on_yellow => "\e[43m",
362
+ :on_blue => "\e[44m",
363
+ :on_magenta => "\e[45m",
364
+ :on_cyan => "\e[46m",
365
+ :on_white => "\e[47m"
366
+ }
367
+ def say(phrase, *args)
368
+ options = args.last.is_a?(Hash) ? args.pop : {}
369
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
370
+ keys = options.keys
371
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
372
+
373
+ color = options[:color]
374
+ bold = options.has_key?(:bold)
375
+
376
+ parts = [phrase]
377
+ parts.unshift(This.ansi[color]) if color
378
+ parts.unshift(This.ansi[:bold]) if bold
379
+ parts.push(This.ansi[:clear]) if parts.size > 1
380
+
381
+ method = options[:method] || :puts
382
+
383
+ Kernel.send(method, parts.join)
384
+ end
385
+
386
+ # always run out of the project dir
387
+ #
388
+ Dir.chdir(This.dir)
389
+ }
@@ -0,0 +1,35 @@
1
+ #! /usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require_relative '../lib/cielli.rb'
5
+
6
+ cielli do
7
+ run do
8
+ puts CLI
9
+ end
10
+
11
+ CLI = <<~________
12
+ #! /usr/bin/env ruby
13
+ # encoding: utf-8
14
+
15
+ require 'cielli'
16
+
17
+ cielli do
18
+ help <<~____
19
+ #{ Cielli.utils.indent(Cielli::DEFAULT_HELP, 4).strip }
20
+ ____
21
+
22
+ run do
23
+ p [@argv, @options]
24
+ end
25
+
26
+ run(:foo) do
27
+ p [@mode, @argv, @options]
28
+ end
29
+
30
+ run(:bar) do
31
+ p [@mode, @argv, @options]
32
+ end
33
+ end
34
+ ________
35
+ end
@@ -0,0 +1,41 @@
1
+ ## cielli.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "cielli"
6
+ spec.version = "4.2.2"
7
+ spec.platform = Gem::Platform::RUBY
8
+ spec.summary = "cielli"
9
+ spec.description = "description: cielli kicks the ass"
10
+ spec.license = "Ruby"
11
+
12
+ spec.files =
13
+ ["README.md",
14
+ "README.md.erb",
15
+ "Rakefile",
16
+ "bin",
17
+ "bin/cielli",
18
+ "cielli.gemspec",
19
+ "lib",
20
+ "lib/cielli",
21
+ "lib/cielli.rb",
22
+ "lib/cielli/_lib.rb",
23
+ "lib/cielli/slug.rb",
24
+ "lib/cielli/utils.rb",
25
+ "samples",
26
+ "samples/a.rb"]
27
+
28
+ spec.executables = ["cielli"]
29
+
30
+ spec.require_path = "lib"
31
+
32
+ spec.test_files = nil
33
+
34
+
35
+
36
+ spec.extensions.push(*[])
37
+
38
+ spec.author = "Ara T. Howard"
39
+ spec.email = "ara.t.howard@gmail.com"
40
+ spec.homepage = "https://github.com/ahoward/cielli"
41
+ end
@@ -0,0 +1,240 @@
1
+ #
2
+ Object.send(:remove_const, :Cielli) if Object.const_defined?(:Cielli)
3
+
4
+ #
5
+ require 'json'
6
+ require 'yaml'
7
+ require 'base64'
8
+ require 'securerandom'
9
+ require 'fileutils'
10
+ require 'pathname'
11
+ require 'set'
12
+ require 'openssl'
13
+ require 'uri'
14
+ require 'cgi'
15
+ require 'shellwords'
16
+ require 'tmpdir'
17
+ require 'tempfile'
18
+ require 'pp'
19
+ require 'open3'
20
+
21
+ #
22
+ require_relative 'cielli/_lib'
23
+
24
+ #
25
+ class Cielli
26
+ attr_accessor :source
27
+ attr_accessor :root
28
+ attr_accessor :env
29
+ attr_accessor :argv
30
+ attr_accessor :stdout
31
+ attr_accessor :stdin
32
+ attr_accessor :stderr
33
+ attr_accessor :help
34
+
35
+ def run!(env = ENV, argv = ARGV)
36
+ init!(env, argv)
37
+ parse_command_line!
38
+ set_mode!
39
+ run_mode!
40
+ end
41
+
42
+ def init!(env, argv)
43
+ @klass = self.class
44
+ @env = env.to_hash.dup
45
+ @argv = argv.map{|arg| arg.dup}
46
+ @stdout = $stdout.dup
47
+ @stdin = $stdin.dup
48
+ @stderr = $stderr.dup
49
+ @help = @klass.help || utils.unindent(EXAMPLE_HELP)
50
+ end
51
+
52
+ EXAMPLE_HELP = <<-__
53
+ NAME
54
+ #TODO
55
+
56
+ SYNOPSIS
57
+ #TODO
58
+
59
+ DESCRIPTION
60
+ #TODO
61
+
62
+ EXAMPLES
63
+ #TODO
64
+ __
65
+
66
+ def parse_command_line!
67
+ @options = Hash.new
68
+ @opts = Hash.new
69
+
70
+ argv = []
71
+ head = []
72
+ tail = []
73
+
74
+ %w[ :: -- ].each do |stop|
75
+ if((i = @argv.index(stop)))
76
+ head = @argv.slice(0 ... i)
77
+ tail = @argv.slice((i + 1) ... @argv.size)
78
+ @argv = head
79
+ break
80
+ end
81
+ end
82
+
83
+ @argv.each do |arg|
84
+ case
85
+ when arg =~ %r`^\s*:([^:\s]+)[=](.+)`
86
+ key = $1
87
+ val = $2
88
+ @options[key] = val
89
+ when arg =~ %r`^\s*(:+)(.+)`
90
+ leader = $1
91
+ key = $2
92
+ val = leader.size.odd?
93
+ @options[key] = val
94
+ else
95
+ argv.push(arg)
96
+ end
97
+ end
98
+
99
+ argv += tail
100
+
101
+ @argv.replace(argv)
102
+
103
+ @options.each do |key, val|
104
+ @opts[key.to_s.to_sym] = val
105
+ end
106
+
107
+ [@options, @opts]
108
+ end
109
+
110
+ def set_mode!
111
+ case
112
+ when respond_to?("run_#{ @argv[0] }")
113
+ @mode = @argv.shift
114
+ else
115
+ @mode = nil
116
+ end
117
+ end
118
+
119
+ def run_mode!
120
+ if @mode
121
+ return send("run_#{ @mode }")
122
+ else
123
+ if respond_to?(:run)
124
+ return send(:run)
125
+ end
126
+
127
+ if @argv.empty?
128
+ run_help!
129
+ else
130
+ abort("#{ $0 } help")
131
+ end
132
+ end
133
+ end
134
+
135
+ def run_help!
136
+ STDOUT.puts(@help)
137
+ end
138
+
139
+ def help!
140
+ run_help!
141
+ abort
142
+ end
143
+
144
+ #
145
+ def Cielli.help(*args)
146
+ @help ||= nil
147
+
148
+ unless args.empty?
149
+ @help = utils.unindent(args.join)
150
+ end
151
+
152
+ @help
153
+ end
154
+
155
+ def Cielli.run(*args, &block)
156
+ modes =
157
+ if args.empty?
158
+ [nil]
159
+ else
160
+ args
161
+ end
162
+
163
+ modes.each do |mode|
164
+ method_name =
165
+ if mode
166
+ "run_#{ mode }"
167
+ else
168
+ "run"
169
+ end
170
+
171
+ define_method(method_name, &block)
172
+ end
173
+ end
174
+
175
+ #
176
+ def Cielli.klass_for(&block)
177
+ Class.new(Cielli) do |klass|
178
+ def klass.name; "Cielli::Klass__#{ SecureRandom.uuid.to_s.gsub('-', '_') }"; end
179
+ klass.class_eval(&block)
180
+ end
181
+ end
182
+
183
+ def Cielli.run!(*args, &block)
184
+ STDOUT.sync = true
185
+ STDERR.sync = true
186
+
187
+ %w[ PIPE INT ].each{|signal| Signal.trap(signal, "EXIT")}
188
+
189
+ cielli = (
190
+ source =
191
+ if binding.respond_to?(:source_location)
192
+ File.expand_path(binding.source_location.first)
193
+ else
194
+ File.expand_path(eval('__FILE__', block.binding))
195
+ end
196
+
197
+ root = File.dirname(source)
198
+
199
+ klass = Cielli.klass_for(&block)
200
+
201
+ instance = klass.new
202
+
203
+ instance.source = source
204
+
205
+ instance.root = root
206
+
207
+ instance
208
+ )
209
+
210
+ cielli.run!(*args)
211
+ end
212
+ end
213
+
214
+ #
215
+ require_relative 'cielli/utils'
216
+
217
+ def Cielli.utils(&block)
218
+ block ? Cielli::Utils.module_eval(&block) : Cielli::Utils
219
+ end
220
+
221
+ def Cielli.u(&block)
222
+ Cielli.utils(&block)
223
+ end
224
+
225
+ def utils
226
+ Cielli::Utils
227
+ end
228
+
229
+ def u
230
+ Cielli::Utils
231
+ end
232
+
233
+ #
234
+ class << self
235
+ def cielli(*args, &block)
236
+ Cielli.run!(*args, &block)
237
+ end
238
+
239
+ alias_method :cli, :cielli
240
+ end
@@ -0,0 +1,49 @@
1
+ class Cielli
2
+ Version = '4.2.2' unless defined?(Version)
3
+
4
+ class << self
5
+ def version
6
+ Version
7
+ end
8
+
9
+ def summary
10
+ "a minimalist's toolkit for quickly writing well behaved CLI/cee-el-ahy programs"
11
+ end
12
+
13
+ def dependencies
14
+ { }
15
+ end
16
+
17
+ def load_dependencies!
18
+ begin
19
+ require 'rubygems'
20
+ rescue LoadError
21
+ nil
22
+ end
23
+
24
+ dependencies.each do |lib, dependency|
25
+ gem(*dependency) if defined?(gem)
26
+ require(lib)
27
+ end
28
+ end
29
+
30
+ def libdir(*args, &block)
31
+ @libdir ||= File.dirname(File.expand_path(__FILE__).sub(/\.rb$/,''))
32
+ args.empty? ? @libdir : File.join(@libdir, *args)
33
+ ensure
34
+ if block
35
+ begin
36
+ $LOAD_PATH.unshift(@libdir)
37
+ block.call()
38
+ ensure
39
+ $LOAD_PATH.shift()
40
+ end
41
+ end
42
+ end
43
+
44
+ def load(*libs)
45
+ libs = libs.join(' ').scan(/[^\s+]+/)
46
+ libdir{ libs.each{|lib| Kernel.load(lib) } }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,25 @@
1
+ class Cielli
2
+ class Slug < ::String
3
+ Join = '-'
4
+
5
+ def Slug.for(*args)
6
+ options = args.last.is_a?(Hash) ? args.pop : {}
7
+
8
+ join = (options[:join] || options['join'] || Join).to_s
9
+
10
+ string = args.flatten.compact.join(' ')
11
+
12
+ tokens = string.scan(%r`[^\s#{ join }]+`)
13
+
14
+ tokens.map! do |token|
15
+ token.gsub(%r`[^\p{L}/.]`, '').downcase
16
+ end
17
+
18
+ tokens.map! do |token|
19
+ token.gsub(%r`[/.]`, join * 2)
20
+ end
21
+
22
+ tokens.join(join)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,277 @@
1
+ class Cielli
2
+ module Utils
3
+ def unindent(arg)
4
+ string = arg.to_s.dup
5
+ margin = nil
6
+ string.each_line do |line|
7
+ next if line =~ %r/^\s*$/
8
+ margin = line[%r/^\s*/] and break
9
+ end
10
+ string.gsub!(%r/^#{ margin }/, "") if margin
11
+ margin ? string : nil
12
+ end
13
+
14
+ def indent(arg, *args)
15
+ opts = extract_options!(args)
16
+ n = (args.shift || opts[:n] || 2).to_i
17
+
18
+ string = unindent(arg)
19
+
20
+ indentation = ' ' * n
21
+
22
+ string.gsub(/^/, indentation)
23
+ end
24
+
25
+ def esc(*args)
26
+ args.flatten.compact.map{|arg| Shellwords.escape(arg)}.join(' ')
27
+ end
28
+
29
+ def uuid
30
+ SecureRandom.uuid
31
+ end
32
+
33
+ def tmpname(*args)
34
+ opts = extract_options!(*args)
35
+
36
+ base = opts.fetch(:base){ uuid }.to_s.strip
37
+ ext = opts.fetch(:ext){ 'tmp' }.to_s.strip.sub(/^[.]+/, '')
38
+ basename = opts.fetch(:basename){ "#{ base }.#{ ext }" }
39
+
40
+ File.join(Dir.tmpdir, basename)
41
+ end
42
+
43
+ def tmpfile(*args, &block)
44
+ opts = extract_options!(args)
45
+
46
+ path = tmpname(opts)
47
+
48
+
49
+ tmp = open(path, 'w+')
50
+ tmp.binmode
51
+ tmp.sync = true
52
+
53
+ unless args.empty?
54
+ src = args.join
55
+ tmp.write(src)
56
+ tmp.flush
57
+ tmp.rewind
58
+ end
59
+
60
+ if block
61
+ begin
62
+ block.call(tmp)
63
+ ensure
64
+ FileUtilss.rm_rf(path)
65
+ end
66
+ else
67
+ at_exit{ Kernel.system("rm -rf #{ esc(path) }") }
68
+ return tmp
69
+ end
70
+ end
71
+
72
+ def extract_options!(args)
73
+ unless args.is_a?(Array)
74
+ args = [args]
75
+ end
76
+
77
+ opts = args.last.is_a?(Hash) ? args.pop : {}
78
+
79
+ symbolize_keys!(opts)
80
+
81
+ return opts
82
+ end
83
+
84
+ def extract_options(args)
85
+ opts = extract_options!(args)
86
+
87
+ args.push(opts)
88
+
89
+ opts
90
+ end
91
+
92
+ def symbolize_keys!(hash)
93
+ hash.keys.each do |key|
94
+ if key.is_a?(String)
95
+ val = hash.delete(key)
96
+
97
+ if val.is_a?(Hash)
98
+ symbolize_keys!(val)
99
+ end
100
+
101
+ hash[key.to_s.gsub('-', '_').to_sym] = val
102
+ end
103
+ end
104
+
105
+ return hash
106
+ end
107
+
108
+ def symbolize_keys(hash)
109
+ symbolize_keys!(deepcopy(hash))
110
+ end
111
+
112
+ def deepcopy(object)
113
+ Marshal.load(Marshal.dump(object))
114
+ end
115
+
116
+ def debug!(arg)
117
+ if arg.is_a?(String)
118
+ warn "[DEBUG] #{ arg }"
119
+ else
120
+ warn "[DEBUG] >\n#{ arg.to_yaml rescue arg.pretty_inspect }"
121
+ end
122
+ end
123
+
124
+ def debug(arg)
125
+ debug!(arg) if debug?
126
+ end
127
+
128
+ def debug?
129
+ ENV['CIELLI_DEBUG'] || ENV['DEBUG']
130
+ end
131
+
132
+ def noop
133
+ ENV['CIELLI_NOOP'] || ENV['NOOP']
134
+ end
135
+ alias_method :noop?, :noop
136
+
137
+ def sys!(*args, &block)
138
+ opts = extract_options!(args)
139
+
140
+ cmd = args
141
+
142
+ debug(:cmd => cmd)
143
+
144
+ open3 = (
145
+ block ||
146
+ opts[:stdin] ||
147
+ opts[:quiet] ||
148
+ opts[:capture]
149
+ )
150
+
151
+ die = proc do |command, *args|
152
+ status = args.shift || $?
153
+ warn("#{ [command].join(' ') } #=> status=#{ status.exitstatus }") unless opts[:quiet]
154
+ exit(1)
155
+ end
156
+
157
+ if(open3)
158
+ stdin = opts[:stdin]
159
+ stdout = ''
160
+ stderr = ''
161
+ status = nil
162
+
163
+ begin
164
+ Open3.popen3(*cmd) do |i, o, e, t|
165
+ ot = async_reader_thread_for(o, stdout)
166
+ et = async_reader_thread_for(e, stderr)
167
+
168
+ i.write(stdin) if stdin
169
+ i.close
170
+
171
+ ot.join
172
+ et.join
173
+
174
+ status = t.value
175
+ end
176
+ rescue
177
+ die[cmd]
178
+ end
179
+
180
+ if status.exitstatus == 0
181
+ result = nil
182
+
183
+ if opts[:capture]
184
+ result = stdout.to_s.strip
185
+ else
186
+ if block
187
+ result = block.call(status, stdout, stderr)
188
+ else
189
+ result = [status, stdout, stderr]
190
+ end
191
+ end
192
+
193
+ return(result)
194
+ else
195
+ die[cmd, status]
196
+ end
197
+ else
198
+ env = opts[:env] || {}
199
+ argv = [env, *cmd]
200
+ system(*argv) || die[cmd]
201
+ return true
202
+ end
203
+ end
204
+
205
+ def sys(*args, &block)
206
+ opts = extract_options!(args)
207
+ opts[:quiet] = true
208
+
209
+ args.push(opts)
210
+
211
+ begin
212
+ sys!(*args, &block)
213
+ rescue Object
214
+ false
215
+ end
216
+ end
217
+
218
+ def async_reader_thread_for(io, accum)
219
+ Thread.new(io, accum) do |i, a|
220
+ Thread.current.abort_on_exception = true
221
+
222
+ while true
223
+ buf = i.read(8192)
224
+
225
+ if buf
226
+ a << buf
227
+ else
228
+ break
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ def realpath(path)
235
+ Pathname.new(path.to_s).expand_path.realpath.to_s
236
+ end
237
+
238
+ def filelist(*args, &block)
239
+ accum = (block || proc{ Set.new }).call
240
+ raise ArgumentError.new('accum.class != Set') unless accum.is_a?(Set)
241
+
242
+ _ = args.last.is_a?(Hash) ? args.pop : {}
243
+
244
+ entries = args.flatten.compact.map{|arg| realpath("#{ arg }")}.uniq.sort
245
+
246
+ entries.each do |entry|
247
+ case
248
+ when test(?f, entry)
249
+ file = realpath(entry)
250
+ accum << file
251
+
252
+ when test(?d, entry)
253
+ glob = File.join(entry, '**/**')
254
+
255
+ Dir.glob(glob) do |_entry|
256
+ case
257
+ when test(?f, _entry)
258
+ filelist(_entry){ accum }
259
+ when test(?d, entry)
260
+ filelist(_entry){ accum }
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ accum.to_a
267
+ end
268
+
269
+ require_relative 'slug.rb'
270
+
271
+ def slug_for(*args, &block)
272
+ Slug.for(*args, &block)
273
+ end
274
+
275
+ extend Utils
276
+ end
277
+ end
@@ -0,0 +1,9 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'cielli'
4
+
5
+ cli do
6
+ run do
7
+ p [@argv, @options]
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cielli
3
+ version: !ruby/object:Gem::Version
4
+ version: 4.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Ara T. Howard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-12-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: 'description: cielli kicks the ass'
14
+ email: ara.t.howard@gmail.com
15
+ executables:
16
+ - cielli
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - README.md.erb
22
+ - Rakefile
23
+ - bin/cielli
24
+ - cielli.gemspec
25
+ - lib/cielli.rb
26
+ - lib/cielli/_lib.rb
27
+ - lib/cielli/slug.rb
28
+ - lib/cielli/utils.rb
29
+ - samples/a.rb
30
+ homepage: https://github.com/ahoward/cielli
31
+ licenses:
32
+ - Ruby
33
+ metadata: {}
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubygems_version: 3.0.3
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: cielli
53
+ test_files: []