clee 0.4.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.
data/Rakefile ADDED
@@ -0,0 +1,448 @@
1
+ This.author = "Ara T. Howard"
2
+ This.email = "ara.t.howard@gmail.com"
3
+ This.github = "ahoward"
4
+ This.homepage = "https://github.com/#{ This.github }/#{ This.basename }"
5
+ This.repo = "https://github.com/#{ This.github }/#{ This.basename }"
6
+
7
+ task :default do
8
+ puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
9
+ end
10
+
11
+ task :test do
12
+ run_tests!
13
+ end
14
+
15
+ namespace :test do
16
+ task(:unit){ run_tests!(:unit) }
17
+ task(:functional){ run_tests!(:functional) }
18
+ task(:integration){ run_tests!(:integration) }
19
+ end
20
+
21
+ def run_tests!(which = nil)
22
+ which ||= '**'
23
+ test_dir = File.join(This.dir, "test")
24
+ test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
25
+ test_rbs = Dir.glob(test_glob).sort
26
+
27
+ div = ('=' * 119)
28
+ line = ('-' * 119)
29
+
30
+ test_rbs.each_with_index do |test_rb, index|
31
+ testno = index + 1
32
+ command = "#{ This.ruby } -w -I ./lib -I ./test/lib #{ test_rb }"
33
+
34
+ puts
35
+ say(div, :color => :cyan, :bold => true)
36
+ say("@#{ testno } => ", :bold => true, :method => :print)
37
+ say(command, :color => :cyan, :bold => true)
38
+ say(line, :color => :cyan, :bold => true)
39
+
40
+ system(command)
41
+
42
+ say(line, :color => :cyan, :bold => true)
43
+
44
+ status = $?.exitstatus
45
+
46
+ if status.zero?
47
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
48
+ say("SUCCESS", :color => :green, :bold => true)
49
+ else
50
+ say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
51
+ say("FAILURE", :color => :red, :bold => true)
52
+ end
53
+ say(line, :color => :cyan, :bold => true)
54
+
55
+ exit(status) unless status.zero?
56
+ end
57
+ end
58
+
59
+
60
+ task :gemspec do
61
+ ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
62
+ ignore_directories = ['pkg']
63
+ ignore_files = ['test/log']
64
+
65
+ shiteless =
66
+ lambda do |list|
67
+ list.delete_if do |entry|
68
+ next unless test(?e, entry)
69
+ extension = File.basename(entry).split(%r/[.]/).last
70
+ ignore_extensions.any?{|ext| ext === extension}
71
+ end
72
+
73
+ list.delete_if do |entry|
74
+ next unless test(?d, entry)
75
+ dirname = File.expand_path(entry)
76
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
77
+ end
78
+
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
+ name = This.basename
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
+ summary = Util.unindent(This.summary).strip
92
+ description = Util.unindent(This.description).strip
93
+ license = "LicenseRef-LICENSE.md"
94
+
95
+ if This.extensions.nil?
96
+ This.extensions = []
97
+ extensions = This.extensions
98
+ %w( Makefile configure extconf.rb ).each do |ext|
99
+ extensions << ext if File.exist?(ext)
100
+ end
101
+ end
102
+ extensions = [extensions].flatten.compact
103
+
104
+ if This.dependencies.nil?
105
+ dependencies = []
106
+ else
107
+ case This.dependencies
108
+ when Hash
109
+ dependencies = This.dependencies.values
110
+ when Array
111
+ dependencies = This.dependencies
112
+ end
113
+ end
114
+
115
+ template =
116
+ if test(?e, 'gemspec.erb')
117
+ Template{ IO.read('gemspec.erb') }
118
+ else
119
+ Template {
120
+ <<-__
121
+ ## <%= name %>.gemspec
122
+ #
123
+
124
+ Gem::Specification::new do |spec|
125
+ spec.name = <%= name.inspect %>
126
+ spec.version = <%= version.inspect %>
127
+ spec.required_ruby_version = '>= 3.0'
128
+ spec.platform = Gem::Platform::RUBY
129
+ spec.summary = <%= summary.inspect %>
130
+ spec.description = <%= description.inspect %>
131
+ spec.license = <%= license.inspect %>
132
+
133
+ spec.files =\n<%= files.sort.pretty_inspect %>
134
+ spec.executables = <%= executables.inspect %>
135
+
136
+ spec.require_path = "lib"
137
+
138
+ <% dependencies.each do |lib_version| %>
139
+ spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
140
+ <% end %>
141
+
142
+ spec.extensions.push(*<%= extensions.inspect %>)
143
+
144
+ spec.author = <%= This.author.inspect %>
145
+ spec.email = <%= This.email.inspect %>
146
+ spec.homepage = <%= This.homepage.inspect %>
147
+ end
148
+ __
149
+ }
150
+ end
151
+
152
+ Fu.mkdir_p(This.pkgdir)
153
+ gemspec = "#{ name }.gemspec"
154
+ open(gemspec, "w"){|fd| fd.puts(template)}
155
+ This.gemspec = gemspec
156
+ end
157
+
158
+ task :gem => [:clean, :gemspec] do
159
+ Fu.mkdir_p(This.pkgdir)
160
+ before = Dir['*.gem']
161
+ cmd = "gem build #{ This.gemspec }"
162
+ `#{ cmd }`
163
+ after = Dir['*.gem']
164
+ gem = ((after - before).first || after.first) or abort('no gem!')
165
+ Fu.mv(gem, This.pkgdir)
166
+ This.gem = File.join(This.pkgdir, File.basename(gem))
167
+ end
168
+
169
+ task :README => [:readme]
170
+
171
+ task :readme do
172
+ samples = ''
173
+ prompt = '~ > '
174
+ lib = This.lib
175
+ version = This.version
176
+
177
+ Dir['sample*/**/**.rb'].sort.each do |sample|
178
+ link = "[#{ sample }](#{ This.repo }/blob/main/#{ sample })"
179
+ samples << " #### <========< #{ link } >========>\n"
180
+
181
+ cmd = "cat #{ sample }"
182
+ samples << "```sh\n"
183
+ samples << Util.indent(prompt + cmd, 2) << "\n"
184
+ samples << "```\n"
185
+ samples << "```ruby\n"
186
+ samples << Util.indent(IO.binread(sample), 4) << "\n"
187
+ samples << "```\n"
188
+
189
+ samples << "\n"
190
+
191
+ cmd = "ruby #{ sample }"
192
+ samples << "```sh\n"
193
+ samples << Util.indent(prompt + cmd, 2) << "\n"
194
+ samples << "```\n"
195
+
196
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
197
+ oe = `#{ cmd } 2>&1`
198
+ samples << "```txt\n"
199
+ samples << Util.indent(oe, 4) << "\n"
200
+ samples << "```\n"
201
+
202
+ samples << "\n"
203
+ end
204
+
205
+ This.samples = samples
206
+
207
+ template =
208
+ case
209
+ when test(?e, 'README.md.erb')
210
+ Template{ IO.read('README.md.erb') }
211
+ when test(?e, 'README.erb')
212
+ Template{ IO.read('README.erb') }
213
+ else
214
+ Template {
215
+ <<-__
216
+ NAME
217
+ #{ lib }
218
+
219
+ DESCRIPTION
220
+
221
+ INSTALL
222
+ gem install #{ lib }
223
+
224
+ SAMPLES
225
+ #{ samples }
226
+ __
227
+ }
228
+ end
229
+
230
+ IO.binwrite('README.md', template)
231
+ end
232
+
233
+ task :clean do
234
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
235
+ end
236
+
237
+ task :release => [:dist, :gem] do
238
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
239
+ abort "which one? : #{ gems.inspect }" if gems.size > 1
240
+ abort "no gems?" if gems.size < 1
241
+
242
+ cmd = "gem push #{ This.gem }"
243
+ puts cmd
244
+ puts
245
+ system(cmd)
246
+ abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
247
+ end
248
+
249
+
250
+
251
+
252
+
253
+ BEGIN {
254
+ # support for this rakefile
255
+ #
256
+ $VERBOSE = nil
257
+
258
+ require 'ostruct'
259
+ require 'erb'
260
+ require 'fileutils'
261
+ require 'rbconfig'
262
+ require 'pp'
263
+
264
+ # fu shortcut!
265
+ #
266
+ Fu = FileUtils
267
+
268
+ # guess a bunch of stuff about this rakefile/environment based on the
269
+ #
270
+ This = OpenStruct.new
271
+
272
+ This.file = File.expand_path(__FILE__)
273
+ This.dir = File.dirname(This.file)
274
+ This.pkgdir = File.join(This.dir, 'pkg')
275
+ This.basename = File.basename(This.dir)
276
+
277
+ # load actual shit _lib
278
+ #
279
+ _libpath = ["./lib/#{ This.basename }/_lib.rb", "./lib/#{ This.basename }.rb"]
280
+ _lib = _libpath.detect{|l| test(?s, l)}
281
+
282
+ abort "could not find a _lib in ./lib/ via #{ _libpath.join(':') }" unless _lib
283
+
284
+ This._lib = _lib
285
+ require This._lib
286
+
287
+ # extract the name from the _lib
288
+ #
289
+ lines = IO.binread(This._lib).split("\n")
290
+ re = %r`\A \s* (module|class) \s+ ([^\s]+) \s* \z`iomx
291
+ name = nil
292
+ lines.each do |line|
293
+ match = line.match(re)
294
+ if match
295
+ name = match.to_a.last
296
+ break
297
+ end
298
+ end
299
+ unless name
300
+ abort "could not extract `name` from #{ This._lib }"
301
+ end
302
+ This.name = name
303
+ This.basename = This.name.downcase
304
+
305
+ # now, fully grok This
306
+ #
307
+ This.object = eval(This.name)
308
+ This.version = This.object.version
309
+ This.dependencies = This.object.dependencies
310
+ This.summary = This.object.summary
311
+ This.description = This.object.respond_to?(:description) ? This.object.description : This.summary
312
+ This.license = "LicenseRef-LICENSE.md"
313
+
314
+ # discover full path to this ruby executable
315
+ #
316
+ c = RbConfig::CONFIG
317
+ bindir = c["bindir"] || c['BINDIR']
318
+ ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
319
+ ruby_ext = c['EXEEXT'] || ''
320
+ ruby = File.join(bindir, (ruby_install_name + ruby_ext))
321
+ This.ruby = ruby
322
+
323
+ # some utils, alwayze teh utils...
324
+ #
325
+ module Util
326
+ def indent(s, n = 2)
327
+ s = unindent(s)
328
+ ws = ' ' * n
329
+ s.gsub(%r/^/, ws)
330
+ end
331
+
332
+ def unindent(s)
333
+ indent = nil
334
+ s.each_line do |line|
335
+ next if line =~ %r/^\s*$/
336
+ indent = line[%r/^\s*/] and break
337
+ end
338
+ unindented = indent ? s.gsub(%r/^#{ indent }/, "") : s
339
+ unindented.strip
340
+ end
341
+ extend self
342
+ end
343
+
344
+ # template support
345
+ #
346
+ class Template
347
+ def Template.indent(string, n = 2)
348
+ string = string.to_s
349
+ n = n.to_i
350
+ padding = (42 - 10).chr * n
351
+ initial = %r/^#{ Regexp.escape(padding) }/
352
+ #require 'debug'
353
+ #binding.break
354
+ Util.indent(string, n).sub(initial, '')
355
+ end
356
+ def initialize(&block)
357
+ @block = block
358
+ @template = block.call.to_s
359
+ end
360
+ def expand(b=nil)
361
+ ERB.new(Util.unindent(@template), trim_mode: '%<>-').result((b||@block).binding)
362
+ end
363
+ alias_method 'to_s', 'expand'
364
+ end
365
+ def Template(*args, &block) Template.new(*args, &block) end
366
+
367
+ # os / platform support
368
+ #
369
+ module Platform
370
+ def Platform.windows?
371
+ (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
372
+ end
373
+
374
+ def Platform.darwin?
375
+ (/darwin/ =~ RUBY_PLATFORM) != nil
376
+ end
377
+
378
+ def Platform.mac?
379
+ Platform.darwin?
380
+ end
381
+
382
+ def Platform.unix?
383
+ !Platform.windows?
384
+ end
385
+
386
+ def Platform.linux?
387
+ Platform.unix? and not Platform.darwin?
388
+ end
389
+
390
+ def Platform.jruby?
391
+ RUBY_ENGINE == 'jruby'
392
+ end
393
+ end
394
+
395
+ # colored console output support
396
+ #
397
+ This.ansi = {
398
+ :clear => "\e[0m",
399
+ :reset => "\e[0m",
400
+ :erase_line => "\e[K",
401
+ :erase_char => "\e[P",
402
+ :bold => "\e[1m",
403
+ :dark => "\e[2m",
404
+ :underline => "\e[4m",
405
+ :underscore => "\e[4m",
406
+ :blink => "\e[5m",
407
+ :reverse => "\e[7m",
408
+ :concealed => "\e[8m",
409
+ :black => "\e[30m",
410
+ :red => "\e[31m",
411
+ :green => "\e[32m",
412
+ :yellow => "\e[33m",
413
+ :blue => "\e[34m",
414
+ :magenta => "\e[35m",
415
+ :cyan => "\e[36m",
416
+ :white => "\e[37m",
417
+ :on_black => "\e[40m",
418
+ :on_red => "\e[41m",
419
+ :on_green => "\e[42m",
420
+ :on_yellow => "\e[43m",
421
+ :on_blue => "\e[44m",
422
+ :on_magenta => "\e[45m",
423
+ :on_cyan => "\e[46m",
424
+ :on_white => "\e[47m"
425
+ }
426
+ def say(phrase, *args)
427
+ options = args.last.is_a?(Hash) ? args.pop : {}
428
+ options[:color] = args.shift.to_s.to_sym unless args.empty?
429
+ keys = options.keys
430
+ keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
431
+
432
+ color = options[:color]
433
+ bold = options.has_key?(:bold)
434
+
435
+ parts = [phrase]
436
+ parts.unshift(This.ansi[color]) if color
437
+ parts.unshift(This.ansi[:bold]) if bold
438
+ parts.push(This.ansi[:clear]) if parts.size > 1
439
+
440
+ method = options[:method] || :puts
441
+
442
+ Kernel.send(method, parts.join)
443
+ end
444
+
445
+ # always run out of the project dir
446
+ #
447
+ Dir.chdir(This.dir)
448
+ }
data/TODO.md ADDED
@@ -0,0 +1 @@
1
+ #FIXME
data/bin/clee ADDED
@@ -0,0 +1,55 @@
1
+ #! /usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ clee do
5
+ #
6
+ tldr <<~____
7
+ ~> clee new $script_name
8
+ ____
9
+
10
+ run :new do
11
+ name = argv.shift
12
+ template = DATA.read
13
+ script_name = name ? "#{ name.inspect } " : ""
14
+ puts template.gsub(%r`[$]script_name\s*`, script_name)
15
+ end
16
+ end
17
+
18
+ BEGIN {
19
+ bindir = File.expand_path(__dir__)
20
+ root = File.dirname(bindir)
21
+ libdir = File.join(root, 'lib')
22
+
23
+ require "#{ libdir }/clee.rb"
24
+ }
25
+
26
+ __END__
27
+ #! /usr/bin/env ruby
28
+ # encoding: utf-8
29
+ # rubocop:disable all
30
+
31
+ clee $script_name do
32
+ tldr <<~____
33
+ NAME
34
+ # FIXME
35
+
36
+ TL;DR;
37
+ # FIXME
38
+ ____
39
+
40
+ run do
41
+ p [@mode, @argv, @options]
42
+ end
43
+
44
+ run :foo do
45
+ p [@mode, @argv, @options]
46
+ end
47
+
48
+ run :foo, :bar do
49
+ p [@mode, @argv, @options]
50
+ end
51
+ end
52
+
53
+ BEGIN {
54
+ require "clee"
55
+ }
data/clee.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ ## clee.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "clee"
6
+ spec.version = "0.4.2"
7
+ spec.required_ruby_version = '>= 3.0'
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.summary = "`clee` is a tiny, 0 dependency, DSL for building über clean CLIs in Ruby"
10
+ spec.description = "`clee` has everything you need, and nothing you don't"
11
+ spec.license = "LicenseRef-LICENSE.md"
12
+
13
+ spec.files =
14
+ ["LICENSE.md",
15
+ "README.md",
16
+ "Rakefile",
17
+ "TODO.md",
18
+ "bin",
19
+ "bin/clee",
20
+ "clee.gemspec",
21
+ "docs",
22
+ "docs/sunwukong.md",
23
+ "lib",
24
+ "lib/clee",
25
+ "lib/clee.rb",
26
+ "lib/clee/_lib.rb",
27
+ "test"]
28
+
29
+ spec.executables = ["clee"]
30
+
31
+ spec.require_path = "lib"
32
+
33
+
34
+
35
+ spec.extensions.push(*[])
36
+
37
+ spec.author = "Ara T. Howard"
38
+ spec.email = "ara.t.howard@gmail.com"
39
+ spec.homepage = "https://github.com/ahoward/clee"
40
+ end
data/docs/sunwukong.md ADDED
@@ -0,0 +1,38 @@
1
+ **Sun Wukong (Journey to the West)**
2
+
3
+ Sun Wukong, also known as the Monkey King, is an iconic figure from the 16th-century Chinese novel "Journey to the West." He's a character brimming with personality and extraordinary abilities.
4
+
5
+ **Origins and Abilities:**
6
+
7
+ * **Born from Stone:**
8
+ * Emerges from a magical stone atop Flower Fruit Mountain, imbued with the powers of heaven and earth.
9
+ * **Supernatural Powers:**
10
+ * **72 Transformations:** Shapeshifts into virtually anything.
11
+ * **Cloud Somersault:** Travels immense distances in a single leap.
12
+ * **Immortality:** Achieves a form of immortality.
13
+ * **Cloning:** Creates clones by plucking his hairs.
14
+ * Great martial arts skills, and immense strength.
15
+ * **Rebellious Nature:**
16
+ * Mischievous and rebellious spirit, challenging authority, especially the heavenly court.
17
+
18
+ **The Journey to the West:**
19
+
20
+ * **Pilgrimage:**
21
+ * Protector and disciple of the Buddhist monk Tang Sanzang on a journey to retrieve sacred scriptures.
22
+ * **Redemption:**
23
+ * Journey serves as a path of redemption, learning to control his impulsive nature.
24
+ * **Character Arc:**
25
+ * Matures from a wild, self-centered being to a protector of the innocent.
26
+
27
+ **Cultural Significance:**
28
+
29
+ * **Enduring Popularity:**
30
+ * Inspires countless adaptations in various media.
31
+ * **Symbolism:**
32
+ * Represents themes of freedom, rebellion, and the pursuit of enlightenment.
33
+ * **Influence:**
34
+ * Son Goku from "Dragon Ball" is heavily based on Sun Wukong.
35
+
36
+ **References**
37
+
38
+ * https://en.wikipedia.org/wiki/Sun_Wukong#:~:text=Sun%20Wukong%20(Chinese%3A%20%E5%AD%AB%E6%82%9F%E7%A9%BA%2C,known%20as%20one%20of%20the
data/lib/clee/_lib.rb ADDED
@@ -0,0 +1,75 @@
1
+ class Clee
2
+ VERSION = '0.4.2'
3
+
4
+ class << Clee
5
+ def version
6
+ VERSION
7
+ end
8
+
9
+ def repo
10
+ 'https://github.com/ahoward/clee'
11
+ end
12
+
13
+ def summary
14
+ <<~____
15
+ `clee` is a tiny, 0 dependency, DSL for building über clean CLIs in Ruby
16
+ ____
17
+ end
18
+
19
+ def description
20
+ <<~____
21
+ `clee` has everything you need, and nothing you don't
22
+ ____
23
+ end
24
+
25
+ def libs
26
+ %w[
27
+ optparse
28
+ time
29
+ ]
30
+ end
31
+
32
+ def dependencies
33
+ {
34
+ }
35
+ end
36
+
37
+ def libdir(*args, &block)
38
+ @libdir ||= File.dirname(File.expand_path(__FILE__))
39
+ args.empty? ? @libdir : File.join(@libdir, *args)
40
+ ensure
41
+ if block
42
+ begin
43
+ $LOAD_PATH.unshift(@libdir)
44
+ block.call
45
+ ensure
46
+ $LOAD_PATH.shift
47
+ end
48
+ end
49
+ end
50
+
51
+ def load(*libs)
52
+ libs = libs.join(' ').scan(/[^\s+]+/)
53
+ libdir { libs.each { |lib| Kernel.load(lib) } }
54
+ end
55
+
56
+ def load_dependencies!
57
+ libs.each do |lib|
58
+ require lib
59
+ end
60
+
61
+ begin
62
+ require 'rubygems'
63
+ rescue LoadError
64
+ nil
65
+ end
66
+
67
+ has_rubygems = defined?(gem)
68
+
69
+ dependencies.each do |lib, dependency|
70
+ gem(*dependency) if has_rubygems
71
+ require(lib)
72
+ end
73
+ end
74
+ end
75
+ end