ergane 0.0.1 → 0.1.0

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/lib/ergane.rb CHANGED
@@ -1,85 +1,40 @@
1
- require 'active_support'
2
- require 'active_support/core_ext'
3
- require 'active_support/dependencies'
4
- require 'optparse'
5
- require 'colorize'
6
- require 'notifier'
7
- require 'pry-byebug'
1
+ # frozen_string_literal: true
8
2
 
9
- $LOAD_PATH.unshift File.expand_path("#{__dir__}/ergane")
3
+ require "zeitwerk"
4
+ require "optparse"
5
+ require "colorize"
10
6
 
11
- require 'ergane/version'
12
- require 'ergane/command_definition'
13
- require 'ergane/tool'
7
+ # Eager-loaded (not autoloadable by convention)
8
+ require_relative "ergane/errors"
9
+ require_relative "ergane/core_ext/string"
10
+ require_relative "ergane/core_ext/object"
11
+ require_relative "ergane/core_ext/array"
12
+ require_relative "ergane/core_ext/hash"
13
+ require_relative "ergane/core_ext/option_parser"
14
14
 
15
15
  module Ergane
16
-
17
- Help = Class.new(StandardError)
18
- Interrupt = Class.new(StandardError)
19
-
20
- class << self
21
- attr_reader :logger
22
-
23
- def root(*args)
24
- (@root ||= Pathname.new(File.expand_path('../', __dir__))).join(*args)
25
- end
26
-
27
- def logger
28
- @logger ||= Logger.new($stdout).tap do |log|
29
- log.progname = @@active_tool&.title || self.name
30
- log.level = :warn
31
- end
32
- end
33
-
34
- # def debug(string)
35
- # old_level = logger.level
36
- # logger.level = :debug if $debug
37
- # logger.debug(string)
38
- # ensure
39
- # logger.level = old_level
40
- # end
41
-
42
- @@active_tool = nil
43
-
44
- def active_tool
45
- @@active_tool
46
- end
47
-
48
- def activate_tool(tool)
49
- previous_tool = @@active_tool
50
- @@active_tool = tool
51
- yield if block_given?
52
- ensure
53
- @@active_tool = previous_tool
54
- end
55
-
56
- def notify(message, title: nil, sound: nil, icon: nil, group: nil)
57
- cmd = ['terminal-notifier']
58
- cmd << "-group #{Process.pid}#{group}"
59
- cmd << "-title #{active_tool.label}"
60
- cmd << "-subtitle #{title}" if title
61
- cmd << "-appIcon 'assets/athena md-light-shadow.png'" if icon
62
- cmd << "-message '#{message}'"
63
- cmd << "-activate 'com.apple.Terminal'" # if macos
64
- cmd << "-sound #{sound}" if sound
65
- Thread.new { `afplay /System/Library/Sounds/#{sound == true ? 'Blow' : sound}.aiff` } unless sound == false
66
-
67
- `#{cmd.join(' ')}`
68
- # Notifier.notify(title: title, message: message, image: 'assets/athena md-light-shadow.png')
69
- end
70
-
71
- # Show a list of available extensions to use
72
- def extensions
73
- Extension.library
74
- end
16
+ LOADER = Zeitwerk::Loader.new.tap do |loader|
17
+ loader.tag = "ergane"
18
+ loader.inflector.inflect(
19
+ "dsl" => "DSL",
20
+ "command_dsl" => "CommandDSL",
21
+ "block_dsl" => "BlockDSL"
22
+ )
23
+ loader.push_dir(File.expand_path("..", __FILE__))
24
+ loader.ignore(File.expand_path("ergane/errors.rb", __dir__))
25
+ loader.ignore(File.expand_path("ergane/core_ext", __dir__))
26
+ loader.ignore(File.expand_path("ergane.rb", __dir__))
27
+ loader.setup
75
28
  end
76
- end
77
29
 
78
- if ARGV.include?('--debug')
79
- $debug = true
80
- Ergane.logger.level = :debug
81
- end
30
+ def self.root
31
+ @root ||= Pathname.new(File.expand_path("../..", __FILE__))
32
+ end
82
33
 
83
- Dir[Ergane.root('lib', 'core_ext', "*.rb")].each do |path|
84
- require path
34
+ # The shared registry of path-prefix abbreviations used by
35
+ # Command#abbreviate_path. Seeded with $HOME → "~"; consumers may
36
+ # register additional substitutions.
37
+ def self.paths
38
+ @paths ||= PathRegistry.new.register("~", "~")
39
+ end
85
40
  end
