sod 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/pathnames"
4
+
5
+ module Sod
6
+ module Prefabs
7
+ module Actions
8
+ module Config
9
+ # Displays project configuration.
10
+ class View < Action
11
+ include Import[:kernel, :logger]
12
+
13
+ using Refinements::Pathnames
14
+
15
+ description "View project configuration."
16
+
17
+ on %w[-v --view]
18
+
19
+ # :reek:ControlParameter
20
+ def initialize(path = nil, **)
21
+ super(**)
22
+ @path = Pathname(path || context.xdg_config.active)
23
+ end
24
+
25
+ def call(*)
26
+ return unless check
27
+
28
+ logger.info { "Viewing (#{path.to_s.inspect}):" }
29
+ kernel.puts path.read
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :path
35
+
36
+ def check
37
+ return true if path.exist?
38
+
39
+ logger.error { "Configuration doesn't exist: #{path.to_s.inspect}." }
40
+ kernel.abort
41
+ false
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sod
4
+ module Prefabs
5
+ module Actions
6
+ # Displays help (usage) information.
7
+ class Help < Action
8
+ include Import[:kernel]
9
+
10
+ description "Show this message."
11
+
12
+ on %w[-h --help], argument: "[COMMAND]"
13
+
14
+ def initialize(graph, presenter: Presenters::Node, **)
15
+ super(**)
16
+ @graph = graph
17
+ @presenter = presenter
18
+ end
19
+
20
+ def call *lineage
21
+ if lineage.empty?
22
+ kernel.puts presenter.new(graph).to_s
23
+ else
24
+ kernel.puts presenter.new(graph.get_child(*lineage)).to_s
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :graph, :presenter
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sod
4
+ module Prefabs
5
+ module Actions
6
+ # Provides a generic version action for use in upstream applications.
7
+ class Version < Action
8
+ include Import[:kernel]
9
+
10
+ description "Show version."
11
+
12
+ on %w[-v --version]
13
+
14
+ def initialize(label = nil, **)
15
+ super(**)
16
+ @label = context[label, :version_label]
17
+ end
18
+
19
+ def call(*) = kernel.puts label
20
+
21
+ private
22
+
23
+ attr_reader :label
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sod
4
+ module Prefabs
5
+ module Commands
6
+ # Provides a generic configuration command for use in upstream applications.
7
+ class Config < Sod::Command
8
+ handle "config"
9
+
10
+ description "Manage configuration."
11
+
12
+ ancillary "Path is dynamic per current directory."
13
+
14
+ on Prefabs::Actions::Config::Create
15
+ on Prefabs::Actions::Config::Edit
16
+ on Prefabs::Actions::Config::View
17
+ on Prefabs::Actions::Config::Delete
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "refinements/arrays"
5
+
6
+ module Sod
7
+ module Presenters
8
+ # Aids in rendering an action for display.
9
+ class Action
10
+ include Import[:color]
11
+
12
+ extend Forwardable
13
+
14
+ using Refinements::Arrays
15
+
16
+ delegate [*Models::Action.members, :handle] => :record
17
+
18
+ def initialize(record, **)
19
+ super(**)
20
+ @record = record
21
+ end
22
+
23
+ def colored_handle = [color_aliases, argument].tap(&:compact!).join(" ")
24
+
25
+ def colored_documentation = [*ancillary, color_allows, color_default].tap(&:compact!)
26
+
27
+ private
28
+
29
+ attr_reader :record
30
+
31
+ def color_aliases
32
+ Array(record.aliases).map { |value| color[value, :cyan] }
33
+ .join ", "
34
+ end
35
+
36
+ def color_allows
37
+ return unless allow
38
+
39
+ values = Array(allow).map { |value| color[value, :green] }
40
+ .to_sentence "or"
41
+ "Use: #{values}."
42
+ end
43
+
44
+ def color_default
45
+ cast = default.to_s
46
+
47
+ return if cast.empty?
48
+
49
+ value = cast == "false" ? color[default, :red] : color[default, :green]
50
+ "Default: #{value}."
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "refinements/arrays"
5
+ require "refinements/strings"
6
+
7
+ module Sod
8
+ module Presenters
9
+ # Aids in rendering a node for display.
10
+ # :reek:TooManyInstanceVariables
11
+ class Node
12
+ include Import[:color]
13
+
14
+ extend Forwardable
15
+
16
+ using Refinements::Arrays
17
+ using Refinements::Strings
18
+
19
+ delegate Graph::Node.members => :node
20
+
21
+ attr_reader :actions
22
+
23
+ # rubocop:todo Metrics/ParameterLists
24
+ def initialize(node, indent: 2, gap: 5, action_presenter: Presenters::Action, **)
25
+ super(**)
26
+ @node = node
27
+ @indent = indent
28
+ @gap = gap
29
+ @actions = node.actions.map { |action| action_presenter.new action.record }
30
+ @all = actions + children.to_a
31
+ end
32
+ # rubocop:enable Metrics/ParameterLists
33
+
34
+ def to_s
35
+ [banner, "", *usage, "", *colored_actions, "", *colored_commands].tap(&:compact!)
36
+ .join("\n")
37
+ .strip
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :node, :indent, :gap, :all
43
+
44
+ def banner = color[description, :bold]
45
+
46
+ def usage
47
+ actions = " #{colored_handle} [OPTIONS]" unless all.empty?
48
+ commands = " #{colored_handle} COMMAND [OPTIONS]" unless children.empty?
49
+
50
+ add_section "USAGE", [actions, commands].tap(&:compact!)
51
+ end
52
+
53
+ def colored_handle = color[handle, :cyan]
54
+
55
+ def colored_actions
56
+ return if actions.empty?
57
+
58
+ collection = actions.each_with_object [] do |action, content|
59
+ content.append " #{action.colored_handle}#{description_padding action}" \
60
+ "#{action.description}"
61
+ add_ancillary action, :colored_documentation, content
62
+ end
63
+
64
+ add_section "OPTIONS", collection
65
+ end
66
+
67
+ def colored_commands
68
+ return if children.empty?
69
+
70
+ collection = children.each_with_object [] do |command, content|
71
+ content.append " #{color[command.handle, :cyan]}#{description_padding command}" \
72
+ "#{command.description}"
73
+ add_ancillary command, :ancillary, content
74
+ end
75
+
76
+ add_section "COMMANDS", collection
77
+ end
78
+
79
+ def description_padding(item) = " " * ((max_handle_size - item.handle.size) + gap)
80
+
81
+ def max_handle_size = all.map(&:handle).maximum :size
82
+
83
+ def add_ancillary target, message, content
84
+ target.public_send(message).each do |line|
85
+ content.append line.indent (max_handle_size + gap + indent), pad: " "
86
+ end
87
+ end
88
+
89
+ # :reek:FeatureEnvy
90
+ def add_section text, collection
91
+ collection.empty? ? collection : collection.prepend(color[text, :bold, :underline])
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+
5
+ module Sod
6
+ module Refines
7
+ # Provides additional enhancements to the option parser primitive.
8
+ module OptionParsers
9
+ refine OptionParser do
10
+ def order!(argument = default_argv, into: nil, command: nil, &)
11
+ super(argument, into:, &)
12
+ command.call if command
13
+ end
14
+
15
+ def replicate
16
+ self.class.new banner, summary_width, summary_indent do |instance|
17
+ instance.set_program_name program_name
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
data/lib/sod/shell.rb ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cogger"
4
+
5
+ module Sod
6
+ # The Command Line Interface (CLI).
7
+ class Shell
8
+ attr_reader :name, :banner
9
+
10
+ # rubocop:todo Metrics/ParameterLists
11
+ def initialize name = Cogger::Program.call,
12
+ banner: nil,
13
+ node: Graph::Node,
14
+ runner: Graph::Runner,
15
+ &block
16
+ @name = name.to_s
17
+ @banner = banner
18
+ graph = node[handle: name, description: banner]
19
+ graph.instance_eval(&block) if block
20
+ @runner = runner.new graph
21
+ end
22
+ # rubocop:enable Metrics/ParameterLists
23
+
24
+ def call arguments = ARGV, process: Process
25
+ process.setproctitle name
26
+ runner.call arguments
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :runner
32
+ end
33
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+ require "pathname"
5
+
6
+ OptionParser.accept(Pathname) { |value| Pathname value }
data/lib/sod.rb ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zeitwerk"
4
+
5
+ Zeitwerk::Loader.for_gem.then do |loader|
6
+ loader.ignore "#{__dir__}/sod/types"
7
+ loader.setup
8
+ end
9
+
10
+ # Main namespace.
11
+ module Sod
12
+ def self.new(...) = Shell.new(...)
13
+ end
data/sod.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "sod"
5
+ spec.version = "0.0.0"
6
+ spec.authors = ["Brooke Kuhlmann"]
7
+ spec.email = ["brooke@alchemists.io"]
8
+ spec.homepage = "https://alchemists.io/projects/sod"
9
+ spec.summary = "A Domain Specific Language for creating composable Command Line Interfaces."
10
+ spec.license = "Hippocratic-2.1"
11
+
12
+ spec.metadata = {
13
+ "bug_tracker_uri" => "https://github.com/bkuhlmann/sod/issues",
14
+ "changelog_uri" => "https://alchemists.io/projects/sod/versions",
15
+ "documentation_uri" => "https://alchemists.io/projects/sod",
16
+ "funding_uri" => "https://github.com/sponsors/bkuhlmann",
17
+ "label" => "Sod",
18
+ "rubygems_mfa_required" => "true",
19
+ "source_code_uri" => "https://github.com/bkuhlmann/sod"
20
+ }
21
+
22
+ spec.signing_key = Gem.default_key_path
23
+ spec.cert_chain = [Gem.default_cert_path]
24
+
25
+ spec.required_ruby_version = "~> 3.2"
26
+ spec.add_dependency "cogger", "~> 0.10"
27
+ spec.add_dependency "dry-container", "~> 0.11"
28
+ spec.add_dependency "infusible", "~> 2.0"
29
+ spec.add_dependency "refinements", "~> 11.0"
30
+ spec.add_dependency "tone", "~> 0.3"
31
+ spec.add_dependency "zeitwerk", "~> 2.6"
32
+
33
+ spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
34
+ spec.files = Dir["*.gemspec", "lib/**/*"]
35
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1,4 @@
1
+ �ē�U����{�RAm���� \�o�CO�%�~���}h�%J�p�g�}�o�ދ[_��N��� ��-ǩ2��&Y�'9���(�$�؍���v�q�����"W���Ǽa��a`)p�.p�0(z2���Gp)r5g��u�X���a����ć��LW�
2
+ ��F���o��c`��'���U�$�^�`cTe!P��
3
+ ���z�����-R?�I%d{L�62=�#}�Pp��ʫ6sVѣ�H
4
+ i�����7/v|
metadata ADDED
@@ -0,0 +1,190 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sod
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brooke Kuhlmann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEeDCCAuCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMQ8wDQYDVQQDDAZicm9v
14
+ a2UxGjAYBgoJkiaJk/IsZAEZFgphbGNoZW1pc3RzMRIwEAYKCZImiZPyLGQBGRYC
15
+ aW8wHhcNMjMwMzIyMTYxNDQxWhcNMjUwMzIxMTYxNDQxWjBBMQ8wDQYDVQQDDAZi
16
+ cm9va2UxGjAYBgoJkiaJk/IsZAEZFgphbGNoZW1pc3RzMRIwEAYKCZImiZPyLGQB
17
+ GRYCaW8wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCro8tj5/E1Hg88
18
+ f4qfiwPVd2zJQHvdYt4GHVvuHRRgx4HGhJuNp+4BId08RBn7V6V1MW6MY3kezRBs
19
+ M+7QOQ4b1xNLTvY7FYQB1wGK5a4x7TTokDrPYQxDB2jmsdDYCzVbIMrAvUfcecRi
20
+ khyGZCdByiiCl4fKv77P12tTT+NfsvXkLt/AYCGwjOUyGKTQ01Z6eC09T27GayPH
21
+ QQvIkakyFgcJtzSyGzs8bzK5q9u7wQ12MNTjJoXzW69lqp0oNvDylu81EiSUb5S6
22
+ QzzPxZBiRB1sgtbt1gUbVI262ZDq1gR+HxPFmp+Cgt7ZLIJZAtesQvtcMzseXpfn
23
+ hpmm0Sw22KGhRAy/mqHBRhDl5HqS1SJp2Ko3lcnpXeFResp0HNlt8NSu13vhC08j
24
+ GUHU9MyIXbFOsnp3K3ADrAVjPWop8EZkmUR3MV/CUm00w2cZHCSGiXl1KMpiVKvk
25
+ Ywr1gd2ZME4QLSo+EXUtLxDUa/W3xnBS8dBOuMMz02FPWYr3PN8CAwEAAaN7MHkw
26
+ CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFAFgmv0tYMZnItuPycSM
27
+ F5wykJEVMB8GA1UdEQQYMBaBFGJyb29rZUBhbGNoZW1pc3RzLmlvMB8GA1UdEgQY
28
+ MBaBFGJyb29rZUBhbGNoZW1pc3RzLmlvMA0GCSqGSIb3DQEBCwUAA4IBgQAX+EGY
29
+ 9RLYGxF1VLZz+G1ACQc4uyrCB6kXwI06kzUa5dF9tPXqTX9ffnz3/W8ck2IQhKzu
30
+ MKO2FVijzbDWTsZeZGglS4E+4Jxpau1lU9HhOIcKolv6LeC6UdALTFudY+GLb8Xw
31
+ REXgaJkjzzhkUSILmEnRwEbY08dVSl7ZAaxVI679vfI2yapLlIwpbBgmQTiTvPr3
32
+ qyyLUno9flYEOv9fmGHunSrM+gE0/0niGTXa5GgXBXYGS2he4LQGgSBfGp/cTwMU
33
+ rDKJRcusZ12lNBeDfgqACz/BBJF8FLodgk6rGMRZz7+ZmjjHEmpG5bQpR6Q2BuWL
34
+ XMtYk/QzaWuhiR7pWjiF8jbdd7RO6or0ohq7iFkokz/5xrtQ/vPzU2RQ3Qc6YaKw
35
+ 3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
36
+ gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
37
+ -----END CERTIFICATE-----
38
+ date: 2023-06-15 00:00:00.000000000 Z
39
+ dependencies:
40
+ - !ruby/object:Gem::Dependency
41
+ name: cogger
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.10'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.10'
54
+ - !ruby/object:Gem::Dependency
55
+ name: dry-container
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.11'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.11'
68
+ - !ruby/object:Gem::Dependency
69
+ name: infusible
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: refinements
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '11.0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '11.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: tone
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '0.3'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.3'
110
+ - !ruby/object:Gem::Dependency
111
+ name: zeitwerk
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '2.6'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '2.6'
124
+ description:
125
+ email:
126
+ - brooke@alchemists.io
127
+ executables: []
128
+ extensions: []
129
+ extra_rdoc_files:
130
+ - README.adoc
131
+ - LICENSE.adoc
132
+ files:
133
+ - LICENSE.adoc
134
+ - README.adoc
135
+ - lib/sod.rb
136
+ - lib/sod/action.rb
137
+ - lib/sod/command.rb
138
+ - lib/sod/container.rb
139
+ - lib/sod/context.rb
140
+ - lib/sod/error.rb
141
+ - lib/sod/graph/loader.rb
142
+ - lib/sod/graph/node.rb
143
+ - lib/sod/graph/runner.rb
144
+ - lib/sod/import.rb
145
+ - lib/sod/models/action.rb
146
+ - lib/sod/models/command.rb
147
+ - lib/sod/prefabs/actions/config/create.rb
148
+ - lib/sod/prefabs/actions/config/delete.rb
149
+ - lib/sod/prefabs/actions/config/edit.rb
150
+ - lib/sod/prefabs/actions/config/view.rb
151
+ - lib/sod/prefabs/actions/help.rb
152
+ - lib/sod/prefabs/actions/version.rb
153
+ - lib/sod/prefabs/commands/config.rb
154
+ - lib/sod/presenters/action.rb
155
+ - lib/sod/presenters/node.rb
156
+ - lib/sod/refines/option_parsers.rb
157
+ - lib/sod/shell.rb
158
+ - lib/sod/types/pathname.rb
159
+ - sod.gemspec
160
+ homepage: https://alchemists.io/projects/sod
161
+ licenses:
162
+ - Hippocratic-2.1
163
+ metadata:
164
+ bug_tracker_uri: https://github.com/bkuhlmann/sod/issues
165
+ changelog_uri: https://alchemists.io/projects/sod/versions
166
+ documentation_uri: https://alchemists.io/projects/sod
167
+ funding_uri: https://github.com/sponsors/bkuhlmann
168
+ label: Sod
169
+ rubygems_mfa_required: 'true'
170
+ source_code_uri: https://github.com/bkuhlmann/sod
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '3.2'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubygems_version: 3.4.14
187
+ signing_key:
188
+ specification_version: 4
189
+ summary: A Domain Specific Language for creating composable Command Line Interfaces.
190
+ test_files: []
metadata.gz.sig ADDED
Binary file