amber_component 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -1
  5. data/CONTRIBUTING.md +87 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +16 -91
  8. data/README.md +25 -42
  9. data/Rakefile +17 -1
  10. data/amber_component.gemspec +4 -2
  11. data/banner.png +0 -0
  12. data/docs/.bundle/config +2 -0
  13. data/docs/.gitignore +5 -0
  14. data/docs/404.html +25 -0
  15. data/docs/Gemfile +37 -0
  16. data/docs/Gemfile.lock +89 -0
  17. data/docs/README.md +19 -0
  18. data/docs/_config.yml +148 -0
  19. data/docs/_data/amber_component.yml +3 -0
  20. data/docs/_sass/_variables.scss +2 -0
  21. data/docs/_sass/color_schemes/amber_component.scss +11 -0
  22. data/docs/_sass/custom/custom.scss +60 -0
  23. data/docs/api/index.md +8 -0
  24. data/docs/assets/images/logo_wide.png +0 -0
  25. data/docs/changelog/index.md +8 -0
  26. data/docs/favicon.ico +0 -0
  27. data/docs/getting_started/index.md +8 -0
  28. data/docs/getting_started/installation.md +7 -0
  29. data/docs/getting_started/ruby_support.md +7 -0
  30. data/docs/getting_started/wireframes.md +7 -0
  31. data/docs/index.md +17 -0
  32. data/docs/introduction/basic_usage.md +7 -0
  33. data/docs/introduction/index.md +8 -0
  34. data/docs/introduction/why_amber_component.md +7 -0
  35. data/docs/resources/index.md +8 -0
  36. data/docs/styles/index.md +8 -0
  37. data/docs/styles/usage.md +7 -0
  38. data/docs/views/index.md +8 -0
  39. data/docs/views/usage.md +7 -0
  40. data/icon.png +0 -0
  41. data/lib/amber_component/assets.rb +59 -0
  42. data/lib/amber_component/base.rb +66 -434
  43. data/lib/amber_component/helpers/class_helper.rb +22 -0
  44. data/lib/amber_component/helpers/component_helper.rb +18 -0
  45. data/lib/amber_component/helpers/css_helper.rb +25 -0
  46. data/lib/amber_component/helpers.rb +11 -0
  47. data/lib/amber_component/railtie.rb +21 -0
  48. data/lib/amber_component/rendering.rb +53 -0
  49. data/lib/amber_component/template_handler/erb.rb +17 -0
  50. data/lib/amber_component/template_handler.rb +26 -0
  51. data/lib/amber_component/version.rb +1 -1
  52. data/lib/amber_component/views.rb +198 -0
  53. data/lib/amber_component.rb +6 -2
  54. data/lib/generators/amber_component/install_generator.rb +23 -0
  55. data/lib/generators/amber_component/templates/application_component.rb +13 -0
  56. data/lib/generators/amber_component_generator.rb +24 -0
  57. data/lib/generators/templates/component.rb.erb +9 -0
  58. data/lib/generators/templates/component_test.rb.erb +9 -0
  59. data/lib/generators/templates/style.css.erb +3 -0
  60. data/lib/generators/templates/view.html.erb +3 -0
  61. metadata +85 -19
  62. data/.kanbn/index.md +0 -23
  63. data/.kanbn/tasks/add-instance-variables-to-view-when-block-given-markdown.md +0 -9
  64. data/.kanbn/tasks/bind-clas-to-action-view-method-call-example-component-data-data-without-calling-any-method.md +0 -9
  65. data/.kanbn/tasks/bind-scoped-css-to-head-of-doc.md +0 -10
  66. data/.kanbn/tasks/check-if-we-need-full-rails-gem-pack.md +0 -9
  67. data/.kanbn/tasks/simple-proto.md +0 -10
  68. data/.kanbn/tasks/verify-if-template-is-haml-or-erb.md +0 -9
  69. data/PLANS.md +0 -17
  70. data/lib/amber_component/helper.rb +0 -8
  71. data/lib/amber_component/style_injector.rb +0 -52
  72. data/sig/amber_components.rbs +0 -4
@@ -3,226 +3,102 @@
3
3
  require 'set'
4
4
  require 'erb'
5
5
  require 'tilt'
6
- require 'active_model/callbacks'
7
6
  require 'memery'