metadata CHANGED
@@ -1,65 +1,50 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ergane
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dale Stevens
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-05-08 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: activesupport
13
+ name: zeitwerk
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - ">="
16
+ - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '0'
18
+ version: '2.6'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
- - - ">="
23
+ - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '0'
25
+ version: '2.6'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: colorize
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: terminal-notifier
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
30
+ - - "~>"
46
31
  - !ruby/object:Gem::Version
47
- version: '0'
32
+ version: '1.1'
48
33
  type: :runtime
49
34
  prerelease: false
50
35
  version_requirements: !ruby/object:Gem::Requirement
51
36
  requirements:
52
- - - ">="
37
+ - - "~>"
53
38
  - !ruby/object:Gem::Version
54
- version: '0'
39
+ version: '1.1'
55
40
  - !ruby/object:Gem::Dependency
56
- name: notifier
41
+ name: bundler
57
42
  requirement: !ruby/object:Gem::Requirement
58
43
  requirements:
59
44
  - - ">="
60
45
  - !ruby/object:Gem::Version
61
46
  version: '0'
62
- type: :runtime
47
+ type: :development
63
48
  prerelease: false
64
49
  version_requirements: !ruby/object:Gem::Requirement
65
50
  requirements:
@@ -73,7 +58,7 @@ dependencies:
73
58
  - - ">="
74
59
  - !ruby/object:Gem::Version
75
60
  version: '0'
76
- type: :runtime
61
+ type: :development
77
62
  prerelease: false
78
63
  version_requirements: !ruby/object:Gem::Requirement
79
64
  requirements:
@@ -81,105 +66,118 @@ dependencies:
81
66
  - !ruby/object:Gem::Version
82
67
  version: '0'
83
68
  - !ruby/object:Gem::Dependency
84
- name: bundler
69
+ name: rake
85
70
  requirement: !ruby/object:Gem::Requirement
86
71
  requirements:
87
- - - ">="
72
+ - - "~>"
88
73
  - !ruby/object:Gem::Version
89
- version: '0'
74
+ version: '13.0'
90
75
  type: :development
91
76
  prerelease: false
92
77
  version_requirements: !ruby/object:Gem::Requirement
93
78
  requirements:
94
- - - ">="
79
+ - - "~>"
95
80
  - !ruby/object:Gem::Version
96
- version: '0'
81
+ version: '13.0'
97
82
  - !ruby/object:Gem::Dependency
98
- name: ruby-prof
83
+ name: rspec
99
84
  requirement: !ruby/object:Gem::Requirement
100
85
  requirements:
101
- - - ">="
86
+ - - "~>"
102
87
  - !ruby/object:Gem::Version
103
- version: '0'
88
+ version: '3.12'
104
89
  type: :development
105
90
  prerelease: false
106
91
  version_requirements: !ruby/object:Gem::Requirement
107
92
  requirements:
108
- - - ">="
93
+ - - "~>"
109
94
  - !ruby/object:Gem::Version
110
- version: '0'
95
+ version: '3.12'
111
96
  - !ruby/object:Gem::Dependency
112
- name: rspec
97
+ name: rubocop
113
98
  requirement: !ruby/object:Gem::Requirement
114
99
  requirements:
115
- - - ">="
100
+ - - "~>"
116
101
  - !ruby/object:Gem::Version
117
- version: '0'
102
+ version: '1.50'
118
103
  type: :development
119
104
  prerelease: false
120
105
  version_requirements: !ruby/object:Gem::Requirement
121
106
  requirements:
122
- - - ">="
107
+ - - "~>"
123
108
  - !ruby/object:Gem::Version
124
- version: '0'
109
+ version: '1.50'
125
110
  - !ruby/object:Gem::Dependency
126
- name: pry-byebug
111
+ name: simplecov
127
112
  requirement: !ruby/object:Gem::Requirement
128
113
  requirements:
129
- - - ">="
114
+ - - "~>"
130
115
  - !ruby/object:Gem::Version
131
- version: '0'
116
+ version: '0.22'
132
117
  type: :development
133
118
  prerelease: false
134
119
  version_requirements: !ruby/object:Gem::Requirement
135
120
  requirements:
