hanami 0.8.0 → 0.9.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/FEATURES.md +13 -0
  4. data/README.md +28 -1
  5. data/hanami.gemspec +20 -17
  6. data/lib/hanami.rb +106 -7
  7. data/lib/hanami/action/routing_helpers.rb +2 -2
  8. data/lib/hanami/app.rb +72 -0
  9. data/lib/hanami/application.rb +144 -183
  10. data/lib/hanami/application_configuration.rb +1541 -0
  11. data/lib/hanami/application_name.rb +2 -2
  12. data/lib/hanami/application_namespace.rb +12 -0
  13. data/lib/hanami/assets/asset.rb +3 -1
  14. data/lib/hanami/assets/static.rb +3 -9
  15. data/lib/hanami/cli.rb +10 -7
  16. data/lib/hanami/cli_sub_commands/assets.rb +1 -9
  17. data/lib/hanami/cli_sub_commands/generate.rb +16 -0
  18. data/lib/hanami/commands/apps.rb +4 -0
  19. data/lib/hanami/commands/assets/precompile.rb +6 -19
  20. data/lib/hanami/commands/command.rb +64 -0
  21. data/lib/hanami/commands/console.rb +37 -26
  22. data/lib/hanami/commands/db/apply.rb +4 -2
  23. data/lib/hanami/commands/db/console.rb +11 -27
  24. data/lib/hanami/commands/db/create.rb +4 -2
  25. data/lib/hanami/commands/db/drop.rb +4 -2
  26. data/lib/hanami/commands/db/migrate.rb +11 -5
  27. data/lib/hanami/commands/db/prepare.rb +4 -2
  28. data/lib/hanami/commands/db/version.rb +4 -2
  29. data/lib/hanami/commands/generate/abstract.rb +5 -7
  30. data/lib/hanami/commands/generate/action.rb +18 -6
  31. data/lib/hanami/commands/generate/app.rb +15 -2
  32. data/lib/hanami/commands/generate/migration.rb +3 -2
  33. data/lib/hanami/commands/generate/model.rb +4 -3
  34. data/lib/hanami/commands/generate/secret_token.rb +31 -0
  35. data/lib/hanami/commands/new/abstract.rb +14 -5
  36. data/lib/hanami/commands/new/container.rb +1 -0
  37. data/lib/hanami/commands/routes.rb +5 -22
  38. data/lib/hanami/commands/server.rb +14 -142
  39. data/lib/hanami/components.rb +107 -0
  40. data/lib/hanami/components/app/assets.rb +55 -0
  41. data/lib/hanami/components/app/controller.rb +69 -0
  42. data/lib/hanami/components/app/logger.rb +30 -0
  43. data/lib/hanami/components/app/routes.rb +51 -0
  44. data/lib/hanami/components/app/view.rb +40 -0
  45. data/lib/hanami/components/component.rb +166 -0
  46. data/lib/hanami/components/components.rb +366 -0
  47. data/lib/hanami/components/routes_inspector.rb +70 -0
  48. data/lib/hanami/config/load_paths.rb +7 -6
  49. data/lib/hanami/config/mapper.rb +1 -1
  50. data/lib/hanami/config/security.rb +0 -8
  51. data/lib/hanami/configuration.rb +27 -1697
  52. data/lib/hanami/env.rb +67 -0
  53. data/lib/hanami/environment.rb +31 -21
  54. data/lib/hanami/environment_application_configurations.rb +30 -0
  55. data/lib/hanami/frameworks.rb +1 -0
  56. data/lib/hanami/generators/app/application.rb.tt +2 -2
  57. data/lib/hanami/generators/application/app/Gemfile.tt +3 -1
  58. data/lib/hanami/generators/application/app/config/application.rb.tt +2 -2
  59. data/lib/hanami/generators/application/app/gitignore_with_sqlite.tt +3 -0
  60. data/lib/hanami/generators/application/app/lib/app_name.rb.tt +4 -25
  61. data/lib/hanami/generators/application/app/spec_helper.rb.minitest.tt +1 -1
  62. data/lib/hanami/generators/application/app/spec_helper.rb.rspec.tt +1 -1
  63. data/lib/hanami/generators/application/container/Gemfile.tt +3 -1
  64. data/lib/hanami/generators/application/container/capybara.rb.rspec.tt +1 -1
  65. data/lib/hanami/generators/application/container/config.ru.tt +1 -1
  66. data/lib/hanami/generators/application/container/config/environment.rb.tt +35 -1
  67. data/lib/hanami/generators/application/container/features_helper.rb.minitest.tt +1 -1
  68. data/lib/hanami/generators/application/container/gitignore_with_sqlite.tt +3 -0
  69. data/lib/hanami/generators/application/container/lib/project.rb.tt +1 -57
  70. data/lib/hanami/generators/application/container/spec_helper.rb.minitest.tt +1 -1
  71. data/lib/hanami/generators/application/container/spec_helper.rb.rspec.tt +2 -3
  72. data/lib/hanami/generators/database_config.rb +8 -11
  73. data/lib/hanami/generators/model/entity.rb.tt +1 -2
  74. data/lib/hanami/generators/model/repository.rb.tt +1 -2
  75. data/lib/hanami/generators/template_engine.rb +8 -3
  76. data/lib/hanami/generators/test_framework.rb +4 -3
  77. data/lib/hanami/middleware.rb +41 -21
  78. data/lib/hanami/rake_helper.rb +6 -8
  79. data/lib/hanami/server.rb +43 -33
  80. data/lib/hanami/static.rb +2 -2
  81. data/lib/hanami/version.rb +35 -1
  82. data/lib/hanami/welcome.rb +4 -5
  83. metadata +68 -42
  84. data/lib/hanami/commands/db/abstract.rb +0 -19
  85. data/lib/hanami/config/configure.rb +0 -17
  86. data/lib/hanami/config/mapping.rb +0 -12
  87. data/lib/hanami/container.rb +0 -71
  88. data/lib/hanami/generators/application/container/gitignore_with_db.tt +0 -4
  89. data/lib/hanami/loader.rb +0 -257
  90. data/lib/hanami/repositories/car_repository.rb +0 -3
  91. data/lib/hanami/repositories/name_repository.rb +0 -3