7
+ require 'active_model/callbacks'
8
+ require 'action_view'
8
9
 
9
- require_relative './style_injector'
10
-
11
- # Abstract class which serves as a base
12
- # for all Amber Components.
13
- #
14
- # There are a few life cycle callbacks that can be defined.
15
- # The same way as in `ActiveRecord` models and `ActionController` controllers.
16
- #
17
- # - before_render
18
- # - around_render
19
- # - after_render
20
- # - before_initialize
21
- # - around_initialize
22
- # - after_initialize
23
- #
24
- # class ButtonComponent < ::AmberComponent::Base
25
- # # You can provide a Symbol of the method that should be called
26
- # before_render :before_render_method
27
- # # Or provide a block that will be executed
28
- # after_initialize do
29
- # # Your code here
30
- # end
31
- #
32
- # def before_render_method
33
- # # Your code here
34
- # end
35
- # end
36
- #
37
- #
38
- # @abstract Create a subclass to define a new component.
39
10
  module ::AmberComponent
40
- class Base # :nodoc:
11
+ # Abstract class which serves as a base
12
+ # for all Amber Components.
13
+ #
14
+ # There are a few life cycle callbacks that can be defined.
15
+ # The same way as in `ActiveRecord` models and `ActionController` controllers.
16
+ #
17
+ # - before_render
18
+ # - around_render
19
+ # - after_render
20
+ # - before_initialize
21
+ # - around_initialize
22
+ # - after_initialize
23
+ #
24
+ # class ButtonComponent < ::AmberComponent::Base
25
+ # # You can provide a Symbol of the method that should be called
26
+ # before_render :before_render_method
27
+ # # Or provide a block that will be executed
28
+ # after_initialize do
29
+ # # Your code here
30
+ # end
31
+ #
32
+ # def before_render_method
33
+ # # Your code here
34
+ # end
35
+ # end
36
+ #
37
+ #
38
+ # @abstract Create a subclass to define a new component.
39
+ class Base < ::ActionView::Base
40
+ # for defining callback such as `after_initialize`
41
41
  extend ::ActiveModel::Callbacks
42
+ extend Helpers::ClassHelper
42
43
 
43
- include Helper
44
-
45
- # @return [Regexp]
46
- VIEW_FILE_REGEXP = /^view\./.freeze
47
- # @return [Regexp]
48
- STYLE_FILE_REGEXP = /^style\./.freeze
49
-
50
- # View types with built-in embedded Ruby
51
- #
52
- # @return [Set<Symbol>]
53
- VIEW_TYPES_WITH_RUBY = ::Set[:erb, :haml, :slim].freeze
54
- # @return [Set<Symbol>]
55
- ALLOWED_VIEW_TYPES = ::Set[:erb, :haml, :slim, :html, :md, :markdown].freeze
56
- # @return [Set<Symbol>]
57
- ALLOWED_STYLE_TYPES = ::Set[:sass, :scss, :less].freeze
44
+ include Helpers::CssHelper
45
+ include Views::InstanceMethods
46
+ extend Views::ClassMethods
47
+ include Assets::InstanceMethods
48
+ extend Assets::ClassMethods
49
+ include Rendering::InstanceMethods
50
+ extend Rendering::ClassMethods
58
51
 
59
52
  class << self
60
53
  include ::Memery
61
54
 
62
- # @param kwargs [Hash{Symbol => Object}]
63
- # @return [String]
64
- def run(**kwargs, &block)
65
- comp = new(**kwargs)
66
-
67
- comp.render(&block)
68
- end
69
-
70
- alias call run
71
-
72
-
73
- # @return [String]
74
- memoize def asset_dir_path
75
- class_const_name = name.split('::').last
76
- component_file_path, = module_parent.const_source_location(class_const_name)
77
-
78
- component_file_path.delete_suffix('.rb')
79
- end
80
-
81
- # @return [String]
82
- def view_path
83
- asset_path view_file_name
84
- end
85
-
86
- # @return [String, nil]
87
- def view_file_name
88
- files = asset_file_names(VIEW_FILE_REGEXP)
89
- raise MultipleViews, "More than one view file for `#{name}` found!" if files.length > 1
90
-
91
- files.first
92
- end
93
-
94
- # @return [Symbol]
95
- def view_type
96
- (view_file_name.split('.')[1..].reject { _1.match?(/erb/) }.last || 'erb')&.to_sym
97
- end
98
-
99
- # @return [String]
100
- def style_path
101
- asset_path style_file_name
102
- end
103
-
104
- # @return [String, nil]
105
- def style_file_name
106
- files = asset_file_names(STYLE_FILE_REGEXP)
107
- raise MultipleStyles, "More than one style file for `#{name}` found!" if files.length > 1
108
-
109
- files.first
110
- end
111
-
112
- # @return [Symbol]
113
- def style_type
114
- (style_file_name.split('.')[1..].reject { _1.match?(/erb/) }.last || 'erb')&.to_sym
115
- end
55
+ memoize :asset_dir_path
116
56
 
