amber_component 1.1.0 → 1.2.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 +33 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -5
- data/README.md +38 -6
- data/lib/amber_component/assets.rb +9 -12
- data/lib/amber_component/base.rb +28 -3
- data/lib/amber_component/configuration.rb +47 -5
- data/lib/amber_component/rendering.rb +107 -9
- data/lib/amber_component/template_handler.rb +8 -9
- data/lib/amber_component/version.rb +1 -1
- data/lib/amber_component/views.rb +26 -151
- data/lib/amber_component.rb +1 -1
- data/lib/generators/amber_component/install_generator.rb +103 -17
- data/lib/generators/amber_component_generator.rb +22 -20
- metadata +2 -3
- data/lib/amber_component/template_handler/erb.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0142826c9117720944d7c6f3ab6a8c56e551ed684c92e1d7ce4857ccbe2632c0'
|
4
|
+
data.tar.gz: 749a03720a2a3a6b7131ffc0e432af7dce37e11d4375052f6b051b799f9f66be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c06aa0648eb8767949de4b69ab288a1534333f0281095d757daf9564402c24c896bb94b78206d2b9219ddbccd61db1dc67281480ee8ac52abf541d8c17e18bc9
|
7
|
+
data.tar.gz: 196d879455fc376f6558048e801522a865753ece6aec2ecb6f0888a867707a43a04b629d87c2a2767800280482ec9d375cf56008e74bdbafd56d4b5ab5f8f2e5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,37 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [
|
3
|
+
## [1.2.0] - 2023-01-25
|
4
|
+
|
5
|
+
### Breaking changes
|
6
|
+
|
7
|
+
- Inline view syntax has been changed from `view :[view_type] { '[content]' }` to `view '[content]', type: :[view_type]`
|
8
|
+
|
9
|
+
- Overriding the view template when rendering a component has been removed (eg. `ExampleComponent.call view: '<h1>Some overriden view</h1>'`)
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- ERB compiled template caching in production
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
|
17
|
+
- View rendering pipeline has been rewritten
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
|
21
|
+
- Nesting components has been fixed
|
22
|
+
|
23
|
+
## [1.1.1] - 2022-11-14
|
24
|
+
|
25
|
+
### Added
|
26
|
+
|
27
|
+
- Support for webpacker
|
28
|
+
|
29
|
+
## [1.1.0] - 2022-11-13
|
30
|
+
|
31
|
+
### Added
|
32
|
+
|
33
|
+
- StimulusJS controllers for components
|
34
|
+
|
35
|
+
## [1.0.0] - 2022-11-07
|
4
36
|
|
5
37
|
- Initial release
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
amber_component (1.
|
4
|
+
amber_component (1.2.0)
|
5
5
|
actionview (>= 6)
|
6
6
|
activemodel (>= 6)
|
7
7
|
activesupport (>= 6)
|
@@ -48,9 +48,15 @@ GEM
|
|
48
48
|
ffi (1.15.5)
|
49
49
|
git (1.11.0)
|
50
50
|
rchardet (~> 1.8)
|
51
|
-
haml (
|
52
|
-
temple (>= 0.8.
|
51
|
+
haml (6.1.1)
|
52
|
+
temple (>= 0.8.2)
|
53
|
+
thor
|
53
54
|
tilt
|
55
|
+
haml-rails (2.1.0)
|
56
|
+
actionpack (>= 5.1)
|
57
|
+
activesupport (>= 5.1)
|
58
|
+
haml (>= 4.0.6)
|
59
|
+
railties (>= 5.1)
|
54
60
|
i18n (1.12.0)
|
55
61
|
concurrent-ruby (~> 1.0)
|
56
62
|
jaro_winkler (1.5.4)
|
@@ -139,7 +145,7 @@ GEM
|
|
139
145
|
thor (~> 1.0)
|
140
146
|
tilt (~> 2.0)
|
141
147
|
yard (~> 0.9, >= 0.9.24)
|
142
|
-
temple (0.
|
148
|
+
temple (0.10.0)
|
143
149
|
thor (1.2.1)
|
144
150
|
tilt (2.0.11)
|
145
151
|
tzinfo (2.0.5)
|
@@ -159,7 +165,7 @@ DEPENDENCIES
|
|
159
165
|
bundler-audit
|
160
166
|
byebug
|
161
167
|
git
|
162
|
-
haml
|
168
|
+
haml-rails
|
163
169
|
minitest (~> 5.0)
|
164
170
|
railties
|
165
171
|
rake (~> 13.0)
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[](https://codeclimate.com/github/amber-ruby/amber_component/maintainability)
|
4
4
|
[](https://github.com/amber-ruby/amber_component/actions/workflows/ci_ruby.yml)
|
5
5
|
[](https://github.com/amber-ruby/amber_component/actions/workflows/ci_ruby.yml)
|
6
|
-
[]((https://rubygems.org/gems/amber_component))
|
6
|
+
<!-- []((https://rubygems.org/gems/amber_component)) -->
|
7
7
|
|
8
8
|
<img src="banner.png" width="500px" style="margin-bottom: 2rem;"/>
|
9
9
|
|
@@ -54,6 +54,13 @@ Every component consists of:
|
|
54
54
|
- a style file (css, scss, sass etc.)
|
55
55
|
- [optional] a JavaScript file with a Stimulus controller (if you installed the gem with `--stimulus`)
|
56
56
|
|
57
|
+
`amber_component` automatically detects what kind of view and stylesheet formats your app is configured to use.
|
58
|
+
|
59
|
+
So if you've got `haml-rails`, components will be generated with `haml`. When your app uses `slim-rails`, components will be generated with `slim`. When your `Gemfile` contains `sassc-rails`, components will use `scss` etc.
|
60
|
+
|
61
|
+
All of these formats can be overridden in
|
62
|
+
an initializer or by adding arguments to the component generator.
|
63
|
+
|
57
64
|
```
|
58
65
|
app/components/
|
59
66
|
├─ [name]_component.rb
|
@@ -197,13 +204,20 @@ This will generate a new component in `app/components/[name]_component.rb` along
|
|
197
204
|
app/components/
|
198
205
|
├─ [name]_component.rb
|
199
206
|
└─ [name]_component/
|
200
|
-
├─ style.css
|
201
|
-
├─ view.html.erb
|
207
|
+
├─ style.css # may be `.scss` or `.sass`
|
208
|
+
├─ view.html.erb # may be `.haml` or `.slim`
|
202
209
|
└─ controller.js # if stimulus is configured
|
203
210
|
test/components/
|
204
211
|
└─ [name]_component_test.rb
|
205
212
|
```
|
206
213
|
|
214
|
+
View and stylesheet formats can be overridden by providing options.
|
215
|
+
|
216
|
+
```
|
217
|
+
-v, [--view=VIEW] # Indicate what type of view should be generated eg. [:erb, :haml, :slim]
|
218
|
+
--styles, -c, [--css=CSS] # Indicate what type of styles should be generated eg. [:css, :scss, :sass]
|
219
|
+
```
|
220
|
+
|
207
221
|
### Component properties
|
208
222
|
|
209
223
|
There is a neat prop DSL.
|
@@ -323,7 +337,10 @@ custom HTML to a component.
|
|
323
337
|
|
324
338
|
This works similarly to React's `props.children`.
|
325
339
|
|
326
|
-
To render the passed nested content call `
|
340
|
+
To render the passed nested content call `children(&block)` somewhere inside the ERB template/view.
|
341
|
+
If you're using another template language like Haml,
|
342
|
+
you may need to use `children{yield}` instead. This difference
|
343
|
+
is due to how these templates are compiled.
|
327
344
|
|
328
345
|
```ruby
|
329
346
|
# app/components/modal_component.rb
|
@@ -344,7 +361,7 @@ end
|
|
344
361
|
|
345
362
|
<div class="modal_body">
|
346
363
|
<!-- nested content will be rendered here -->
|
347
|
-
<%=
|
364
|
+
<%= children(&block) %>
|
348
365
|
</div>
|
349
366
|
|
350
367
|
<div class="modal_footer">
|
@@ -375,7 +392,7 @@ Note that this will raise an error when no block/nested content is provided.
|
|
375
392
|
|
376
393
|
In order to render nested content
|
377
394
|
only when it is present (will work without nested content)
|
378
|
-
you can use `yield
|
395
|
+
you can use `children(&block) if block_given?` in ERB templates (or `children{yield} if block_given?` for Haml and others)
|
379
396
|
|
380
397
|
In general `block_given?` will return `true` when a block/nested content is present, otherwise `false`.
|
381
398
|
You can use it to render content conditionally based on
|
@@ -411,6 +428,21 @@ This makes component views very flexible and convenient.
|
|
411
428
|
<% end %>
|
412
429
|
```
|
413
430
|
|
431
|
+
### Configuration
|
432
|
+
|
433
|
+
This gem can be configured in an initializer.
|
434
|
+
If you used the installer generator it should already be present.
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
# config/initializers/amber_component.rb
|
438
|
+
|
439
|
+
::AmberComponent.configure do |c|
|
440
|
+
c.stimulus = nil # [nil, :importmap, :webpacker, :jsbundling, :webpack, :esbuild, :rollup]
|
441
|
+
c.stylesheet_format = :css # [:css, :scss, :sass]
|
442
|
+
c.view_format = :erb # [:erb, :haml, :slim]
|
443
|
+
end
|
444
|
+
```
|
445
|
+
|
414
446
|
### Testing Components
|
415
447
|
|
416
448
|
### Rails
|
@@ -5,15 +5,15 @@ module ::AmberComponent
|
|
5
5
|
module Assets
|
6
6
|
# Class methods for assets.
|
7
7
|
module ClassMethods
|
8
|
-
# @return [
|
8
|
+
# @return [Pathname]
|
9
9
|
def asset_dir_path
|
10
|
-
component_file_path
|
10
|
+
component_file_path = source_location.first
|
11
11
|
return asset_dir_from_name unless component_file_path
|
12
12
|
|
13
|
-
component_file_path.delete_suffix('.rb')
|
13
|
+
::Pathname.new component_file_path.delete_suffix('.rb')
|
14
14
|
end
|
15
15
|
|
16
|
-
# @return [
|
16
|
+
# @return [Pathname, nil]
|
17
17
|
def asset_dir_from_name
|
18
18
|
return unless defined?(::Rails)
|
19
19
|
|
@@ -23,17 +23,17 @@ module ::AmberComponent
|
|
23
23
|
# Get an array of all folders containing component assets.
|
24
24
|
# This method should only be used on the parent class `AmberComponent::Base` or `ApplicationComponent`.
|
25
25
|
#
|
26
|
-
# @return [Array<
|
26
|
+
# @return [Array<Pathname>]
|
27
27
|
def all_asset_dir_paths
|
28
28
|
subclasses.map(&:asset_dir_path)
|
29
29
|
end
|
30
30
|
|
31
|
-
# @param file_name [String, nil]
|
32
|
-
# @return [
|
31
|
+
# @param file_name [String, Pathname, nil]
|
32
|
+
# @return [Pathname, nil]
|
33
33
|
def asset_path(file_name)
|
34
34
|
return unless file_name
|
35
35
|
|
36
|
-
|
36
|
+
asset_dir_path / file_name
|
37
37
|
end
|
38
38
|
|
39
39
|
# Returns the name of the file inside the asset directory
|
@@ -45,15 +45,12 @@ module ::AmberComponent
|
|
45
45
|
return [] unless ::File.directory?(asset_dir_path)
|
46
46
|
|
47
47
|
::Dir.entries(asset_dir_path).select do |file|
|
48
|
-
next unless ::File.file?(
|
48
|
+
next unless ::File.file?(asset_dir_path / file)
|
49
49
|
|
50
50
|
file.match? type_regexp
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
# Instance methods for assets.
|
56
|
-
module InstanceMethods
|
57
|
-
end
|
58
55
|
end
|
59
56
|
end
|
data/lib/amber_component/base.rb
CHANGED
@@ -42,9 +42,7 @@ module ::AmberComponent
|
|
42
42
|
extend Helpers::ClassHelper
|
43
43
|
|
44
44
|
include Helpers::CssHelper
|
45
|
-
include Views::InstanceMethods
|
46
45
|
extend Views::ClassMethods
|
47
|
-
include Assets::InstanceMethods
|
48
46
|
extend Assets::ClassMethods
|
49
47
|
include Rendering::InstanceMethods
|
50
48
|
extend Rendering::ClassMethods
|
@@ -57,18 +55,40 @@ module ::AmberComponent
|
|
57
55
|
memoize :asset_dir_path
|
58
56
|
|
59
57
|
# Memoize these methods in production
|
60
|
-
if ::
|
58
|
+
if defined?(::Rails.env) && ::Rails.env.production?
|
61
59
|
memoize :view_path
|
62
60
|
memoize :view_file_name
|
63
61
|
memoize :view_type
|
64
62
|
end
|
65
63
|
|
64
|
+
# @return [Class]
|
65
|
+
def compiled_method_container
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [String]
|
70
|
+
def type
|
71
|
+
'text/html'
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Symbol]
|
75
|
+
def format
|
76
|
+
:html
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [String]
|
80
|
+
def identifier
|
81
|
+
source_location.first
|
82
|
+
end
|
83
|
+
|
66
84
|
private
|
67
85
|
|
68
86
|
# @param subclass [Class]
|
69
87
|
# @return [void]
|
70
88
|
def inherited(subclass)
|
71
89
|
super
|
90
|
+
return unless subclass.name
|
91
|
+
|
72
92
|
method_body = lambda do |**kwargs, &block|
|
73
93
|
subclass.render(**kwargs, &block)
|
74
94
|
end
|
@@ -130,6 +150,11 @@ module ::AmberComponent
|
|
130
150
|
end
|
131
151
|
end
|
132
152
|
|
153
|
+
# @return [Class]
|
154
|
+
def compiled_method_container
|
155
|
+
self.class
|
156
|
+
end
|
157
|
+
|
133
158
|
private
|
134
159
|
|
135
160
|
# @param kwargs [Hash{Symbol => Object}]
|
@@ -4,18 +4,36 @@ module ::AmberComponent
|
|
4
4
|
# Object which stores configuration options
|
5
5
|
# for this gem.
|
6
6
|
class Configuration
|
7
|
-
# @return [
|
8
|
-
STIMULUS_INTEGRATIONS =
|
7
|
+
# @return [Set<Symbol>]
|
8
|
+
STIMULUS_INTEGRATIONS = ::Set[nil, :importmap, :webpacker, :jsbundling, :webpack, :esbuild, :rollup]
|
9
|
+
# @return [Set<Symbol>]
|
10
|
+
ALLOWED_STYLES = ::Set.new(%i[css scss sass])
|
11
|
+
# @return [Set<Symbol>]
|
12
|
+
ALLOWED_VIEWS = ::Set.new(%i[erb haml slim])
|
9
13
|
|
10
14
|
# How Stimulus.js is bundled in this app.
|
11
|
-
# Possible values: `[nil, :importmap, :jsbundling, :webpack, :esbuild, :rollup]`
|
15
|
+
# Possible values: `[nil, :importmap, :webpacker, :jsbundling, :webpack, :esbuild, :rollup]`
|
12
16
|
# `nil` indicates that stimulus should not be used (default behaviour).
|
13
17
|
#
|
14
18
|
# @return [Symbol, nil]
|
15
19
|
attr_reader :stimulus
|
16
20
|
|
21
|
+
# The default format that the generators will use
|
22
|
+
# for the view/template file of a component.
|
23
|
+
# Possible values: `[nil, :erb, :haml, :slim]`
|
24
|
+
#
|
25
|
+
# @return [Symbol, nil]
|
26
|
+
attr_reader :view_format
|
27
|
+
|
28
|
+
# The default format that the generators will use
|
29
|
+
# for the stylesheets of a component.
|
30
|
+
# Possible values: `[nil, :css, :scss, :sass]`
|
31
|
+
#
|
32
|
+
# @return [Symbol, nil]
|
33
|
+
attr_reader :stylesheet_format
|
34
|
+
|
17
35
|
# How Stimulus.js is bundled in this app.
|
18
|
-
# Possible values: `[nil, :importmap, :jsbundling, :webpack, :esbuild, :rollup]`
|
36
|
+
# Possible values: `[nil, :importmap, :webpacker, :jsbundling, :webpack, :esbuild, :rollup]`
|
19
37
|
# `nil` indicates that stimulus should not be used (default behaviour).
|
20
38
|
#
|
21
39
|
# @param val [Symbol, String, nil]
|
@@ -23,13 +41,37 @@ module ::AmberComponent
|
|
23
41
|
val = val&.to_sym
|
24
42
|
unless val.nil? || STIMULUS_INTEGRATIONS.include?(val)
|
25
43
|
raise(::ArgumentError,
|
26
|
-
"Invalid value for `
|
44
|
+
"Invalid value for `#{__method__}` bundling. " \
|
27
45
|
"Received #{val.inspect}, expected one of #{STIMULUS_INTEGRATIONS.inspect}")
|
28
46
|
end
|
29
47
|
|
30
48
|
@stimulus = val
|
31
49
|
end
|
32
50
|
|
51
|
+
# @param val [Symbol, String, nil]
|
52
|
+
def stylesheet_format=(val)
|
53
|
+
val = val&.to_sym
|
54
|
+
unless val.nil? || ALLOWED_STYLES.include?(val)
|
55
|
+
raise(::ArgumentError,
|
56
|
+
"Invalid value for `#{__method__}`. " \
|
57
|
+
"Received #{val.inspect}, expected one of #{ALLOWED_STYLES.inspect}")
|
58
|
+
end
|
59
|
+
|
60
|
+
@stylesheet_format = val
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param val [Symbol, String, nil]
|
64
|
+
def view_format=(val)
|
65
|
+
val = val&.to_sym
|
66
|
+
unless val.nil? || ALLOWED_VIEWS.include?(val)
|
67
|
+
raise(::ArgumentError,
|
68
|
+
"Invalid value for `#{__method__}`. " \
|
69
|
+
"Received #{val.inspect}, expected one of #{ALLOWED_VIEWS.inspect}")
|
70
|
+
end
|
71
|
+
|
72
|
+
@view_format = val
|
73
|
+
end
|
74
|
+
|
33
75
|
# @return [Boolean]
|
34
76
|
def stimulus?
|
35
77
|
!@stimulus.nil?
|
@@ -3,17 +3,82 @@
|
|
3
3
|
module ::AmberComponent
|
4
4
|
# Provides universal methods for rendering components.
|
5
5
|
module Rendering
|
6
|
+
|
7
|
+
# @return [Symbol]
|
8
|
+
RENDER_TEMPLATE_METHOD_NAME = :__render
|
9
|
+
|
6
10
|
# Class methods for rendering.
|
7
11
|
module ClassMethods
|
8
12
|
# @param kwargs [Hash{Symbol => Object}]
|
9
13
|
# @return [String]
|
10
14
|
def render(**kwargs, &block)
|
11
|
-
|
12
|
-
|
13
|
-
comp.render(&block)
|
15
|
+
new(**kwargs).render(&block)
|
14
16
|
end
|
15
17
|
|
16
18
|
alias call render
|
19
|
+
|
20
|
+
# @return [Boolean]
|
21
|
+
def compiled?
|
22
|
+
method_defined?(RENDER_TEMPLATE_METHOD_NAME)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean]
|
26
|
+
def compile?
|
27
|
+
return true if defined?(::Rails.env) && ::Rails.env.development?
|
28
|
+
|
29
|
+
!compiled?
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param force [Boolean] force recompilation
|
33
|
+
# @return [void]
|
34
|
+
def compile(force: false)
|
35
|
+
return if !compile? && !force
|
36
|
+
return if template_handler.nil?
|
37
|
+
|
38
|
+
render_template_method_redefinition_lock.synchronize do
|
39
|
+
silence_redefinition_of_method(RENDER_TEMPLATE_METHOD_NAME)
|
40
|
+
# rubocop:disable Style/EvalWithLocation
|
41
|
+
class_eval <<~CODE, view_path.to_s, 0 # rubocop:disable Style/DocumentDynamicEvalDefinition
|
42
|
+
def #{RENDER_TEMPLATE_METHOD_NAME}(local_assigns, output_buffer, &block)
|
43
|
+
#{compiled_template_source}
|
44
|
+
end
|
45
|
+
CODE
|
46
|
+
# rubocop:enable Style/EvalWithLocation
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Class, nil]
|
51
|
+
def template_handler
|
52
|
+
@template_handler ||= ::ActionView::Template.registered_template_handler(view_type)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# @return [Mutex]
|
58
|
+
def render_template_method_redefinition_lock
|
59
|
+
@render_template_method_redefinition_lock ||= ::Mutex.new
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [String]
|
63
|
+
def compiled_template_source
|
64
|
+
handler = template_handler
|
65
|
+
unless handler
|
66
|
+
raise UnknownViewTypeError,
|
67
|
+
"view type `#{view_type.inspect}` is not known in #{self}, " \
|
68
|
+
"available types: #{::ActionView::Template.template_handler_extensions.inspect}"
|
69
|
+
end
|
70
|
+
|
71
|
+
if handler.method(:call).parameters.length > 1
|
72
|
+
handler.call(self, view_template_source)
|
73
|
+
else
|
74
|
+
handler.call(
|
75
|
+
source: view_template_source,
|
76
|
+
identifier: identifier,
|
77
|
+
type: type
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
17
82
|
end
|
18
83
|
|
19
84
|
# Instance methods for rendering.
|
@@ -21,10 +86,7 @@ module ::AmberComponent
|
|
21
86
|
# @return [String]
|
22
87
|
def render(&block)
|
23
88
|
run_callbacks :render do
|
24
|
-
|
25
|
-
# styles = inject_styles
|
26
|
-
# element += styles unless styles.nil?
|
27
|
-
element.html_safe
|
89
|
+
compile_and_render(&block)
|
28
90
|
end
|
29
91
|
end
|
30
92
|
|
@@ -39,13 +101,49 @@ module ::AmberComponent
|
|
39
101
|
render
|
40
102
|
end
|
41
103
|
|
42
|
-
|
104
|
+
# @param args [Array<Object>]
|
105
|
+
# @return [String]
|
106
|
+
def nested_content(*args, &block)
|
107
|
+
block_self = block.binding.receiver
|
108
|
+
return block_self.safe_capture(*args, &block) if block_self.respond_to?(:safe_capture)
|
109
|
+
|
110
|
+
safe_capture(*args, &block)
|
111
|
+
end
|
112
|
+
alias children nested_content
|
113
|
+
|
114
|
+
def safe_capture(*args)
|
115
|
+
value = nil
|
116
|
+
buffer = with_output_buffer { value = yield(*args) }
|
117
|
+
buffer.presence || value.html_safe
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
# @return [String]
|
123
|
+
def compile_and_render(&block)
|
124
|
+
self.class.compile
|
125
|
+
if self.class.compiled?
|
126
|
+
return _run(
|
127
|
+
RENDER_TEMPLATE_METHOD_NAME,
|
128
|
+
self.class.template_handler,
|
129
|
+
[],
|
130
|
+
::ActionView::OutputBuffer.new,
|
131
|
+
&block
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
render_non_rails_string(
|
136
|
+
self.class.view_template_source,
|
137
|
+
self.class.view_type,
|
138
|
+
block
|
139
|
+
)
|
140
|
+
end
|
43
141
|
|
44
142
|
# @param content [String]
|
45
143
|
# @param type [Symbol]
|
46
144
|
# @param block [Proc, nil]
|
47
145
|
# @return [String]
|
48
|
-
def
|
146
|
+
def render_non_rails_string(content, type, block = nil)
|
49
147
|
TemplateHandler.render_from_string(self, content, type, block)
|
50
148
|
end
|
51
149
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ::AmberComponent
|
4
4
|
# Provides code which handles rendering different
|
5
|
-
# template languages.
|
5
|
+
# template languages outside of Rails.
|
6
6
|
module TemplateHandler
|
7
7
|
class << self
|
8
8
|
# @param context [AmberComponent::Base]
|
@@ -11,16 +11,15 @@ module ::AmberComponent
|
|
11
11
|
# @param block [Proc, nil]
|
12
12
|
# @return [String]
|
13
13
|
def render_from_string(context, content, type, block = nil)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
tilt_handler = ::Tilt[type]
|
15
|
+
raise UnknownViewTypeError, <<~ERR.squish unless tilt_handler
|
16
|
+
Unknown view type for `#{context.class}`!
|
17
|
+
Check return value of param type in `view type: :[type]`
|
18
|
+
or the view file extension.
|
19
|
+
ERR
|
19
20
|
|
20
|
-
|
21
|
+
tilt_handler.new { content }.render(context, &block).html_safe
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
25
|
-
|
26
|
-
require_relative 'template_handler/erb'
|
@@ -1,14 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pathname'
|
4
|
+
|
3
5
|
module ::AmberComponent
|
4
6
|
# Provides methods concerning view registering and rendering.
|
5
7
|
module Views
|
6
|
-
# View types with built-in embedded Ruby
|
7
|
-
#
|
8
|
-
# @return [Set<Symbol>]
|
9
|
-
VIEW_TYPES_WITH_RUBY = ::Set[:erb, :haml, :slim].freeze
|
10
|
-
# @return [Set<Symbol>]
|
11
|
-
ALLOWED_VIEW_TYPES = ::Set[:erb, :haml, :slim, :html, :md, :markdown].freeze
|
12
8
|
# @return [Regexp]
|
13
9
|
VIEW_FILE_REGEXP = /^view\./.freeze
|
14
10
|
|
@@ -18,28 +14,25 @@ module ::AmberComponent
|
|
18
14
|
#
|
19
15
|
# Usage:
|
20
16
|
#
|
21
|
-
# view
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# ERB
|
27
|
-
# end
|
17
|
+
# view <<~ERB
|
18
|
+
# <h1>
|
19
|
+
# Hello <%= @name %>
|
20
|
+
# </h1>
|
21
|
+
# ERB
|
28
22
|
#
|
29
23
|
# or:
|
30
24
|
#
|
31
|
-
# view :haml
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
# HAML
|
37
|
-
# end
|
25
|
+
# view <<~HAML, type: :haml
|
26
|
+
# %h1
|
27
|
+
# Hello
|
28
|
+
# = @name
|
29
|
+
# HAML
|
38
30
|
#
|
31
|
+
# @param content [String, Proc]
|
39
32
|
# @param type [Symbol]
|
40
33
|
# @return [void]
|
41
|
-
def view(type
|
42
|
-
@method_view = TypedContent.new(type: type, content:
|
34
|
+
def view(content, type: :erb)
|
35
|
+
@method_view = TypedContent.new(type: type, content: content)
|
43
36
|
end
|
44
37
|
|
45
38
|
# ERB/Haml/Slim view registered through the `view` method.
|
@@ -48,6 +41,13 @@ module ::AmberComponent
|
|
48
41
|
attr_reader :method_view
|
49
42
|
|
50
43
|
# @return [String]
|
44
|
+
def view_template_source
|
45
|
+
return @method_view.to_s if @method_view
|
46
|
+
|
47
|
+
::File.read(view_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [String, nil]
|
51
51
|
def view_path
|
52
52
|
asset_path view_file_name
|
53
53
|
end
|
@@ -62,136 +62,11 @@ module ::AmberComponent
|
|
62
62
|
|
63
63
|
# @return [Symbol]
|
64
64
|
def view_type
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
# Instance methods for views.
|
70
|
-
module InstanceMethods
|
71
|
-
protected
|
72
|
-
|
73
|
-
# @return [String]
|
74
|
-
def render_view(&block)
|
75
|
-
view_from_file = render_view_from_file(&block)
|
76
|
-
view_from_method = render_class_method_view(&block)
|
77
|
-
view_from_inline = render_view_from_inline(&block)
|
78
|
-
|
79
|
-
view_content = view_from_file unless view_from_file.empty?
|
80
|
-
view_content = view_from_method unless view_from_method.empty?
|
81
|
-
view_content = view_from_inline unless view_from_inline.empty?
|
82
|
-
|
83
|
-
if view_content.nil? || view_content.empty?
|
84
|
-
raise ViewFileNotFoundError, "View for `#{self.class}` could not be found!"
|
85
|
-
end
|
86
|
-
|
87
|
-
view_content
|
88
|
-
end
|
89
|
-
|
90
|
-
# Helper method to render view from string or with other provided type.
|
91
|
-
#
|
92
|
-
# Usage:
|
93
|
-
#
|
94
|
-
# render_view_from_content('<h1>Hello World</h1>')
|
95
|
-
#
|
96
|
-
# or:
|
97
|
-
#
|
98
|
-
# render_view_from_content content: '**Hello World**', type: 'md'
|
99
|
-
#
|
100
|
-
# @param content [TypedContent, Hash{Symbol => String, Symbol, Proc}, String]
|
101
|
-
# @return [String, nil]
|
102
|
-
def render_view_from_content(content, &block)
|
103
|
-
return '' unless content
|
104
|
-
return content if content.is_a?(::String)
|
105
|
-
|
106
|
-
content = TypedContent.wrap(content)
|
107
|
-
type = content.type
|
108
|
-
content = content.to_s
|
109
|
-
|
110
|
-
if content.empty?
|
111
|
-
raise EmptyViewError, <<~ERR.squish
|
112
|
-
Custom view for `#{self.class}` from view method cannot be empty!
|
113
|
-
ERR
|
114
|
-
end
|
115
|
-
|
116
|
-
unless ALLOWED_VIEW_TYPES.include? type
|
117
|
-
raise UnknownViewTypeError, <<~ERR.squish
|
118
|
-
Unknown view type for `#{self.class}` from view method!
|
119
|
-
Check return value of param type in `view :[type] do`
|
120
|
-
ERR
|
121
|
-
end
|
122
|
-
|
123
|
-
unless VIEW_TYPES_WITH_RUBY.include? type
|
124
|
-
# first render the content with ERB if the
|
125
|
-
# type does not support embedding Ruby by default
|
126
|
-
content = render_string(content, :erb, block)
|
127
|
-
end
|
128
|
-
|
129
|
-
render_string(content, type, block)
|
130
|
-
end
|
131
|
-
|
132
|
-
# @return [String]
|
133
|
-
def render_view_from_file(&block)
|
134
|
-
view_path = self.class.view_path
|
135
|
-
return '' if view_path.nil? || !::File.file?(view_path)
|
136
|
-
|
137
|
-
content = ::File.read(view_path)
|
138
|
-
type = self.class.view_type
|
139
|
-
|
140
|
-
unless VIEW_TYPES_WITH_RUBY.include? type
|
141
|
-
content = render_string(content, :erb, block)
|
142
|
-
end
|
143
|
-
|
144
|
-
render_string(content, type, block)
|
145
|
-
end
|
146
|
-
|
147
|
-
# Method returning view from method in class file.
|
148
|
-
# Usage:
|
149
|
-
#
|
150
|
-
# view do
|
151
|
-
# <<~HTML
|
152
|
-
# <h1>
|
153
|
-
# Hello <%= @name %>
|
154
|
-
# </h1>
|
155
|
-
# HTML
|
156
|
-
# end
|
157
|
-
#
|
158
|
-
# or:
|
159
|
-
#
|
160
|
-
# view :haml do
|
161
|
-
# <<~HAML
|
162
|
-
# %h1
|
163
|
-
# Hello
|
164
|
-
# = @name
|
165
|
-
# HAML
|
166
|
-
# end
|
167
|
-
#
|
168
|
-
# @return [String]
|
169
|
-
def render_class_method_view(&block)
|
170
|
-
render_view_from_content(self.class.method_view, &block)
|
171
|
-
end
|
172
|
-
|
173
|
-
# Method returning view from params in view.
|
174
|
-
# Usage:
|
175
|
-
#
|
176
|
-
# <%= ExampleComponent data: data, view: "<h1>Hello #{@name}</h1>" %>
|
177
|
-
#
|
178
|
-
# or:
|
179
|
-
#
|
180
|
-
# <%= ExampleComponent data: data, view: { content: "<h1>Hello #{@name}</h1>", type: 'erb' } %>
|
181
|
-
#
|
182
|
-
# @return [String]
|
183
|
-
def render_view_from_inline(&block)
|
184
|
-
data = \
|
185
|
-
if @view.is_a? ::String
|
186
|
-
TypedContent.new(
|
187
|
-
type: :erb,
|
188
|
-
content: @view
|
189
|
-
)
|
190
|
-
else
|
191
|
-
@view
|
192
|
-
end
|
65
|
+
return @method_view.type if @method_view
|
66
|
+
raise ViewFileNotFoundError, "No view file for #{self}" unless view_file_name
|
193
67
|
|
194
|
-
|
68
|
+
view_file_path = ::Pathname.new view_file_name
|
69
|
+
view_file_path.extname.delete_prefix('.').to_sym
|
195
70
|
end
|
196
71
|
end
|
197
72
|
end
|
data/lib/amber_component.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'active_support'
|
4
4
|
require 'active_support/core_ext'
|
5
5
|
require 'pathname'
|
6
|
+
require 'set'
|
6
7
|
|
7
8
|
require_relative 'amber_component/configuration'
|
8
9
|
|
@@ -11,7 +12,6 @@ module ::AmberComponent
|
|
11
12
|
class Error < ::StandardError; end
|
12
13
|
class MissingPropsError < Error; end
|
13
14
|
class IncorrectPropTypeError < Error; end
|
14
|
-
class ViewFileNotFoundError < Error; end
|
15
15
|
class InvalidTypeError < Error; end
|
16
16
|
|
17
17
|
class EmptyViewError < Error; end
|
@@ -10,14 +10,22 @@ module ::AmberComponent
|
|
10
10
|
desc 'Install the AmberComponent gem'
|
11
11
|
source_root ::File.expand_path('templates', __dir__)
|
12
12
|
|
13
|
-
# @return [Array<Symbol>]
|
14
|
-
STIMULUS_INTEGRATIONS = %i[stimulus importmap jsbundling webpack esbuild rollup].freeze
|
15
|
-
|
16
13
|
class_option :stimulus,
|
17
14
|
desc: "Configure the app to use Stimulus.js wih components to make them interactive " \
|
18
|
-
"[options: importmap (default), jsbundling, webpack, esbuild, rollup]"
|
15
|
+
"[options: importmap (default), webpacker (legacy), jsbundling, webpack, esbuild, rollup]"
|
16
|
+
|
17
|
+
class_option :styles,
|
18
|
+
desc: "Configure the app to generate components with a particular stylesheet format " \
|
19
|
+
"[options: css (default), scss, sass]"
|
20
|
+
|
21
|
+
class_option :views,
|
22
|
+
desc: "Configure the app to generate components with a particular view format " \
|
23
|
+
"[options: erb (default), haml, slim]"
|
19
24
|
|
20
25
|
def setup
|
26
|
+
detect_stimulus
|
27
|
+
detect_styles
|
28
|
+
detect_views
|
21
29
|
copy_file 'application_component.rb', 'app/components/application_component.rb'
|
22
30
|
copy_file 'application_component_test_case.rb', 'test/application_component_test_case.rb'
|
23
31
|
append_file 'test/test_helper.rb', "require_relative 'application_component_test_case'"
|
@@ -30,40 +38,107 @@ module ::AmberComponent
|
|
30
38
|
require_components_css_in 'app/assets/stylesheets/application.scss.sass'
|
31
39
|
require_components_css_in 'app/assets/stylesheets/application.sass.scss'
|
32
40
|
configure_stimulus
|
41
|
+
create_initializer
|
33
42
|
end
|
34
43
|
|
35
44
|
private
|
36
45
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
46
|
+
def detect_styles
|
47
|
+
styles_option = options[:styles]&.to_sym
|
48
|
+
if !styles_option.nil? && !Configuration::ALLOWED_STYLES.include?(styles_option)
|
49
|
+
raise ::ArgumentError, "no such `stylesheet_format` as #{styles_option.inspect}"
|
50
|
+
end
|
40
51
|
|
41
|
-
|
52
|
+
@styles =
|
53
|
+
if styles_option
|
54
|
+
styles_option
|
55
|
+
elsif defined?(::SassC)
|
56
|
+
:scss
|
57
|
+
else
|
58
|
+
:css
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def detect_views
|
63
|
+
views_option = options[:views]&.to_sym
|
64
|
+
if !views_option.nil? && !Configuration::ALLOWED_VIEWS.include?(views_option)
|
65
|
+
raise ::ArgumentError, "no such `view_format` as #{views_option.inspect}"
|
66
|
+
end
|
67
|
+
|
68
|
+
@views =
|
69
|
+
if views_option
|
70
|
+
views_option
|
71
|
+
elsif defined?(::Haml)
|
72
|
+
:haml
|
73
|
+
elsif defined?(::Slim)
|
74
|
+
:slim
|
75
|
+
else
|
76
|
+
:erb
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def detect_stimulus
|
81
|
+
stimulus_option = options[:stimulus]&.to_sym
|
82
|
+
return unless stimulus_option
|
83
|
+
|
84
|
+
case stimulus_option
|
42
85
|
when :stimulus
|
43
86
|
if defined?(::Jsbundling)
|
44
|
-
|
45
|
-
|
87
|
+
stimulus_jsbundling!
|
88
|
+
elsif defined?(::Webpacker)
|
89
|
+
stimulus_webpacker!
|
46
90
|
else
|
47
|
-
|
48
|
-
configure_stimulus_importmap
|
91
|
+
stimulus_importmap!
|
49
92
|
end
|
50
93
|
when :importmap
|
51
|
-
|
52
|
-
configure_stimulus_importmap
|
94
|
+
stimulus_importmap!
|
53
95
|
when :jsbundling, :webpack, :esbuild, :rollup
|
54
|
-
|
55
|
-
|
96
|
+
stimulus_jsbundling!
|
97
|
+
when :webpacker
|
98
|
+
stimulus_webpacker!
|
99
|
+
else
|
100
|
+
raise ::ArgumentError,
|
101
|
+
"no such stimulus integration as `#{options[:stimulus].inspect}`"
|
56
102
|
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def assert_styles
|
106
|
+
return if options[:styles].nil?
|
107
|
+
return if options[:styles].nil?
|
108
|
+
end
|
57
109
|
|
110
|
+
def configure_stimulus
|
111
|
+
case @stimulus
|
112
|
+
when :importmap then configure_stimulus_importmap
|
113
|
+
when :jsbundling then configure_stimulus_jsbundling
|
114
|
+
when :webpacker then configure_stimulus_webpacker
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def create_initializer
|
58
119
|
create_file 'config/initializers/amber_component.rb', <<~RUBY
|
59
120
|
# frozen_string_literal: true
|
60
121
|
|
61
122
|
::AmberComponent.configure do |c|
|
62
|
-
c.stimulus =
|
123
|
+
c.stimulus = #{@stimulus.inspect} # #{Configuration::STIMULUS_INTEGRATIONS.to_a}
|
124
|
+
c.stylesheet_format = #{@styles.inspect} # #{Configuration::ALLOWED_STYLES.to_a}
|
125
|
+
c.view_format = #{@views.inspect} # #{Configuration::ALLOWED_VIEWS.to_a}
|
63
126
|
end
|
64
127
|
RUBY
|
65
128
|
end
|
66
129
|
|
130
|
+
def stimulus_jsbundling!
|
131
|
+
@stimulus = :jsbundling
|
132
|
+
end
|
133
|
+
|
134
|
+
def stimulus_importmap!
|
135
|
+
@stimulus = :importmap
|
136
|
+
end
|
137
|
+
|
138
|
+
def stimulus_webpacker!
|
139
|
+
@stimulus = :webpacker
|
140
|
+
end
|
141
|
+
|
67
142
|
def configure_stimulus_importmap
|
68
143
|
install_importmap
|
69
144
|
install_stimulus
|
@@ -88,6 +163,17 @@ module ::AmberComponent
|
|
88
163
|
JS
|
89
164
|
end
|
90
165
|
|
166
|
+
def configure_stimulus_webpacker
|
167
|
+
install_stimulus
|
168
|
+
append_file 'app/javascript/packs/application.js', %(import "controllers"\n)
|
169
|
+
append_file 'app/javascript/controllers/index.js', %(import "./components"\n)
|
170
|
+
create_file 'app/javascript/controllers/components.js', <<~JS
|
171
|
+
// This file has been created by `amber_component` and will
|
172
|
+
// register all stimulus controllers from your components
|
173
|
+
import { application } from "./application"
|
174
|
+
JS
|
175
|
+
end
|
176
|
+
|
91
177
|
# @return [void]
|
92
178
|
def install_importmap
|
93
179
|
return if ::File.exist?('config/importmap.rb') && defined?(::Importmap)
|
@@ -7,33 +7,26 @@ class AmberComponentGenerator < ::Rails::Generators::NamedBase
|
|
7
7
|
desc 'Generate a new component'
|
8
8
|
source_root ::File.expand_path('templates', __dir__)
|
9
9
|
|
10
|
-
# @return [Array<Symbol>]
|
11
|
-
VIEW_FORMATS = %i[html erb haml slim].freeze
|
12
|
-
# @return [Array<Symbol>]
|
13
|
-
STYLE_FORMATS = %i[css scss sass].freeze
|
14
|
-
|
15
10
|
class_option :view,
|
16
11
|
aliases: ['-v'],
|
17
|
-
desc: "Indicate what type of view should be generated
|
12
|
+
desc: "Indicate what type of view should be generated " \
|
13
|
+
"eg. #{::AmberComponent::Configuration::ALLOWED_VIEWS}"
|
18
14
|
|
19
15
|
class_option :css,
|
20
|
-
aliases: ['--
|
21
|
-
desc: "Indicate what type of styles should be generated
|
16
|
+
aliases: ['--styles', '-c'],
|
17
|
+
desc: "Indicate what type of styles should be generated " \
|
18
|
+
"eg. #{::AmberComponent::Configuration::ALLOWED_STYLES}"
|
22
19
|
|
23
20
|
def generate_component
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@style_format = options[:css]&.to_sym
|
21
|
+
set_view_format
|
22
|
+
set_stylesheet_format
|
28
23
|
|
29
|
-
unless
|
30
|
-
|
31
|
-
return
|
24
|
+
unless ::AmberComponent::Configuration::ALLOWED_VIEWS.include? @view_format
|
25
|
+
raise ::ArgumentError, "No such view format as `#{@view_format}`"
|
32
26
|
end
|
33
27
|
|
34
|
-
|
35
|
-
|
36
|
-
return
|
28
|
+
unless ::AmberComponent::Configuration::ALLOWED_STYLES.include?(@stylesheet_format)
|
29
|
+
raise ::ArgumentError, "No such css/style format as `#{@stylesheet_format}`"
|
37
30
|
end
|
38
31
|
|
39
32
|
template 'component.rb.erb', "app/components/#{file_path}.rb"
|
@@ -53,6 +46,14 @@ class AmberComponentGenerator < ::Rails::Generators::NamedBase
|
|
53
46
|
|
54
47
|
private
|
55
48
|
|
49
|
+
def set_view_format
|
50
|
+
@view_format = options[:view]&.to_sym || ::AmberComponent.configuration.view_format || :erb
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_stylesheet_format
|
54
|
+
@stylesheet_format = options[:style]&.to_sym || ::AmberComponent.configuration.stylesheet_format || :css
|
55
|
+
end
|
56
|
+
|
56
57
|
# @return [Boolean]
|
57
58
|
def stimulus?
|
58
59
|
::AmberComponent.configuration.stimulus?
|
@@ -90,9 +91,10 @@ class AmberComponentGenerator < ::Rails::Generators::NamedBase
|
|
90
91
|
|
91
92
|
# @return [void]
|
92
93
|
def create_stylesheet
|
93
|
-
|
94
|
+
case @stylesheet_format
|
95
|
+
when :scss
|
94
96
|
template 'style.scss.erb', "app/components/#{file_path}/style.scss"
|
95
|
-
|
97
|
+
when :sass
|
96
98
|
template 'style.sass.erb', "app/components/#{file_path}/style.sass"
|
97
99
|
else
|
98
100
|
template 'style.css.erb', "app/components/#{file_path}/style.css"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amber_component
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruby-Amber
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2023-01-25 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: actionview
|
@@ -123,7 +123,6 @@ files:
|
|
123
123
|
- lib/amber_component/railtie.rb
|
124
124
|
- lib/amber_component/rendering.rb
|
125
125
|
- lib/amber_component/template_handler.rb
|
126
|
-
- lib/amber_component/template_handler/erb.rb
|
127
126
|
- lib/amber_component/test_helper.rb
|
128
127
|
- lib/amber_component/typed_content.rb
|
129
128
|
- lib/amber_component/version.rb
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'action_view'
|
4
|
-
require 'ostruct'
|
5
|
-
|
6
|
-
module ::AmberComponent
|
7
|
-
module TemplateHandler
|
8
|
-
# Handles rendering ERB with Rails-like syntax
|
9
|
-
class ERB < ::ActionView::Template::Handlers::ERB::Erubi
|
10
|
-
def initialize(input, properties = {})
|
11
|
-
properties[:bufvar] ||= "@output_buffer"
|
12
|
-
properties[:preamble] = "#{properties[:bufvar]}=#{::ActionView::OutputBuffer}.new;"
|
13
|
-
super
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|