hanami-view 0.0.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|