117
57
  # Memoize these methods in production
118
- if defined?(::Rails) && ::Rails.env.production?
58
+ if ::ENV['RAILS_ENV'] == 'production'
119
59
  memoize :view_path
120
60
  memoize :view_file_name
121
61
  memoize :view_type
122
-
123
- memoize :style_path
124
- memoize :style_file_name
125
- memoize :style_type
126
- end
127
-
128
- # Register an inline view by returning a String from the passed block.
129
- #
130
- # Usage:
131
- #
132
- # view do
133
- # <<~ERB
134
- # <h1>
135
- # Hello <%= @name %>
136
- # </h1>
137
- # ERB
138
- # end
139
- #
140
- # or:
141
- #
142
- # view :haml do
143
- # <<~HAML
144
- # %h1
145
- # Hello
146
- # = @name
147
- # HAML
148
- # end
149
- #
150
- # @param type [Symbol]
151
- # @return [void]
152
- def view(type = :erb, &block)
153
- @method_view = TypedContent.new(type: type, content: block)
154
- end
155
-
156
- # ERB/Haml/Slim view registered through the `view` method.
157
- #
158
- # @return [TypedContent]
159
- attr_reader :method_view
160
-
161
- # Register an inline style by returning a String from the passed block.
162
- #
163
- # Usage:
164
- #
165
- # style do
166
- # '.my-class { color: red; }'
167
- # end
168
- #
169
- # or:
170
- #
171
- # style :sass do
172
- # <<~SASS
173
- # .my-class
174
- # color: red
175
- # SASS
176
- # end
177
- #
178
- # @param type [Symbol]
179
- # @return [void]
180
- def style(type = :css, &block)
181
- @method_style = TypedContent.new(type: type, content: block)
182
62
  end
183
63
 
184
- # CSS/SCSS/Sass styles registered through the `style` method.
185
- #
186
- # @return [TypedContent]
187
- attr_reader :method_style
188
-
189
64
  private
190
65
 
191
66
  # @param subclass [Class]
192
67
  # @return [void]
193
68
  def inherited(subclass)
69
+ super
194
70
  # @type [Module]
195
- parent_module = subclass.module_parent
196
71
  method_body = proc do |**kwargs, &block|
197
- subclass.run(**kwargs, &block)
72
+ subclass.render(**kwargs, &block)
198
73
  end
74
+ parent_module = subclass.module_parent
199
75
 
200
- Helper.define_method(subclass.name, &method_body) && return if parent_module.equal? ::Object
201
-
202
- parent_module.define_singleton_method(subclass.name.split('::').last, &method_body)
203
- end
204
-
205
- # @param file_name [String, nil]
206
- # @return [String, nil]
207
- def asset_path(file_name)
208
- return unless file_name
76
+ if parent_module.equal?(::Object)
77
+ method_name = subclass.name
78
+ define_helper_method(subclass, Helpers::ComponentHelper, method_name, method_body)
79
+ define_helper_method(subclass, Helpers::ComponentHelper, method_name.underscore, method_body)
80
+ return
81
+ end
209
82
 
210
- ::File.join(asset_dir_path, file_name)
83
+ method_name = subclass.const_name
84
+ define_helper_method(subclass, parent_module.singleton_class, method_name, method_body)
85
+ define_helper_method(subclass, parent_module.singleton_class, method_name.underscore, method_body)
211
86
  end
212
87
 
