hanami 0.0.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +214 -0
  3. data/FEATURES.md +156 -0
  4. data/LICENSE.md +22 -0
  5. data/README.md +80 -15
  6. data/bin/hanami +5 -0
  7. data/hanami.gemspec +27 -12
  8. data/lib/hanami.rb +78 -2
  9. data/lib/hanami/action/csrf_protection.rb +167 -0
  10. data/lib/hanami/action/routing_helpers.rb +40 -0
  11. data/lib/hanami/application.rb +244 -0
  12. data/lib/hanami/application_name.rb +101 -0
  13. data/lib/hanami/cli.rb +119 -0
  14. data/lib/hanami/cli_sub_commands/assets.rb +29 -0
  15. data/lib/hanami/cli_sub_commands/db.rb +124 -0
  16. data/lib/hanami/cli_sub_commands/destroy.rb +102 -0
  17. data/lib/hanami/cli_sub_commands/generate.rb +127 -0
  18. data/lib/hanami/commands/assets/precompile.rb +35 -0
  19. data/lib/hanami/commands/console.rb +90 -0
  20. data/lib/hanami/commands/db/abstract.rb +19 -0
  21. data/lib/hanami/commands/db/apply.rb +14 -0
  22. data/lib/hanami/commands/db/console.rb +50 -0
  23. data/lib/hanami/commands/db/create.rb +14 -0
  24. data/lib/hanami/commands/db/drop.rb +14 -0
  25. data/lib/hanami/commands/db/migrate.rb +19 -0
  26. data/lib/hanami/commands/db/prepare.rb +14 -0
  27. data/lib/hanami/commands/db/version.rb +14 -0
  28. data/lib/hanami/commands/generate/abstract.rb +63 -0
  29. data/lib/hanami/commands/generate/action.rb +262 -0
  30. data/lib/hanami/commands/generate/app.rb +116 -0
  31. data/lib/hanami/commands/generate/mailer.rb +118 -0
  32. data/lib/hanami/commands/generate/migration.rb +63 -0
  33. data/lib/hanami/commands/generate/model.rb +96 -0
  34. data/lib/hanami/commands/new/abstract.rb +128 -0
  35. data/lib/hanami/commands/new/app.rb +116 -0
  36. data/lib/hanami/commands/new/container.rb +102 -0
  37. data/lib/hanami/commands/routes.rb +41 -0
  38. data/lib/hanami/commands/server.rb +79 -0
  39. data/lib/hanami/config/configure.rb +17 -0
  40. data/lib/hanami/config/cookies.rb +68 -0
  41. data/lib/hanami/config/framework_configuration.rb +42 -0
  42. data/lib/hanami/config/load_paths.rb +27 -0
  43. data/lib/hanami/config/mapper.rb +36 -0
  44. data/lib/hanami/config/mapping.rb +12 -0
  45. data/lib/hanami/config/routes.rb +16 -0
  46. data/lib/hanami/config/security.rb +58 -0
  47. data/lib/hanami/config/sessions.rb +97 -0
  48. data/lib/hanami/configuration.rb +1728 -0
  49. data/lib/hanami/container.rb +59 -0
  50. data/lib/hanami/environment.rb +485 -0
  51. data/lib/hanami/frameworks.rb +14 -0
  52. data/lib/hanami/generators/action/action.rb.tt +8 -0
  53. data/lib/hanami/generators/action/action_spec.minitest.tt +12 -0
  54. data/lib/hanami/generators/action/action_spec.rspec.tt +11 -0
  55. data/lib/hanami/generators/action/action_without_view.rb.tt +9 -0
  56. data/lib/hanami/generators/action/template.tt +0 -0
  57. data/lib/hanami/generators/action/view.rb.tt +5 -0
  58. data/lib/hanami/generators/action/view_spec.minitest.tt +13 -0
  59. data/lib/hanami/generators/action/view_spec.rspec.tt +12 -0
  60. data/lib/hanami/generators/app/.gitkeep.tt +1 -0
  61. data/lib/hanami/generators/app/application.rb.tt +273 -0
  62. data/lib/hanami/generators/app/config/initializers/.gitkeep +0 -0
  63. data/lib/hanami/generators/app/config/routes.rb.tt +2 -0
  64. data/lib/hanami/generators/app/favicon.ico +0 -0
  65. data/lib/hanami/generators/app/templates/application.html.erb.tt +10 -0
  66. data/lib/hanami/generators/app/views/application_layout.rb.tt +7 -0
  67. data/lib/hanami/generators/application/app/.env.development.tt +4 -0
  68. data/lib/hanami/generators/application/app/.env.test.tt +4 -0
  69. data/lib/hanami/generators/application/app/.env.tt +1 -0
  70. data/lib/hanami/generators/application/app/.gitignore +0 -0
  71. data/lib/hanami/generators/application/app/.gitkeep +1 -0
  72. data/lib/hanami/generators/application/app/Gemfile.tt +37 -0
  73. data/lib/hanami/generators/application/app/Rakefile.minitest.tt +11 -0
  74. data/lib/hanami/generators/application/app/Rakefile.rspec.tt +6 -0
  75. data/lib/hanami/generators/application/app/apps/.gitkeep.tt +1 -0
  76. data/lib/hanami/generators/application/app/capybara.rb.rspec.tt +8 -0
  77. data/lib/hanami/generators/application/app/config.ru.tt +3 -0
  78. data/lib/hanami/generators/application/app/config/application.rb.tt +270 -0
  79. data/lib/hanami/generators/application/app/config/environment.rb.tt +5 -0
  80. data/lib/hanami/generators/application/app/config/initializers/.gitkeep +0 -0
  81. data/lib/hanami/generators/application/app/config/routes.rb.tt +2 -0
  82. data/lib/hanami/generators/application/app/db/.gitkeep +1 -0
  83. data/lib/hanami/generators/application/app/favicon.ico +0 -0
  84. data/lib/hanami/generators/application/app/features_helper.rb.minitest.tt +11 -0
  85. data/lib/hanami/generators/application/app/features_helper.rb.rspec.tt +12 -0
  86. data/lib/hanami/generators/application/app/gitignore.tt +2 -0
  87. data/lib/hanami/generators/application/app/gitignore_with_db.tt +4 -0
  88. data/lib/hanami/generators/application/app/hanamirc.tt +3 -0
  89. data/lib/hanami/generators/application/app/lib/app_name.rb.tt +59 -0
  90. data/lib/hanami/generators/application/app/lib/chirp/entities/.gitkeep +1 -0
  91. data/lib/hanami/generators/application/app/lib/chirp/repositories/.gitkeep +1 -0
  92. data/lib/hanami/generators/application/app/lib/config/mapping.rb.tt +7 -0
  93. data/lib/hanami/generators/application/app/rspec.rspec.tt +2 -0
  94. data/lib/hanami/generators/application/app/schema.sql.tt +0 -0
  95. data/lib/hanami/generators/application/app/spec_helper.rb.minitest.tt +7 -0
  96. data/lib/hanami/generators/application/app/spec_helper.rb.rspec.tt +104 -0
  97. data/lib/hanami/generators/application/app/templates/application.html.erb.tt +10 -0
  98. data/lib/hanami/generators/application/app/views/application_layout.rb.tt +7 -0
  99. data/lib/hanami/generators/application/container/.env.development.tt +3 -0
  100. data/lib/hanami/generators/application/container/.env.test.tt +3 -0
  101. data/lib/hanami/generators/application/container/.env.tt +1 -0
  102. data/lib/hanami/generators/application/container/.gitignore +0 -0
  103. data/lib/hanami/generators/application/container/.gitkeep +1 -0
  104. data/lib/hanami/generators/application/container/Gemfile.tt +36 -0
  105. data/lib/hanami/generators/application/container/Rakefile.minitest.tt +11 -0
  106. data/lib/hanami/generators/application/container/Rakefile.rspec.tt +6 -0
  107. data/lib/hanami/generators/application/container/capybara.rb.rspec.tt +8 -0
  108. data/lib/hanami/generators/application/container/config.ru.tt +3 -0
  109. data/lib/hanami/generators/application/container/config/environment.rb.tt +7 -0
  110. data/lib/hanami/generators/application/container/config/initializers/.gitkeep +0 -0
  111. data/lib/hanami/generators/application/container/db/.gitkeep +1 -0
  112. data/lib/hanami/generators/application/container/features_helper.rb.minitest.tt +11 -0
  113. data/lib/hanami/generators/application/container/features_helper.rb.rspec.tt +12 -0
  114. data/lib/hanami/generators/application/container/gitignore.tt +2 -0
  115. data/lib/hanami/generators/application/container/gitignore_with_db.tt +4 -0
  116. data/lib/hanami/generators/application/container/hanamirc.tt +3 -0
  117. data/lib/hanami/generators/application/container/lib/app_name.rb.tt +60 -0
  118. data/lib/hanami/generators/application/container/lib/chirp/entities/.gitkeep +1 -0
  119. data/lib/hanami/generators/application/container/lib/chirp/mailers/.gitkeep +0 -0
  120. data/lib/hanami/generators/application/container/lib/chirp/mailers/templates/.gitkeep +0 -0
  121. data/lib/hanami/generators/application/container/lib/chirp/repositories/.gitkeep +1 -0
  122. data/lib/hanami/generators/application/container/lib/config/mapping.rb.tt +7 -0
  123. data/lib/hanami/generators/application/container/rspec.rspec.tt +2 -0
  124. data/lib/hanami/generators/application/container/schema.sql.tt +0 -0
  125. data/lib/hanami/generators/application/container/spec_helper.rb.minitest.tt +7 -0
  126. data/lib/hanami/generators/application/container/spec_helper.rb.rspec.tt +104 -0
  127. data/lib/hanami/generators/database_config.rb +99 -0
  128. data/lib/hanami/generators/generatable.rb +51 -0
  129. data/lib/hanami/generators/generator.rb +35 -0
  130. data/lib/hanami/generators/mailer/mailer.rb.tt +7 -0
  131. data/lib/hanami/generators/mailer/mailer_spec.rb.tt +7 -0
  132. data/lib/hanami/generators/mailer/template.html.tt +0 -0
  133. data/lib/hanami/generators/mailer/template.txt.tt +0 -0
  134. data/lib/hanami/generators/migration/migration.rb.tt +4 -0
  135. data/lib/hanami/generators/model/entity.rb.tt +3 -0
  136. data/lib/hanami/generators/model/entity_spec.minitest.tt +5 -0
  137. data/lib/hanami/generators/model/entity_spec.rspec.tt +3 -0
  138. data/lib/hanami/generators/model/repository.rb.tt +3 -0
  139. data/lib/hanami/generators/model/repository_spec.minitest.tt +5 -0
  140. data/lib/hanami/generators/model/repository_spec.rspec.tt +3 -0
  141. data/lib/hanami/generators/test_framework.rb +42 -0
  142. data/lib/hanami/hanamirc.rb +152 -0
  143. data/lib/hanami/loader.rb +258 -0
  144. data/lib/hanami/mailer/glue.rb +68 -0
  145. data/lib/hanami/middleware.rb +143 -0
  146. data/lib/hanami/rake_helper.rb +68 -0
  147. data/lib/hanami/rake_tasks.rb +2 -0
  148. data/lib/hanami/rendering_policy.rb +77 -0
  149. data/lib/hanami/repositories/car_repository.rb +3 -0
  150. data/lib/hanami/repositories/name_repository.rb +3 -0
  151. data/lib/hanami/root.rb +7 -0
  152. data/lib/hanami/routes.rb +151 -0
  153. data/lib/hanami/routing/default.rb +25 -0
  154. data/lib/hanami/setup.rb +3 -0
  155. data/lib/hanami/static.rb +77 -0
  156. data/lib/hanami/templates/default.html.erb +9 -0
  157. data/lib/hanami/templates/welcome.html.erb +52 -0
  158. data/lib/hanami/version.rb +4 -1
  159. data/lib/hanami/views/default.rb +34 -0
  160. data/lib/hanami/views/default_template_finder.rb +20 -0
  161. data/lib/hanami/views/null_view.rb +17 -0
  162. data/lib/hanami/welcome.rb +40 -0
  163. metadata +357 -16
  164. data/.gitignore +0 -9
  165. data/Gemfile +0 -4
  166. data/Rakefile +0 -2
  167. data/bin/console +0 -14
  168. data/bin/setup +0 -8
