hanami 0.8.0 → 0.9.0

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