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,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler'
4
+ require 'hanami/cli'
5
+ Hanami::Cli.start
@@ -4,20 +4,35 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'hanami/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "hanami"
7
+ spec.name = 'hanami'
8
8
  spec.version = Hanami::VERSION
9
- spec.authors = ["Luca Guidi"]
10
- spec.email = ["me@lucaguidi.com"]
11
-
12
- spec.summary = %q{The web, with simplicity}
9
+ spec.authors = ['Luca Guidi', 'Trung Lê', 'Alfonso Uceda Pompa']
10
+ spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com', 'uceda73@gmail.com']
11
+ spec.summary = %q{The web, with simplicity.}
13
12
  spec.description = %q{Hanami is a web framework for Ruby}
14
- spec.homepage = "http://hanamirb.org"
13
+ spec.homepage = 'http://hanamirb.org'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z -- lib/* bin/* LICENSE.md README.md CHANGELOG.md FEATURES.md hanami.gemspec`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test)/})
19
+ spec.require_paths = ['lib']
20
+ spec.required_ruby_version = '>= 2.0.0'
15
21
 
16
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.bindir = "exe"
18
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
- spec.require_paths = ["lib"]
22
+ spec.add_dependency 'hanami-utils', '~> 0.7'
23
+ spec.add_dependency 'hanami-router', '~> 0.6'
24
+ spec.add_dependency 'hanami-controller', '~> 0.6'
25
+ spec.add_dependency 'hanami-view', '~> 0.6'
26
+ spec.add_dependency 'hanami-helpers', '~> 0.3'
27
+ spec.add_dependency 'hanami-mailer', '~> 0.2'
28
+ spec.add_dependency 'hanami-assets', '~> 0.2'
29
+ spec.add_dependency 'shotgun', '~> 0.9'
30
+ spec.add_dependency 'dotenv', '~> 2.0'
31
+ spec.add_dependency 'thor', '~> 0.19'
32
+ spec.add_dependency 'bundler', '~> 1.6'
20
33
 
21
- spec.add_development_dependency "bundler", "~> 1.11"
22
- spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency 'minispec-metadata', '~> 3.2.1'
35
+ spec.add_development_dependency 'minitest', '~> 5'
36
+ spec.add_development_dependency 'rack-test', '~> 0.6'
37
+ spec.add_development_dependency 'rake', '~> 10'
23
38
  end
@@ -1,5 +1,81 @@
1
- require "hanami/version"
1
+ require 'hanami/version'
2
+ require 'hanami/application'
3
+ require 'hanami/container'
4
+ require 'hanami/environment'
2
5
 
6
+ # A complete web framework for Ruby
7
+ #
8
+ # @since 0.1.0
9
+ #
10
+ # @see http://hanamirb.org
3
11
  module Hanami
4
- # Your code goes here...
12
+ DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
13
+
14
+ # Return root of the project (top level directory).
15
+ #
16
+ # @return [Pathname] root path
17
+ #
18
+ # @since 0.3.2
19
+ #
20
+ # @example
21
+ # Hanami.root # => #<Pathname:/Users/luca/Code/bookshelf>
22
+ def self.root
23
+ environment.root
24
+ end
25
+
26
+ def self.public_directory
27
+ root.join(DEFAULT_PUBLIC_DIRECTORY)
28
+ end
29
+
30
+ # Return the current environment
31
+ #
32
+ # @return [String] the current environment
33
+ #
34
+ # @since 0.3.1
35
+ #
36
+ # @see Hanami::Environment#environment
37
+ #
38
+ # @example
39
+ # Hanami.env => "development"
40
+ def self.env
41
+ environment.environment
42
+ end
43
+
44
+ # Check to see if specified environment(s) matches the current environment.
45
+ #
46
+ # If multiple names are given, it returns true, if at least one of them
47
+ # matches the current environment.
48
+ #
49
+ # @return [TrueClass,FalseClass] the result of the check
50
+ #
51
+ # @since 0.3.1
52
+ #
53
+ # @see Hanami.env
54
+ #
55
+ # @example Single name
56
+ # puts ENV['HANAMI_ENV'] # => "development"
57
+ #
58
+ # Hanami.env?(:development) # => true
59
+ # Hanami.env?('development') # => true
60
+ #
61
+ # Hanami.env?(:production) # => false
62
+ #
63
+ # @example Multiple names
64
+ # puts ENV['HANAMI_ENV'] # => "development"
65
+ #
66
+ # Hanami.env?(:development, :test) # => true
67
+ # Hanami.env?(:production, :staging) # => false
68
+ def self.env?(*names)
69
+ environment.environment?(*names)
70
+ end
71
+
72
+ # Return environment
73
+ #
74
+ # @return [Hanami::Environment] environment
75
+ #
76
+ # @api private
77
+ # @since 0.3.2
78
+ def self.environment
79
+ Environment.new
80
+ end
5
81
  end
@@ -0,0 +1,167 @@
1
+ require 'securerandom'
2
+
3
+ module Hanami
4
+ module Action
5
+ # Invalid CSRF Token
6
+ #
7
+ # @since 0.4.0
8
+ class InvalidCSRFTokenError < ::StandardError
9
+ end
10
+
11
+ # CSRF Protection
12
+ #
13
+ # This security mechanism is enabled automatically if sessions are turned on.
14
+ #
15
+ # It stores a "challenge" token in session. For each "state changing request"
16
+ # (eg. <tt>POST</tt>, <tt>PATCH</tt> etc..), we should send a special param:
17
+ # <tt>_csrf_token</tt>.
18
+ #
19
+ # If the param matches with the challenge token, the flow can continue.
20
+ # Otherwise the application detects an attack attempt, it reset the session
21
+ # and <tt>Hanami::Action::InvalidCSRFTokenError</tt> is raised.
22
+ #
23
+ # We can specify a custom handling strategy, by overriding <tt>#handle_invalid_csrf_token</tt>.
24
+ #
25
+ # Form helper (<tt>#form_for</tt>) automatically sets a hidden field with the
26
+ # correct token. A special view method (<tt>#csrf_token</tt>) is available in
27
+ # case the form markup is manually crafted.
28
+ #
29
+ # We can disable this check on action basis, by overriding <tt>#verify_csrf_token?</tt>.
30
+ #
31
+ # @since 0.4.0
32
+ #
33
+ # @see https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29
34
+ # @see https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
35
+ #
36
+ # @example Custom Handling
37
+ # module Web::Controllers::Books
38
+ # class Create
39
+ # include Web::Action
40
+ #
41
+ # def call(params)
42
+ # # ...
43
+ # end
44
+ #
45
+ # private
46
+ #
47
+ # def handle_invalid_csrf_token
48
+ # Web::Logger.warn "CSRF attack: expected #{ session[:_csrf_token] }, was #{ params[:_csrf_token] }"
49
+ # # manual handling
50
+ # end
51
+ # end
52
+ # end
53
+ #
54
+ # @example Bypass Security Check
55
+ # module Web::Controllers::Books
56
+ # class Create
57
+ # include Web::Action
58
+ #
59
+ # def call(params)
60
+ # # ...
61
+ # end
62
+ #
63
+ # private
64
+ #
65
+ # def verify_csrf_token?
66
+ # false
67
+ # end
68
+ # end
69
+ # end
70
+ module CSRFProtection
71
+ # Session and params key for CSRF token.
72
+ #
73
+ # This key is shared with <tt>hanami-controller</tt> and <tt>hanami-helpers</tt>
74
+ #
75
+ # @since 0.4.0
76
+ # @api private
77
+ CSRF_TOKEN = :_csrf_token
78
+
79
+ # Idempotent HTTP methods
80
+ #
81
+ # By default, the check isn't performed if the request method is included
82
+ # in this list.
83
+ #
84
+ # @since 0.4.0
85
+ # @api private
86
+ IDEMPOTENT_HTTP_METHODS = Hash[
87
+ 'GET' => true,
88
+ 'HEAD' => true,
89
+ 'TRACE' => true,
90
+ 'OPTIONS' => true
91
+ ].freeze
92
+
93
+ # @since 0.4.0
94
+ # @api private
95
+ def self.included(action)
96
+ action.class_eval do
97
+ before :set_csrf_token, :verify_csrf_token
98
+ end unless Hanami.env?(:test)
99
+ end
100
+
101
+ private
102
+ # Set CSRF Token in session
103
+ #
104
+ # @since 0.4.0
105
+ # @api private
106
+ def set_csrf_token
107
+ session[CSRF_TOKEN] ||= generate_csrf_token
108
+ end
109
+
110
+ # Verify if CSRF token from params, matches the one stored in session.
111
+ # If not, it raises an error.
112
+ #
113
+ # Don't override this method.
114
+ #
115
+ # To bypass the security check, please override <tt>#verify_csrf_token?</tt>.
116
+ # For custom handling of an attack, please override <tt>#handle_invalid_csrf_token</tt>.
117
+ #
118
+ # @since 0.4.0
119
+ # @api private
120
+ def verify_csrf_token
121
+ handle_invalid_csrf_token if invalid_csrf_token?
122
+ end
123
+
124
+ # Verify if CSRF token from params, matches the one stored in session.
125
+ #
126
+ # Don't override this method.
127
+ #
128
+ # @since 0.4.0
129
+ # @api private
130
+ def invalid_csrf_token?
131
+ verify_csrf_token? &&
132
+ ! ::Rack::Utils.secure_compare(session[CSRF_TOKEN], params[CSRF_TOKEN])
133
+ end
134
+
135
+ # Generates a random CSRF Token
136
+ #
137
+ # @since 0.4.0
138
+ # @api private
139
+ def generate_csrf_token
140
+ SecureRandom.hex(32)
141
+ end
142
+
143
+ # Decide if perform the check or not.
144
+ #
145
+ # Override and return <tt>false</tt> if you want to bypass security check.
146
+ #
147
+ # @since 0.4.0
148
+ def verify_csrf_token?
149
+ !IDEMPOTENT_HTTP_METHODS[request_method]
150
+ end
151
+
152
+ # Handle CSRF attack.
153
+ #
154
+ # The default policy resets the session and raises an exception.
155
+ #
156
+ # Override this method, for custom handling.
157
+ #
158
+ # @raise [Hanami::Action::InvalidCSRFTokenError]
159
+ #
160
+ # @since 0.4.0
161
+ def handle_invalid_csrf_token
162
+ session.clear
163
+ raise InvalidCSRFTokenError.new
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,40 @@
1
+ require 'hanami/utils/string'
2
+
3
+ module Hanami
4
+ module Action
5
+ # Routing helper for full stack Hanami web applications.
6
+ #
7
+ # For a given application called <tt>Web::Application</tt>, at runtime
8
+ # Hanami creates a routes factory called <tt>Web::Routes</tt>.
9
+ #
10
+ # Included by default in every controller.
11
+ #
12
+ # @since 0.3.2
13
+ #
14
+ # @example Usage in controller
15
+ # require 'hanami'
16
+ #
17
+ # module Web::Controllers::Protected
18
+ # class Index
19
+ # include Web::Action
20
+ #
21
+ # def call(params)
22
+ # redirect_to routes.root_path
23
+ # end
24
+ # end
25
+ # end
26
+ module RoutingHelpers
27
+ def self.included(base)
28
+ factory = "#{ Utils::String.new(base).namespace }::Routes"
29
+
30
+ base.class_eval <<-END_EVAL, __FILE__, __LINE__
31
+ private
32
+
33
+ def routes
34
+ #{ factory }
35
+ end
36
+ END_EVAL
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,244 @@
1
+ require 'hanami/utils/class_attribute'
2
+ require 'hanami/frameworks'
3
+ require 'hanami/configuration'
4
+ require 'hanami/loader'
5
+ require 'hanami/logger'
6
+ require 'hanami/rendering_policy'
7
+ require 'hanami/middleware'
8
+
9
+ module Hanami
10
+ # A full stack Hanami application
11
+ #
12
+ # @since 0.1.0
13
+ #
14
+ # @example
15
+ # require 'hanami'
16
+ #
17
+ # module Bookshelf
18
+ # class Application < Hanami::Application
19
+ # end
20
+ # end
21
+ class Application
22
+ # Override Ruby's Class#inherited
23
+ #
24
+ # @since 0.2.0
25
+ # @api private
26
+ #
27
+ # @see http://www.ruby-doc.org/core/Class.html#method-i-inherited
28
+ def self.inherited(base)
29
+ super
30
+
31
+ base.class_eval do
32
+ include Hanami::Utils::ClassAttribute
33
+
34
+ class_attribute :configuration
35
+ self.configuration = Configuration.new
36
+ end
37
+
38
+ synchronize do
39
+ applications.add(base)
40
+ end
41
+ end
42
+
43
+ # Registry of Hanami applications in the current Ruby process
44
+ #
45
+ # @return [Set] a set of all the registered applications
46
+ #
47
+ # @since 0.2.0
48
+ # @api private
49
+ def self.applications
50
+ synchronize do
51
+ @@applications ||= Set.new
52
+ end
53
+ end
54
+
55
+ # Configure the application.
56
+ # It yields the given block in the context of the configuration
57
+ #
58
+ # @param environment [Symbol,nil] the configuration environment name
59
+ # @param blk [Proc] the configuration block
60
+ #
61
+ # @since 0.1.0
62
+ #
63
+ # @see Hanami::Configuration
64
+ #
65
+ # @example
66
+ # require 'hanami'
67
+ #
68
+ # module Bookshelf
69
+ # Application < Hanami::Application
70
+ # configure do
71
+ # # ...
72
+ # end
73
+ # end
74
+ # end
75
+ def self.configure(environment = nil, &blk)
76
+ configuration.configure(environment, &blk)
77
+ end
78
+
79
+ # Return the routes for this application
80
+ #
81
+ # @return [Hanami::Router] a route set
82
+ #
83
+ # @since 0.1.0
84
+ #
85
+ # @see Hanami::Configuration#routes
86
+ attr_reader :routes
87
+
88
+ # Set the routes for this application
89
+ #
90
+ # @param [Hanami::Router]
91
+ #
92
+ # @since 0.1.0
93
+ # @api private
94
+ attr_writer :routes
95
+
96
+ # Rendering policy
97
+ #
98
+ # @param [Hanami::RenderingPolicy]
99
+ #
100
+ # @since 0.2.0
101
+ # @api private
102
+ attr_accessor :renderer
103
+
104
+ # Initialize and load a new instance of the application
105
+ #
106
+ # @return [Hanami::Application] a new instance of the application
107
+ #
108
+ # @since 0.1.0
109
+ def initialize(options = {})
110
+ self.class.configuration.path_prefix options[:path_prefix]
111
+ self.class.load!(self)
112
+ end
113
+
114
+ # Eager load the application configuration, by activating the framework
115
+ # duplication mechanisms.
116
+ #
117
+ # @param application [Hanami::Application, Class<Hanami::Application>]
118
+ # @return void
119
+ #
120
+ # @since 0.1.1
121
+ #
122
+ # @example
123
+ # require 'hanami'
124
+ #
125
+ # module OneFile
126
+ # class Application < Hanami::Application
127
+ # configure do
128
+ # routes do
129
+ # get '/', to: 'dashboard#index'
130
+ # end
131
+ # end
132
+ #
133
+ # load!
134
+ # end
135
+ #
136
+ # module Controllers::Dashboard
137
+ # class Index
138
+ # include OneFile::Action
139
+ #
140
+ # def call(params)
141
+ # self.body = 'Hello!'
142
+ # end
143
+ # end
144
+ # end
145
+ # end
146
+ def self.load!(application = self)
147
+ Hanami::Loader.new(application).load!
148
+ end
149
+
150
+ # Preload all the registered applications, by yielding their configurations
151
+ # and preparing the frameworks.
152
+ #
153
+ # This is useful for testing suites, where we want to make Hanami frameworks
154
+ # ready, but not preload applications code.
155
+ #
156
+ # This allows to test components such as views or actions in isolation and
157
+ # to have faster boot times.
158
+ #
159
+ # @return [void]
160
+ #
161
+ # @since 0.2.0
162
+ def self.preload!
163
+ synchronize do
164
+ applications.each(&:load!)
165
+ end
166
+
167
+ nil
168
+ end
169
+
170
+ # Full preload for all the registered applications.
171
+ #
172
+ # This is useful in console where we want all the application code available.
173
+ #
174
+ # @return [void]
175
+ #
176
+ # @since 0.2.1
177
+ # @api private
178
+ def self.preload_applications!
179
+ synchronize do
180
+ applications.each { |app| app.new }
181
+ end
182
+
183
+ nil
184
+ end
185
+
186
+ # Return the configuration for this application
187
+ #
188
+ # @since 0.1.0
189
+ # @api private
190
+ #
191
+ # @see Hanami::Application.configuration
192
+ def configuration
193
+ self.class.configuration
194
+ end
195
+
196
+ # Return the application name
197
+ #
198
+ # @since 0.2.0
199
+ # @api private
200
+ def name
201
+ self.class.name
202
+ end
203
+
204
+ # Process a request.
205
+ # This method makes Hanami applications compatible with the Rack protocol.
206
+ #
207
+ # @param env [Hash] a Rack env
208
+ #
209
+ # @return [Array] a serialized Rack response
210
+ #
211
+ # @since 0.1.0
212
+ #
213
+ # @see http://rack.github.io
214
+ # @see Hanami::RenderingPolicy#render
215
+ # @see Hanami::Application#middleware
216
+ def call(env)
217
+ renderer.render(env, middleware.call(env))
218
+ end
219
+
220
+ # Rack middleware stack
221
+ #
222
+ # @return [Hanami::Middleware] the middleware stack
223
+ #
224
+ # @since 0.1.0
225
+ # @api private
226
+ #
227
+ # @see Hanami::Middleware
228
+ def middleware
229
+ @middleware ||= configuration.middleware
230
+ end
231
+
232
+ private
233
+
234
+ # Yields the given block in a critical section
235
+ #
236
+ # @since 0.2.0
237
+ # @api private
238
+ def self.synchronize
239
+ Mutex.new.synchronize do
240
+ yield
241
+ end
242
+ end
243
+ end
244
+ end