hanami-view 0.0.0 → 0.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +96 -0
- data/LICENSE.md +22 -0
- data/README.md +826 -7
- data/hanami-view.gemspec +17 -12
- data/lib/hanami-view.rb +1 -0
- data/lib/hanami/layout.rb +142 -0
- data/lib/hanami/presenter.rb +126 -0
- data/lib/hanami/view.rb +259 -2
- data/lib/hanami/view/configuration.rb +464 -0
- data/lib/hanami/view/dsl.rb +346 -0
- data/lib/hanami/view/errors.rb +47 -0
- data/lib/hanami/view/escape.rb +180 -0
- data/lib/hanami/view/inheritable.rb +54 -0
- data/lib/hanami/view/rendering.rb +265 -0
- data/lib/hanami/view/rendering/layout_finder.rb +128 -0
- data/lib/hanami/view/rendering/layout_registry.rb +63 -0
- data/lib/hanami/view/rendering/layout_scope.rb +240 -0
- data/lib/hanami/view/rendering/null_layout.rb +52 -0
- data/lib/hanami/view/rendering/null_template.rb +83 -0
- data/lib/hanami/view/rendering/partial.rb +29 -0
- data/lib/hanami/view/rendering/partial_finder.rb +73 -0
- data/lib/hanami/view/rendering/registry.rb +128 -0
- data/lib/hanami/view/rendering/scope.rb +88 -0
- data/lib/hanami/view/rendering/template.rb +67 -0
- data/lib/hanami/view/rendering/template_finder.rb +53 -0
- data/lib/hanami/view/rendering/template_name.rb +37 -0
- data/lib/hanami/view/rendering/templates_finder.rb +129 -0
- data/lib/hanami/view/rendering/view_finder.rb +37 -0
- data/lib/hanami/view/template.rb +43 -0
- data/lib/hanami/view/version.rb +4 -1
- metadata +91 -16
- data/.gitignore +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -2
- data/bin/console +0 -14
- data/bin/setup +0 -8
data/hanami-view.gemspec
CHANGED
@@ -4,20 +4,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'hanami/view/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'hanami-view'
|
8
8
|
spec.version = Hanami::View::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Luca Guidi', 'Trung Lê', 'Alfonso Uceda']
|
10
|
+
spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com', 'uceda73@gmail.com']
|
11
|
+
spec.description = %q{View layer for Hanami}
|
12
|
+
spec.summary = %q{View layer for Hanami, with a separation between views and templates}
|
13
|
+
spec.homepage = 'http://hanamirb.org'
|
14
|
+
spec.license = 'MIT'
|
11
15
|
|
12
|
-
spec.
|
13
|
-
spec.
|
14
|
-
spec.
|
16
|
+
spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-view.gemspec`.split($/)
|
17
|
+
spec.executables = []
|
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.
|
17
|
-
spec.
|
18
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
-
spec.require_paths = ["lib"]
|
22
|
+
spec.add_runtime_dependency 'tilt', '~> 2.0', '>= 2.0.1'
|
23
|
+
spec.add_runtime_dependency 'hanami-utils', '~> 0.7'
|
20
24
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
26
|
+
spec.add_development_dependency 'minitest', '~> 5'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10'
|
23
28
|
end
|
data/lib/hanami-view.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'hanami/view'
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'hanami/utils/class_attribute'
|
2
|
+
require 'hanami/view/rendering/layout_registry'
|
3
|
+
require 'hanami/view/rendering/layout_scope'
|
4
|
+
require 'hanami/view/rendering/null_layout'
|
5
|
+
|
6
|
+
module Hanami
|
7
|
+
# Layout
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
#
|
11
|
+
# @see Hanami::Layout::ClassMethods
|
12
|
+
module Layout
|
13
|
+
# Register a layout
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @since 0.1.0
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# require 'hanami/view'
|
20
|
+
#
|
21
|
+
# class ApplicationLayout
|
22
|
+
# include Hanami::Layout
|
23
|
+
# end
|
24
|
+
def self.included(base)
|
25
|
+
conf = Hanami::View::Configuration.for(base)
|
26
|
+
conf.add_layout(base)
|
27
|
+
|
28
|
+
base.class_eval do
|
29
|
+
extend Hanami::View::Dsl.dup
|
30
|
+
extend ClassMethods
|
31
|
+
|
32
|
+
include Utils::ClassAttribute
|
33
|
+
class_attribute :configuration
|
34
|
+
|
35
|
+
self.configuration = conf.duplicate
|
36
|
+
end
|
37
|
+
|
38
|
+
conf.copy!(base)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Class level API
|
42
|
+
#
|
43
|
+
# @since 0.1.0
|
44
|
+
module ClassMethods
|
45
|
+
# Template name suffix
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
# @since 0.1.0
|
49
|
+
#
|
50
|
+
# @see Hanami::Layout::ClassMethods#suffix
|
51
|
+
# @see Hanami::Layout::ClassMethods#template
|
52
|
+
SUFFIX = '_layout'.freeze
|
53
|
+
|
54
|
+
# A registry that holds all the registered layouts.
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @since 0.1.0
|
58
|
+
#
|
59
|
+
# @see Hanami::View::Rendering::LayoutRegistry
|
60
|
+
def registry
|
61
|
+
@registry ||= View::Rendering::LayoutRegistry.new(self)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Template name
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
# @since 0.1.0
|
68
|
+
#
|
69
|
+
# @see Hanami::Layout::ClassMethods#SUFFIX
|
70
|
+
# @see Hanami::Layout::ClassMethods#suffix
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# # Given a template 'templates/application.html.erb'
|
74
|
+
#
|
75
|
+
# class ApplicationLayout
|
76
|
+
# include Hanami::Layout
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# ApplicationLayout.template # => 'application'
|
80
|
+
def template
|
81
|
+
super.sub(suffix, '')
|
82
|
+
end
|
83
|
+
|
84
|
+
# Template name suffix
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
# @since 0.1.0
|
88
|
+
#
|
89
|
+
# @see Hanami::Layout::ClassMethods#SUFFIX
|
90
|
+
# @see Hanami::Layout::ClassMethods#template
|
91
|
+
def suffix
|
92
|
+
SUFFIX
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
# Loading mechanism hook.
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
# @since 0.1.0
|
100
|
+
#
|
101
|
+
# @see Hanami::View.load!
|
102
|
+
def load!
|
103
|
+
registry.freeze
|
104
|
+
configuration.freeze
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Initialize a layout
|
109
|
+
#
|
110
|
+
# @param scope [Hanami::View::Rendering::Scope] view rendering scope
|
111
|
+
# @param rendered [String] the output of the view rendering process
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
# @since 0.1.0
|
115
|
+
#
|
116
|
+
# @see Hanami::View::Rendering#render
|
117
|
+
def initialize(scope, rendered)
|
118
|
+
@scope, @rendered = View::Rendering::LayoutScope.new(self, scope), rendered
|
119
|
+
end
|
120
|
+
|
121
|
+
# Render the layout
|
122
|
+
#
|
123
|
+
# @return [String] the output of the rendering process
|
124
|
+
#
|
125
|
+
# @api private
|
126
|
+
# @since 0.1.0
|
127
|
+
#
|
128
|
+
# @see Hanami::View::Rendering#render
|
129
|
+
def render
|
130
|
+
template.render(@scope, &Proc.new{@rendered})
|
131
|
+
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
# The template for the current format
|
135
|
+
#
|
136
|
+
# @api private
|
137
|
+
# @since 0.1.0
|
138
|
+
def template
|
139
|
+
self.class.registry.resolve({format: @scope.format})
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'hanami/view/escape'
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
# Presenter pattern implementation
|
5
|
+
#
|
6
|
+
# It delegates to the wrapped object the missing method invocations.
|
7
|
+
#
|
8
|
+
# The output of concrete and delegated methods is escaped as XSS prevention.
|
9
|
+
#
|
10
|
+
# @since 0.1.0
|
11
|
+
#
|
12
|
+
# @example Basic usage
|
13
|
+
# require 'hanami/view'
|
14
|
+
#
|
15
|
+
# class Map
|
16
|
+
# attr_reader :locations
|
17
|
+
#
|
18
|
+
# def initialize(locations)
|
19
|
+
# @locations = locations
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def location_names
|
23
|
+
# @locations.join(', ')
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# class MapPresenter
|
28
|
+
# include Hanami::Presenter
|
29
|
+
#
|
30
|
+
# def count
|
31
|
+
# locations.count
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# def location_names
|
35
|
+
# super.upcase
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def inspect_object
|
39
|
+
# @object.inspect
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# map = Map.new(['Rome', 'Boston'])
|
44
|
+
# presenter = MapPresenter.new(map)
|
45
|
+
#
|
46
|
+
# # access a map method
|
47
|
+
# puts presenter.locations # => ['Rome', 'Boston']
|
48
|
+
#
|
49
|
+
# # access presenter concrete methods
|
50
|
+
# puts presenter.count # => 1
|
51
|
+
#
|
52
|
+
# # uses super to access original object implementation
|
53
|
+
# puts presenter.location_names # => 'ROME, BOSTON'
|
54
|
+
#
|
55
|
+
# # it has private access to the original object
|
56
|
+
# puts presenter.inspect_object # => #<Map:0x007fdeada0b2f0 @locations=["Rome", "Boston"]>
|
57
|
+
#
|
58
|
+
# @example Escape
|
59
|
+
# require 'hanami/view'
|
60
|
+
#
|
61
|
+
# User = Struct.new(:first_name, :last_name)
|
62
|
+
#
|
63
|
+
# class UserPresenter
|
64
|
+
# include Hanami::Presenter
|
65
|
+
#
|
66
|
+
# def full_name
|
67
|
+
# [first_name, last_name].join(' ')
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# def raw_first_name
|
71
|
+
# _raw first_name
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# first_name = '<script>alert('xss')</script>'
|
76
|
+
#
|
77
|
+
# user = User.new(first_name, nil)
|
78
|
+
# presenter = UserPresenter.new(user)
|
79
|
+
#
|
80
|
+
# presenter.full_name
|
81
|
+
# # => "<script>alert('xss')</script>"
|
82
|
+
#
|
83
|
+
# presenter.raw_full_name
|
84
|
+
# # => "<script>alert('xss')</script>"
|
85
|
+
module Presenter
|
86
|
+
# Inject escape logic into the given class.
|
87
|
+
#
|
88
|
+
# @since 0.4.0
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
# @see Hanami::View::Escape
|
92
|
+
def self.included(base)
|
93
|
+
base.extend ::Hanami::View::Escape
|
94
|
+
end
|
95
|
+
|
96
|
+
# Initialize the presenter
|
97
|
+
#
|
98
|
+
# @param object [Object] the object to present
|
99
|
+
#
|
100
|
+
# @since 0.1.0
|
101
|
+
def initialize(object)
|
102
|
+
@object = object
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
# Override Ruby's method_missing
|
107
|
+
#
|
108
|
+
# @api private
|
109
|
+
# @since 0.1.0
|
110
|
+
def method_missing(m, *args, &blk)
|
111
|
+
if @object.respond_to?(m)
|
112
|
+
::Hanami::View::Escape.html(@object.__send__(m, *args, &blk))
|
113
|
+
else
|
114
|
+
super
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Override Ruby's respond_to_missing? in order to support proper delegation
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
# @since 0.3.0
|
122
|
+
def respond_to_missing?(m, include_private = false)
|
123
|
+
@object.respond_to?(m, include_private)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/hanami/view.rb
CHANGED
@@ -1,7 +1,264 @@
|
|
1
|
-
require
|
1
|
+
require 'set'
|
2
|
+
require 'pathname'
|
3
|
+
require 'hanami/utils/class_attribute'
|
4
|
+
require 'hanami/view/version'
|
5
|
+
require 'hanami/view/configuration'
|
6
|
+
require 'hanami/view/inheritable'
|
7
|
+
require 'hanami/view/rendering'
|
8
|
+
require 'hanami/view/escape'
|
9
|
+
require 'hanami/view/dsl'
|
10
|
+
require 'hanami/view/errors'
|
11
|
+
require 'hanami/layout'
|
12
|
+
require 'hanami/presenter'
|
2
13
|
|
3
14
|
module Hanami
|
15
|
+
# View
|
16
|
+
#
|
17
|
+
# @since 0.1.0
|
4
18
|
module View
|
5
|
-
|
19
|
+
include Utils::ClassAttribute
|
20
|
+
# Framework configuration
|
21
|
+
#
|
22
|
+
# @since 0.2.0
|
23
|
+
# @api private
|
24
|
+
class_attribute :configuration
|
25
|
+
self.configuration = Configuration.new
|
26
|
+
|
27
|
+
# Configure the framework.
|
28
|
+
# It yields the given block in the context of the configuration
|
29
|
+
#
|
30
|
+
# @param blk [Proc] the configuration block
|
31
|
+
#
|
32
|
+
# @since 0.2.0
|
33
|
+
#
|
34
|
+
# @see Hanami::View::Configuration
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# require 'hanami/view'
|
38
|
+
#
|
39
|
+
# Hanami::View.configure do
|
40
|
+
# root '/path/to/root'
|
41
|
+
# end
|
42
|
+
def self.configure(&blk)
|
43
|
+
configuration.instance_eval(&blk)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Duplicate Hanami::View in order to create a new separated instance
|
47
|
+
# of the framework.
|
48
|
+
#
|
49
|
+
# The new instance of the framework will be completely decoupled from the
|
50
|
+
# original. It will inherit the configuration, but all the changes that
|
51
|
+
# happen after the duplication, won't be reflected on the other copies.
|
52
|
+
#
|
53
|
+
# @return [Module] a copy of Hanami::View
|
54
|
+
#
|
55
|
+
# @since 0.2.0
|
56
|
+
# @api private
|
57
|
+
#
|
58
|
+
# @example Basic usage
|
59
|
+
# require 'hanami/view'
|
60
|
+
#
|
61
|
+
# module MyApp
|
62
|
+
# View = Hanami::View.dupe
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# MyApp::View == Hanami::View # => false
|
66
|
+
#
|
67
|
+
# MyApp::View.configuration ==
|
68
|
+
# Hanami::View.configuration # => false
|
69
|
+
#
|
70
|
+
# @example Inheriting configuration
|
71
|
+
# require 'hanami/view'
|
72
|
+
#
|
73
|
+
# Hanami::View.configure do
|
74
|
+
# root '/path/to/root'
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# module MyApp
|
78
|
+
# View = Hanami::View.dupe
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# module MyApi
|
82
|
+
# View = Hanami::View.dupe
|
83
|
+
# View.configure do
|
84
|
+
# root '/another/root'
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# Hanami::View.configuration.root # => #<Pathname:/path/to/root>
|
89
|
+
# MyApp::View.configuration.root # => #<Pathname:/path/to/root>
|
90
|
+
# MyApi::View.configuration.root # => #<Pathname:/another/root>
|
91
|
+
def self.dupe
|
92
|
+
dup.tap do |duplicated|
|
93
|
+
duplicated.configuration = configuration.duplicate
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Duplicate the framework and generate modules for the target application
|
98
|
+
#
|
99
|
+
# @param mod [Module] the Ruby namespace of the application
|
100
|
+
# @param views [String] the optional namespace where the application's
|
101
|
+
# views will live
|
102
|
+
# @param blk [Proc] an optional block to configure the framework
|
103
|
+
#
|
104
|
+
# @return [Module] a copy of Hanami::View
|
105
|
+
#
|
106
|
+
# @since 0.2.0
|
107
|
+
#
|
108
|
+
# @see Hanami::View#dupe
|
109
|
+
# @see Hanami::View::Configuration
|
110
|
+
# @see Hanami::View::Configuration#namespace
|
111
|
+
#
|
112
|
+
# @example Basic usage
|
113
|
+
# require 'hanami/view'
|
114
|
+
#
|
115
|
+
# module MyApp
|
116
|
+
# View = Hanami::View.duplicate(self)
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# # It will:
|
120
|
+
# #
|
121
|
+
# # 1. Generate MyApp::View
|
122
|
+
# # 2. Generate MyApp::Layout
|
123
|
+
# # 3. Generate MyApp::Presenter
|
124
|
+
# # 4. Generate MyApp::Views
|
125
|
+
# # 5. Configure MyApp::Views as the default namespace for views
|
126
|
+
#
|
127
|
+
# module MyApp::Views::Dashboard
|
128
|
+
# class Index
|
129
|
+
# include MyApp::View
|
130
|
+
# end
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# @example Compare code
|
134
|
+
# require 'hanami/view'
|
135
|
+
#
|
136
|
+
# module MyApp
|
137
|
+
# View = Hanami::View.duplicate(self) do
|
138
|
+
# # ...
|
139
|
+
# end
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# # it's equivalent to:
|
143
|
+
#
|
144
|
+
# module MyApp
|
145
|
+
# View = Hanami::View.dupe
|
146
|
+
# Layout = Hanami::Layout.dup
|
147
|
+
#
|
148
|
+
# module Views
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# View.configure do
|
152
|
+
# namespace 'MyApp::Views'
|
153
|
+
# end
|
154
|
+
#
|
155
|
+
# View.configure do
|
156
|
+
# # ...
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# @example Custom views module
|
161
|
+
# require 'hanami/view
|
162
|
+
#
|
163
|
+
# module MyApp
|
164
|
+
# View = Hanami::View.duplicate(self, 'Vs')
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# defined?(MyApp::Views) # => nil
|
168
|
+
# defined?(MyApp::Vs) # => "constant"
|
169
|
+
#
|
170
|
+
# # Developers can namespace views under Vs
|
171
|
+
# module MyApp::Vs::Dashboard
|
172
|
+
# # ...
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# @example Nil views module
|
176
|
+
# require 'hanami/view'
|
177
|
+
#
|
178
|
+
# module MyApp
|
179
|
+
# View = Hanami::View.duplicate(self, nil)
|
180
|
+
# end
|
181
|
+
#
|
182
|
+
# defined?(MyApp::Views) # => nil
|
183
|
+
#
|
184
|
+
# # Developers can namespace views under MyApp
|
185
|
+
# module MyApp
|
186
|
+
# # ...
|
187
|
+
# end
|
188
|
+
#
|
189
|
+
# @example Block usage
|
190
|
+
# require 'hanami/view'
|
191
|
+
#
|
192
|
+
# module MyApp
|
193
|
+
# View = Hanami::View.duplicate(self) do
|
194
|
+
# root '/path/to/root'
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# Hanami::View.configuration.root # => #<Pathname:.>
|
199
|
+
# MyApp::View.configuration.root # => #<Pathname:/path/to/root>
|
200
|
+
def self.duplicate(mod, views = 'Views', &blk)
|
201
|
+
dupe.tap do |duplicated|
|
202
|
+
mod.module_eval %{ module #{ views }; end } if views
|
203
|
+
mod.module_eval %{
|
204
|
+
Layout = Hanami::Layout.dup
|
205
|
+
Presenter = Hanami::Presenter.dup
|
206
|
+
}
|
207
|
+
|
208
|
+
duplicated.configure do
|
209
|
+
namespace [mod, views].compact.join '::'
|
210
|
+
end
|
211
|
+
|
212
|
+
duplicated.configure(&blk) if block_given?
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Override Ruby's hook for modules.
|
217
|
+
# It includes basic Hanami::View modules to the given Class.
|
218
|
+
# It sets a copy of the framework configuration
|
219
|
+
#
|
220
|
+
# @param base [Class] the target view
|
221
|
+
#
|
222
|
+
# @since 0.1.0
|
223
|
+
# @api private
|
224
|
+
#
|
225
|
+
# @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
|
226
|
+
#
|
227
|
+
# @see Hanami::View::Dsl
|
228
|
+
# @see Hanami::View::Inheritable
|
229
|
+
# @see Hanami::View::Rendering
|
230
|
+
#
|
231
|
+
# @example
|
232
|
+
# require 'hanami/view'
|
233
|
+
#
|
234
|
+
# class IndexView
|
235
|
+
# include Hanami::View
|
236
|
+
# end
|
237
|
+
def self.included(base)
|
238
|
+
conf = self.configuration
|
239
|
+
conf.add_view(base)
|
240
|
+
|
241
|
+
base.class_eval do
|
242
|
+
extend Inheritable
|
243
|
+
extend Dsl
|
244
|
+
extend Rendering
|
245
|
+
extend Escape
|
246
|
+
|
247
|
+
include Utils::ClassAttribute
|
248
|
+
class_attribute :configuration
|
249
|
+
|
250
|
+
self.configuration = conf.duplicate
|
251
|
+
end
|
252
|
+
|
253
|
+
conf.copy!(base)
|
254
|
+
end
|
255
|
+
|
256
|
+
# Load the framework
|
257
|
+
#
|
258
|
+
# @since 0.1.0
|
259
|
+
# @api private
|
260
|
+
def self.load!
|
261
|
+
configuration.load!
|
262
|
+
end
|
6
263
|
end
|
7
264
|
end
|