hanami 1.0.0.beta2 → 1.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/FEATURES.md +2 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +1 -1
  6. data/hanami.gemspec +8 -8
  7. data/lib/hanami.rb +0 -5
  8. data/lib/hanami/action/csrf_protection.rb +35 -0
  9. data/lib/hanami/app.rb +1 -1
  10. data/lib/hanami/application.rb +2 -0
  11. data/lib/hanami/application_configuration.rb +1 -12
  12. data/lib/hanami/application_name.rb +8 -2
  13. data/lib/hanami/application_namespace.rb +2 -0
  14. data/lib/hanami/assets/asset.rb +1 -0
  15. data/lib/hanami/cli.rb +7 -0
  16. data/lib/hanami/cli_base.rb +3 -0
  17. data/lib/hanami/cli_sub_commands/assets.rb +2 -0
  18. data/lib/hanami/cli_sub_commands/db.rb +15 -2
  19. data/lib/hanami/cli_sub_commands/destroy.rb +6 -0
  20. data/lib/hanami/cli_sub_commands/generate.rb +7 -2
  21. data/lib/hanami/commands/assets/precompile.rb +4 -0
  22. data/lib/hanami/commands/command.rb +13 -0
  23. data/lib/hanami/commands/console.rb +6 -0
  24. data/lib/hanami/commands/db/apply.rb +3 -0
  25. data/lib/hanami/commands/db/console.rb +7 -0
  26. data/lib/hanami/commands/db/create.rb +3 -0
  27. data/lib/hanami/commands/db/drop.rb +3 -0
  28. data/lib/hanami/commands/db/migrate.rb +5 -0
  29. data/lib/hanami/commands/db/prepare.rb +3 -0
  30. data/lib/hanami/commands/db/version.rb +3 -0
  31. data/lib/hanami/commands/generate/abstract.rb +13 -1
  32. data/lib/hanami/commands/generate/action.rb +21 -0
  33. data/lib/hanami/commands/generate/app.rb +21 -0
  34. data/lib/hanami/commands/generate/mailer.rb +16 -3
  35. data/lib/hanami/commands/generate/migration.rb +13 -2
  36. data/lib/hanami/commands/generate/model.rb +14 -1
  37. data/lib/hanami/commands/generate/secret_token.rb +6 -0
  38. data/lib/hanami/commands/new/abstract.rb +39 -4
  39. data/lib/hanami/commands/new/app.rb +15 -0
  40. data/lib/hanami/commands/new/container.rb +14 -0
  41. data/lib/hanami/commands/routes.rb +2 -0
  42. data/lib/hanami/commands/server.rb +4 -0
  43. data/lib/hanami/components/app/assets.rb +4 -0
  44. data/lib/hanami/components/app/controller.rb +4 -0
  45. data/lib/hanami/components/app/routes.rb +6 -0
  46. data/lib/hanami/components/app/view.rb +4 -0
  47. data/lib/hanami/components/component.rb +2 -0
  48. data/lib/hanami/components/components.rb +12 -5
  49. data/lib/hanami/components/routes_inspector.rb +2 -0
  50. data/lib/hanami/config/cookies.rb +1 -0
  51. data/lib/hanami/config/framework_configuration.rb +1 -0
  52. data/lib/hanami/config/load_paths.rb +4 -0
  53. data/lib/hanami/config/mapper.rb +11 -0
  54. data/lib/hanami/config/routes.rb +4 -0
  55. data/lib/hanami/config/security.rb +2 -0
  56. data/lib/hanami/config/sessions.rb +6 -0
  57. data/lib/hanami/configuration.rb +102 -0
  58. data/lib/hanami/environment.rb +13 -0
  59. data/lib/hanami/environment_application_configurations.rb +7 -0
  60. data/lib/hanami/generators/app/application.rb.tt +31 -23
  61. data/lib/hanami/generators/app/favicon.ico +0 -0
  62. data/lib/hanami/generators/database_config.rb +19 -1
  63. data/lib/hanami/generators/generatable.rb +13 -0
  64. data/lib/hanami/generators/generator.rb +8 -0
  65. data/lib/hanami/generators/template_engine.rb +9 -0
  66. data/lib/hanami/generators/test_framework.rb +12 -0
  67. data/lib/hanami/hanamirc.rb +2 -0
  68. data/lib/hanami/mailer/glue.rb +1 -0
  69. data/lib/hanami/middleware.rb +24 -0
  70. data/lib/hanami/rendering_policy.rb +15 -0
  71. data/lib/hanami/routes.rb +14 -12
  72. data/lib/hanami/routing/default.rb +7 -0
  73. data/lib/hanami/server.rb +6 -0
  74. data/lib/hanami/version.rb +1 -1
  75. data/lib/hanami/views/default.rb +3 -0
  76. data/lib/hanami/views/default_template_finder.rb +2 -0
  77. data/lib/hanami/views/null_view.rb +2 -0
  78. data/lib/hanami/welcome.rb +7 -0
  79. metadata +18 -19
  80. data/lib/hanami/root.rb +0 -7
