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,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