hanami-view 2.3.0 → 3.0.0.rc1

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.
data/lib/hanami/view.rb CHANGED
@@ -22,7 +22,6 @@ module Hanami
22
22
  # @since 2.1.0
23
23
  class View
24
24
  # @api private
25
- # @since 2.1.0
26
25
  def self.gem_loader
27
26
  @gem_loader ||= Zeitwerk::Loader.new.tap do |loader|
28
27
  root = File.expand_path("..", __dir__)
@@ -31,13 +30,13 @@ module Hanami
31
30
  loader.ignore(
32
31
  "#{root}/hanami-view.rb",
33
32
  "#{root}/hanami/view/version.rb",
34
- "#{root}/hanami/view/errors.rb",
33
+ "#{root}/hanami/view/errors.rb"
35
34
  )
36
35
  loader.inflector = Zeitwerk::GemInflector.new("#{root}/hanami-view.rb")
37
36
  loader.inflector.inflect(
38
37
  "erb" => "ERB",
39
38
  "html" => "HTML",
40
- "html_safe_string_buffer" => "HTMLSafeStringBuffer",
39
+ "html_safe_string_buffer" => "HTMLSafeStringBuffer"
41
40
  )
42
41
  end
43
42
  end
@@ -45,7 +44,6 @@ module Hanami
45
44
  gem_loader.setup
46
45
 
47
46
  # @api private
48
- # @since 2.1.0
49
47
  DEFAULT_RENDERER_OPTIONS = {default_encoding: "utf-8"}.freeze
50
48
 
51
49
  include Dry::Equalizer(:config, :exposures)
@@ -235,6 +233,23 @@ module Hanami
235
233
  # @!scope class
236
234
  setting :inflector, default: Dry::Inflector.new
237
235
 
236
+ # @overload config.decorate_exposures=(value)
237
+ # Controls whether exposures are decorated by default.
238
+ #
239
+ # When set to `true`, all exposures will be decorated with matching Parts unless explicitly
240
+ # marked with `decorate: false`.
241
+ #
242
+ # When set to `false` (the default), exposures will not be decorated unless explicitly marked
243
+ # with `decorate: true`, or declared with `decorate`.
244
+ #
245
+ # Defaults to `false`.
246
+ #
247
+ # @param value [Boolean] whether to decorate exposures by default
248
+ # @api public
249
+ # @since x.x.x
250
+ # @!scope class
251
+ setting :decorate_exposures, default: false
252
+
238
253
  # @overload config.renderer_options=(options)
239
254
  # A hash of options to pass to the template engine. Template engines are
240
255
  # provided by Tilt; see Tilt's documentation for what options your
@@ -273,7 +288,6 @@ module Hanami
273
288
  # @!endgroup
274
289
 
275
290
  # @api private
276
- # @since 2.1.0
277
291
  def self.inherited(klass)
278
292
  super
279
293
 
@@ -288,13 +302,13 @@ module Hanami
288
302
  # @param options [Hash] the exposure's options
289
303
  # @option options [Boolean] :layout expose this value to the layout (defaults to false)
290
304
  # @option options [Boolean] :decorate decorate this value in a matching Part (defaults to
291
- # true)
305
+ # false, or the value of `config.decorate_exposures`)
292
306
  # @option options [Symbol, Class] :as an alternative name or class to use when finding a
293
307
  # matching Part
294
308
 
295
309
  # @overload expose(name, **options, &block)
296
310
  # Define a value to be passed to the template. The return value of the
297
- # block will be decorated by a matching Part and passed to the template.
311
+ # block will be passed to the template.
298
312
  #
299
313
  # The block will be evaluated with the view instance as its `self`. The
300
314
  # block's parameters will determine what it is given:
@@ -329,8 +343,8 @@ module Hanami
329
343
  #
330
344
  # @overload expose(name, **options)
331
345
  # Define a value to be passed to the template, provided by an instance
332
- # method matching the name. The method's return value will be decorated by
333
- # a matching Part and passed to the template.
346
+ # method matching the name. The method's return value will be passed to
347
+ # the template.
334
348
  #
335
349
  # The method's parameters will determine what it is given:
336
350
  #
@@ -342,7 +356,7 @@ module Hanami
342
356
  # default values for these parameters to make the corresponding input
343
357
  # keys optional
344
358
  # - To receive the Context object, provide a `context:` keyword parameter
345
- # - To receive the view's input arguments in their entirey, provide a
359
+ # - To receive the view's input arguments in their entirety, provide a
346
360
  # keywords splat parameter (i.e. `**input`)