@@ -4,12 +4,17 @@ require 'hanami/utils/blank'
4
4
  require 'securerandom'
5
5
 
6
6
  module Hanami
7
+ # @api private
7
8
  module Commands
9
+ # @api private
8
10
  class Generate
11
+ # @api private
9
12
  class App < Abstract
10
13
 
14
+ # @api private
11
15
  attr_reader :base_path
12
16
 
17
+ # @api private
13
18
  def initialize(options, application_name)
14
19
  @environment = Hanami::Environment.new(options)
15
20
  @options = Hanami::Utils::Hash.new(options).symbolize!
@@ -24,6 +29,7 @@ module Hanami
24
29
  @base_path = Pathname.pwd
25
30
  end
26
31
 
32
+ # @api private
27
33
  def map_templates
28
34
  add_mapping('application.rb.tt', 'application.rb')
29
35
  add_mapping('config/routes.rb.tt', 'config/routes.rb')
@@ -40,6 +46,7 @@ module Hanami
40
46
  add_mapping('.gitkeep', "../../spec/#{ app_name }/views/.gitkeep")
41
47
  end
42
48
 
49
+ # @api private
43
50
  def template_options
44
51
  {
45
52
  app_name: app_name,
@@ -51,6 +58,7 @@ module Hanami
51
58
  }
52
59
  end
53
60
 
61
+ # @api private
54
62
  def post_process_templates
55
63
  add_require_app
56
64
  add_mount_app
@@ -59,10 +67,12 @@ module Hanami
59
67
 
60
68
  private
61
69
 
70
+ # @api private
62
71
  def application_base_url
63
72
  options.fetch(:application_base_url, "/#{app_name}")
64
73
  end
65
74
 
75
+ # @api private
66
76
  def add_require_app
67
77
  # Add "require_relative '../apps/web/application'"
68
78
  generator.inject_into_file base_path.join('config/environment.rb'), after: /require_relative '\.\.\/lib\/.*'/ do
@@ -70,12 +80,14 @@ module Hanami
70
80
  end
71
81
  end
72
82
 
83
+ # @api private
73
84
  def add_mount_app
74
85
  generator.inject_into_file base_path.join('config/environment.rb'), after: /Hanami.configure do/ do |match|
75
86
  "\n mount #{ classified_app_name }::Application, at: '#{ application_base_url }'"
76
87
  end
77
88
  end
78
89
 
90
+ # @api private
79
91
  def add_web_session_secret
80
92
  ['development', 'test'].each do |environment|
81
93
  # Add WEB_SESSIONS_SECRET="abc123" (random hex)
@@ -85,42 +97,51 @@ module Hanami
85
97
  end
86
98
  end
87
99
 
100
+ # @api private
88
101
  def hanamirc
89
102
  @hanamirc ||= Hanamirc.new(base_path)
90
103
  end
91
104
 
105
+ # @api private
92
106
  def target_path
93
107
  base_path.join(application_base_path)
94
108
  end
95
109
 
110
+ # @api private
96
111
  def app_name
97
112
  @application_name.to_s
98
113
  end
99
114
 
115
+ # @api private
100
116
  def upcase_app_name
101
117
  @application_name.to_env_s
102
118
  end
103
119
 
120
+ # @api private
104
121
  def application_base_path
105
122
  ["apps", @application_name].join(::File::SEPARATOR)