@@ -30,7 +30,7 @@ module Hanami
30
30
  #
31
31
  # @since 0.2.1
32
32
  def initialize(name)
33
- @name = sanitize(name)
33
+ @name = sanitize(name.to_s)
34
34
  ensure_validity!
35
35
  end
36
36
 
@@ -98,7 +98,7 @@ module Hanami
98
98
  def sanitize(name)
99
99
  Utils::String.new(
100
100
  name.strip
101
- ).underscore.to_s
101
+ ).namespace.underscore.to_s
102
102
  end
103
103
  end
104
104
  end
@@ -0,0 +1,12 @@
1
+ require 'hanami/utils/class'
2
+ require 'hanami/utils/string'
3
+
4
+ module Hanami
5
+ class ApplicationNamespace
6
+ def self.resolve(name)
7
+ Utils::Class.load!(
8
+ Utils::String.new(name).namespace
9
+ )
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,5 @@
1
+ require 'hanami/utils/file_list'
2
+
1
3
  module Hanami
2
4
  module Assets
3
5
  # Requested asset
@@ -60,7 +62,7 @@ module Hanami
60
62
  # @since 0.8.0
61
63
  # @api private
62
64
  def find_asset
63
- Dir[PUBLIC_DIRECTORY].find do |asset|
65
+ Utils::FileList[PUBLIC_DIRECTORY].find do |asset|
64
66
  yield asset unless ::File.directory?(asset)
65
67
  end
66
68
  end
@@ -11,7 +11,7 @@ require 'hanami/assets/asset'
11
11
 
12
12
  module Hanami
13
13
  module Assets
14
- # Serve static assets in development enviroments (development, test).
14
+ # Serve static assets in development environments (development, test).
15
15
  #
16
16
  # While serving static assets is a role delegated in production to web
17
17
  # servers (like Nginx), in development it's rare to use a web server.
@@ -92,17 +92,11 @@ module Hanami
92
92
  # @since 0.8.0
93
93
  # @api private
94
94
  def _sources_from_applications
95
- Hanami::Application.applications.each_with_object({}) do |application, result|
96
- config = _assets_configuration(application)
95
+ Hanami::Components.resolve('apps.assets.configurations')
96
+ Hanami::Components['apps.assets.configurations'].each_with_object({}) do |config, result|
97
97
  result["#{config.prefix}/"] = config