@@ -0,0 +1,99 @@
1
+ require 'shellwords'
2
+
3
+ module Hanami
4
+ module Generators
5
+ class DatabaseConfig
6
+
7
+ SUPPORTED_ENGINES = {
8
+ 'mysql' => { type: :sql, mri: 'mysql2', jruby: 'jdbc-mysql' },
9
+ 'mysql2' => { type: :sql, mri: 'mysql2', jruby: 'jdbc-mysql' },
10
+ 'postgresql' => { type: :sql, mri: 'pg', jruby: 'jdbc-postgres' },
11
+ 'postgres' => { type: :sql, mri: 'pg', jruby: 'jdbc-postgres' },
12
+ 'sqlite' => { type: :sql, mri: 'sqlite3', jruby: 'jdbc-sqlite3' },
13
+ 'sqlite3' => { type: :sql, mri: 'sqlite3', jruby: 'jdbc-sqlite3' },
14
+ 'filesystem' => { type: :file_system, mri: nil, jruby: nil },
15
+ 'memory' => { type: :memory, mri: nil, jruby: nil }
16
+ }.freeze
17
+
18
+ DEFAULT_ENGINE = 'filesystem'.freeze
19
+
20
+ attr_reader :engine, :name
21
+
22
+ def initialize(engine, name)
23
+ @engine = engine
24
+ @name = name
25
+
26
+ SUPPORTED_ENGINES.key?(engine.to_s) or fail "\"#{ engine }\" is not a valid database type"
27
+ end
28
+
29
+ def to_hash
30
+ {
31
+ gem: gem,
32
+ uri: uri,
33
+ type: type
34
+ }
35
+ end
36
+
37
+ def type
38
+ SUPPORTED_ENGINES[engine][:type]
39
+ end
40
+
41
+ def sql?
42
+ type == :sql
43
+ end
44
+
45
+ def filesystem?
46
+ type == :file_system
47
+ end
48
+
49
+ private
50
+
51
+ def platform
52
+ Hanami::Utils.jruby? ? :jruby : :mri
53
+ end
54
+
55
+ def platform_prefix
56
+ 'jdbc:'.freeze if Hanami::Utils.jruby?
57
+ end
58
+
59
+ def uri
60
+ {
61
+ development: environment_uri(:development),
62
+ test: environment_uri(:test)
63
+ }
64
+ end
65
+
66
+ def gem
67
+ SUPPORTED_ENGINES[engine][platform]
68
+ end
69
+
70
+ def base_uri
71
+ case engine
72
+ when 'mysql', 'mysql2'
73
+ if Hanami::Utils.jruby?
74
+ "mysql://localhost/#{ name }"
75
+ else
76
+ "mysql2://localhost/#{ name }"
77
+ end
78
+ when 'postgresql', 'postgres'
79
+ "postgres://localhost/#{ name }"
80
+ when 'sqlite', 'sqlite3'
81
+ "sqlite://db/#{ Shellwords.escape(name) }"
82
+ when 'memory'
83
+ "memory://localhost/#{ name }"
84
+ when 'filesystem'
85
+ "file:///db/#{ Shellwords.escape(name) }"
86
+ end
87
+ end
88
+
89
+ def environment_uri(environment)
90
+ case engine
91
+ when 'sqlite', 'sqlite3'
92
+ "#{ platform_prefix }#{ base_uri }_#{ environment }.sqlite"
93
+ else
94
+ "#{ platform_prefix if sql? }#{ base_uri }_#{ environment }"
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,51 @@
1
+ require 'hanami/generators/generator'
2
+
3
+ module Hanami
4
+ module Generators
5
+ module Generatable
6
+
7
+ def start
8
+ map_templates
9
+ process_templates
10
+ end
11
+
12
+ def destroy
13
+ generator.behavior = :revoke
14
+ self
15
+ end
16
+
17
+ def generator
18
+ @generator ||= Hanami::Generators::Generator.new(template_source_path, target_path)
19
+ end
20
+
21
+ def map_templates
22
+ raise NotImplementedError, "must implement the map_templates method"
23
+ end
24
+
25
+ def add_mapping(source, target)
26
+ generator.add_mapping(source, target)
27
+ end
28
+
29
+ def process_templates
30
+ generator.process_templates(template_options)
31
+ post_process_templates
32
+ end
33
+
34
+ def post_process_templates
35
+ nil
36
+ end
37
+
38
+ def template_options
39
+ {}
40
+ end
41
+
42
+ def template_source_path
43
+ raise NotImplementedError, "must implement the template_source_path method"
44
+ end
45
+
46
+ def target_path
47
+ raise NotImplementedError, "must implement the target_path method"
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,35 @@
1
+ require 'thor'
2
+ require 'forwardable'
3
+
4
+ module Hanami
5
+ module Generators
6
+ class Generator
7
+
8
+ extend Forwardable
9
+
10
+ def_delegators :@processor, :run, :behavior=, :inject_into_file, :append_to_file, :prepend_to_file
11
+
12
+ class Processor < Thor
13
+ include Thor::Actions
14
+ end
15
+
16
+ def initialize(template_source_path, target_path)
17
+ @template_source_path = template_source_path
18
+ @target_path = target_path
19
+ @template_mappings = []
20
+ @processor = Processor.new
21
+ @processor.class.source_root(@template_source_path)
22
+ end
23
+
24
+ def add_mapping(source, target)
25
+ @template_mappings << [source, target]
26
+ end
27
+
28
+ def process_templates(options = {})
29
+ @template_mappings.each do |src, dst|
30
+ @processor.template(@template_source_path.join(src), @target_path.join(dst), options)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ class Mailers::<%= config[:mailer] %>
2
+ include Hanami::Mailer
3
+
4
+ from <%= config[:from] %>
5
+ to <%= config[:to] %>
6
+ subject <%= config[:subject] %>
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mailers::<%= config[:mailer] %> do
4
+ it 'delivers email' do
5
+ mail = Mailers::<%= config[:mailer] %>.deliver
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ Hanami::Model.migration do
2
+ change do
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ class <%= config[:model_name] %>
2
+ include Hanami::Entity
3
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= config[:model_name] %> do
4
+ # place your tests here
5
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.describe <%= config[:model_name] %> do
2
+ # place your tests here
3
+ end
@@ -0,0 +1,3 @@
1
+ class <%= config[:model_name] %>Repository
2
+ include Hanami::Repository
3
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= config[:model_name] %>Repository do
4
+ # place your tests here
5
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.describe <%= config[:model_name] %>Repository do
2
+ # place your tests here
3
+ end
@@ -0,0 +1,42 @@
1
+ require 'hanami/hanamirc'
2
+ module Hanami
3
+ module Generators
4
+ class TestFramework
5
+ RSPEC = 'rspec'.freeze
6
+ MINITEST = 'minitest'.freeze
7
+ VALID_FRAMEWORKS = [RSPEC, MINITEST].freeze
8
+
9
+ attr_reader :framework
10
+
11
+ def initialize(hanamirc, framework)
12
+ @framework = (framework || hanamirc.options.fetch(:test))
13
+ assert_framework!
14
+ end
15
+
16
+ def rspec?
17
+ framework == RSPEC
18
+ end
19
+
20
+ def minitest?
21
+ framework == MINITEST
22
+ end
23
+
24
+ private
25
+
26
+ def assert_framework!
27
+ if !supported_framework?
28
+ raise ArgumentError.new("Unknown test framework '#{ framework}'. Please use one of #{ valid_test_frameworks.join(', ')}")
29
+ end
30
+ end
31
+
32
+ def valid_test_frameworks
33
+ VALID_FRAMEWORKS.map { |name| "'#{ name }'"}
34
+ end
35
+
36
+ def supported_framework?
37
+ VALID_FRAMEWORKS.include?(framework)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,152 @@
1
+ require 'pathname'
2
+ require 'dotenv/parser'
3
+ require 'hanami/utils/hash'
4
+
5
+ module Hanami
6
+ # Read the .hanamirc file in the root of the application
7
+ #
8
+ # @since 0.3.0
9
+ # @api private
10
+ class Hanamirc
11
+ # Hanamirc name file
12
+ #
13
+ # @since 0.3.0
14
+ # @api private
15
+ #
16
+ # @see Hanami::Hanamirc#path_file
17
+ FILE_NAME = '.hanamirc'.freeze
18
+
19
+ # Architecture default value
20
+ #
21
+ # @since 0.3.0
22
+ # @api private
23
+ #
24
+ # @see Hanami::Hanamirc#options
25
+ DEFAULT_ARCHITECTURE = 'container'.freeze
26
+
27
+ # Application architecture value
28
+ #
29
+ # @since 0.6.0
30
+ # @api private
31
+ APP_ARCHITECTURE = 'app'.freeze
32
+
33
+ # Architecture key for writing the hanamirc file
34
+ #
35
+ # @since 0.3.0
36
+ # @api private
37
+ #
38
+ # @see Hanami::Hanamirc::DEFAULT_OPTIONS
39
+ ARCHITECTURE_KEY = 'architecture'.freeze
40
+
41
+ # Test suite default value
42
+ #
43
+ # @since 0.3.0
44
+ # @api private
45
+ #
46
+ # @see Hanami::Hanamirc::DEFAULT_OPTIONS
47
+ DEFAULT_TEST_SUITE = 'minitest'.freeze
48
+
49
+ # Test suite key for writing the hanamirc file
50
+ #
51
+ # @since 0.3.0
52
+ # @api private
53
+ #
54
+ # @see Hanami::Hanamirc::DEFAULT_OPTIONS
55
+ TEST_KEY = 'test'.freeze
56
+
57
+ # Template default value
58
+ #
59
+ # @since 0.3.0
60
+ # @api private
61
+ #
62
+ # @see Hanami::Hanamirc::DEFAULT_OPTIONS
63
+ DEFAULT_TEMPLATE = 'erb'.freeze
64
+
65
+ # Template key for writing the hanamirc file
66
+ #
67
+ # @since 0.3.0
68
+ # @api private
69
+ #
70
+ # @see Hanami::Hanamirc::DEFAULT_OPTIONS
71
+ TEMPLATE_KEY = 'template'.freeze
72
+
73
+ # Default values for writing the hanamirc file
74
+ #
75
+ # @since 0.5.1
76
+ # @api private
77
+ #
78
+ # @see Hanami::Hanamirc#options
79
+ DEFAULT_OPTIONS = Utils::Hash.new({
80
+ ARCHITECTURE_KEY => DEFAULT_ARCHITECTURE,
81
+ TEST_KEY => DEFAULT_TEST_SUITE,
82
+ TEMPLATE_KEY => DEFAULT_TEMPLATE
83
+ }).symbolize!.freeze
84
+
85
+ # Initialize Hanamirc class with application's root and environment options.
86
+ #
87
+ # @param root [Pathname] Application's root
88
+ #
89
+ # @see Hanami::Environment#initialize
90
+ def initialize(root)
91
+ @root = root
92
+ end
93
+
94
+ # Read hanamirc file (if exists) and parse it's values or return default.
95
+ #
96
+ # @return [Hanami::Utils::Hash] parsed values
97
+ #
98
+ # @example Default values if file doesn't exist
99
+ # Hanami::Hanamirc.new(Pathname.new(Dir.pwd)).options
100
+ # # => { architecture: 'container', test: 'minitest', template: 'erb' }
101
+ #
102
+ # @example Custom values if file doesn't exist
103
+ # options = { architect: 'application', test: 'rspec', template: 'slim' }
104
+ # Hanami::Hanamirc.new(Pathname.new(Dir.pwd), options).options
105
+ # # => { architecture: 'application', test: 'rspec', template: 'slim' }
106
+ def options
107
+ @options ||= symbolize(DEFAULT_OPTIONS.merge(file_options))
108
+ end
109
+
110
+ # Check if hanamirc file exists
111
+ #
112
+ # @since 0.3.0
113
+ # @api private
114
+ #
115
+ # @return [Boolean] hanamirc file's path existing
116
+ def exists?
117
+ path_file.exist?
118
+ end
119
+
120
+ private
121
+
122
+ def symbolize(hash)
123
+ Utils::Hash.new(hash).symbolize!
124
+ end
125
+
126
+ def file_options
127
+ symbolize(exists? ? Dotenv::Parser.call(content) : {})
128
+ end
129
+
130
+ # Return the hanamirc file's path
131
+ #
132
+ # @since 0.3.0
133
+ # @api private
134
+ #
135
+ # @return [Pathname] hanamirc file's path
136
+ #
137
+ # @see Hanami::Hanamirc::FILE_NAME
138
+ def path_file
139
+ @root.join FILE_NAME
140
+ end
141
+
142
+ # Return the content of hanamirc file
143
+ #
144
+ # @since 0.3.0
145
+ # @api private
146
+ #
147
+ # @return [String] content of hanamirc file
148
+ def content
149
+ path_file.read
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,258 @@
1
+ require 'hanami/utils/class'
2
+ require 'hanami/utils/kernel'
3
+ require 'hanami/utils/string'
4
+ require 'hanami/routes'
5
+ require 'hanami/routing/default'
6
+ require 'hanami/action/session'
7
+ require 'hanami/config/security'
8
+ require 'hanami/action/routing_helpers'
9
+
10
+ module Hanami
11
+ # Load an application
12
+ #
13
+ # @since 0.1.0
14
+ # @api private
15
+ class Loader
16
+
17
+ STRICT_TRANSPORT_SECURITY_HEADER = 'Strict-Transport-Security'.freeze
18
+ STRICT_TRANSPORT_SECURITY_DEFAULT_VALUE = 'max-age=31536000'.freeze
19
+
20
+ def initialize(application)
21
+ @application = application
22
+ @configuration = @application.configuration
23
+
24
+ @mutex = Mutex.new
25
+ end
26
+
27
+ def load!
28
+ @mutex.synchronize do
29
+ load_configuration!
30
+ configure_frameworks!
31
+ load_configuration_load_paths!
32
+ load_rack!
33
+ load_frameworks!
34
+ load_initializers!
35
+ end
36
+ end
37
+
38
+ private
39
+ attr_reader :application, :configuration
40
+
41
+ def load_configuration!
42
+ configuration.load!(application_module)
43
+ end
44
+
45
+ def configure_frameworks!
46
+ _configure_model_framework! if defined?(Hanami::Model)
47
+ _configure_controller_framework!
48
+ _configure_view_framework!
49
+ _configure_assets_framework!
50
+ _configure_logger!
51
+ end
52
+
53
+ def _configure_controller_framework!
54
+ config = configuration
55
+ unless namespace.const_defined?('Controller')
56
+ controller = Hanami::Controller.duplicate(namespace) do
57
+ handle_exceptions config.handle_exceptions
58
+ default_request_format config.default_request_format
59
+ default_response_format config.default_response_format
60
+ default_headers({
61
+ Hanami::Config::Security::X_FRAME_OPTIONS_HEADER => config.security.x_frame_options,
62
+ Hanami::Config::Security::CONTENT_SECURITY_POLICY_HEADER => config.security.content_security_policy
63
+ })
64
+ default_headers.merge!(STRICT_TRANSPORT_SECURITY_HEADER => STRICT_TRANSPORT_SECURITY_DEFAULT_VALUE) if config.force_ssl
65
+
66
+ if config.cookies.enabled?
67
+ require 'hanami/action/cookies'
68
+ prepare { include Hanami::Action::Cookies }
69
+ cookies config.cookies.default_options
70
+ end
71
+
72
+ if config.sessions.enabled?
73
+ prepare do
74
+ include Hanami::Action::Session
75
+ include Hanami::Action::CSRFProtection
76
+ end
77
+ end
78
+
79
+ prepare { include Hanami::Action::RoutingHelpers }
80
+
81
+ config.controller.__apply(self)
82
+ end
83
+
84
+ namespace.const_set('Controller', controller)
85
+ end
86
+ end
87
+
88
+ def _configure_view_framework!
89
+ config = configuration
90
+ unless namespace.const_defined?('View')
91
+ view = Hanami::View.duplicate(namespace) do
92
+ root config.templates
93
+ layout config.layout
94
+
95
+ config.view.__apply(self)
96
+ end
97
+
98
+ namespace.const_set('View', view)
99
+ end
100
+ end
101
+
102
+ def _configure_assets_framework!
103
+ config = configuration
104
+
105
+ unless application_module.const_defined?('Assets')
106
+ assets = Hanami::Assets.duplicate(namespace) do
107
+ root config.root
108
+
109
+ scheme config.scheme
110
+ host config.host
111
+ port config.port
112
+
113
+ public_directory Hanami.public_directory
114
+ prefix Utils::PathPrefix.new('/assets').join(config.path_prefix)
115
+
116
+ manifest Hanami.public_directory.join('assets.json')
117
+ compile true
118
+
119
+ config.assets.__apply(self)
120
+ end
121
+
122
+ assets.configure do
123
+ cdn host != config.host
124
+ end
125
+
126
+ application_module.const_set('Assets', assets)
127
+ end
128
+ end
129
+
130
+ def _configure_model_framework!
131
+ config = configuration
132
+ if _hanami_model_loaded? && !application_module.const_defined?('Model')
133
+ model = Hanami::Model.duplicate(application_module) do
134
+ adapter(config.adapter) if config.adapter
135
+ mapping(&config.mapping) if config.mapping
136
+
137
+ config.model.__apply(self)
138
+ end
139
+
140
+ application_module.const_set('Model', model)
141
+ end
142
+ end
143
+
144
+ def _configure_logger!
145
+ unless application_module.const_defined?('Logger', false)
146
+ if configuration.logger.nil?
147
+ configuration.logger Hanami::Logger.new(application_module.to_s)
148
+ end
149
+ application_module.const_set('Logger', configuration.logger)
150
+ end
151
+ end
152
+
153
+ def load_frameworks!
154
+ _load_view_framework!
155
+ _load_assets_framework!
156
+ _load_model_framework!
157
+ end
158
+
159
+ def _load_view_framework!
160
+ namespace.module_eval %{
161
+ #{ namespace }::View.load!
162
+ }
163
+ end
164
+
165
+ def _load_assets_framework!
166
+ application_module.module_eval %{
167
+ #{ application_module }::Assets.load!
168
+ }
169
+ end
170
+
171
+ def _load_model_framework!
172
+ return unless _load_model_framework?
173
+
174
+ application_module.module_eval %{
175
+ #{ application_module }::Model.load!
176
+ }
177
+ end
178
+
179
+ def _load_model_framework?
180
+ if _hanami_model_loaded? && application_module.const_defined?('Model')
181
+ model = application_module.const_get('Model')
182
+ model.configuration.adapter
183
+ end
184
+ end
185
+
186
+ def _hanami_model_loaded?
187
+ defined?(Hanami::Model)
188
+ end
189
+
190
+ def _hanami_mailer_loaded?
191
+ defined?(Hanami::Mailer)
192
+ end
193
+
194
+ def load_configuration_load_paths!
195
+ configuration.load_paths.load!(configuration.root)
196
+ end
197
+
198
+ def load_rack!
199
+ _assign_routes_to_application_module!
200
+
201
+ return if application.is_a?(Class)
202
+ _assign_rendering_policy!
203
+ _assign_rack_routes!
204
+ _load_rack_middleware!
205
+ end
206
+
207
+ def _assign_rendering_policy!
208
+ application.renderer = RenderingPolicy.new(configuration)
209
+ end
210
+
211
+ def _assign_rack_routes!
212
+ application.routes = application_routes
213
+ end
214
+
215
+ def _load_rack_middleware!
216
+ configuration.middleware.load!(application, namespace)
217
+ end
218
+
219
+ def _assign_routes_to_application_module!
220
+ unless application_module.const_defined?('Routes')
221
+ routes = Hanami::Routes.new(application_routes)
222
+ application_module.const_set('Routes', routes)
223
+ end
224
+ end
225
+
226
+ def application_module
227
+ @application_module ||= Utils::Class.load!(
228
+ Utils::String.new(application.name).namespace
229
+ )
230
+ end
231
+
232
+ def application_routes
233
+ resolver = Hanami::Routing::EndpointResolver.new(pattern: configuration.controller_pattern, namespace: namespace)
234
+ default_app = Hanami::Routing::Default.new
235
+ Hanami::Router.new(
236
+ parsers: configuration.body_parsers,
237
+ resolver: resolver,
238
+ default_app: default_app,
239
+ scheme: configuration.scheme,
240
+ host: configuration.host,
241
+ port: configuration.port,
242
+ prefix: configuration.path_prefix,
243
+ force_ssl: configuration.force_ssl,
244
+ &configuration.routes
245
+ )
246
+ end
247
+
248
+ def namespace
249
+ configuration.namespace || application_module
250
+ end
251
+
252
+ def load_initializers!
253
+ Dir["#{configuration.root}/config/initializers/**/*.rb"].each do |file|
254
+ require file
255
+ end
256
+ end
257
+ end
258
+ end