347
361
  #
348
362
  # @example Accessing input arguments
@@ -369,8 +383,8 @@ module Hanami
369
383
  #
370
384
  # @overload expose(name, **options)
371
385
  # Define a single value to pass through from the input data (when there is
372
- # no instance method matching the `name`). This value will be decorated by
373
- # a matching Part and passed to the template.
386
+ # no instance method matching the `name`). This value will be passed to
387
+ # the template.
374
388
  #
375
389
  # @param name [Symbol] name for the exposure
376
390
  # @macro exposure_options
@@ -380,7 +394,7 @@ module Hanami
380
394
  # @overload expose(*names, **options)
381
395
  # Define multiple values to pass through from the input data (when there
382
396
  # is no instance methods matching their names). These values will be
383
- # decorated by matching Parts and passed through to the template.
397
+ # passed through to the template.
384
398
  #
385
399
  # The provided options will be applied to all the exposures.
386
400
  #
@@ -411,12 +425,23 @@ module Hanami
411
425
  expose(*names, **options, private: true, &block)
412
426
  end
413
427
 
428
+ # Defines an exposure that will be decorated with a matching Part.
429
+ #
430
+ # This is a shorthand for `expose(..., decorate: true)`.
431
+ #
432
+ # @see expose
433
+ #
434
+ # @api public
435
+ # @since 2.1.0
436
+ def self.decorate(*names, **options, &block)
437
+ expose(*names, **options, decorate: true, &block)
438
+ end
439
+
414
440
  # Returns the defined exposures. These are unbound, since bound exposures
415
441
  # are only created when initializing a View instance.
416
442
  #
417
443
  # @return [Exposures]
418
444
  # @api private
419
- # @since 2.1.0
420
445
  def self.exposures
421
446
  @exposures ||= Exposures.new
422
447
  end
@@ -512,13 +537,6 @@ module Hanami
512
537
  # @!endgroup
513
538
 
514
539
  # @api private
515
- # @since 2.1.0
516
- def self.layout_path(layout)
517
- File.join(*[config.layouts_dir, layout].compact)
518
- end
519
-
520
- # @api private
521
- # @since 2.1.0
522
540
  def self.cache
523
541
  Cache
524
542
  end
@@ -534,6 +552,7 @@ module Hanami
534
552
  self.class.config.finalize!
535
553
  ensure_config
536
554
 
555
+ @config_data = config.to_data
537
556
  @exposures = self.class.exposures.bind(self)
538
557
  end
539
558
 
@@ -550,8 +569,7 @@ module Hanami
550
569
  # @return [Exposures]
551
570
  #
552
571
  # @api private
553
- # @since 2.1.0
554
- def exposures
572
+ def exposures # rubocop:disable Style/TrivialAccessors
555
573
  @exposures
556
574
  end
557
575
 
@@ -566,16 +584,20 @@ module Hanami
566
584
  #
567
585
  # @api public
568
586
  # @since 2.1.0
569
- def call(format: config.default_format, context: config.default_context, layout: config.layout, **input)
587
+ def call(format: config_data.default_format,
588
+ context: config_data.default_context,
589
+ layout: config_data.layout,
590
+ **input)
570
591
  rendering = self.rendering(format: format, context: context)
592
+ scope_class = config_data.scope
571
593
 
572
594
  locals = locals(rendering, input)
573
- output = rendering.template(config.template, rendering.scope(config.scope, locals))
595
+ output = rendering.template(config_data.template, rendering.scope(scope_class, locals))
574
596
 
575
597
  if layout
576
598
  output = rendering.template(
577
- self.class.layout_path(layout),
578
- rendering.scope(config.scope, layout_locals(locals))
599
+ layout_path(layout),
600
+ rendering.scope(scope_class, layout_locals(locals))
579
601
  ) { output }
580
602
  end
581
603
 
@@ -583,13 +605,18 @@ module Hanami
583
605
  end
584
606
 
585
607
  # @api private
586
- # @since 2.1.0
587
- def rendering(format: config.default_format, context: config.default_context)
588
- Rendering.new(config: config, format: format, context: context)
608
+ def rendering(format: config_data.default_format, context: config_data.default_context)
609
+ Rendering.new(config_data:, format:, context:)
589
610
  end
590
611
 
591
612
  private
592
613
 
614
+ # Frozen Data snapshot of the view's resolved configuration values.
615
+ # Used for fast hot-path reads during rendering.
616
+ #
617
+ # @api private
618
+ attr_reader :config_data
619
+
593
620
  def ensure_config