98
98
  end
99
99
  end
100
-
101
- # @since 0.8.0
102
- # @api private
103
- def _assets_configuration(application)
104
- application.configuration.namespace::Assets.configuration
105
- end
106
100
  end
107
101
  end
108
102
  end
data/lib/hanami/cli.rb CHANGED
@@ -85,16 +85,16 @@ module Hanami
85
85
  end
86
86
  end
87
87
 
88
- desc 'new APPLICATION_NAME', 'Generate a new hanami project'
88
+ desc 'new PROJECT_NAME', 'Generate a new hanami project'
89
89
  long_desc <<-EOS
90
- `hanami new` creates a new hanami project.
91
- You can specify various options such as the database to be used as well as the path and architecture.
90
+ `hanami new` creates a new hanami project.
91
+ You can specify various options such as the database to be used as well as the path and architecture.
92
92
 
93
- $ > hanami new fancy_app --application_name=admin
93
+ $ > hanami new fancy_app --application_name=admin
94
94
 
95
- $ > hanami new fancy_app --arch=app
95
+ $ > hanami new fancy_app --arch=app
96
96
 
97
- $ > hanami new fancy_app --hanami-head=true
97
+ $ > hanami new fancy_app --hanami-head=true
98
98
  EOS
99
99
  method_option :database, aliases: ['-d', '--db'], desc: "Application database (#{Hanami::Generators::DatabaseConfig::SUPPORTED_ENGINES.keys.join('/')})", default: Hanami::Generators::DatabaseConfig::DEFAULT_ENGINE
100
100
  method_option :architecture, aliases: ['-a', '--arch'], desc: 'Project architecture (container/app)', default: Hanami::Commands::New::Abstract::DEFAULT_ARCHITECTURE
@@ -104,9 +104,12 @@ module Hanami
104
104
  method_option :test, desc: "Project test framework (#{Hanami::Generators::TestFramework::VALID_FRAMEWORKS.join('/')})", default: Hanami::Hanamirc::DEFAULT_TEST_SUITE
105
105
  method_option :hanami_head, desc: 'Use hanami HEAD (true/false)', type: :boolean, default: false
106
106
  method_option :help, desc: 'Displays the usage method'
107
- def new(application_name)
107
+ def new(application_name=nil)
108
108
  if options[:help]
109
109
  invoke :help, ['new']
110
+ elsif application_name.nil?
111
+ warn %(`hanami new` was called with no arguments\nUsage: `hanami new PROJECT_NAME`)
112
+ exit(1)
110
113
  elsif options[:architecture] == 'app'
111
114
  Hanami::Commands::New::App.new(options, application_name).start
112
115
  else
@@ -15,15 +15,7 @@ module Hanami
15
15
  desc 'precompile', 'Precompile assets for deployment'
16
16
  def precompile
17
17
  require 'hanami/commands/assets/precompile'
18
- Hanami::Commands::Assets::Precompile.new(options, environment).start
19
- end
20
-
21
- private
22
-
23
- # @since 0.6.0
24
- # @api private
25
- def environment
26
- Hanami::Environment.new(options)
18
+ Hanami::Commands::Assets::Precompile.new(options).start
27
19
  end
28
20
  end
29
21
  end
@@ -123,6 +123,22 @@ module Hanami
123
123
  Hanami::Commands::Generate::App.new(options, application_name).start
124
124
  end
125
125
  end
126
+
127
+ desc 'secret APPLICATION_NAME', 'Print a fresh secret token for production'
128
+ long_desc <<-EOS
129
+ `hanami generate secret` prints a new secret for a given app
130
+
131
+ > $ hanami generate secret web
132
+
133
+ EOS
134
+ def secret(application_name = nil)
135
+ if options[:help]
136
+ invoke :help, ['secret']
137
+ else
138
+ require 'hanami/commands/generate/secret_token'
139
+ Hanami::Commands::Generate::SecretToken.new(application_name).start
140
+ end
141
+ end
126
142
  end
127
143
  end
128
144
  end
@@ -0,0 +1,4 @@
1
+ module Hanami
2
+ module Components
3
+ end
4
+ end
@@ -1,33 +1,20 @@
1
1
  require 'hanami/assets'
