gemsmith 19.8.0 → 20.0.0

Sign up to get free protection for your applications and to get access to all the features.
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