213
- # Returns the name of the file inside the asset directory
214
- # of this component that matches the provided `Regexp`
215
- #
216
- # @param type_regexp [Regexp]
217
- # @return [Array<String>]
218
- def asset_file_names(type_regexp)
219
- return [] unless ::File.directory?(asset_dir_path)
88
+ # @param component [Class]
89
+ # @param mod [Module, Class]
90
+ # @param method_name [String, Symbol]
91
+ # @param body [Proc]
92
+ def define_helper_method(component, mod, method_name, body)
93
+ mod.define_method(method_name, &body)
220
94
 
221
- ::Dir.entries(asset_dir_path).select do |file|
222
- next unless ::File.file?(::File.join(asset_dir_path, file))
95
+ return if ::ENV['RAILS_ENV'] == 'production'
223
96
 
224
- file.match? type_regexp
225
- end
97
+ ::Warning.warn <<~WARN if mod.instance_methods.include?(method_name)
98
+ #{caller(0, 1).first}: warning:
99
+ `#{component}` shadows the name of an already existing `#{mod}` method `#{method_name}`.
100
+ Consider renaming this component, because the original method will be overwritten.
101
+ WARN
226
102
  end
227
103
  end
228
104
 
@@ -235,20 +111,6 @@ module ::AmberComponent
235
111
  end
236
112
  end
237
113
 
238
- # @return [String]
239
- def render(&block)
240
- run_callbacks :render do
241
- element = inject_views(&block)
242
- styles = inject_styles
243
- element += styles unless styles.nil?
244
- element.html_safe
245
- end
246
- end
247
-
248
- def render_in(context)
249
- byebug
250
- end
251
-
252
114
  private
253
115
 
254
116
  # @param kwargs [Hash{Symbol => Object}]
@@ -258,235 +120,5 @@ module ::AmberComponent
258
120
  instance_variable_set("@#{key}", value)
259
121
  end
260
122
  end