106
123
  end
107
124
 
125
+ # @api private
108
126
  def classified_app_name
109
127
  Utils::String.new(app_name).classify.tr('::', '')
110
128
  end
111
129
 
130
+ # @api private
112
131
  def assert_application_name!(value)
113
132
  if argument_blank?(value)
114
133
  raise ArgumentError.new('Application name is missing')
115
134
  end
116
135
  end
117
136
 
137
+ # @api private
118
138
  def assert_architecture!
119
139
  if !environment.container?
120
140
  raise ArgumentError.new('App generator is only available for container architecture.')
121
141
  end
122
142
  end
123
143
 
144
+ # @api private
124
145
  def assert_application_base_url!
125
146
  if options.key?(:application_base_url) && Utils::Blank.blank?(options[:application_base_url])
126
147
  warn "`' is not a valid URL"
@@ -1,13 +1,23 @@
1
1
  require "hanami/commands/generate/abstract"
2
2
 
3
3
  module Hanami
4
+ # @api private
4
5
  module Commands
6
+ # @api private
5
7
  class Generate
6
8
  # @since 0.5.0
7
9
  # @api private
8
10
  class Mailer < Abstract
9
-
10
- attr_reader :name, :name_underscored, :from, :to, :subject
11
+ # @api private
12
+ attr_reader :name
13
+ # @api private
14
+ attr_reader :name_underscored
15
+ # @api private
16
+ attr_reader :from
17
+ # @api private
18
+ attr_reader :to
19
+ # @api private
20
+ attr_reader :subject
11
21
 
12
22
  # @since 0.5.0
13
23
  # @api private
@@ -47,7 +57,7 @@ module Hanami
47
57
  assert_name!
48
58
  end
49
59
 
50
- # @since 0.x.x
60
+ # @since 0.5.0
51
61
  # @api private
52
62
  def map_templates
53
63
  add_mapping("mailer_spec.rb.#{test_framework.framework}.tt", mailer_spec_path)
@@ -56,6 +66,7 @@ module Hanami
56
66
  add_mapping("template.html.tt", html_template_path)
57
67
  end
58
68
 
69
+ # @api private
59
70
  def template_options
