Class: Bridgetown::Resource::Base

Inherits:
Object
  • Object
show all
Includes:
LayoutPlaceable, Localizable, Publishable, Bridgetown::RodaCallable, Comparable
Defined in:
lib/bridgetown-core/resource/base.rb

Overview

rubocop:todo Metrics/ClassLength

Constant Summary collapse

DATE_FILENAME_MATCHER =
%r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Localizable

#all_locales, #localeless_path, #matches_resource?

Methods included from LayoutPlaceable

#no_layout?, #place_in_layout?

Methods included from Publishable

#publishable?, #published?

Methods included from Bridgetown::RodaCallable

===

Constructor Details

#initialize(model:) ⇒ Base

Returns a new instance of Base.

Parameters:



40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/bridgetown-core/resource/base.rb', line 40

def initialize(model:)
  @model = model
  @site = model.site
  @data = Signalize.signal(
    collection.data? ? HashWithDotAccess::Hash.new : front_matter_defaults
  )
  # we track content subscriptions under the hood numerically…cleans up internal issues
  @content_signal = Signalize.signal(0)
  @slots = []

  trigger_hooks :post_init
end

Instance Attribute Details

#contentString

Returns the resource content minus its layout.

Returns:

  • (String)

    the resource content minus its layout



123
124
125
126
# File 'lib/bridgetown-core/resource/base.rb', line 123

def content
  @content_signal.value # subscribe for Fast Refresh
  @content
end

#destinationDestination (readonly)

Returns:



14
15
16
# File 'lib/bridgetown-core/resource/base.rb', line 14

def destination
  @destination
end

#fast_refresh_orderBoolean (readonly)

Returns:

  • (Boolean)


26
27
28
# File 'lib/bridgetown-core/resource/base.rb', line 26

def fast_refresh_order
  @fast_refresh_order
end

#modelBridgetown::Model::Base (readonly)



17
18
19
# File 'lib/bridgetown-core/resource/base.rb', line 17

def model
  @model
end

#outputString

Returns:

  • (String)


34
35
36
# File 'lib/bridgetown-core/resource/base.rb', line 34

def output
  @output
end

#siteBridgetown::Site (readonly)

Returns:



20
21
22
# File 'lib/bridgetown-core/resource/base.rb', line 20

def site
  @site
end

#slotsArray<Bridgetown::Slot> (readonly)

Returns:



23
24
25
# File 'lib/bridgetown-core/resource/base.rb', line 23

def slots
  @slots
end

#untransformed_contentString

Returns:

  • (String)


29
30
31
# File 'lib/bridgetown-core/resource/base.rb', line 29

def untransformed_content
  @untransformed_content
end

Instance Method Details

#<=>(other) ⇒ Integer

Compare this resource against another resource. Comparison is a comparison between the 2 dates or paths of the resources.

Returns:

  • (Integer)

    -1, 0, or +1



323
324
325
326
327
328
329
330
331
332
333
# File 'lib/bridgetown-core/resource/base.rb', line 323

def <=>(other) # rubocop:todo Metrics/AbcSize
  return nil unless other.respond_to?(:data)

  cmp = if data.date.respond_to?(:to_datetime) && other.data.date.respond_to?(:to_datetime)
          data.date.to_datetime <=> other.data.date.to_datetime
        end

  cmp = data["date"] <=> other.data["date"] if cmp.nil?
  cmp = path <=> other.path if cmp.nil? || cmp.zero?
  cmp
end

#absolute_urlString

Returns:

  • (String)


223
224
225
# File 'lib/bridgetown-core/resource/base.rb', line 223

def absolute_url
  format_url destination&.absolute_url
end

#around_hook(hook_suffix) ⇒ Object



182
183
184
185
186
# File 'lib/bridgetown-core/resource/base.rb', line 182

def around_hook(hook_suffix)
  trigger_hooks :"pre_#{hook_suffix}"
  yield
  trigger_hooks :"post_#{hook_suffix}"
end

#as_jsonObject



307
308
309
# File 'lib/bridgetown-core/resource/base.rb', line 307

def as_json(*)
  to_h
end

#basename_without_extString

Returns:

  • (String)


203
204
205
# File 'lib/bridgetown-core/resource/base.rb', line 203

def basename_without_ext
  relative_path.basename(".*").to_s
end

#callString

Transforms the resource and returns the full output

Returns:

  • (String)


175
# File 'lib/bridgetown-core/resource/base.rb', line 175

def call(*) = transform!.output

#collectionBridgetown::Collection

Collection associated with this resource



56
57
58
# File 'lib/bridgetown-core/resource/base.rb', line 56

def collection
  model.collection
end

#dataHashWithDotAccess::Hash



101
102
103
# File 'lib/bridgetown-core/resource/base.rb', line 101

def data
  @data.value
end

#data=(new_data) ⇒ Object

Merges new data into the existing data hash.

Parameters:



108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/bridgetown-core/resource/base.rb', line 108

def data=(new_data)
  if site.config.fast_refresh && write?
    # TODO: investigate if this would be better:
    # @data.value = front_matter_defaults
    mark_for_fast_refresh!
  end

  Signalize.batch do
    @content_signal.value += 1
    @data.value = @data.value.merge(new_data)
  end
  @data.peek
end

#dateObject



242
243
244
# File 'lib/bridgetown-core/resource/base.rb', line 242

def date
  data["date"] ||= site.time
end

#deconstruct_keysObject



349
350
351
# File 'lib/bridgetown-core/resource/base.rb', line 349

def deconstruct_keys(...)
  @data.value.deconstruct_keys(...)
end

#dispose_of_transform_effectObject



381
382
383
# File 'lib/bridgetown-core/resource/base.rb', line 381

def dispose_of_transform_effect
  @transform_effect_disposal&.()
end

#extnameString

Returns:

  • (String)


208
209
210
# File 'lib/bridgetown-core/resource/base.rb', line 208

def extname
  relative_path.extname
end

#front_matter_defaultsHashWithDotAccess::Hash

Loads in any default front matter associated with the resource.



96
97
98
# File 'lib/bridgetown-core/resource/base.rb', line 96

def front_matter_defaults
  site.frontmatter_defaults.all(relative_path.to_s, collection.label.to_sym).as_dots
end

#idString

Returns:

  • (String)


233
234
235
# File 'lib/bridgetown-core/resource/base.rb', line 233

def id
  model.origin.id
end

#inspectObject



315
316
317
# File 'lib/bridgetown-core/resource/base.rb', line 315

def inspect
  "#<#{self.class} #{id}>"
end

#layoutBridgetown::Layout

Layout associated with this resource This will output a warning if the layout can't be found.

Returns:



64
65
66
67
68
69
70
71
72
73
74
# File 'lib/bridgetown-core/resource/base.rb', line 64

def layout
  return @layout if @layout
  return if no_layout?

  @layout = site.layouts[data.layout].tap do |layout|
    unless layout
      Bridgetown.logger.warn "Resource:", "Layout '#{data.layout}' " \
                                          "requested via #{relative_path} does not exist."
    end
  end
end

#mark_for_fast_refresh!Object



353
354
355
356
# File 'lib/bridgetown-core/resource/base.rb', line 353

def mark_for_fast_refresh!
  @fast_refresh_order = site.fast_refresh_ordering
  site.fast_refresh_ordering += 1
end

#next_resourceObject Also known as: next_doc, next



335
336
337
338
# File 'lib/bridgetown-core/resource/base.rb', line 335

def next_resource
  pos = collection.resources.index { |item| item.equal?(self) }
  collection.resources[pos + 1] if pos && pos < collection.resources.length - 1
end

#output_extString

Returns:

  • (String)


238
239
240
# File 'lib/bridgetown-core/resource/base.rb', line 238

def output_ext
  destination&.output_ext
end

#pathString

Returns:

  • (String)


218
219
220
# File 'lib/bridgetown-core/resource/base.rb', line 218

def path
  (model.origin.respond_to?(:original_path) ? model.origin.original_path : relative_path).to_s
end

Returns:

  • (String, nil)


213
214
215
# File 'lib/bridgetown-core/resource/base.rb', line 213

def permalink
  data&.permalink
end

#prepare_for_fast_refresh!Object

rubocop:todo Metrics



362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/bridgetown-core/resource/base.rb', line 362

def prepare_for_fast_refresh! # rubocop:todo Metrics
  dispose_of_transform_effect
  FileUtils.rm(destination.output_path, force: true) if requires_destination?
  past_values = @data.peek.select do |key|
    key == "categories" || key == "tags" || site.taxonomy_types.keys.any?(key)
  end
  model.attributes = model.origin.read
  read!
  tax_diff = past_values.any? { |k, v| @data.peek[k] != v }

  if tax_diff && !collection.data?
    # If the taxonomy values are different, we should just abort the fast refresh process.
    unmark_for_fast_refresh!
    false
  else
    true
  end
end

#previous_resourceObject Also known as: previous_doc, previous



342
343
344
345
# File 'lib/bridgetown-core/resource/base.rb', line 342

def previous_resource
  pos = collection.resources.index { |item| item.equal?(self) }
  collection.resources[pos - 1] if pos&.positive?
end

#read!Bridgetown::Resource::Base Also known as: read



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/bridgetown-core/resource/base.rb', line 129

def read!
  self.data = model.data_attributes
  self.content = model.content # could be nil

  unless collection.data?
    self.untransformed_content = content
    normalize_categories_and_tags
    import_taxonomies_from_data
    ensure_default_data
    transformer.execute_inline_ruby!
    set_date_from_string(data.date)
  end

  @destination = Destination.new(self) if requires_destination?

  trigger_hooks :post_read

  self
end

#relationsBridgetown::Resource::Relations