261
-
262
- # Helper method to render view from string or with other provided type.
263
- #
264
- # Usage:
265
- #
266
- # render_custom_view('<h1>Hello World</h1>')
267
- #
268
- # or:
269
- #
270
- # render_custom_view content: '**Hello World**', type: 'md'
271
- #
272
- # @param style [TypedContent, Hash{Symbol => String, Symbol, Proc}, String]
273
- # @return [String, nil]
274
- def render_custom_view(view, &block)
275
- return '' unless view
276
- return view if view.is_a?(::String)
277
-
278
- view = TypedContent.wrap(view)
279
- type = view.type
280
- content = view.to_s
281
-
282
- if content.empty?
283
- raise EmptyView, <<~ERR.squish
284
- Custom view for `#{self.class}` from view method cannot be empty!
285
- ERR
286
- end
287
-
288
- unless ALLOWED_VIEW_TYPES.include? type
289
- raise UnknownViewType, <<~ERR.squish
290
- Unknown view type for `#{self.class}` from view method!
291
- Check return value of param type in `view :[type] do`
292
- ERR
293
- end
294
-
295
- unless VIEW_TYPES_WITH_RUBY.include? type
296
- # first render the content with ERB if the
297
- # type does not support embedding Ruby by default
298
- content = render_string(content, :erb, block)
299
- end
300
-
301
- render_string(content, type, block)
302
- end
303
-
304
- # @return [String]
305
- def render_view_from_file(&block)
306
- view_path = self.class.view_path
307
- return '' if view_path.nil? || !::File.file?(view_path)
308
-
309
- content = ::File.read(view_path)
310
- type = self.class.view_type
311
-
312
- unless VIEW_TYPES_WITH_RUBY.include? type
313
- content = render_string(content, :erb, block)
314
- end
315
-
316
- render_string(content, type, block)
317
- end
318
-
319
- # Method returning view from method in class file.
320
- # Usage:
321
- #
322
- # view do
323
- # <<~HTML
324
- # <h1>
325
- # Hello <%= @name %>
326
- # </h1>
327
- # HTML
328
- # end
329
- #
330
- # or:
331
- #
332
- # view :haml do
333
- # <<~HAML
334
- # %h1
335
- # Hello
336
- # = @name
337
- # HAML
338
- # end
339
- #
340
- # @return [String]
341
- def render_class_method_view(&block)
342
- render_custom_view(self.class.method_view, &block)
343
- end
344
-
345
- # Method returning view from params in view.
346
- # Usage:
347
- #
348
- # <%= ExampleComponent data: data, view: "<h1>Hello #{@name}</h1>" %>
349
- #
350
- # or:
351
- #
352
- # <%= ExampleComponent data: data, view: { content: "<h1>Hello #{@name}</h1>", type: 'erb' } %>
353
- #
354
- # @return [String]
355
- def render_view_from_inline(&block)
356
- data = \
357
- if @view.is_a? String
358
- TypedContent.new(
359
- type: :erb,
360
- content: @view
361
- )
362
- else
363
- @view
364
- end
365
-
366
- render_custom_view(data, &block)
367
- end
368
-
369
- # @return [String]
370
- def inject_views(&block)
371
- view_from_file = render_view_from_file(&block)
372
- view_from_method = render_class_method_view(&block)
373
- view_from_inline = render_view_from_inline(&block)
374
-
375
- view_content = view_from_file unless view_from_file.empty?
376
- view_content = view_from_method unless view_from_method.empty?
377
- view_content = view_from_inline unless view_from_inline.empty?
378
-
379
- if view_content.nil? || view_content.empty?
380
- raise ViewFileNotFound, "View for `#{self.class}` could not be found!"
381
- end
382
-
383
- view_content
384
- end
385
-
386
- # Helper method to render style from css string or with other provided type.
387
- #
388
- # Usage:
389
- #
390
- # render_custom_style('.my-class { color: red; }')
391
- #
392
- # or:
393
- #
394
- # render_custom_style style: '.my-class { color: red; }', type: 'sass'
395
- #
396
- # @param style [TypedContent, Hash{Symbol => Symbol, String, Proc}, String]
397
- # @return [String, nil]
398
- def render_custom_style(style)
399
- return '' unless style
400
- return style if style.is_a?(::String)
401
-
402
- style = TypedContent.wrap(style)
403
- type = style.type
404
- content = style.to_s
405
-
406
- if content.empty?
407
- raise EmptyStyle, <<~ERR.squish
408
- Custom style for `#{self.class}` from style method cannot be empty!
409
- ERR
410
- end
411
-
412
- unless ALLOWED_STYLE_TYPES.include? type
413
- raise UnknownStyleType, <<~ERR.squish
414
- Unknown style type for `#{self.class}` from style method!
415
- Check return value of param type in `style :[type] do`
416
- ERR
417
- end
418
-
419
- # first render the content with ERB
420
- content = render_string(content, :erb)
421
-
422
- render_string(content, type)
423
- end
424
-
425
- # Method returning style from file (style.(css|sass|scss|less)) if exists.
426
- #
427
- # @return [String]
428
- def render_style_from_file
429
- style_path = self.class.style_path
430
- return '' unless style_path
431
-
432
- content = ::File.read(style_path)
433
- type = self.class.style_type
434
-
435
- return content if type == :css
436
-
437
- content = render_string(content, :erb)
438
- render_string(content, type)
439
- end
440
-
441
- # Method returning style from method in class file.
442
- # Usage:
443
- #
444
- # style do
445
- # '.my-class { color: red; }'
446
- # end
447
- #
448
- # or:
449
- #
450
- # style :sass do
451
- # <<~SASS
452
- # .my-class
453
- # color: red
454
- # SASS
455
- # end
456
- #
457
- # @return [String]
458
- def render_class_method_style
459
- render_custom_style(self.class.method_style)
460
- end
461
-
462
- # Method returning style from params in view.
463
- # Usage:
464
- #
465
- # <%= ExampleComponent data: data, style: '.my-class { color: red; }' %>
466
- #
467
- # or:
468
- #
469
- # <%= ExampleComponent data: data, style: {style: '.my-class { color: red; }', type: 'sass'} %>
470
- #
471
- # @return [String]
472
- def render_style_from_inline
473
- render_custom_style(@style)
474
- end
475
-
476
- # @param content [String]
477
- # @param type [Symbol]
478
- # @param block [Proc, nil]
479
- # @return [String]
480
- def render_string(content, type, block = nil)
481
- ::Tilt[type].new { content }.render(self, &block)
482
- end
483
-
484
- # @return [String]
485
- def inject_styles
486
- style_content = render_style_from_file + render_class_method_style + render_style_from_inline
487
- return if style_content.empty?
488
-
489
- ::AmberComponent::StyleInjector.inject(style_content)
490
- end
491
123
  end
