hanami 2.0.2 → 2.1.0.beta1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/LICENSE.md +1 -1
- data/README.md +25 -9
- data/hanami.gemspec +2 -2
- data/lib/hanami/config/actions.rb +0 -4
- data/lib/hanami/config/logger.rb +1 -1
- data/lib/hanami/config/views.rb +0 -4
- data/lib/hanami/config.rb +54 -0
- data/lib/hanami/extensions/action/slice_configured_action.rb +15 -7
- data/lib/hanami/extensions/action.rb +4 -4
- data/lib/hanami/extensions/router/errors.rb +58 -0
- data/lib/hanami/extensions/view/context.rb +129 -60
- data/lib/hanami/extensions/view/part.rb +26 -0
- data/lib/hanami/extensions/view/scope.rb +26 -0
- data/lib/hanami/extensions/view/slice_configured_context.rb +0 -2
- data/lib/hanami/extensions/view/slice_configured_helpers.rb +44 -0
- data/lib/hanami/extensions/view/slice_configured_view.rb +106 -21
- data/lib/hanami/extensions/view/standard_helpers.rb +14 -0
- data/lib/hanami/extensions.rb +10 -3
- data/lib/hanami/helpers/form_helper/form_builder.rb +1391 -0
- data/lib/hanami/helpers/form_helper/values.rb +75 -0
- data/lib/hanami/helpers/form_helper.rb +213 -0
- data/lib/hanami/middleware/public_errors_app.rb +75 -0
- data/lib/hanami/middleware/render_errors.rb +93 -0
- data/lib/hanami/slice.rb +28 -2
- data/lib/hanami/slice_configurable.rb +3 -2
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +8 -20
- data/lib/hanami.rb +1 -1
- data/spec/integration/action/view_rendering/view_context_spec.rb +221 -0
- data/spec/integration/action/view_rendering_spec.rb +0 -18
- data/spec/integration/rack_app/middleware_spec.rb +23 -23
- data/spec/integration/rack_app/rack_app_spec.rb +5 -1
- data/spec/integration/slices/slice_registrations_spec.rb +80 -0
- data/spec/integration/view/config/default_context_spec.rb +149 -0
- data/spec/integration/view/{inflector_spec.rb → config/inflector_spec.rb} +1 -1
- data/spec/integration/view/config/part_class_spec.rb +147 -0
- data/spec/integration/view/config/part_namespace_spec.rb +103 -0
- data/spec/integration/view/config/paths_spec.rb +119 -0
- data/spec/integration/view/config/scope_class_spec.rb +147 -0
- data/spec/integration/view/config/scope_namespace_spec.rb +103 -0
- data/spec/integration/view/config/template_spec.rb +38 -0
- data/spec/integration/view/context/request_spec.rb +3 -7
- data/spec/integration/view/helpers/form_helper_spec.rb +174 -0
- data/spec/integration/view/helpers/part_helpers_spec.rb +124 -0
- data/spec/integration/view/helpers/scope_helpers_spec.rb +84 -0
- data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +162 -0
- data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +119 -0
- data/spec/integration/view/slice_configuration_spec.rb +9 -9
- data/spec/integration/web/render_detailed_errors_spec.rb +90 -0
- data/spec/integration/web/render_errors_spec.rb +240 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/matchers.rb +32 -0
- data/spec/unit/hanami/config/actions/default_values_spec.rb +0 -4
- data/spec/unit/hanami/config/logger_spec.rb +9 -0
- data/spec/unit/hanami/config/render_detailed_errors_spec.rb +25 -0
- data/spec/unit/hanami/config/render_errors_spec.rb +25 -0
- data/spec/unit/hanami/config/views_spec.rb +0 -18
- data/spec/unit/hanami/extensions/view/context_spec.rb +59 -0
- data/spec/unit/hanami/helpers/form_helper_spec.rb +2826 -0
- data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +27 -0
- data/spec/unit/hanami/router/errors/not_found_error_spec.rb +22 -0
- data/spec/unit/hanami/slice_configurable_spec.rb +18 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- data/spec/unit/hanami/web/rack_logger_spec.rb +1 -1
- metadata +67 -33
- data/spec/integration/action/view_integration_spec.rb +0 -165
- data/spec/integration/view/part_namespace_spec.rb +0 -96
- data/spec/integration/view/path_spec.rb +0 -56
- data/spec/integration/view/template_spec.rb +0 -68
- data/spec/isolation/hanami/application/already_configured_spec.rb +0 -19
- data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +0 -10
- data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +0 -14
- data/spec/isolation/hanami/application/not_configured_spec.rb +0 -9
- data/spec/isolation/hanami/application/routes/configured_spec.rb +0 -44
- data/spec/isolation/hanami/application/routes/not_configured_spec.rb +0 -16
- data/spec/isolation/hanami/boot/success_spec.rb +0 -50
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Extensions
|
5
|
+
module View
|
6
|
+
# @api private
|
7
|
+
class SliceConfiguredHelpers < Module
|
8
|
+
attr_reader :slice
|
9
|
+
|
10
|
+
def initialize(slice)
|
11
|
+
super()
|
12
|
+
@slice = slice
|
13
|
+
end
|
14
|
+
|
15
|
+
def extended(klass)
|
16
|
+
include_helpers(klass)
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"#<#{self.class.name}[#{slice.name}]>"
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def include_helpers(klass)
|
26
|
+
if mod = helpers_module(slice.app)
|
27
|
+
klass.include(mod)
|
28
|
+
end
|
29
|
+
|
30
|
+
if mod = helpers_module(slice)
|
31
|
+
klass.include(mod)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def helpers_module(slice)
|
36
|
+
return unless slice.namespace.const_defined?(:Views)
|
37
|
+
return unless slice.namespace.const_get(:Views).const_defined?(:Helpers)
|
38
|
+
|
39
|
+
slice.namespace.const_get(:Views).const_get(:Helpers)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "hanami/view"
|
4
|
-
|
5
3
|
module Hanami
|
6
4
|
module Extensions
|
7
5
|
module View
|
@@ -11,6 +9,11 @@ module Hanami
|
|
11
9
|
# @api private
|
12
10
|
# @since 2.0.0
|
13
11
|
class SliceConfiguredView < Module
|
12
|
+
TEMPLATES_DIR = "templates"
|
13
|
+
VIEWS_DIR = "views"
|
14
|
+
PARTS_DIR = "parts"
|
15
|
+
SCOPES_DIR = "scopes"
|
16
|
+
|
14
17
|
attr_reader :slice
|
15
18
|
|
16
19
|
def initialize(slice)
|
@@ -19,6 +22,7 @@ module Hanami
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def extended(view_class)
|
25
|
+
load_app_view
|
22
26
|
configure_view(view_class)
|
23
27
|
define_inherited
|
24
28
|
end
|
@@ -29,6 +33,19 @@ module Hanami
|
|
29
33
|
|
30
34
|
private
|
31
35
|
|
36
|
+
# If the given view doesn't inherit from the app view, attempt to load it anyway, since
|
37
|
+
# requiring the app view is necessary for _its_ `SliceConfiguredView` hook to execute and
|
38
|
+
# define the app-level part and scope classes that we refer to here.
|
39
|
+
def load_app_view
|
40
|
+
return if app?
|
41
|
+
|
42
|
+
begin
|
43
|
+
slice.app.namespace.const_get(:View, false)
|
44
|
+
rescue NameError => e
|
45
|
+
raise unless e.name == :View
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
32
49
|
# rubocop:disable Metrics/AbcSize
|
33
50
|
def configure_view(view_class)
|
34
51
|
view_class.settings.each do |setting|
|
@@ -84,12 +101,30 @@ module Hanami
|
|
84
101
|
end
|
85
102
|
|
86
103
|
view_class.config.inflector = inflector
|
87
|
-
|
104
|
+
|
105
|
+
# Configure the paths for this view if:
|
106
|
+
# - We are the app, and a user hasn't provided custom `paths` (in this case, we need to
|
107
|
+
# set the defaults)
|
108
|
+
# - We are a slice, and the view's inherited `paths` is identical to the parent's config
|
109
|
+
# (which would result in the view in a slice erroneously trying to find templates in
|
110
|
+
# the app)
|
111
|
+
if (!slice.parent && view_class.config.paths.empty?) ||
|
112
|
+
(slice.parent && view_class.config.paths.map(&:dir) == [templates_path(slice.parent)])
|
113
|
+
view_class.config.paths = templates_path(slice)
|
114
|
+
end
|
115
|
+
|
88
116
|
view_class.config.template = template_name(view_class)
|
117
|
+
view_class.config.default_context = Extensions::View::Context.context_class(slice).new
|
89
118
|
|
90
|
-
|
119
|
+
view_class.config.part_class = part_class
|
120
|
+
view_class.config.scope_class = scope_class
|
121
|
+
|
122
|
+
if (part_namespace = namespace_from_path("#{VIEWS_DIR}/#{PARTS_DIR}"))
|
91
123
|
view_class.config.part_namespace = part_namespace
|
92
124
|
end
|
125
|
+
if (scope_namespace = namespace_from_path("#{VIEWS_DIR}/#{SCOPES_DIR}"))
|
126
|
+
view_class.config.scope_namespace = scope_namespace
|
127
|
+
end
|
93
128
|
end
|
94
129
|
# rubocop:enable Metrics/AbcSize
|
95
130
|
|
@@ -102,20 +137,12 @@ module Hanami
|
|
102
137
|
end
|
103
138
|
end
|
104
139
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
else
|
112
|
-
# Other slice templates are in the root slice dir
|
113
|
-
slice.root.join(path.dir)
|
114
|
-
end
|
115
|
-
else
|
116
|
-
path
|
117
|
-
end
|
118
|
-
}
|
140
|
+
def templates_path(slice)
|
141
|
+
if slice.app.equal?(slice)
|
142
|
+
slice.root.join(APP_DIR, TEMPLATES_DIR)
|
143
|
+
else
|
144
|
+
slice.root.join(TEMPLATES_DIR)
|
145
|
+
end
|
119
146
|
end
|
120
147
|
|
121
148
|
def namespace_from_path(path)
|
@@ -134,16 +161,74 @@ module Hanami
|
|
134
161
|
end
|
135
162
|
|
136
163
|
def template_name(view_class)
|
137
|
-
|
138
|
-
.inflector
|
164
|
+
inflector
|
139
165
|
.underscore(view_class.name)
|
140
166
|
.sub(/^#{slice.slice_name.path}\//, "")
|
141
|
-
.sub(/^#{
|
167
|
+
.sub(/^#{VIEWS_DIR}\//, "")
|
142
168
|
end
|
143
169
|
|
144
170
|
def inflector
|
145
171
|
slice.inflector
|
146
172
|
end
|
173
|
+
|
174
|
+
def part_class
|
175
|
+
@part_class ||=
|
176
|
+
if views_namespace.const_defined?(:Part)
|
177
|
+
views_namespace.const_get(:Part)
|
178
|
+
else
|
179
|
+
views_namespace.const_set(:Part, Class.new(part_superclass).tap { |klass|
|
180
|
+
# Give the slice to `configure_for_slice`, since it cannot be inferred when it is
|
181
|
+
# called via `.inherited`, since the class is anonymous at this point
|
182
|
+
klass.configure_for_slice(slice)
|
183
|
+
})
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def part_superclass
|
188
|
+
return Hanami::View::Part if app?
|
189
|
+
|
190
|
+
begin
|
191
|
+
inflector.constantize(inflector.camelize("#{slice.app.slice_name.name}/views/part"))
|
192
|
+
rescue NameError
|
193
|
+
Hanami::View::Part
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def scope_class
|
198
|
+
@scope_class ||=
|
199
|
+
if views_namespace.const_defined?(:Scope)
|
200
|
+
views_namespace.const_get(:Scope)
|
201
|
+
else
|
202
|
+
views_namespace.const_set(:Scope, Class.new(scope_superclass).tap { |klass|
|
203
|
+
# Give the slice to `configure_for_slice`, since it cannot be inferred when it is
|
204
|
+
# called via `.inherited`, since the class is anonymous at this point
|
205
|
+
klass.configure_for_slice(slice)
|
206
|
+
})
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def scope_superclass
|
211
|
+
return Hanami::View::Scope if app?
|
212
|
+
|
213
|
+
begin
|
214
|
+
inflector.constantize(inflector.camelize("#{slice.app.slice_name.name}/views/scope"))
|
215
|
+
rescue NameError
|
216
|
+
Hanami::View::Scope
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def views_namespace
|
221
|
+
@slice_views_namespace ||=
|
222
|
+
if slice.namespace.const_defined?(:Views)
|
223
|
+
slice.namespace.const_get(:Views)
|
224
|
+
else
|
225
|
+
slice.namespace.const_set(:Views, Module.new)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def app?
|
230
|
+
slice.app == slice
|
231
|
+
end
|
147
232
|
end
|
148
233
|
end
|
149
234
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Extensions
|
5
|
+
module View
|
6
|
+
module StandardHelpers
|
7
|
+
include Hanami::View::Helpers::EscapeHelper
|
8
|
+
include Hanami::View::Helpers::NumberFormattingHelper
|
9
|
+
include Hanami::View::Helpers::TagHelper
|
10
|
+
include Helpers::FormHelper
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/hanami/extensions.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
if Hanami.bundled?("hanami-controller")
|
4
|
-
require_relative "
|
4
|
+
require_relative "extensions/action"
|
5
5
|
end
|
6
6
|
|
7
7
|
if Hanami.bundled?("hanami-view")
|
8
|
-
|
9
|
-
require_relative "
|
8
|
+
require "hanami/view"
|
9
|
+
require_relative "extensions/view"
|
10
|
+
require_relative "extensions/view/context"
|
11
|
+
require_relative "extensions/view/part"
|
12
|
+
require_relative "extensions/view/scope"
|
13
|
+
end
|
14
|
+
|
15
|
+
if Hanami.bundled?("hanami-router")
|
16
|
+
require_relative "extensions/router/errors"
|
10
17
|
end
|