89
90
91
# File 'lib/bridgetown-core/resource/base.rb', line 89

def relations
  @relations ||= Bridgetown::Resource::Relations.new(self)
end

#relative_pathPathname

The relative path of source file or file-like origin

Returns:

  • (Pathname)


79
80
81
# File 'lib/bridgetown-core/resource/base.rb', line 79

def relative_path
  model.origin.relative_path
end

#relative_path_basename_without_prefixString

Returns:

  • (String)


189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/bridgetown-core/resource/base.rb', line 189

def relative_path_basename_without_prefix
  return_path = Pathname.new("")
  relative_path.each_filename do |filename|
    if matches = DATE_FILENAME_MATCHER.match(filename) # rubocop:disable Lint/AssignmentInCondition
      filename = matches[2] + matches[3]
    end

    return_path += filename unless filename.starts_with?("_")
  end

  (return_path.dirname + return_path.basename(".*")).to_s
end

#relative_urlString

Returns:

  • (String)


228
229
230
# File 'lib/bridgetown-core/resource/base.rb', line 228

def relative_url
  format_url destination&.relative_url
end

#requires_destination?Boolean Also known as: write?

Returns:

  • (Boolean)


269
270
271
# File 'lib/bridgetown-core/resource/base.rb', line 269

def requires_destination?
  collection.write? && data.config&.output != false
end

#summaryString

Ask the configured summary extension to output a summary of the content, otherwise return the first line.

Returns:

  • (String)


250
251
252
253
254
# File 'lib/bridgetown-core/resource/base.rb', line 250

def summary
  return summary_extension_output if respond_to?(:summary_extension_output)

  content.to_s.strip.lines.first.to_s.strip.html_safe
end

#taxonomiesHash<String, Hash<String => Bridgetown::Resource::TaxonomyType, Array<Bridgetown::Resource::TaxonomyTerm>>>

Returns:



258
259
260
261
262
263
264
265
266
267
# File 'lib/bridgetown-core/resource/base.rb', line 258

def taxonomies
  @taxonomies ||= site.taxonomy_types.values.each_with_object(
    HashWithDotAccess::Hash.new
  ) do |taxonomy, hsh|
    hsh[taxonomy.label] = {
      type: taxonomy,
      terms: [],
    }
  end
end

#to_hObject



292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/bridgetown-core/resource/base.rb', line 292

def to_h
  {
    id:,
    absolute_url:,
    relative_path:,
    relative_url:,
    date:,
    data:,
    taxonomies:,
    untransformed_content:,
    content:,
    output:,
  }
end

#to_jsonObject



311
312
313
# File 'lib/bridgetown-core/resource/base.rb', line 311

def to_json(...)
  as_json(...).to_json(...)
end

#to_liquidDrops::ResourceDrop

Create a Liquid-understandable version of this resource.

Returns:



288
289
290
# File 'lib/bridgetown-core/resource/base.rb', line 288

def to_liquid
  @to_liquid ||= Drops::ResourceDrop.new(self)
end

#to_sObject



281
282
283
# File 'lib/bridgetown-core/resource/base.rb', line 281

def to_s
  output || content || ""
end

#transform!Object

rubocop:todo Metrics/CyclomaticComplexity



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/bridgetown-core/resource/base.rb', line 150

def transform! # rubocop:todo Metrics/CyclomaticComplexity
  internal_error = nil
  @transform_effect_disposal = Signalize.effect do
    if !@fast_refresh_order && @previously_transformed
      self.content = untransformed_content
      @transformer = nil
      mark_for_fast_refresh! if site.config.fast_refresh && write?
      next
    end

    transformer.process! unless collection.data?
    slots.clear
    @previously_transformed = true
  rescue StandardError, SyntaxError => e
    internal_error = e
  end

  raise internal_error if internal_error

  self
end

#transformerBridgetown::Resource::Transformer



84
85
86
# File 'lib/bridgetown-core/resource/base.rb', line 84

def transformer
  @transformer ||= Bridgetown::Resource::Transformer.new(self)
end

#trigger_hooks(hook_name, *args) ⇒ Object



177
178
179
180
# File 'lib/bridgetown-core/resource/base.rb', line 177

def trigger_hooks(hook_name, *args)
  Bridgetown::Hooks.trigger collection.label.to_sym, hook_name, self, *args if collection
  Bridgetown::Hooks.trigger :resources, hook_name, self, *args
end

#unmark_for_fast_refresh!Object



358
359
360
# File 'lib/bridgetown-core/resource/base.rb', line 358

def unmark_for_fast_refresh!
  @fast_refresh_order = nil
end

#write(_dest = nil) ⇒ Object

Write the generated resource file to the destination directory.



275
276
277
278
279
# File 'lib/bridgetown-core/resource/base.rb', line 275

def write(_dest = nil)
  destination.write(output)
  unmark_for_fast_refresh!
  trigger_hooks(:post_write)
end