594
621
  raise UndefinedConfigError, :paths unless Array(config.paths).any?
595
622
  raise UndefinedConfigError, :template unless config.template
@@ -597,7 +624,7 @@ module Hanami
597
624
 
598
625
  def locals(rendering, input)
599
626
  exposures.(context: rendering.context, **input) do |value, exposure|
600
- if exposure.decorate? && value
627
+ if exposure.decorate?(default: config_data.decorate_exposures) && value
601
628
  rendering.part(exposure.name, value, as: exposure.options[:as])
602
629
  else
603
630
  value
@@ -605,6 +632,11 @@ module Hanami
605
632
  end
606
633
  end
607
634
 
635
+ # @api private
636
+ def layout_path(layout)
637
+ File.join(*[config_data.layouts_dir, layout].compact)
638
+ end
639
+
608
640
  def layout_locals(locals)
609
641
  locals.each_with_object({}) do |(key, value), layout_locals|
610
642
  layout_locals[key] = value if exposures[key].for_layout?
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-view
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 3.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hanakai team
8
- bindir: bin
8
+ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '1.0'
18
+ version: '1.4'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '1.0'
25
+ version: '1.4'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: dry-core
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -105,57 +105,19 @@ dependencies:
105
105
  - - "~>"
106
106
  - !ruby/object:Gem::Version
107
107
  version: '2.6'
108
- - !ruby/object:Gem::Dependency
109
- name: bundler
110
- requirement: !ruby/object:Gem::Requirement
111
- requirements:
112
- - - ">="
113
- - !ruby/object:Gem::Version
114
- version: '0'
115
- type: :development
116
- prerelease: false
117
- version_requirements: !ruby/object:Gem::Requirement
118
- requirements:
119
- - - ">="
120
- - !ruby/object:Gem::Version
121
- version: '0'
122
- - !ruby/object:Gem::Dependency
123
- name: rake
124
- requirement: !ruby/object:Gem::Requirement
125
- requirements:
126
- - - ">="
127
- - !ruby/object:Gem::Version
128
- version: '0'
129
- type: :development
130
- prerelease: false
131
- version_requirements: !ruby/object:Gem::Requirement
132
- requirements:
133
- - - ">="
134
- - !ruby/object:Gem::Version
135
- version: '0'
136
- - !ruby/object:Gem::Dependency
137
- name: rspec
138
- requirement: !ruby/object:Gem::Requirement
139
- requirements:
140
- - - ">="
141
- - !ruby/object:Gem::Version
142
- version: '0'
143
- type: :development
144
- prerelease: false
145
- version_requirements: !ruby/object:Gem::Requirement
146
- requirements:
147
- - - ">="
148
- - !ruby/object:Gem::Version
149
- version: '0'
150
108
  description: A complete, standalone view rendering system that gives you everything
151
109
  you need to write well-factored view code
152
110
  email:
153
111
  - info@hanakai.org
154
112
  executables: []
155
113
  extensions: []
156
- extra_rdoc_files: []
114
+ extra_rdoc_files:
115
+ - CHANGELOG.md
116
+ - LICENSE
117
+ - README.md
157
118
  files:
158
119
  - CHANGELOG.md
120
+ - LICENSE
159
121
  - README.md
160
122
  - hanami-view.gemspec
161
123
  - lib/hanami-view.rb
@@ -194,11 +156,10 @@ homepage: https://hanamirb.org
194
156
  licenses:
195
157
  - MIT
196
158
  metadata:
197
- rubygems_mfa_required: 'true'
198
- allowed_push_host: https://rubygems.org
199
- changelog_uri: https://github.com/hanami/view/blob/main/CHANGELOG.md
200
- source_code_uri: https://github.com/hanami/view
201
- bug_tracker_uri: https://github.com/hanami/view/issues
159
+ changelog_uri: https://github.com/hanami/hanami-view/blob/main/CHANGELOG.md
160
+ source_code_uri: https://github.com/hanami/hanami-view
161
+ bug_tracker_uri: https://github.com/hanami/hanami-view/issues
162
+ funding_uri: https://github.com/sponsors/hanami
202
163
  rdoc_options: []
203
164
  require_paths:
204
165
  - lib
@@ -206,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
206
167
  requirements:
207
168
  - - ">="
208
169
  - !ruby/object:Gem::Version
209
- version: '3.2'
170
+ version: '3.3'
210
171
  required_rubygems_version: !ruby/object:Gem::Requirement
211
172
  requirements:
212
173
  - - ">="