hanamismith 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +2 -0
  3. data/LICENSE.adoc +134 -0
  4. data/README.adoc +206 -0
  5. data/exe/hanamismith +6 -0
  6. data/hanamismith.gemspec +42 -0
  7. data/lib/hanamismith/builders/binstub.rb +31 -0
  8. data/lib/hanamismith/builders/bundler.rb +95 -0
  9. data/lib/hanamismith/builders/caliber.rb +26 -0
  10. data/lib/hanamismith/builders/console.rb +22 -0
  11. data/lib/hanamismith/builders/core.rb +64 -0
  12. data/lib/hanamismith/builders/documentation/readme.rb +31 -0
  13. data/lib/hanamismith/builders/environment.rb +31 -0
  14. data/lib/hanamismith/builders/git/commit.rb +12 -0
  15. data/lib/hanamismith/builders/guard.rb +20 -0
  16. data/lib/hanamismith/builders/puma/configuration.rb +32 -0
  17. data/lib/hanamismith/builders/puma/procfile.rb +31 -0
  18. data/lib/hanamismith/builders/rack.rb +28 -0
  19. data/lib/hanamismith/builders/rake.rb +27 -0
  20. data/lib/hanamismith/builders/rspec/hanami.rb +34 -0
  21. data/lib/hanamismith/builders/rspec/helper.rb +24 -0
  22. data/lib/hanamismith/builders/slices/main.rb +67 -0
  23. data/lib/hanamismith/cli/actions/build.rb +66 -0
  24. data/lib/hanamismith/cli/actions/config.rb +34 -0
  25. data/lib/hanamismith/cli/actions/container.rb +19 -0
  26. data/lib/hanamismith/cli/actions/import.rb +11 -0
  27. data/lib/hanamismith/cli/parser.rb +38 -0
  28. data/lib/hanamismith/cli/parsers/core.rb +69 -0
  29. data/lib/hanamismith/cli/shell.rb +36 -0
  30. data/lib/hanamismith/configuration/content.rb +18 -0
  31. data/lib/hanamismith/configuration/defaults.yml +0 -0
  32. data/lib/hanamismith/configuration/loader.rb +27 -0
  33. data/lib/hanamismith/container.rb +17 -0
  34. data/lib/hanamismith/import.rb +7 -0
  35. data/lib/hanamismith/templates/%project_name%/Guardfile.erb +19 -0
  36. data/lib/hanamismith/templates/%project_name%/Procfile.dev.erb +1 -0
  37. data/lib/hanamismith/templates/%project_name%/Procfile.erb +1 -0
  38. data/lib/hanamismith/templates/%project_name%/app/action.rb.erb +9 -0
  39. data/lib/hanamismith/templates/%project_name%/app/repo.rb.erb +10 -0
  40. data/lib/hanamismith/templates/%project_name%/app/view.rb.erb +10 -0
  41. data/lib/hanamismith/templates/%project_name%/bin/hanami.erb +20 -0
  42. data/lib/hanamismith/templates/%project_name%/config/app.rb.erb +8 -0
  43. data/lib/hanamismith/templates/%project_name%/config/providers/persistence.rb.erb +28 -0
  44. data/lib/hanamismith/templates/%project_name%/config/puma.rb.erb +20 -0
  45. data/lib/hanamismith/templates/%project_name%/config/routes.rb.erb +8 -0
  46. data/lib/hanamismith/templates/%project_name%/config/settings.rb.erb +6 -0
  47. data/lib/hanamismith/templates/%project_name%/config.ru.erb +4 -0
  48. data/lib/hanamismith/templates/%project_name%/envrc.erb +1 -0
  49. data/lib/hanamismith/templates/%project_name%/lib/%project_path%/types.rb.erb +10 -0
  50. data/lib/hanamismith/templates/%project_name%/slices/main/action.rb.erb +7 -0
  51. data/lib/hanamismith/templates/%project_name%/slices/main/actions/home/show.rb.erb +10 -0
  52. data/lib/hanamismith/templates/%project_name%/slices/main/repo.rb.erb +7 -0
  53. data/lib/hanamismith/templates/%project_name%/slices/main/templates/home/show.html.erb.erb +3 -0
  54. data/lib/hanamismith/templates/%project_name%/slices/main/templates/layouts/app.html.erb.erb +32 -0
  55. data/lib/hanamismith/templates/%project_name%/slices/main/view.rb.erb +8 -0
  56. data/lib/hanamismith/templates/%project_name%/slices/main/views/home/show.rb.erb +9 -0
  57. data/lib/hanamismith/templates/%project_name%/spec/hanami_helper.rb.erb +22 -0
  58. data/lib/hanamismith.rb +13 -0
  59. data.tar.gz.sig +0 -0
  60. metadata +283 -0
  61. metadata.gz.sig +2 -0
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ # Builds project environment skeleton.
8
+ class Environment
9
+ using Refinements::Structs
10
+
11
+ def self.call(...) = new(...).call
12
+
13
+ def initialize configuration, builder: Rubysmith::Builder
14
+ @configuration = configuration
15
+ @builder = builder
16
+ end
17
+
18
+ def call
19
+ builder.call(configuration.merge(template_path: "%project_name%/envrc.erb"))
20
+ .render
21
+ .rename(".envrc")
22
+
23
+ configuration
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :configuration, :builder
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanamismith
4
+ module Builders
5
+ module Git
6
+ # Builds project skeleton initial Git commit message.
7
+ class Commit < Rubysmith::Builders::Git::Commit
8
+ include Import[:specification]
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ # Builds project skeleton Guard support for a red, green, refactor loop.
8
+ class Guard < Rubysmith::Builders::Guard
9
+ using Refinements::Structs
10
+
11
+ def call
12
+ return configuration unless configuration.build_guard
13
+
14
+ super
15
+ builder.call(configuration.merge(template_path: "%project_name%/Guardfile.erb")).render
16
+ configuration
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ module Puma
8
+ # Builds project skeleton Puma configuration.
9
+ class Configuration
10
+ using Refinements::Structs
11
+
12
+ def self.call(...) = new(...).call
13
+
14
+ def initialize configuration, builder: Rubysmith::Builder
15
+ @configuration = configuration
16
+ @builder = builder
17
+ end
18
+
19
+ def call
20
+ builder.call(configuration.merge(template_path: "%project_name%/config/puma.rb.erb"))
21
+ .render
22
+
23
+ configuration
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :configuration, :builder
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ module Puma
8
+ # Builds project skeleton Puma Procfile for production and development environments.
9
+ class Procfile
10
+ using Refinements::Structs
11
+
12
+ def self.call(...) = new(...).call
13
+
14
+ def initialize configuration, builder: Rubysmith::Builder
15
+ @configuration = configuration
16
+ @builder = builder
17
+ end
18
+
19
+ def call
20
+ builder.call(configuration.merge(template_path: "%project_name%/Procfile.erb")).render
21
+ builder.call(configuration.merge(template_path: "%project_name%/Procfile.dev.erb")).render
22
+ configuration
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :configuration, :builder
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ # Builds project skeleton Rack support.
8
+ class Rack
9
+ using Refinements::Structs
10
+
11
+ def self.call(...) = new(...).call
12
+
13
+ def initialize configuration, builder: Rubysmith::Builder
14
+ @configuration = configuration
15
+ @builder = builder
16
+ end
17
+
18
+ def call
19
+ builder.call(configuration.merge(template_path: "%project_name%/config.ru.erb")).render
20
+ configuration
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :configuration, :builder
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ # Builds project skeleton Rake support.
8
+ class Rake < Rubysmith::Builders::Rake
9
+ using Refinements::Structs
10
+
11
+ def call
12
+ return configuration unless configuration.build_rake
13
+
14
+ super
15
+ builder.call(configuration.merge(template_path: "%project_name%/Rakefile.erb"))
16
+ .render
17
+ .insert_after(%r(bundler/setup), %(require "hanami/rake_tasks"))
18
+
19
+ configuration
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :configuration, :builder
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ module RSpec
8
+ # Builds project skeleton RSpec helper.
9
+ class Hanami
10
+ using Refinements::Structs
11
+
12
+ def self.call(...) = new(...).call
13
+
14
+ def initialize configuration, builder: Rubysmith::Builder
15
+ @configuration = configuration
16
+ @builder = builder
17
+ end
18
+
19
+ def call
20
+ return configuration unless configuration.build_rspec
21
+
22
+ path = "%project_name%/spec/hanami_helper.rb.erb"
23
+ builder.call(configuration.merge(template_path: path)).render
24
+
25
+ configuration
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :configuration, :builder
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ module RSpec
8
+ # Builds project skeleton RSpec helper.
9
+ class Helper < Rubysmith::Builders::RSpec::Helper
10
+ using Refinements::Structs
11
+
12
+ def call
13
+ return configuration unless configuration.build_rspec
14
+
15
+ super
16
+ path = "%project_name%/spec/spec_helper.rb.erb"
17
+ builder.call(configuration.merge(template_path: path))
18
+ .replace(/require.+#{configuration.project_name}.+\n/, "")
19
+ configuration
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "refinements/structs"
4
+
5
+ module Hanamismith
6
+ module Builders
7
+ module Slices
8
+ # Builds project skeleton foundation.
9
+ class Main
10
+ using Refinements::Structs
11
+
12
+ def self.call(...) = new(...).call
13
+
14
+ def initialize configuration, builder: Rubysmith::Builder
15
+ @configuration = configuration
16
+ @builder = builder
17
+ end
18
+
19
+ def call
20
+ private_methods.grep(/\Aadd_/).sort.each { |method| __send__ method }
21
+ configuration
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :configuration, :builder
27
+
28
+ def add_action
29
+ path = "%project_name%/slices/main/action.rb.erb"
30
+ builder.call(configuration.merge(template_path: path)).render
31
+ end
32
+
33
+ def add_repository
34
+ path = "%project_name%/slices/main/repo.rb.erb"
35
+ builder.call(configuration.merge(template_path: path)).render
36
+ end
37
+
38
+ def add_view
39
+ path = "%project_name%/slices/main/view.rb.erb"
40
+ builder.call(configuration.merge(template_path: path)).render
41
+ end
42
+
43
+ def add_layout_template
44
+ path = "%project_name%/slices/main/templates/layouts/app.html.erb.erb"
45
+ builder.call(configuration.merge(template_path: path))
46
+ .render
47
+ .replace("<!-- yield -->", "<%= yield %>")
48
+ end
49
+
50
+ def add_show_template
51
+ path = "%project_name%/slices/main/templates/home/show.html.erb.erb"
52
+ builder.call(configuration.merge(template_path: path)).render
53
+ end
54
+
55
+ def add_show_view
56
+ path = "%project_name%/slices/main/views/home/show.rb.erb"
57
+ builder.call(configuration.merge(template_path: path)).render
58
+ end
59
+
60
+ def add_show_action
61
+ path = "%project_name%/slices/main/actions/home/show.rb.erb"
62
+ builder.call(configuration.merge(template_path: path)).render
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanamismith
4
+ module CLI
5
+ module Actions
6
+ # Handles the build action.
7
+ class Build
8
+ include Hanamismith::Import[:logger]
9
+
10
+ # Order is important.
11
+ BUILDERS = [
12
+ Builders::Core,
13
+ Builders::Slices::Main,
14
+ Rubysmith::Builders::Version,
15
+ Builders::Documentation::Readme,
16
+ Rubysmith::Builders::Documentation::Citation,
17
+ Rubysmith::Builders::Documentation::License,
18
+ Rubysmith::Builders::Documentation::Version,
19
+ Rubysmith::Builders::Git::Setup,
20
+ Rubysmith::Builders::Git::Ignore,
21
+ Builders::Bundler,
22
+ Builders::Rake,
23
+ Builders::Binstub,
24
+ Builders::Console,
25
+ Rubysmith::Builders::CircleCI,
26
+ Rubysmith::Builders::Setup,
27
+ Rubysmith::Builders::GitHub,
28
+ Rubysmith::Builders::GitHubCI,
29
+ Builders::Guard,
30
+ Rubysmith::Builders::Reek,
31
+ Rubysmith::Builders::RSpec::Binstub,
32
+ Rubysmith::Builders::RSpec::Context,
33
+ Builders::RSpec::Helper,
34
+ Builders::RSpec::Hanami,
35
+ Builders::Rack,
36
+ Builders::Puma::Configuration,
37
+ Builders::Puma::Procfile,
38
+ Builders::Caliber,
39
+ Rubysmith::Extensions::Bundler,
40
+ Rubysmith::Extensions::Pragmater,
41
+ Rubysmith::Extensions::Tocer,
42
+ Rubysmith::Extensions::Rubocop,
43
+ Builders::Environment,
44
+ Builders::Git::Commit
45
+ ].freeze
46
+
47
+ def initialize builders: BUILDERS, **dependencies
48
+ super(**dependencies)
49
+ @builders = builders
50
+ end
51
+
52
+ def call configuration
53
+ log_info "Building project skeleton: #{configuration.project_name}..."
54
+ builders.each { |builder| builder.call configuration }
55
+ log_info "Project skeleton complete!"
56
+ end
57
+
58
+ private
59
+
60
+ attr_reader :builders
61
+
62
+ def log_info(message) = logger.info { message }
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanamismith
4
+ module CLI
5
+ module Actions
6
+ # Handles the config action.
7
+ class Config
8
+ include Hanamismith::Import[:kernel, :logger]
9
+
10
+ def initialize client: Configuration::Loader::CLIENT, **dependencies
11
+ super(**dependencies)
12
+
13
+ @client = client
14
+ end
15
+
16
+ def call selection
17
+ case selection
18
+ when :edit then edit
19
+ when :view then view
20
+ else logger.error { "Invalid configuration selection: #{selection}." }
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :client
27
+
28
+ def edit = kernel.system("$EDITOR #{client.current}")
29
+
30
+ def view = kernel.system("cat #{client.current}")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/container"
4
+
5
+ module Hanamismith
6
+ module CLI
7
+ module Actions
8
+ # Provides a single container of application and action specific dependencies.
9
+ module Container
10
+ extend Dry::Container::Mixin
11
+
12
+ merge Hanamismith::Container
13
+
14
+ register(:build) { Build.new }
15
+ register(:config) { Config.new }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "infusible"
4
+
5
+ module Hanamismith
6
+ module CLI
7
+ module Actions
8
+ Import = Infusible.with Container
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "core"
4
+ require "optparse"
5
+
6
+ module Hanamismith
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].freeze
16
+
17
+ def initialize sections: SECTIONS, client: CLIENT, **dependencies
18
+ super(**dependencies)
19
+
20
+ @sections = sections
21
+ @client = client
22
+ @configuration_duplicate = configuration.dup
23
+ end
24
+
25
+ def call arguments = Core::EMPTY_ARRAY
26
+ sections.each { |section| section.call configuration_duplicate, client: }
27
+ client.parse arguments
28
+ configuration_duplicate.freeze
29
+ end
30
+
31
+ def to_s = client.to_s
32
+
33
+ private
34
+
35
+ attr_reader :sections, :client, :configuration_duplicate
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "core"
4
+ require "refinements/structs"
5
+
6
+ module Hanamismith
7
+ module CLI
8
+ module Parsers
9
+ # Handles parsing of Command Line Interface (CLI) core options.
10
+ class Core
11
+ include Import[:specification]
12
+
13
+ using Refinements::Structs
14
+
15
+ def self.call(...) = new(...).call
16
+
17
+ def initialize configuration = Container[:configuration],
18
+ client: Parser::CLIENT,
19
+ **dependencies
20
+
21
+ super(**dependencies)
22
+ @configuration = configuration
23
+ @client = client
24
+ end
25
+
26
+ def call arguments = ::Core::EMPTY_ARRAY
27
+ client.banner = specification.labeled_summary
28
+ client.separator "\nUSAGE:\n"
29
+ collate
30
+ client.parse arguments
31
+ configuration
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :configuration, :client
37
+
38
+ def collate = private_methods.sort.grep(/add_/).each { |method| __send__ method }
39
+
40
+ def add_build
41
+ client.on "-b", "--build NAME [options]", "Build new project." do |name|
42
+ configuration.merge! action_build: true, project_name: name
43
+ end
44
+ end
45
+
46
+ def add_config
47
+ client.on "-c",
48
+ "--config ACTION",
49
+ %i[edit view],
50
+ "Manage gem configuration: edit or view." do |action|
51
+ configuration.merge! action_config: action
52
+ end
53
+ end
54
+
55
+ def add_version
56
+ client.on "-v", "--version", "Show gem version." do
57
+ configuration.merge! action_version: true
58
+ end
59
+ end
60
+
61
+ def add_help
62
+ client.on "-h", "--help", "Show this message." do
63
+ configuration.merge! action_help: true
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "core"
4
+
5
+ module Hanamismith
6
+ module CLI
7
+ # The main Command Line Interface (CLI) object.
8
+ class Shell
9
+ include Actions::Import[:config, :build, :specification, :logger]
10
+
11
+ def initialize parser: Parser.new, **dependencies
12
+ super(**dependencies)
13
+ @parser = parser
14
+ end
15
+
16
+ def call arguments = Core::EMPTY_ARRAY
17
+ perform parser.call(arguments)
18
+ rescue OptionParser::ParseError => error
19
+ logger.error { error.message }
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :parser
25
+
26
+ def perform configuration
27
+ case configuration
28
+ in action_build: true then build.call configuration
29
+ in action_config: Symbol => action then config.call action
30
+ in action_version: true then logger.info { specification.labeled_version }
31
+ else logger.any { parser.to_s }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanamismith
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
File without changes
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "runcom"
4
+
5
+ module Hanamismith
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 "hanamismith/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
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cogger"
4
+ require "dry/container"
5
+ require "spek"
6
+
7
+ module Hanamismith
8
+ # Provides a global gem container for injection into other objects.
9
+ module Container
10
+ extend Dry::Container::Mixin
11
+
12
+ register(:configuration) { Configuration::Loader.call }
13
+ register(:specification) { Spek::Loader.call "#{__dir__}/../../hanamismith.gemspec" }
14
+ register(:kernel) { Kernel }
15
+ register(:logger) { Cogger::Client.new }
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "infusible"
4
+
5
+ module Hanamismith
6
+ Import = Infusible.with Container
7
+ end