2
+ require 'hanami/commands/command'
2
3
 
3
4
  module Hanami
4
5
  module Commands
5
6
  class Assets
6
- class Precompile
7
- def initialize(options, environment)
8
- @options = options
9
- @environment = environment
10
- end
7
+ class Precompile < Command
8
+ requires 'apps.assets.configurations'
11
9
 
12
10
  def start
13
- preload_applications
14
- precompile
11
+ Hanami::Assets.precompile(configurations)
15
12
  end
16
13
 
17
14
  private
18
15
 
19
- def preload_applications
20
- @environment.require_application_environment
21
-
22
- if @environment.container?
23
- Hanami::Container.new
24
- else
25
- Hanami::Application.preload!
26
- end
27
- end
28
-
29
- def precompile
30
- Hanami::Assets.deploy
16
+ def configurations
17
+ requirements['apps.assets.configurations']
31
18
  end
32
19
  end
33
20
  end
@@ -0,0 +1,64 @@
1
+ require 'hanami'
2
+ require 'hanami/environment'
3
+ require 'hanami/components'
4
+ require 'concurrent'
5
+
6
+ module Hanami
7
+ module Commands
8
+ # Abstract command
9
+ #
10
+ # @since 0.9.0
11
+ class Command
12
+ def self.inherited(component)
13
+ super
14
+
15
+ component.class_eval do
16
+ @_requirements = Concurrent::Array.new
17
+ extend ClassMethods
18
+ end
19
+ end
20
+
21
+ # Class level interface
22
+ #
23
+ # @since 0.9.0
24
+ module ClassMethods
25
+ def register_as(name)
26
+ Hanami::Components.register(name, self)
27
+ end
28
+
29
+ def requires(*names)
30
+ requirements.concat(names)
31
+ end
32
+
33
+ def requirements
34
+ @_requirements
35
+ end
36
+ end
37
+
38
+ # @param options [Hash] Environment's options
39
+ #
40
+ # @since 0.9.0
41
+ def initialize(options)
42
+ @environment = Hanami::Environment.new(options)
43
+ @environment.require_project_environment
44
+ @configuration = Hanami.configuration
45
+
46
+ requirements.resolved('environment', environment)
47
+ requirements.resolve(self.class.requirements)
48
+ end
49
+
50
+ private
51
+
52
+ # @since 0.9.0
53
+ attr_reader :environment
54
+
55
+ # @since 0.9.0
56
+ attr_reader :configuration
57
+
58
+ # @since 0.9.0
59
+ def requirements
60
+ Hanami::Components
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,5 @@
1
+ require 'hanami/commands/command'
2
+
1
3
  module Hanami
2
4
  module Commands
3
5
  # REPL that supports different engines.
@@ -8,14 +10,24 @@ module Hanami
8
10
  #
9
11
  # @since 0.1.0
10
12
  # @api private
11
- class Console
12
- module Methods
13
+ class Console < Command
14
+ requires 'all'
15
+
16
+ # Implements console code reloading
17
+ #
18
+ # @since 0.2.0
19
+ module CodeReloading
20
+ # @since 0.2.0
13
21
  def reload!
14
22
  puts 'Reloading...'
15
- Kernel.exec "#{$0} console"
23
+ Kernel.exec "#{$PROGRAM_NAME} console"
16
24
  end
17
25
  end
18
26
 
