hanami-view 1.3.3 → 2.0.0.alpha2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -10
- data/LICENSE +20 -0
- data/README.md +20 -862
- data/hanami-view.gemspec +26 -16
- data/lib/hanami-view.rb +3 -1
- data/lib/hanami/view.rb +208 -223
- data/lib/hanami/view/application_configuration.rb +77 -0
- data/lib/hanami/view/application_context.rb +35 -0
- data/lib/hanami/view/application_view.rb +89 -0
- data/lib/hanami/view/context.rb +97 -0
- data/lib/hanami/view/context_helpers/content_helpers.rb +26 -0
- data/lib/hanami/view/decorated_attributes.rb +82 -0
- data/lib/hanami/view/errors.rb +19 -56
- data/lib/hanami/view/exposure.rb +126 -0
- data/lib/hanami/view/exposures.rb +74 -0
- data/lib/hanami/view/part.rb +217 -0
- data/lib/hanami/view/part_builder.rb +140 -0
- data/lib/hanami/view/path.rb +68 -0
- data/lib/hanami/view/render_environment.rb +62 -0
- data/lib/hanami/view/render_environment_missing.rb +44 -0
- data/lib/hanami/view/rendered.rb +55 -0
- data/lib/hanami/view/renderer.rb +79 -0
- data/lib/hanami/view/scope.rb +189 -0
- data/lib/hanami/view/scope_builder.rb +98 -0
- data/lib/hanami/view/standalone_view.rb +396 -0
- data/lib/hanami/view/tilt.rb +78 -0
- data/lib/hanami/view/tilt/erb.rb +26 -0
- data/lib/hanami/view/tilt/erbse.rb +21 -0
- data/lib/hanami/view/tilt/haml.rb +26 -0
- data/lib/hanami/view/version.rb +5 -5
- metadata +114 -70
- data/LICENSE.md +0 -22
- data/lib/hanami/layout.rb +0 -190
- data/lib/hanami/presenter.rb +0 -98
- data/lib/hanami/view/configuration.rb +0 -504
- data/lib/hanami/view/dsl.rb +0 -347
- data/lib/hanami/view/escape.rb +0 -225
- data/lib/hanami/view/inheritable.rb +0 -54
- data/lib/hanami/view/rendering.rb +0 -294
- data/lib/hanami/view/rendering/layout_finder.rb +0 -128
- data/lib/hanami/view/rendering/layout_registry.rb +0 -69
- data/lib/hanami/view/rendering/layout_scope.rb +0 -281
- data/lib/hanami/view/rendering/null_layout.rb +0 -52
- data/lib/hanami/view/rendering/null_local.rb +0 -82
- data/lib/hanami/view/rendering/null_template.rb +0 -83
- data/lib/hanami/view/rendering/null_view.rb +0 -26
- data/lib/hanami/view/rendering/options.rb +0 -24
- data/lib/hanami/view/rendering/partial.rb +0 -31
- data/lib/hanami/view/rendering/partial_file.rb +0 -29
- data/lib/hanami/view/rendering/partial_finder.rb +0 -75
- data/lib/hanami/view/rendering/partial_templates_finder.rb +0 -73
- data/lib/hanami/view/rendering/registry.rb +0 -134
- data/lib/hanami/view/rendering/scope.rb +0 -108
- data/lib/hanami/view/rendering/subscope.rb +0 -56
- data/lib/hanami/view/rendering/template.rb +0 -69
- data/lib/hanami/view/rendering/template_finder.rb +0 -55
- data/lib/hanami/view/rendering/template_name.rb +0 -50
- data/lib/hanami/view/rendering/templates_finder.rb +0 -144
- data/lib/hanami/view/rendering/view_finder.rb +0 -37
- data/lib/hanami/view/template.rb +0 -57
@@ -1,83 +0,0 @@
|
|
1
|
-
module Hanami
|
2
|
-
module View
|
3
|
-
module Rendering
|
4
|
-
# Null Object pattern for layout template
|
5
|
-
#
|
6
|
-
# It's used when a layout doesn't have an associated template.
|
7
|
-
#
|
8
|
-
# A common scenario is for non-html requests.
|
9
|
-
# Usually we have a template for the application layout
|
10
|
-
# (eg `templates/application.html.erb`), but we don't use to have the
|
11
|
-
# template for JSON requests (eg `templates/application.json.erb`).
|
12
|
-
# Because most of the times, we only return the output of the view.
|
13
|
-
#
|
14
|
-
# @api private
|
15
|
-
# @since 0.1.0
|
16
|
-
#
|
17
|
-
# @example
|
18
|
-
# require 'hanami/view'
|
19
|
-
#
|
20
|
-
# # We have an ApplicationLayout (views/application_layout.rb):
|
21
|
-
# class ApplicationLayout
|
22
|
-
# include Hanami::Layout
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# # Our layout has a template for HTML requests, located at:
|
26
|
-
# # templates/application.html.erb
|
27
|
-
#
|
28
|
-
# # We set it as global layout
|
29
|
-
# Hanami::View.layout = :application
|
30
|
-
#
|
31
|
-
# # We have two views for HTML and JSON articles.
|
32
|
-
# # They have a template each:
|
33
|
-
# #
|
34
|
-
# # * templates/articles/show.html.erb
|
35
|
-
# # * templates/articles/show.json.erb
|
36
|
-
# module Articles
|
37
|
-
# class Show
|
38
|
-
# include Hanami::View
|
39
|
-
# format :html
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# class JsonShow < Show
|
43
|
-
# format :json
|
44
|
-
# end
|
45
|
-
# end
|
46
|
-
#
|
47
|
-
# # We initialize the framework
|
48
|
-
# Hanami::View.load!
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# # When we ask for a HTML rendering, it will use `Articles::Show` and
|
53
|
-
# # ApplicationLayout. The output will be a composition of:
|
54
|
-
# #
|
55
|
-
# # * templates/articles/show.html.erb
|
56
|
-
# # * templates/application.html.erb
|
57
|
-
#
|
58
|
-
# # When we ask for a JSON rendering, it will use `Articles::JsonShow`
|
59
|
-
# # and ApplicationLayout. Since, the layout doesn't have any associated
|
60
|
-
# # template for JSON, the output will be a composition of:
|
61
|
-
# #
|
62
|
-
# # * templates/articles/show.json.erb
|
63
|
-
class NullTemplate
|
64
|
-
# Render the layout template
|
65
|
-
#
|
66
|
-
# @param scope [Hanami::View::Scope] the rendering scope
|
67
|
-
# @param locals [Hash] a set of objects available during the rendering
|
68
|
-
# @yield [Proc] yields the given block
|
69
|
-
#
|
70
|
-
# @return [String] the output of the rendering process
|
71
|
-
#
|
72
|
-
# @api private
|
73
|
-
# @since 0.1.0
|
74
|
-
#
|
75
|
-
# @see Hanami::Layout#render
|
76
|
-
# @see Hanami::View::Rendering#render
|
77
|
-
def render(scope, locals = {})
|
78
|
-
yield
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module Hanami
|
2
|
-
module View
|
3
|
-
module Rendering
|
4
|
-
# Null Object pattern for view
|
5
|
-
#
|
6
|
-
# It's used when a layout is rendered direcly for testing purposes
|
7
|
-
#
|
8
|
-
# @api private
|
9
|
-
# @since 1.2.1
|
10
|
-
class NullView
|
11
|
-
# Render the layout template
|
12
|
-
#
|
13
|
-
# @return [String] an empty string
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
# @since 1.2.1
|
17
|
-
#
|
18
|
-
# @see Hanami::Layout#render
|
19
|
-
# @see Hanami::View::Rendering#render
|
20
|
-
def render
|
21
|
-
""
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Hanami
|
4
|
-
module View
|
5
|
-
module Rendering
|
6
|
-
# Rendering options
|
7
|
-
#
|
8
|
-
# @since 1.1.1
|
9
|
-
# @api private
|
10
|
-
class Options
|
11
|
-
# @since 1.1.1
|
12
|
-
# @api private
|
13
|
-
def self.build(options, locals, format)
|
14
|
-
options.dup.tap do |opts|
|
15
|
-
opts[:format] ||= format
|
16
|
-
opts[:locals] = locals
|
17
|
-
opts[:locals].merge!(options.fetch(:locals) { ::Hash.new })
|
18
|
-
opts[:locals].merge!(format: opts.fetch(:format, format))
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'hanami/view/rendering/partial_finder'
|
2
|
-
|
3
|
-
module Hanami
|
4
|
-
module View
|
5
|
-
module Rendering
|
6
|
-
# Rendering partial
|
7
|
-
#
|
8
|
-
# It's used when a template wants to render a partial.
|
9
|
-
#
|
10
|
-
# @api private
|
11
|
-
# @since 0.1.0
|
12
|
-
#
|
13
|
-
# @see Hanami::View::Rendering::Template
|
14
|
-
# @see Hanami::View::Rendering::LayoutScope#render
|
15
|
-
#
|
16
|
-
# @example
|
17
|
-
# # We have an application template (templates/application.html.erb)
|
18
|
-
# # that uses the following line:
|
19
|
-
#
|
20
|
-
# <%= render partial: 'shared/sidebar' %>
|
21
|
-
class Partial < Template
|
22
|
-
protected
|
23
|
-
# @api private
|
24
|
-
# @since 0.1.0
|
25
|
-
def template
|
26
|
-
PartialFinder.new(@view.class, @options).find
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Hanami
|
2
|
-
module View
|
3
|
-
module Rendering
|
4
|
-
# @since 0.7.0
|
5
|
-
# @api private
|
6
|
-
class PartialFile
|
7
|
-
# @since 0.7.0
|
8
|
-
# @api private
|
9
|
-
attr_reader :key
|
10
|
-
|
11
|
-
# @since 0.7.0
|
12
|
-
# @api private
|
13
|
-
attr_reader :format
|
14
|
-
|
15
|
-
# @since 0.7.0
|
16
|
-
# @api private
|
17
|
-
attr_reader :template
|
18
|
-
|
19
|
-
# @since 0.7.0
|
20
|
-
# @api private
|
21
|
-
def initialize(key, format, template)
|
22
|
-
@key = key
|
23
|
-
@format = format
|
24
|
-
@template = template
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'hanami/view/rendering/template_finder'
|
2
|
-
|
3
|
-
module Hanami
|
4
|
-
module View
|
5
|
-
module Rendering
|
6
|
-
# Find a partial for the current view context.
|
7
|
-
# It's used when a template wants to render a partial.
|
8
|
-
#
|
9
|
-
# @see Hanami::View::Rendering::Partial
|
10
|
-
# @see Hanami::View::Rendering::TemplateFinder
|
11
|
-
#
|
12
|
-
# @api private
|
13
|
-
# @since 0.1.0
|
14
|
-
class PartialFinder < TemplateFinder
|
15
|
-
# Template file name prefix.
|
16
|
-
# By convention a partial file name starts with this prefix.
|
17
|
-
#
|
18
|
-
# @api private
|
19
|
-
# @since 0.1.0
|
20
|
-
#
|
21
|
-
# @example
|
22
|
-
# "_sidebar.html.erb"
|
23
|
-
PREFIX = '_'.freeze
|
24
|
-
|
25
|
-
# Find a template for a partial. Initially it will look for the
|
26
|
-
# partial template in the framework configuration where it may
|
27
|
-
# already be cached. Failing that it will look under the
|
28
|
-
# directory of the parent directory view template, if not found
|
29
|
-
# it will search recursively from the view root.
|
30
|
-
#
|
31
|
-
# @return [Hanami::View::Template] the requested template
|
32
|
-
#
|
33
|
-
# @see Hanami::View::Rendering::TemplateFinder#find
|
34
|
-
#
|
35
|
-
# @since 0.4.3
|
36
|
-
# @api private
|
37
|
-
def find
|
38
|
-
Hanami::View::Configuration.for(@view).
|
39
|
-
find_partial(relative_partial_path, template_name, format)
|
40
|
-
end
|
41
|
-
|
42
|
-
protected
|
43
|
-
|
44
|
-
# @since 0.7.0
|
45
|
-
# @api private
|
46
|
-
def relative_partial_path
|
47
|
-
[view_template_dir, template_name].join(separator)
|
48
|
-
end
|
49
|
-
|
50
|
-
# @since 0.4.3
|
51
|
-
# @api private
|
52
|
-
def view_template_dir
|
53
|
-
*all, _ = @view.template.split(separator)
|
54
|
-
all.join(separator)
|
55
|
-
end
|
56
|
-
|
57
|
-
# @api private
|
58
|
-
def template_name
|
59
|
-
*all, last = partial_name.split(separator)
|
60
|
-
all.push( last.prepend(prefix) ).join(separator)
|
61
|
-
end
|
62
|
-
|
63
|
-
# @api private
|
64
|
-
def partial_name
|
65
|
-
@options[:partial]
|
66
|
-
end
|
67
|
-
|
68
|
-
# @api private
|
69
|
-
def prefix
|
70
|
-
PREFIX
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'hanami/view/template'
|
2
|
-
require 'hanami/view/rendering/partial_file'
|
3
|
-
|
4
|
-
module Hanami
|
5
|
-
module View
|
6
|
-
module Rendering
|
7
|
-
# Find partial templates in the file system
|
8
|
-
#
|
9
|
-
# @api private
|
10
|
-
# @since 0.7.0
|
11
|
-
#
|
12
|
-
# @see View::Template
|
13
|
-
class PartialTemplatesFinder
|
14
|
-
# Search pattern for partial file names
|
15
|
-
#
|
16
|
-
# @api private
|
17
|
-
# @since 0.7.0
|
18
|
-
PARTIAL_PATTERN = '_*'.freeze
|
19
|
-
|
20
|
-
# @api private
|
21
|
-
# @since 0.7.0
|
22
|
-
PARTIAL_PARTS_SEPARATOR = '.'.freeze
|
23
|
-
|
24
|
-
# @api private
|
25
|
-
# @since 0.7.0
|
26
|
-
attr_reader :configuration
|
27
|
-
|
28
|
-
# Initializes a new PartialTemplatesFinder
|
29
|
-
#
|
30
|
-
# @param configuration [Configuration] the configuration object
|
31
|
-
#
|
32
|
-
# @since 0.7.0
|
33
|
-
# @api private
|
34
|
-
def initialize(configuration)
|
35
|
-
@configuration = configuration
|
36
|
-
end
|
37
|
-
|
38
|
-
# Find partials under the given path
|
39
|
-
#
|
40
|
-
# @return [Array] array of PartialFinder objects
|
41
|
-
#
|
42
|
-
# @since 0.7.0
|
43
|
-
# @api private
|
44
|
-
def find
|
45
|
-
_find_partials(configuration.root).map do |template|
|
46
|
-
partial_path, partial_base_name = Pathname(template).relative_path_from(configuration.root).split
|
47
|
-
partial_base_parts = partial_base_name.to_s.split(PARTIAL_PARTS_SEPARATOR)
|
48
|
-
|
49
|
-
PartialFile.new(
|
50
|
-
"#{partial_path}#{::File::SEPARATOR}#{partial_base_parts[0]}",
|
51
|
-
partial_base_parts[1],
|
52
|
-
View::Template.new(template, configuration.default_encoding)
|
53
|
-
)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
# Find partial template file paths
|
60
|
-
#
|
61
|
-
# @param path [String] the path under which we should search for partials
|
62
|
-
#
|
63
|
-
# @return [Array] an array of strings for each matching partial template file found
|
64
|
-
#
|
65
|
-
# @since 0.7.0
|
66
|
-
# @api private
|
67
|
-
def _find_partials(path)
|
68
|
-
Dir.glob("#{ [path, TemplatesFinder::RECURSIVE, PARTIAL_PATTERN].join(::File::SEPARATOR) }.#{TemplatesFinder::FORMAT}.#{TemplatesFinder::ENGINES}")
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
require 'hanami/view/rendering/layout_registry'
|
2
|
-
require 'hanami/view/rendering/view_finder'
|
3
|
-
|
4
|
-
module Hanami
|
5
|
-
module View
|
6
|
-
module Rendering
|
7
|
-
# Holds all the references of all the registered subclasses of a view.
|
8
|
-
# We have one registry for each superclass view.
|
9
|
-
#
|
10
|
-
# @api private
|
11
|
-
# @since 0.1.0
|
12
|
-
#
|
13
|
-
# @see Hanami::View::Rendering::LayoutRegistry
|
14
|
-
# @see Hanami::View::Rendering#registry
|
15
|
-
#
|
16
|
-
# @example
|
17
|
-
# require 'hanami/view'
|
18
|
-
#
|
19
|
-
# module Articles
|
20
|
-
# class Index
|
21
|
-
# include Hanami::View
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# class Show
|
25
|
-
# include Hanami::View
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
# class JsonShow < Show
|
29
|
-
# format :json
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# class XmlShow < Show
|
33
|
-
# format :xml
|
34
|
-
#
|
35
|
-
# def render
|
36
|
-
# ArticleSerializer.new(article).to_xml
|
37
|
-
# end
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# # We have the following templates:
|
42
|
-
# #
|
43
|
-
# # * articles/index.html.erb
|
44
|
-
# # * articles/index.atom.erb
|
45
|
-
# # * articles/show.html.erb
|
46
|
-
# # * articles/show.json.erb
|
47
|
-
#
|
48
|
-
# # One registry per superclass view
|
49
|
-
# Articles::Index.send(:registry).object_id # => 70135342862240
|
50
|
-
#
|
51
|
-
# Articles::Show.send(:registry).object_id # => 70135342110540
|
52
|
-
# Articles::XmlShow.send(:registry).object_id # => 70135342110540
|
53
|
-
# Articles::JsonShow.send(:registry).object_id # => 70135342110540
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
# # It holds the references for all the templates and the views
|
58
|
-
# Articles::Index.send(:registry).inspect
|
59
|
-
# # => { :all => [Articles::Index, nil],
|
60
|
-
# # :atom => [Articles::Index, #<Hanami::View::Template ... @file="/path/to/templates/articles/index.atom.erb"],
|
61
|
-
# # :html => [Articles::Index, #<Hanami::View::Template ... @file="/path/to/templates/articles/index.html.erb"] }
|
62
|
-
#
|
63
|
-
# Articles::Show.send(:registry).inspect
|
64
|
-
# # => { :all => [Articles::Show, nil],
|
65
|
-
# # :html => [Articles::Show, #<Hanami::View::Template ... @file="/path/to/templates/articles/show.html.erb"],
|
66
|
-
# # :json => [Articles::JsonShow, #<Hanami::View::Template ... @file="/path/to/templates/articles/show.json.erb"],
|
67
|
-
# # :xml => [Articles::XmlShow, nil] }
|
68
|
-
class Registry < LayoutRegistry
|
69
|
-
# Default format for views without an explicit format.
|
70
|
-
#
|
71
|
-
# @api private
|
72
|
-
# @since 0.1.0
|
73
|
-
#
|
74
|
-
# @see Hanami::View::Dsl#format
|
75
|
-
DEFAULT_FORMAT = :all
|
76
|
-
|
77
|
-
# Returns the view for the given context.
|
78
|
-
#
|
79
|
-
# @param context [Hash] the rendering context
|
80
|
-
# @option context [Symbol] :format the requested format
|
81
|
-
#
|
82
|
-
# @return [Hanami::View] the view associated with the given context
|
83
|
-
#
|
84
|
-
# @raise [Hanami::View::MissingFormatError] if the given context doesn't
|
85
|
-
# have the :format key
|
86
|
-
#
|
87
|
-
# @api private
|
88
|
-
# @since 0.1.0
|
89
|
-
#
|
90
|
-
# @see Hanami::View::Rendering#render
|
91
|
-
def resolve(context)
|
92
|
-
view, template = @registry.fetch(format(context)) { @registry[DEFAULT_FORMAT] }
|
93
|
-
view.new(template, **context)
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
# @api private
|
98
|
-
def prepare!
|
99
|
-
prepare_views!
|
100
|
-
prepare_templates!
|
101
|
-
end
|
102
|
-
|
103
|
-
# @api private
|
104
|
-
def prepare_views!
|
105
|
-
views.each do |view|
|
106
|
-
@registry.merge! view.format || DEFAULT_FORMAT => [ view, template_for(view) ]
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# @api private
|
111
|
-
def prepare_templates!
|
112
|
-
templates.each do |template|
|
113
|
-
@registry.merge! template.format => [ view_for(template), template ]
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# @api private
|
118
|
-
def views
|
119
|
-
@view.subclasses + [ @view ]
|
120
|
-
end
|
121
|
-
|
122
|
-
# @api private
|
123
|
-
def view_for(template)
|
124
|
-
ViewFinder.new(@view).find(template)
|
125
|
-
end
|
126
|
-
|
127
|
-
# @api private
|
128
|
-
def template_for(view)
|
129
|
-
templates.find {|template| template.format == view.format }
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|