492
124
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ::AmberComponent
4
+ module Helpers
5
+ # Adds class-specific utilities.
6
+ module ClassHelper
7
+ # Name of the constant this class/module is saved in (in the parent module).
8
+ #
9
+ # @return [String]
10
+ def const_name
11
+ name.split('::').last
12
+ end
13
+
14
+ # Get the exact place where this class/module has been defined.
15
+ #
16
+ # @return [Array(String, Integer), Array(Boolean, Integer)] File path followed by line number.
17
+ def source_location
18
+ module_parent.const_source_location const_name
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
5
+ module ::AmberComponent
6
+ module Helpers
7
+ # Contains methods for quickly rendering
8
+ # components defined under the root namespace `Object`.
9
+ module ComponentHelper
10
+ end
11
+ end
12
+ end
13
+
14
+ class ::ActionView::Base
15
+ # Add those convenience methods to all
16
+ # controllers and views.
17
+ include ::AmberComponent::Helpers::ComponentHelper
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_view'
4
+
5
+ module ::AmberComponent
6
+ module Helpers
7
+ # Adds a few utility methods for working with CSS
8
+ # inside components.
9
+ module CssHelper
10
+ # Helper method which creates a name for a css class or id
11
+ # which is scoped to the current component class.
12
+ #
13
+ # self.class #=> Navigation::DropdownMenuComponent
14
+ # css_id(:list_item) #=> "navigation-dropdown_menu_component--list_item"
15
+ #
16
+ # @param name [String, Symbol]
17
+ # @return [String]
18
+ def css_identifier(name)
19
+ "#{self.class.name.underscore.gsub('/', '-')}--#{name.to_s.underscore}"
20
+ end
21
+
22
+ alias css_id css_identifier
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ::AmberComponent
4
+ # Contains all helpers added by `amber_component`
5
+ module Helpers
6
+ end
7
+ end
8
+
9
+ require_relative 'helpers/component_helper'
10
+ require_relative 'helpers/class_helper'
11
+ require_relative 'helpers/css_helper'
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ::AmberComponent
4
+ # Class which hooks into Rails
5
+ # and configures the application.
6
+ class Railtie < ::Rails::Railtie
7
+ initializer 'amber_component.initialization' do |app|
8
+ app.config.assets.paths << (app.root / 'app' / 'components')
9
+
10
+ next if ::Rails.env.production?
11
+
12
+ components_root = app.root / 'app' / 'components'
13
+ component_paths = ::Dir[components_root / '**' / '*.rb']
14
+ app.config.eager_load_paths += component_paths
15
+
16
+ ::ActiveSupport::Reloader.to_prepare do
17
+ component_paths.each { |file| require_dependency(components_root / file) }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ::AmberComponent
4
+ # Provides universal methods for rendering components.
5
+ module Rendering
6
+ # Class methods for rendering.
7
+ module ClassMethods
8
+ # @param kwargs [Hash{Symbol => Object}]
9
+ # @return [String]
10
+ def render(**kwargs, &block)
11
+ comp = new(**kwargs)
12
+
13
+ comp.render(&block)
14
+ end
15
+
16
+ alias call render
17
+ end
18
+
19
+ # Instance methods for rendering.
20
+ module InstanceMethods
21
+ # @return [String]
22
+ def render(&block)
23
+ run_callbacks :render do
24
+ element = render_view(&block)
25
+ # styles = inject_styles
26
+ # element += styles unless styles.nil?
27
+ element.html_safe
28
+ end
29
+ end
30
+
31
+ # Method used internally by Rails to render an object
32
+ # passed to the `render` method.
33
+ #
34
+ # render MyComponent.new(some: :attribute)
35
+ #
36
+ # @param _context [ActionView::Base]
37
+ # @return [String]
38
+ def render_in(_context)
39
+ render
40
+ end
41
+
42
+ protected
43
+
44
+ # @param content [String]
45
+ # @param type [Symbol]
46
+ # @param block [Proc, nil]
47
+ # @return [String]
48
+ def render_string(content, type, block = nil)
49
+ TemplateHandler.render_from_string(self, content, type, block)
50
+ end
51
+ end
52
+ end
53
+ end