hanami-view 1.3.1 → 2.0.0.alpha3

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/LICENSE +20 -0
  4. data/README.md +17 -835
  5. data/hanami-view.gemspec +26 -16
  6. data/lib/hanami/view/application_configuration.rb +77 -0
  7. data/lib/hanami/view/application_context.rb +35 -0
  8. data/lib/hanami/view/application_view.rb +89 -0
  9. data/lib/hanami/view/context.rb +97 -0
  10. data/lib/hanami/view/context_helpers/content_helpers.rb +26 -0
  11. data/lib/hanami/view/decorated_attributes.rb +82 -0
  12. data/lib/hanami/view/errors.rb +31 -53
  13. data/lib/hanami/view/exposure.rb +126 -0
  14. data/lib/hanami/view/exposures.rb +74 -0
  15. data/lib/hanami/view/part.rb +217 -0
  16. data/lib/hanami/view/part_builder.rb +140 -0
  17. data/lib/hanami/view/path.rb +68 -0
  18. data/lib/hanami/view/render_environment.rb +62 -0
  19. data/lib/hanami/view/render_environment_missing.rb +44 -0
  20. data/lib/hanami/view/rendered.rb +55 -0
  21. data/lib/hanami/view/renderer.rb +79 -0
  22. data/lib/hanami/view/scope.rb +189 -0
  23. data/lib/hanami/view/scope_builder.rb +98 -0
  24. data/lib/hanami/view/standalone_view.rb +400 -0
  25. data/lib/hanami/view/tilt/erb.rb +26 -0
  26. data/lib/hanami/view/tilt/erbse.rb +21 -0
  27. data/lib/hanami/view/tilt/haml.rb +26 -0
  28. data/lib/hanami/view/tilt.rb +78 -0
  29. data/lib/hanami/view/version.rb +5 -5
  30. data/lib/hanami/view.rb +208 -223
  31. data/lib/hanami-view.rb +3 -1
  32. metadata +120 -70
  33. data/LICENSE.md +0 -22
  34. data/lib/hanami/layout.rb +0 -190
  35. data/lib/hanami/presenter.rb +0 -98
  36. data/lib/hanami/view/configuration.rb +0 -504
  37. data/lib/hanami/view/dsl.rb +0 -347
  38. data/lib/hanami/view/escape.rb +0 -225
  39. data/lib/hanami/view/inheritable.rb +0 -54
  40. data/lib/hanami/view/rendering/layout_finder.rb +0 -128
  41. data/lib/hanami/view/rendering/layout_registry.rb +0 -69
  42. data/lib/hanami/view/rendering/layout_scope.rb +0 -274
  43. data/lib/hanami/view/rendering/null_layout.rb +0 -52
  44. data/lib/hanami/view/rendering/null_local.rb +0 -82
  45. data/lib/hanami/view/rendering/null_template.rb +0 -83
  46. data/lib/hanami/view/rendering/null_view.rb +0 -26
  47. data/lib/hanami/view/rendering/options.rb +0 -24
  48. data/lib/hanami/view/rendering/partial.rb +0 -31
  49. data/lib/hanami/view/rendering/partial_file.rb +0 -29
  50. data/lib/hanami/view/rendering/partial_finder.rb +0 -75
  51. data/lib/hanami/view/rendering/partial_templates_finder.rb +0 -73
  52. data/lib/hanami/view/rendering/registry.rb +0 -134
  53. data/lib/hanami/view/rendering/scope.rb +0 -108
  54. data/lib/hanami/view/rendering/subscope.rb +0 -56
  55. data/lib/hanami/view/rendering/template.rb +0 -69
  56. data/lib/hanami/view/rendering/template_finder.rb +0 -55
  57. data/lib/hanami/view/rendering/template_name.rb +0 -50
  58. data/lib/hanami/view/rendering/templates_finder.rb +0 -144
  59. data/lib/hanami/view/rendering/view_finder.rb +0 -37
  60. data/lib/hanami/view/rendering.rb +0 -294
  61. data/lib/hanami/view/template.rb +0 -57
