gemsmith 19.8.0 → 20.0.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.adoc +28 -52
  4. data/gemsmith.gemspec +12 -9
  5. data/lib/gemsmith/builders/cli.rb +6 -25
  6. data/lib/gemsmith/builders/rspec/helper.rb +3 -16
  7. data/lib/gemsmith/cli/actions/cli.rb +22 -0
  8. data/lib/gemsmith/cli/actions/edit.rb +9 -4
  9. data/lib/gemsmith/cli/actions/install.rb +17 -6
  10. data/lib/gemsmith/cli/actions/publish.rb +17 -6
  11. data/lib/gemsmith/cli/actions/view.rb +9 -4
  12. data/lib/gemsmith/cli/commands/build.rb +106 -0
  13. data/lib/gemsmith/cli/shell.rb +28 -32
  14. data/lib/gemsmith/container.rb +29 -5
  15. data/lib/gemsmith/templates/%project_name%/%project_name%.gemspec.erb +13 -7
  16. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/cli/shell.rb.erb +18 -15
  17. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/configuration/contract.rb.erb +9 -0
  18. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/configuration/model.rb.erb +6 -0
  19. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/container.rb.erb +14 -1
  20. data/lib/gemsmith/templates/%project_name%/spec/lib/%project_path%/cli/shell_spec.rb.erb +8 -23
  21. data/lib/gemsmith/templates/%project_name%/spec/support/shared_contexts/application_dependencies.rb.erb +5 -7
  22. data/lib/gemsmith/tools/versioner.rb +8 -8
  23. data.tar.gz.sig +0 -0
  24. metadata +65 -40
  25. metadata.gz.sig +0 -0
  26. data/lib/gemsmith/cli/actions/build.rb +0 -68
  27. data/lib/gemsmith/cli/actions/config.rb +0 -33
  28. data/lib/gemsmith/cli/actions/container.rb +0 -23
  29. data/lib/gemsmith/cli/actions/import.rb +0 -11
  30. data/lib/gemsmith/cli/parser.rb +0 -37
  31. data/lib/gemsmith/cli/parsers/build.rb +0 -53
  32. data/lib/gemsmith/cli/parsers/core.rb +0 -93
  33. data/lib/gemsmith/configuration/loader.rb +0 -27
  34. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/cli/actions/config.rb.erb +0 -31
  35. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/cli/actions/container.rb.erb +0 -16
  36. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/cli/actions/import.rb.erb +0 -9
  37. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/cli/parser.rb.erb +0 -35
  38. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/cli/parsers/core.rb.erb +0 -58
  39. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/configuration/content.rb.erb +0 -18
  40. data/lib/gemsmith/templates/%project_name%/lib/%project_path%/configuration/loader.rb.erb +0 -33
  41. data/lib/gemsmith/templates/%project_name%/spec/lib/%project_path%/cli/actions/config_spec.rb.erb +0 -24
  42. data/lib/gemsmith/templates/%project_name%/spec/lib/%project_path%/cli/parser_spec.rb.erb +0 -25
  43. data/lib/gemsmith/templates/%project_name%/spec/lib/%project_path%/cli/parsers/core_spec.rb.erb +0 -53
  44. data/lib/gemsmith/templates/%project_name%/spec/lib/%project_path%/configuration/content_spec.rb.erb +0 -15
  45. data/lib/gemsmith/templates/%project_name%/spec/lib/%project_path%/configuration/loader_spec.rb.erb +0 -29
  46. data/lib/gemsmith/templates/%project_name%/spec/support/shared_examples/a_parser.rb.erb +0 -7
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gemsmith
4
- module CLI
5
- module Actions
6
- # Handles the build action.
7
- class Build
8
- include Gemsmith::Import[:logger]
9
-
10
- # Order is important.
11
- # rubocop:todo Metrics/CollectionLiteralLength
12
- BUILDERS = [
13
- Rubysmith::Builders::Core,
14
- Rubysmith::Builders::Version,
15
- Builders::Specification,
16
- Rubysmith::Builders::Documentation::Readme,
17
- Builders::Documentation::Readme,
18
- Rubysmith::Builders::Documentation::Citation,
19
- Rubysmith::Builders::Documentation::License,
20
- Rubysmith::Builders::Documentation::Version,
21
- Rubysmith::Builders::Git::Setup,
22
- Rubysmith::Builders::Git::Ignore,
23
- Rubysmith::Builders::Git::Safe,
24
- Builders::Git::Ignore,
25
- Rubysmith::Builders::Bundler,
26
- Builders::Bundler,
27
- Builders::CLI,
28
- Rubysmith::Builders::Rake,
29
- Rubysmith::Builders::Console,
30
- Rubysmith::Builders::CircleCI,
31
- Builders::CircleCI,
32
- Rubysmith::Builders::Setup,
33
- Rubysmith::Builders::GitHub,
34
- Rubysmith::Builders::Guard,
35
- Rubysmith::Builders::Reek,
36
- Rubysmith::Builders::RSpec::Binstub,
37
- Rubysmith::Builders::RSpec::Context,
38
- Rubysmith::Builders::RSpec::Helper,
39
- Builders::RSpec::Helper,
40
- Rubysmith::Builders::Caliber,
41
- Rubysmith::Extensions::Bundler,
42
- Rubysmith::Extensions::Pragmater,
43
- Rubysmith::Extensions::Tocer,
44
- Rubysmith::Extensions::Rubocop,
45
- Builders::Git::Commit
46
- ].freeze
47
- # rubocop:enable Metrics/CollectionLiteralLength
48
-
49
- def initialize(builders: BUILDERS, **)
50
- super(**)
51
- @builders = builders
52
- end
53
-
54
- def call configuration
55
- log_info "Building project skeleton: #{configuration.project_name}..."
56
- builders.each { |builder| builder.call configuration }
57
- log_info "Project skeleton complete!"
58
- end
59
-
60
- private
61
-
62
- attr_reader :builders
63
-
64
- def log_info(message) = logger.info { message }
65
- end
66
- end
67
- end
68
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Gemsmith
4
- module CLI
5
- module Actions
6
- # Handles the config action.
7
- class Config
8
- include Gemsmith::Import[:kernel, :logger]
9
-
10
- def initialize(client: Configuration::Loader::CLIENT, **)
11
- super(**)
12
- @client = client
13
- end
14
-
15
- def call selection
16
- case selection
17
- when :edit then edit
18
- when :view then view
19
- else logger.error { "Invalid configuration selection: #{selection}." }
20
- end
21
- end
22
-
23
- private
24
-
25
- attr_reader :client
26
-
27
- def edit = kernel.system("$EDITOR #{client.current}")
28
-
29
- def view = kernel.system("cat #{client.current}")
30
- end
31
- end
32
- end
33
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dry/container"
4
-
5
- module Gemsmith
6
- module CLI
7
- module Actions
8
- # Provides a single container with application and action specific dependencies.
9
- module Container
10
- extend Dry::Container::Mixin
11
-
12
- merge Gemsmith::Container
13
-
14
- register(:config) { Config.new }
15
- register(:build) { Build.new }
16
- register(:install) { Install.new }
17
- register(:publish) { Publish.new }
18
- register(:edit) { Edit.new }
19
- register(:view) { View.new }
20
- end
21
- end
22
- end
23
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "infusible"
4
-
5
- module Gemsmith
6
- module CLI
7
- module Actions
8
- Import = Infusible.with Container
9
- end
10
- end
11
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "core"
4
- require "optparse"
5
-
6
- module Gemsmith
7
- module CLI
8
- # Assembles and parses all Command Line Interface (CLI) options.
9
- class Parser
10
- include Import[:configuration]
11
-
12
- CLIENT = OptionParser.new nil, 40, " "
13
-
14
- # Order is important.
15
- SECTIONS = [Parsers::Core, Rubysmith::CLI::Parsers::Build, Parsers::Build].freeze
16
-
17
- def initialize(sections: SECTIONS, client: CLIENT, **)
18
- super(**)
19
- @sections = sections
20
- @client = client
21
- @configuration_duplicate = configuration.dup
22
- end
23
-
24
- def call arguments = Core::EMPTY_ARRAY
25
- sections.each { |section| section.call configuration_duplicate, client: }
26
- client.parse arguments
27
- configuration_duplicate.freeze
28
- end
29
-
30
- def to_s = client.to_s
31
-
32
- private
33
-
34
- attr_reader :sections, :client, :configuration_duplicate
35
- end
36
- end
37
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "core"
4
- require "refinements/structs"
5
-
6
- module Gemsmith
7
- module CLI
8
- module Parsers
9
- # Handles parsing of Command Line Interface (CLI) build options.
10
- class Build
11
- include Import[:color]
12
-
13
- using Refinements::Structs
14
-
15
- def self.call(...) = new(...).call
16
-
17
- def initialize(configuration = Container[:configuration], client: Parser::CLIENT, **)
18
- super(**)
19
- @configuration = configuration
20
- @client = client
21
- end
22
-
23
- def call arguments = ::Core::EMPTY_ARRAY
24
- add_cli
25
- client.parse arguments
26
- configuration
27
- end
28
-
29
- private
30
-
31
- attr_reader :configuration, :client
32
-
33
- def add_cli
34
- client.on(
35
- "--[no-]cli",
36
- "Add command line interface. #{default __method__}."
37
- ) do |value|
38
- configuration.merge! build_refinements: value, build_zeitwerk: value if value
39
- configuration.merge! build_cli: value
40
- end
41
- end
42
-
43
- def default option
44
- option.to_s
45
- .sub("add_", "build_")
46
- .then { |attribute| configuration.public_send attribute }
47
- .then { |boolean| boolean ? color[boolean, :green] : color[boolean, :red] }
48
- .then { |colored_boolean| "Default: #{colored_boolean}" }
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,93 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "core"
4
- require "pathname"
5
- require "refinements/structs"
6
-
7
- module Gemsmith
8
- module CLI
9
- module Parsers
10
- # Handles parsing of Command Line Interface (CLI) core options.
11
- class Core
12
- include Import[:specification]
13
-
14
- using Refinements::Structs
15
-
16
- def self.call(...) = new(...).call
17
-
18
- def initialize(configuration = Container[:configuration], client: Parser::CLIENT, **)
19
- super(**)
20
- @configuration = configuration
21
- @client = client
22
- end
23
-
24
- def call arguments = ::Core::EMPTY_ARRAY
25
- client.banner = specification.labeled_summary
26
- client.separator "\nUSAGE:\n"
27
- collate
28
- client.parse arguments
29
- configuration
30
- end
31
-
32
- private
33
-
34
- attr_reader :configuration, :client
35
-
36
- def collate = private_methods.sort.grep(/add_/).each { |method| __send__ method }
37
-
38
- def add_config
39
- client.on "-c",
40
- "--config ACTION",
41
- %i[edit view],
42
- "Manage gem configuration: edit or view." do |action|
43
- configuration.merge! action_config: action
44
- end
45
- end
46
-
47
- def add_build
48
- client.on "-b", "--build NAME [options]", "Build new project." do |name|
49
- configuration.merge! action_build: true, project_name: name
50
- end
51
- end
52
-
53
- def add_edit
54
- client.on "--edit GEM", "Edit installed gem in default editor." do |gem_name|
55
- configuration.merge! action_edit: gem_name
56
- end
57
- end
58
-
59
- def add_install
60
- client.on "-i", "--install [NAME]", "Install gem for local development." do |name|
61
- configuration.merge! action_install: true,
62
- project_name: name || Pathname.pwd.basename.to_s
63
- end
64
- end
65
-
66
- def add_publish
67
- client.on "-p", "--publish [NAME]", "Publish gem to remote gem server." do |name|
68
- configuration.merge! action_publish: true,
69
- project_name: name || Pathname.pwd.basename.to_s
70
- end
71
- end
72
-
73
- def add_view
74
- client.on "--view GEM", "View installed gem in default browser." do |gem_name|
75
- configuration.merge! action_view: gem_name
76
- end
77
- end
78
-
79
- def add_version
80
- client.on "-v", "--version", "Show gem version." do
81
- configuration.merge! action_version: true
82
- end
83
- end
84
-
85
- def add_help
86
- client.on "-h", "--help", "Show this message." do
87
- configuration.merge! action_help: true
88
- end
89
- end
90
- end
91
- end
92
- end
93
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "runcom"
4
-
5
- module Gemsmith
6
- module Configuration
7
- # Represents the fully assembled Command Line Interface (CLI) configuration.
8
- class Loader < Rubysmith::Configuration::Loader
9
- DEFAULTS = Rubysmith::Configuration::Loader::DEFAULTS
10
- CLIENT = Runcom::Config.new "gemsmith/configuration.yml", defaults: DEFAULTS
11
-
12
- def self.with_overrides
13
- new client: DEFAULTS,
14
- enhancers: {template_root: Rubysmith::Configuration::Enhancers::TemplateRoot}
15
- end
16
-
17
- def initialize(client: CLIENT, **) = super
18
-
19
- def call
20
- return super unless enhancers.key? :template_root
21
-
22
- enhancers[:template_root].call(super, overrides: Pathname(__dir__).join("../templates"))
23
- .freeze
24
- end
25
- end
26
- end
27
- end
@@ -1,31 +0,0 @@
1
- <% namespace do %>
2
- module CLI
3
- module Actions
4
- # Handles the config action.
5
- class Config
6
- include <%= configuration.project_class %>::Import[:kernel, :logger]
7
-
8
- def initialize(client: Configuration::Loader::CLIENT, **)
9
- super(**)
10
- @client = client
11
- end
12
-
13
- def call selection
14
- case selection
15
- when :edit then edit
16
- when :view then view
17
- else logger.error { "Invalid configuration selection: #{selection}." }
18
- end
19
- end
20
-
21
- private
22
-
23
- attr_reader :client
24
-
25
- def edit = kernel.system("$EDITOR #{client.current}")
26
-
27
- def view = kernel.system("cat #{client.current}")
28
- end
29
- end
30
- end
31
- <% end %>
@@ -1,16 +0,0 @@
1
- require "dry/container"
2
-
3
- <% namespace do %>
4
- module CLI
5
- module Actions
6
- # Provides a single container of application and action specific dependencies.
7
- module Container
8
- extend Dry::Container::Mixin
9
-
10
- merge <%= configuration.project_namespaced_class %>::Container
11
-
12
- register(:config) { Config.new }
13
- end
14
- end
15
- end
16
- <% end %>
@@ -1,9 +0,0 @@
1
- require "infusible"
2
-
3
- <% namespace do %>
4
- module CLI
5
- module Actions
6
- Import = Infusible.with Container
7
- end
8
- end
9
- <% end %>
@@ -1,35 +0,0 @@
1
- require "core"
2
- require "optparse"
3
-
4
- <% namespace do %>
5
- module CLI
6
- # Assembles and parses all Command Line Interface (CLI) options.
7
- class Parser
8
- include Import[:configuration]
9
-
10
- CLIENT = OptionParser.new nil, 40, " "
11
-
12
- # Order is important.
13
- SECTIONS = [Parsers::Core].freeze
14
-
15
- def initialize(sections: SECTIONS, client: CLIENT, **)
16
- super(**)
17
- @sections = sections
18
- @client = client
19
- @configuration_duplicate = configuration.dup
20
- end
21
-
22
- def call arguments = Core::EMPTY_ARRAY
23
- sections.each { |section| section.call configuration_duplicate, client: }
24
- client.parse arguments
25
- configuration_duplicate.freeze
26
- end
27
-
28
- def to_s = client.to_s
29
-
30
- private
31
-
32
- attr_reader :sections, :client, :configuration_duplicate
33
- end
34
- end
35
- <% end %>
@@ -1,58 +0,0 @@
1
- require "core"
2
- require "refinements/structs"
3
-
4
- <% namespace do %>
5
- module CLI
6
- module Parsers
7
- # Handles parsing of Command Line Interface (CLI) core options.
8
- class Core
9
- include Import[:specification]
10
-
11
- using Refinements::Structs
12
-
13
- def self.call(...) = new(...).call
14
-
15
- def initialize(configuration = Container[:configuration], client: Parser::CLIENT, **)
16
- super(**)
17
- @configuration = configuration
18
- @client = client
19
- end
20
-
21
- def call arguments = ::Core::EMPTY_ARRAY
22
- client.banner = specification.labeled_summary
23
- client.separator "\nUSAGE:\n"
24
- collate
25
- client.parse arguments
26
- configuration
27
- end
28
-
29
- private
30
-
31
- attr_reader :configuration, :client
32
-
33
- def collate = private_methods.sort.grep(/add_/).each { |method| __send__ method }
34
-
35
- def add_config
36
- client.on "-c",
37
- "--config ACTION",
38
- %i[edit view],
39
- "Manage gem configuration: edit or view." do |action|
40
- configuration.merge! action_config: action
41
- end
42
- end
43
-
44
- def add_version
45
- client.on "-v", "--version", "Show gem version." do
46
- configuration.merge! action_version: true
47
- end
48
- end
49
-
50
- def add_help
51
- client.on "-h", "--help", "Show this message." do
52
- configuration.merge! action_help: true
53
- end
54
- end
55
- end
56
- end
57
- end
58
- <% end %>
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- <% namespace do %>
4
- module Configuration
5
- # Defines the content of the configuration for use throughout the gem.
6
- Content = Struct.new(
7
- :action_config,
8
- :action_help,
9
- :action_version,
10
- keyword_init: true
11
- ) do
12
- def initialize *arguments
13
- super
14
- freeze
15
- end
16
- end
17
- end
18
- <% end %>
@@ -1,33 +0,0 @@
1
- require "pathname"
2
- require "refinements/hashes"
3
- require "refinements/structs"
4
- require "runcom"
5
- require "yaml"
6
-
7
- <% namespace do %>
8
- module Configuration
9
- # Represents the fully assembled Command Line Interface (CLI) configuration.
10
- class Loader
11
- using Refinements::Hashes
12
- using Refinements::Structs
13
-
14
- DEFAULTS = (YAML.load_file(Pathname(__dir__).join("defaults.yml")) || {}).freeze
15
- CLIENT = Runcom::Config.new "<%= configuration.project_name %>/configuration.yml", defaults: DEFAULTS
16
-
17
- def self.call = new.call
18
-
19
- def self.with_defaults = new client: DEFAULTS
20
-
21
- def initialize content: Content.new, client: CLIENT
22
- @content = content
23
- @client = client
24
- end
25
-
26
- def call = content.merge(**client.to_h.flatten_keys).freeze
27
-
28
- private
29
-
30
- attr_reader :content, :client
31
- end
32
- end
33
- <% end %>
@@ -1,24 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe <%= configuration.project_namespaced_class %>::CLI::Actions::Config do
4
- subject(:action) { described_class.new }
5
-
6
- include_context "with application dependencies"
7
-
8
- describe "#call" do
9
- it "edits configuration" do
10
- action.call :edit
11
- expect(kernel).to have_received(:system).with(include("EDITOR"))
12
- end
13
-
14
- it "views configuration" do
15
- action.call :view
16
- expect(kernel).to have_received(:system).with(include("cat"))
17
- end
18
-
19
- it "logs invalid configuration" do
20
- action.call :bogus
21
- expect(logger.reread).to match(/🛑.+Invalid configuration selection: bogus./)
22
- end
23
- end
24
- end
@@ -1,25 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe <%= configuration.project_namespaced_class %>::CLI::Parser do
4
- subject(:parser) { described_class.new }
5
-
6
- include_context "with application dependencies"
7
-
8
- describe "#call" do
9
- it "answers hash with valid option" do
10
- expect(parser.call(%w[--help])).to have_attributes(action_help: true)
11
- end
12
-
13
- it "fails with invalid option" do
14
- expectation = proc { parser.call %w[--bogus] }
15
- expect(&expectation).to raise_error(OptionParser::InvalidOption, /--bogus/)
16
- end
17
- end
18
-
19
- describe "#to_s" do
20
- it "answers usage" do
21
- parser.call
22
- expect(parser.to_s).to match(/.+USAGE.+/m)
23
- end
24
- end
25
- end
@@ -1,53 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe <%= configuration.project_namespaced_class %>::CLI::Parsers::Core do
4
- subject(:parser) { described_class.new configuration.dup }
5
-
6
- include_context "with application dependencies"
7
-
8
- it_behaves_like "a parser"
9
-
10
- describe "#call" do
11
- it "answers config edit (short)" do
12
- expect(parser.call(%w[-c edit])).to have_attributes(action_config: :edit)
13
- end
14
-
15
- it "answers config edit (long)" do
16
- expect(parser.call(%w[--config edit])).to have_attributes(action_config: :edit)
17
- end
18
-
19
- it "answers config view (short)" do
20
- expect(parser.call(%w[-c view])).to have_attributes(action_config: :view)
21
- end
22
-
23
- it "answers config view (long)" do
24
- expect(parser.call(%w[--config view])).to have_attributes(action_config: :view)
25
- end
26
-
27
- it "fails with missing config action" do
28
- expectation = proc { parser.call %w[--config] }
29
- expect(&expectation).to raise_error(OptionParser::MissingArgument, /--config/)
30
- end
31
-
32
- it "fails with invalid config action" do
33
- expectation = proc { parser.call %w[--config bogus] }
34
- expect(&expectation).to raise_error(OptionParser::InvalidArgument, /bogus/)
35
- end
36
-
37
- it "answers version (short)" do
38
- expect(parser.call(%w[-v])).to have_attributes(action_version: true)
39
- end
40
-
41
- it "answers version (long)" do
42
- expect(parser.call(%w[--version])).to have_attributes(action_version: true)
43
- end
44
-
45
- it "enables help (short)" do
46
- expect(parser.call(%w[-h])).to have_attributes(action_help: true)
47
- end
48
-
49
- it "enables help (long)" do
50
- expect(parser.call(%w[--help])).to have_attributes(action_help: true)
51
- end
52
- end
53
- end
@@ -1,15 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe <%= configuration.project_namespaced_class %>::Configuration::Content do
4
- subject(:content) { described_class.new }
5
-
6
- describe "#initialize" do
7
- it "answers default hash" do
8
- expect(content).to have_attributes(
9
- action_config: nil,
10
- action_help: nil,
11
- action_version: nil
12
- )
13
- end
14
- end
15
- end