60
71
  {
61
72
  mailer: name,
@@ -105,10 +116,12 @@ module Hanami
105
116
  core_root.join("mailers", "templates", "#{ name_underscored }#{ format }.#{ DEFAULT_ENGINE }")
106
117
  end
107
118
 
119
+ # @api private
108
120
  def spec_root
109
121
  Pathname.new("spec")
110
122
  end
111
123
 
124
+ # @api private
112
125
  def core_root
113
126
  Pathname.new("lib").join(project_name)
114
127
  end
@@ -2,11 +2,16 @@ require 'hanami/commands/generate/abstract'
2
2
  require 'hanami/utils/file_list'
3
3
 
4
4
  module Hanami
5
+ # @api private
5
6
  module Commands
7
+ # @api private
6
8
  class Generate
9
+ # @api private
7
10
  class Migration < Abstract
8
-
9
- attr_reader :name, :underscored_name
11
+ # @api private
12
+ attr_reader :name
13
+ # @api private
14
+ attr_reader :underscored_name
10
15
 
11
16
  # @since 0.6.0
12
17
  # @api private
@@ -22,6 +27,7 @@ module Hanami
22
27
  # 20150612160502_create_books.rb
23
28
  FILENAME_PATTERN = '%{timestamp}_%{name}.rb'.freeze
24
29
 
30
+ # @api private
25
31
  def initialize(options, name)
26
32
  super(options)
27
33
 
@@ -32,20 +38,24 @@ module Hanami
32
38
  assert_migration_name!
33
39
  end
34
40
 
41
+ # @api private
35
42
  def map_templates
36
43
  add_mapping('migration.rb.tt', destination_path)
37
44
  end
38
45
 
39
46
  private
40
47
 
48
+ # @api private
41
49
  def destination_path
42
50
  existing_migration_path || new_migration_path
43
51
  end
44
52
 
53
+ # @api private
45
54
  def existing_migration_path
46
55
  Utils::FileList["#{Hanami::Model.configuration.migrations}/[0-9]*_#{underscored_name}.rb"].first
47
56
  end
48
57
 
58
+ # @api private
49
59
  def new_migration_path
50
60
  timestamp = Time.now.utc.strftime(TIMESTAMP_FORMAT)
51
61
  filename = FILENAME_PATTERN % { timestamp: timestamp, name: underscored_name}
@@ -53,6 +63,7 @@ module Hanami
53
63
  Hanami::Model.configuration.migrations.join(filename)
54
64
  end
55
65
 
66
+ # @api private
56
67
  def assert_migration_name!
57
68
  if argument_blank?(name)
58
69
  raise ArgumentError.new('Migration name is missing')
@@ -2,12 +2,21 @@ require 'hanami/commands/generate/abstract'
2
2
  require 'hanami/commands/generate/migration'
3
3
 
4
4
  module Hanami
5
+ # @api private
5
6
  module Commands
7
+ # @api private
6
8
  class Generate
9
+ # @api private
7
10
  class Model < Abstract
8
11
 
9
- attr_reader :input, :model_name, :table_name
12
+ # @api private
13
+ attr_reader :input
14
+ # @api private
15
+ attr_reader :model_name
16
+ # @api private
17
+ attr_reader :table_name
10
18
 
19
+ # @api private
11
20
  def initialize(options, model_name)
12
21
  super(options)
13
22
  @input = Utils::String.new(model_name).underscore
@@ -21,6 +30,7 @@ module Hanami
21
30
  assert_model_name!
22
31
  end
23
32
 
33
+ # @api private
24
34
  def map_templates
25
35
  add_mapping('entity.rb.tt', entity_path)
26
36
  add_mapping('repository.rb.tt', repository_path)
@@ -31,6 +41,7 @@ module Hanami
31
41
  add_mapping("repository_spec.#{ test_framework.framework }.tt", repository_spec_path)
32
42
  end
33
43
 
44
+ # @api private
34
45
  def template_options
35
46
  {
36
47
  model_name: model_name,
@@ -67,10 +78,12 @@ module Hanami
67
78
  end
68
79
  end
69
80
 
81
+ # @api private
70
82
  def skip_migration?
71
83
  options.fetch(:skip_migration, false)
72
84
  end
73
85
 
86
+ # @api private
74
87
  def model_root
75
88
  Pathname.new('lib').join(project_name)
76
89
  end
@@ -3,14 +3,19 @@ require 'hanami/application_name'
3
3
  require 'securerandom'
4
4
 
5
5
  module Hanami
6
+ # @api private
6
7
  module Commands
8
+ # @api private
7
9
  class Generate
10
+ # @api private
8
11
  class SecretToken
9
12
 
13
+ # @api private
10
14
  def initialize(application_name)
11
15
  @application_name = application_name
12
16
  end
13
17
 
18
+ # @api private
14
19
  def start
15
20
  if Hanami::Utils::Blank.blank?(@application_name)
16
21
  puts SecureRandom.hex(32)
@@ -21,6 +26,7 @@ module Hanami
21
26
  end
22
27
 
23
28
  private
29
+ # @api private
24
30
  def upcase_app_name
25
31
  @application_name.upcase
26
32
  end
@@ -8,18 +8,34 @@ require 'hanami/utils'
8
8
  require 'hanami/utils/hash'
9
9
 
10
10
  module Hanami
11
+ # @api private
11
12
  module Commands
13
+ # @api private
12
14
  class New
15
+ # @api private
13
16
  class Abstract
14
17
 
15
18
  include Hanami::Generators::Generatable
16
19
 
20
+ # @api private
17
21
  DEFAULT_ARCHITECTURE = 'container'.freeze
22
+ # @api private
18
23
  DEFAULT_APPLICATION_BASE_URL = '/'.freeze
19
24
 
20
- attr_reader :options, :target_path, :database_config,
21
- :test_framework, :hanami_model_version, :template_engine
22
-
25
+ # @api private
26
+ attr_reader :options
27
+ # @api private
28
+ attr_reader :target_path
29
+ # @api private
30
+ attr_reader :database_config
31
+ # @api private
32
+ attr_reader :test_framework
33
+ # @api private
34
+ attr_reader :hanami_model_version
35
+ # @api private
36
+ attr_reader :template_engine
37
+
38
+ # @api private
23
39
  def initialize(options, name)
24
40
  @options = Hanami::Utils::Hash.new(options).symbolize!
25
41
  @name = name
@@ -29,12 +45,13 @@ module Hanami
29
45
  assert_name!
30
46
  assert_architecture!
31
47
 
32
- @hanami_model_version = '~> 1.0.0.beta2'
48
+ @hanami_model_version = '~> 1.0.0.beta3'
33
49
  @database_config = Hanami::Generators::DatabaseConfig.new(options[:database], project_name)
34
50
  @test_framework = Hanami::Generators::TestFramework.new(hanamirc, @options[:test])
35
51
  @template_engine = Hanami::Generators::TemplateEngine.new(hanamirc, @options[:template])
36
52
  end
37
53
 
54
+ # @api private
38
55
  def start
39
56
  FileUtils.mkdir_p(project_directory)
40
57
  Dir.chdir(project_directory) do
@@ -46,20 +63,24 @@ module Hanami
46
63
 
47
64
  private
48
65
 
66
+ # @api private
49
67
  def hanamirc
50
68
  @hanamirc ||= Hanamirc.new(Pathname.new('.'))
51
69
  end
52
70
 
71
+ # @api private
53
72
  def start_in_app_dir
54
73
  raise NotImplementedError
55
74
  end
56
75
 
76
+ # @api private
57
77
  def add_sql_templates
58
78
  return if !database_config.sql?
59
79
 
60
80
  add_mapping('schema.sql.tt', 'db/schema.sql')
61
81
  end
62
82
 
83
+ # @api private
63
84
  def add_git_templates
64
85
  return if git_dir_present?
65
86
 
@@ -68,64 +89,78 @@ module Hanami
68
89
  add_mapping(source, target)
69
90
  end
70
91
 
92
+ # @api private
71
93
  def real_project_name
72
94
  @name == '.' ? ::File.basename(Dir.getwd) : @name
73
95
  end
74
96
 
97
+ # @api private
75
98
  def project_name
76
99
  ApplicationName.new(real_project_name)
77
100
  end
78
101
 
102
+ # @api private
79
103
  def project_directory
80
104
  @name == '.' ? '.' : project_name
81
105
  end
82
106
 
107
+ # @api private
83
108
  def target
84
109
  Pathname.new('.')
85
110
  end
86
111
 
112
+ # @api private
87
113
  def init_git
88
114
  return if git_dir_present?
89
115
 
90
116
  generator.run("git init #{Shellwords.escape(target)}", capture: true)
91
117
  end
92
118
 
119
+ # @api private
93
120
  def git_dir_present?
94
121
  File.directory?(target.join('.git'))
95
122
  end
96
123
 
124
+ # @api private
97
125
  def hanami_version
98
126
  Hanami::Version.gem_requirement
99
127
  end
100
128
 
129
+ # @api private
101
130
  def hanami_head?
102
131
  options.fetch(:hanami_head, false)
103
132
  end
104
133
 
134
+ # @api private
105
135
  def code_reloading?
106
136
  !Hanami::Utils.jruby?
107
137
  end
108
138
 
139
+ # @api private
109
140
  def architecture
110
141
  options.fetch(:architecture, DEFAULT_ARCHITECTURE)
111
142
  end
112
143
 
144
+ # @api private
113
145
  def assert_name!
114
146
  if argument_blank?(@name) || @name.include?(File::SEPARATOR)
115
147
  raise ArgumentError.new("APPLICATION_NAME is required and must not contain #{File::SEPARATOR}.")
116
148
  end
117
149
  end
118
150
 
151
+ # @api private
119
152
  def assert_architecture!
120
153
  if !['app', 'container'].include?(architecture)
121
154
  raise ArgumentError.new("Architecture must be one of 'app', 'container' but was '#{architecture}'")
122
155
  end
123
156
  end
124
157
 
158
+ # @api private
125
159
  def application_base_url
126
160
  options[:application_base_url] || DEFAULT_APPLICATION_BASE_URL
127
161
  end
128
162
 
163
+ # @api private
129
164
  def assert_options!
130
165
  if options.nil?
131
166
  raise ArgumentError.new('options must not be nil')