@@ -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
@@ -1,108 +0,0 @@
1
- require 'hanami/utils/escape'
2
- require 'hanami/view/rendering/layout_scope'
3
- require 'hanami/view/rendering/template'
4
- require 'hanami/view/rendering/partial'
5
-
6
- module Hanami
7
- module View
8
- module Rendering
9
- # Rendering view scope
10
- #
11
- # @since 0.1.0
12
- #
13
- # @see Hanami::View::Rendering::LayoutScope
14
- class Scope < LayoutScope
15
- # Initialize the scope
16
- #
17
- # @param view [Class] the view
18
- # @param locals [Hash] a set of objects available during the rendering
19
- # @option locals [Symbol] :format the requested format
20
- #
21
- # @api private
22
- # @since 0.1.0
23
- def initialize(view, locals = {})
24
- @view = view
25
- @locals = locals
26
- @layout = layout
27
- @scope = nil
28
- end
29
-
30
- # Returns an inspect String
31
- #
32
- # @return [String] inspect String (contains classname, objectid in hex, available ivars)
33
- #
34
- # @since 0.3.0
35
- def inspect
36
- base = "#<#{ self.class }: #{'%x' % (self.object_id << 1)}"
37
- base << " @view=\"#{@view}\"" if @view
38
- base << " @locals=\"#{@locals}\"" if @locals
39
- base << ">"
40
- end
41
-
42
- # Returns the requested format.
43
- #
44
- # @return [Symbol] the requested format (eg. :html, :json, :xml, etc..)
45
- #
46
- # @since 0.1.0
47
- def format
48
- locals[:format]
49
- end
50
-
51
- # Implements "respond to" logic
52
- #
53
- # @return [TrueClass,FalseClass]
54
- #
55
- # @since 0.3.0
56
- # @api private
57
- #
58
- # @see http://ruby-doc.org/core/Object.html#method-i-respond_to_missing-3F
59
- def respond_to_missing?(m, include_all)
60
- # FIXME: this isn't compatible with Hanami 2.0, as it extends a view
61
- # that we want to be frozen in the future
62
- #
63
- # See https://github.com/hanami/view/issues/130#issuecomment-319326236
64
- @view.respond_to?(m, include_all) ||
65
- @locals.key?(m)
66
- end
67
-
68
- protected
69
-
70
- # @api private
71
- def method_missing(m, *args, &block)
72
- ::Hanami::View::Escape.html(
73
- # FIXME: this isn't compatible with Hanami 2.0, as it extends a view
74
- # that we want to be frozen in the future
75
- #
76
- # See https://github.com/hanami/view/issues/130#issuecomment-319326236
77
- if @view.respond_to?(m, true)
78
- @view.__send__ m, *args, &block
79
- elsif @locals.key?(m)
80
- @locals[m]
81
- else
82
- super
83
- end
84
- )
85
- end
86
-
87
- private
88
-
89
- # @since 1.1.1
90
- # @api private
91
- def _options(options)
92
- current_locals = locals.reject { |key, _| @view.respond_to?(key) }
93
- Options.build(options, current_locals, format)
94
- end
95
-
96
- # @since 0.4.2
97
- # @api private
98
- def layout
99
- if @view.class.respond_to?(:layout)
100
- @view.class.layout.new(self, "")
101
- else
102
- nil
103
- end
104
- end
105
- end
106
- end
107
- end
108
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "hanami/view/rendering/scope"
4
- require "hanami/view/rendering/options"
5
-
6
- module Hanami
7
- module View
8
- module Rendering
9
- # Rendering subscope
10
- #
11
- # @since 1.1.1
12
- # @api private
13
- #
14
- # @see Hanami::View::Rendering::Scope
15
- class Subscope < Scope
16
- # Implements "respond to" logic
17
- #
18
- # @return [TrueClass,FalseClass]
19
- #
20
- # @since 1.1.1
21
- # @api private
22
- #
23
- # @see http://ruby-doc.org/core/Object.html#method-i-respond_to_missing-3F
24
- def respond_to_missing?(m, _include_all)
25
- @locals.key?(m)
26
- end
27
-
28
- protected
29
-
30
- # @since 1.1.1
31
- # @api private
32
- def method_missing(m, *args, &block)
33
- ::Hanami::View::Escape.html(
34
- # FIXME: this isn't compatible with Hanami 2.0, as it extends a view
35
- # that we want to be frozen in the future
36
- #
37
- # See https://github.com/hanami/view/issues/130#issuecomment-319326236
38
- if @locals.key?(m)
39
- @locals[m]
40
- else
41
- super
42
- end
43
- )
44
- end
45
-
46
- private
47
-
48
- # @since 1.1.1
49
- # @api private
50
- def _options(options)
51
- Options.build(options, locals, format)
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,69 +0,0 @@
1
- require 'hanami/view/rendering/template_finder'
2
-
3
- module Hanami
4
- module View
5
- module Rendering
6
- # Rendering template
7
- #
8
- # It's used when a template wants to render another template.
9
- #
10
- # @api private
11
- # @since 0.1.0
12
- #
13
- # @see Hanami::View::Rendering::LayoutScope#render
14
- #
15
- # @example
16
- # # We have an application template (templates/application.html.erb)
17
- # # that uses the following line:
18
- #
19
- # <%= render template: 'articles/show' %>
20
- class Template
21
- # Initialize a template
22
- #
23
- # @param view [Hanami::View] the current view
24
- # @param options [Hash] the rendering informations
25
- # @option options [Symbol] :format the current format
26
- # @option options [Hash] :locals the set of objects available within
27
- # the rendering context
28
- #
29
- # @api private
30
- # @since 0.1.0
31
- def initialize(view, options)
32
- @view, @options = view, options
33
- end
34
-
35
- # Render the template.
36
- #
37
- # @return [String] the output of the rendering process.
38
- #
39
- # @raise [Hanami::View::MissingTemplateError] if template can't be found
40
- #
41
- # @api private
42
- # @since 0.1.0
43
- def render
44
- (template or raise_missing_template_error).render(scope)
45
- end
46
-
47
- protected
48
- # @api private
49
- def template
50
- TemplateFinder.new(@view.class, @options).find
51
- end
52
-
53
- # @api private
54
- def scope
55
- Subscope.new(@view, @options[:locals])
56
- end
57
-
58
- # @since 0.5.0
59
- # @api private
60
- def raise_missing_template_error
61
- raise MissingTemplateError.new(
62
- @options.fetch(:template) { @options.fetch(:partial, nil) },
63
- @options[:format]
64
- )
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,55 +0,0 @@
1
- require 'hanami/view/rendering/templates_finder'
2
-
3
- module Hanami
4
- module View
5
- module Rendering
6
- # Find a template for the current view context.
7
- # It's used when a template wants to render another template.
8
- #
9
- # @see Hanami::View::Rendering::Template
10
- # @see Hanami::View::Rendering::TemplatesFinder
11
- #
12
- # @api private
13
- # @since 0.1.0
14
- class TemplateFinder < TemplatesFinder
15
- # Initialize a finder
16
- #
17
- # @param view [Class] a view
18
- # @param options [Hash] the informations about the context
19
- # @option options [String] :template the template file name
20
- # @option options [Symbol] :format the requested format
21
- #
22
- # @api private
23
- # @since 0.1.0
24
- def initialize(view, options)
25
- super(view)
26
- @options = options
27
- end
28
-
29
- # Find a template for the current view context
30
- #
31
- # @return [Hanami::View::Template] the requested template
32
- #
33
- # @api private
34
- # @since 0.1.0
35
- #
36
- # @see Hanami::View::Rendering::TemplatesFinder#find
37
- # @see Hanami::View::Rendering::Template#render
38
- def find
39
- super.first
40
- end
41
-
42
- protected
43
- # @api private
44
- def template_name
45
- @options[:template]
46
- end
47
-
48
- # @api private
49
- def format
50
- @options[:format]
51
- end
52
- end
53
- end
54
- end
55
- end