cielli 4.2.2

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: 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: []