136
- - - ">="
121
+ - - "~>"
137
122
  - !ruby/object:Gem::Version
138
- version: '0'
123
+ version: '0.22'
139
124
  - !ruby/object:Gem::Dependency
140
- name: rake
125
+ name: simplecov-json
141
126
  requirement: !ruby/object:Gem::Requirement
142
127
  requirements:
143
- - - ">="
128
+ - - "~>"
144
129
  - !ruby/object:Gem::Version
145
- version: '0'
130
+ version: '0.2'
146
131
  type: :development
147
132
  prerelease: false
148
133
  version_requirements: !ruby/object:Gem::Requirement
149
134
  requirements:
150
- - - ">="
135
+ - - "~>"
151
136
  - !ruby/object:Gem::Version
152
- version: '0'
137
+ version: '0.2'
153
138
  description: |
154
- Library for creating lightweight, yet powerful CLI tools in Ruby.
155
- Emphasis and priority on load speed and flexibility.
139
+ A lightweight, powerful CLI framework for Ruby. Define commands using
140
+ class inheritance or block DSL both produce the same command tree.
141
+ An alternative to Thor with a cleaner, more Ruby-native design.
156
142
  email:
157
143
  - dale@twilightcoders.net
158
- executables:
159
- - ergane
144
+ executables: []
160
145
  extensions: []
161
146
  extra_rdoc_files: []
162
147
  files:
163
148
  - CHANGELOG.md
164
149
  - LICENSE
165
150
  - README.md
166
- - app/commands/ergane/console.rb
167
- - bin/ergane
168
- - lib/core_ext/option_parser.rb
169
151
  - lib/ergane.rb
170
- - lib/ergane/command_definition.rb
171
- - lib/ergane/debug.rb
172
- - lib/ergane/helpers/hashall.rb
173
- - lib/ergane/switch_definition.rb
152
+ - lib/ergane/argument_definition.rb
153
+ - lib/ergane/command.rb
154
+ - lib/ergane/concerns/inheritance.rb
155
+ - lib/ergane/concerns/option_handling.rb
156
+ - lib/ergane/core_ext/array.rb
157
+ - lib/ergane/core_ext/hash.rb
158
+ - lib/ergane/core_ext/object.rb
159
+ - lib/ergane/core_ext/option_parser.rb
160
+ - lib/ergane/core_ext/string.rb
161
+ - lib/ergane/dsl/block_dsl.rb
162
+ - lib/ergane/dsl/command_dsl.rb
163
+ - lib/ergane/errors.rb
164
+ - lib/ergane/formatter.rb
165
+ - lib/ergane/help_formatter.rb
166
+ - lib/ergane/option_definition.rb
167
+ - lib/ergane/path_registry.rb
168
+ - lib/ergane/runner.rb
174
169
  - lib/ergane/tool.rb
175
- - lib/ergane/util.rb
170
+ - lib/ergane/util/debug.rb
171
+ - lib/ergane/util/formatting.rb
176
172
  - lib/ergane/version.rb
177
173
  homepage: https://github.com/TwilightCoders/ergane
178
174
  licenses:
179
175
  - MIT
180
176
  metadata:
181
- allowed_push_host: https://rubygems.org
182
- post_install_message:
177
+ rubygems_mfa_required: 'true'
178
+ homepage_uri: https://github.com/TwilightCoders/ergane
179
+ source_code_uri: https://github.com/TwilightCoders/ergane
180
+ changelog_uri: https://github.com/TwilightCoders/ergane/blob/main/CHANGELOG.md
183
181
  rdoc_options: []
184
182
  require_paths:
185
183
  - lib
@@ -187,15 +185,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
187
185
  requirements:
188
186
  - - ">="
189
187
  - !ruby/object:Gem::Version
190
- version: '2.7'
188
+ version: '3.1'
191
189
  required_rubygems_version: !ruby/object:Gem::Requirement
192
190
  requirements:
193
191
  - - ">="
194
192
  - !ruby/object:Gem::Version
195
193
  version: '0'
196
194
  requirements: []
197
- rubygems_version: 3.1.6
198
- signing_key:
195
+ rubygems_version: 3.6.9
199
196
  specification_version: 4
200
- summary: Ergane — The patron goddess of craftsmen and artisans
197
+ summary: Ergane — a CLI framework forged for mortals
201
198
  test_files: []