27
+ # Supported engines
28
+ #
29
+ # @since 0.2.0
30
+ # @api private
19
31
  ENGINES = {
20
32
  'pry' => 'Pry',
21
33
  'ripl' => 'Ripl',
@@ -32,20 +44,14 @@ module Hanami
32
44
  # @since 0.1.0
33
45
  # @see Hanami::Environment#initialize
34
46
  def initialize(options)
35
- @environment = Hanami::Environment.new(options)
36
- @options = @environment.to_options
47
+ super(options)
48
+
49
+ @options = @environment.to_options
37
50
  end
38
51
 
39
52
  # @since 0.1.0
40
53
  def start
41
- # Clear out ARGV so Pry/IRB don't attempt to parse the rest
42
- ARGV.shift until ARGV.empty?
43
- @environment.require_application_environment
44
-
45
- # Add convenience methods to the main:Object binding
46
- TOPLEVEL_BINDING.eval('self').send(:include, Methods)
47
-
48
- load_application
54
+ prepare
49
55
  engine.start
50
56
  end
51
57
 
@@ -57,6 +63,16 @@ module Hanami
57
63
 
58
64
  private
59
65
 
66
+ # @since 0.9.0
67
+ # @api private
68
+ def prepare
69
+ # Clear out ARGV so Pry/IRB don't attempt to parse the rest
70
+ ARGV.shift until ARGV.empty?
71
+
72
+ # Add convenience methods to the main:Object binding
73
+ TOPLEVEL_BINDING.eval('self').__send__(:include, CodeReloading)
74
+ end
75
+
60
76
  # @since 0.1.0
61
77
  # @api private
62
78
  def engine_lookup
@@ -65,26 +81,21 @@ module Hanami
65
81
 
66
82
  # @since 0.1.0
67
83
  # @api private
84
+ #
85
+ # rubocop:disable Lint/HandleExceptions
86
+ # rubocop:disable Lint/EnsureReturn
68
87
  def load_engine(engine)
69
88
  require engine
70
89
  rescue LoadError
71
90
  ensure
72
91
  return Object.const_get(
73
- ENGINES.fetch(engine) {
74
- raise ArgumentError.new("Unknown console engine: #{ engine }")
75
- }
92
+ ENGINES.fetch(engine) do
93
+ raise ArgumentError.new("Unknown console engine: `#{engine}'")
94
+ end
76
95
  )
77
96
  end
78
-
79
- # @since 0.1.0
80
- # @api private
81
- def load_application
82
- if @environment.container?
83
- Hanami::Container.new
84
- else
85
- Hanami::Application.preload_applications!
86
- end
87
- end
97
+ # rubocop:enable Lint/EnsureReturn
98
+ # rubocop:enable Lint/HandleExceptions
88
99
  end
89
100
  end
90
101
  end
@@ -1,9 +1,11 @@
1
- require 'hanami/commands/db/abstract'
1
+ require 'hanami/commands/command'
2
2
 
3
3
  module Hanami
4
4
  module Commands
5
5
  class DB
6
- class Apply < Abstract
6
+ class Apply < Command
7
+ requires 'model.sql'
8
+
7
9
  def start
8
10
  require 'hanami/model/migrator'
9
11
  Hanami::Model::Migrator.apply
@@ -1,48 +1,32 @@
1
1
  require 'hanami/utils/class'
2
- require 'hanami/commands/db/abstract'
2
+ require 'hanami/commands/command'
3
3
 
4
4
  module Hanami
5
5
  module Commands
6
6
  class DB
7
- class Console < Abstract
8
- attr_reader :name, :env_options
7
+ class Console < Command
8
+ requires 'model.sql'
9
9
 
10
10
  def initialize(options, name)
11
11
  super(options)
12
- @name = name
13
- @env_options = environment.to_options
12
+ @name = name
14
13
  end
15
14
 
16
15
  def start
17
- exec connection_string
16
+ exec console.connection_string
18
17
  end
19
18
 
20
19
  private
21
20
 
22
- def config
23
- if name
24
- app_constant = Hanami::Utils::Class.load_from_pattern!(Hanami::Utils::String.new(name).classify)
25
- Hanami::Utils::Class.load_from_pattern!("#{app_constant}::Application").load!
26
- Hanami::Utils::Class.load_from_pattern!("#{app_constant}::Model").configuration
27
- else
28
- Hanami::Model.configuration
29
- end
30
- end
31
-
32
- def adapter_config
33
- config.adapter_config
34
- end
35
-
36
- def mapper
37
- config.mapper
38
- end
21
+ attr_reader :name
39
22
 
40
- def adapter_class
41
- Hanami::Utils::Class.load_from_pattern!(adapter_config.class_name, Hanami::Model::Adapters)
23
+ def configuration
24
+ Hanami::Components['model.configuration']
42
25
  end
43
26
 
44
- def connection_string
45
- adapter_class.new(mapper, adapter_config.uri).connection_string
27
+ def console
28
+ require 'hanami/model/sql/console'
29
+ Hanami::Model::Sql::Console.new(configuration.url)
46
30
  end
47
31
  end
48
32
  end