hanami 0.0.0 → 0.7.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 (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