@@ -1,22 +0,0 @@
1
- define :console do
2
-
3
- description "Jump into an interactive REPL console"
4
-
5
- requirements inherit: true do
6
- require 'colorize'
7
-
8
- end
9
-
10
- switches(inherit: false) do
11
- # option(:help, description: "display help")
12
- end
13
-
14
- run do
15
- Pry.config.prompt_name = "#{Process.argv0.split('/').last.capitalize} #{label} ".light_blue
16
- Pry.start
17
- end
18
-
19
- def support_method
20
-
21
- end
22
- end
data/bin/ergane DELETED
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- profile = nil
4
- if ARGV.include?('--profile')
5
- require 'ruby-prof'
6
- profile = RubyProf::Profile.new
7
- profile.exclude_common_methods!
8
- profile.start
9
- end
10
-
11
- require 'bundler/setup'
12
- require 'ergane'
13
- require 'ergane/tool'
14
-
15
- tool = Ergane::Tool.new :ergane, 'lib/ergane/commands/**/*.rb', 'app/**/commands/**/*.rb'
16
- tool.run
17
-
18
- if profile
19
- result = profile.stop
20
- File.open "profile-graph.html", 'w+' do |file|
21
- # RubyProf::GraphHtmlPrinter.new(results).print(file)
22
- RubyProf::CallStackPrinter.new(result).print(file)
23
- end
24
- end
@@ -1,176 +0,0 @@
1
- # IDEA: "switches" are just "inline commands".
2
- # They share a similar structure to a command.
3
- # They have a label, description, and optionally a "run block"
4
-
5
- require 'pry'
6
- require 'helpers/hashall'
7
- require 'switch_definition'
8
-
9
- module Ergane
10
-
11
- class CommandDefinition < Hashall
12
-
13
- attr_reader :label
14
- attr_reader :chain
15
- attr_reader :description
16
- attr_reader :switch_definitions
17
- attr_reader :switch_parser
18
- attr_reader :requirements_block
19
- attr_reader :run_block
20
-
21
- def pretty_print(q)
22
- q.text "#{self.class.name} (#{label})"
23
- q.text "\n\tCommands:"
24
- q.group(1, " {", "}") do
25
- self.each_pair do |key, value|
26
- q.breakable
27
- q.text "#{key}: #{value}"
28
- end
29
- end
30
- end
31
-
32
- def run(*args)
33
- if run_block
34
- instance_exec(&requirements_block) if requirements_block
35
- instance_exec(*args, &run_block) if run_block
36
- else
37
- puts "show help for this command"
38
- end
39
- end
40
-
41
- def self.define(label, chain: [], &block)
42
- new(label, *chain).tap do |c|
43
- c.define(chain: chain, &block)
44
- end
45
- end
46
-
47
- def define(chain: [], &block)
48
- dsl_parse(&block)
49
- end
50
-
51
- def commands
52
- self.to_h
53
- end
54
-
55
- def arguments
56
- if commands.any?
57
- commands.keys
58
- else
59
- instance_method(:run).parameters.map { |arg| arg[1] }
60
- end
61
- end
62
-
63
- def default_switches
64
- @default_switches ||= switch_definitions.inject({}) do |collector, (label, switch)|
65
- collector[label] = switch.default
66
- collector
67
- end
68
- @default_switches.dup
69
- end
70
-
71
- def parse_args(args, path = [])
72
- if args.any? && args.first.match(/\A(\w+)\z/) && word = args.first.to_sym
73
- case command = self[word]
74
- when CommandDefinition
75
- path << args.shift
76
- command.parse_args(args, path)
77
- else
78
- puts "no such subcommand #{word} for #{self}"
79
- end
80
- else
81
- # These are args for this command now.
82
- Ergane.logger.debug "Now, process these args #{args} for #{label}"
83
- switch_parser.order_recognized!(args)
84
- [self, args || []]
85
- end
86
- end
87
-
88
- protected
89
-
90
- def dsl_parse(&block)
91
- dsl = DSL.new.tap do |dsl|
92
- dsl.instance_eval(&block)
93
- end
94
- @switch_definitions.merge!(dsl.config.delete(:switch_definitions))
95
- dsl.config.each do |k, v|
96
- begin
97
- instance_variable_set("@#{k}", v)
98
- rescue
99
- binding.pry
100
- end
101
- end
102
-
103
- switches = default_switches
104
- switch_definitions.values.each do |o|
105
- o.attach(@switch_parser, self) do |value|
106
- value = case o.kind
107
- when TrueClass
108
- true
109
- when FalseClass
110
- false
111
- else
112
- value.nil? ? true : value
113
- end
114
- Ergane.logger.debug "Setting switches[#{o.label}] = #{value.inspect}"
115
- switches[o.label] = value
116
- end
117
- end
118
- end
119
-
120
- private
121
-
122
- def initialize(label, *chain)
123
- super()
124
- @chain = chain
125
- @label = label
126
- @switch_definitions = {}
127
- @requirement_options = {
128
- inherit: true
129
- }
130
- @run_options = {
131
- inherit: true
132
- }
133
- @switch_parser = OptionParser.new
134
- end
135
-
136
- class DSL
137
- attr_reader :config
138
-
139
- def initialize
140
- @config = {
141
- switch_definitions: {},
142
- run_block: nil,
143
- requirements_block: nil
144
- }
145
- end
146
-
147
- def method_missing(k, v)
148
- @config[k] = v
149
- end
150
-
151
- def switches(inherit: true, drop: [], &block)
152
- def option(label, short: nil, kind: nil, description: nil, default: nil, &block)
153
- label, argument = case label
154
- when Hash
155
- [label.keys.first, "=#{label.values.first}"]
156
- else
157
- [label, nil]
158
- end
159
- warn "Warning! #{label.inspect} option is being redefined.".red if @config[:switch_definitions][label]
160
- @config[:switch_definitions][label] = SwitchDefinition.new(label, argument: argument, short: short, kind: kind, description: description, default: default, &block)
161
- end
162
- block.call if block_given?
163
- @config[:switch_definitions]
164
- end
165
-
166
- def requirements(options, &block)
167
- @config[:requirements_block] = block
168
- end
169
-
170
- def run(&block)
171
- # puts "setting run_block"
172
- @config[:run_block] = block
173
- end
174
- end
175
- end
176
- end
data/lib/ergane/debug.rb DELETED
@@ -1,75 +0,0 @@
1
- module Ergane
2
- module Debug
3
-
4
- class << self
5
-
6
- @nl = false
7
-
8
- def enable_break!
9
- class << self
10
- define_method(:break, &binding.method(:pry))
11
- end
12
- end
13
-
14
- def suppress
15
- original_stdout, original_stderr = $stdout.clone, $stderr.clone
16
- $stderr.reopen File.new('/dev/null', 'w')
17
- $stdout.reopen File.new('/dev/null', 'w')
18
- yield
19
- ensure
20
- $stdout.reopen original_stdout
21
- $stderr.reopen original_stderr
22
- end
23
-
24
- def break
25
- puts "Breakpoints Not Enabled"
26
- end
27
-
28
- def format_print(m)
29
- case m
30
- when String
31
- format_print(m.split("\n"))
32
- when Array
33
- m.join("\n\t")
34
- else
35
- m
36
- end
37
- end
38
-
39
- def puts(m=nil, prefix: false, &block)
40
- prefix ||= $debug ? 'DEBUG' : false
41
- if (prefix)
42
- if @nl || m.blank?
43
- $stdout.puts format_print(m)
44
- else
45
- $stdout.print "[#{prefix.upcase.light_magenta}] " unless prefix.blank?
46
- $stdout.puts format_print(m)
47
- end
48
- else
49
- yield if block_given?
50
- end
51
- @nl = false
52
- end
53
-
54
- def print(m=nil, prefix: false, &block)
55
- @nl = true
56
- prefix ||= $debug ? 'DEBUG' : false
57
- if (prefix)
58
- if (m.blank?)
59
- $stdout.print format_print(m)
60
- else
61
- $stdout.print "[#{prefix.upcase.light_magenta}] " unless prefix.blank?
62
- $stdout.print format_print(m)
63
- end
64
- else
65
- yield if block_given?
66
- end
67
- end
68
-
69
- end
70
-
71
- enable_break! if $debug
72
-
73
- end
74
-
75
- end
@@ -1,8 +0,0 @@
1
- module Ergane
2
- class Hashall < Hash
3
- def initialize(*args)
4
- super()
5
- self.default_proc = -> (h, k) { h[k] = self.class.new(*args) }
6
- end
7
- end
8
- end