Class: Fronde::Org::File

Inherits:
Object
  • Object
show all
Includes:
FileExtracter
Defined in:
lib/fronde/org/file.rb

Overview

Handles org files.

This class is responsible for reading or writing existing or new org files, and formating their content to be used on the generated website.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_name, opts = {}) ⇒ Fronde::Org::File

Prepares the file named by ~file_name~ for read and write

operations.

If the file ~file_name~ does not exist, the new instance may be populated by data given in the ~opts~ parameter.

Examples:

File.exist? './test.org'
=> true
o = Fronde::Org::File.new('./test.org')
=> #<Fronde::Org::File @file='./test.org'...>
o.title
=> "This is an existing test file"
File.exist? '/tmp/does_not_exist.org'
=> false
o = Fronde::Org::File.new('/tmp/does_not_exist.org')
=> #<Fronde::Org::File @file='/tmp/does_not_exist.org'...>
o.title
=> ""
File.exist? '/tmp/other.org'
=> false
o = Fronde::Org::File.new('/tmp/other.org', title: 'New file')
=> #<Fronde::Org::File @file='/tmp/other.org'...>
o.title
=> "New file"

Parameters:

  • file_name (String)

    path to the corresponding Org file

  • opts (Hash) (defaults to: {})

    optional data to initialize new Org file

Options Hash (opts):

  • title (String) — default: ''

    the title of the new Org file

  • author (String) — default: system user or ''

    the author of the document



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/fronde/org/file.rb', line 66

def initialize(file_name, opts = {})
  file_name ||= ''
  @file = ::File.expand_path file_name
  @options = opts
  @project = find_source
  @data = {}
  if ::File.file?(@file)
    extract_data
  else
    init_empty_file
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object



225
226
227
228
229
230
231
232
233
# File 'lib/fronde/org/file.rb', line 225

def method_missing(method_name, *args, &)
  reader_method = method_name.to_s.delete_suffix('=').to_sym
  if @data.has_key? reader_method
    return @data[reader_method] if reader_method == method_name

    return @data[reader_method] = args.first
  end
  super
end

Instance Attribute Details

#fileString (readonly)

Returns the relative path to the source of this document.

Returns:

  • (String)

    the relative path to the source of this document.



26
27
28
# File 'lib/fronde/org/file.rb', line 26

def file
  @file
end

#projectHash (readonly)

Returns the project owning this document.

Returns:

  • (Hash)

    the project owning this document.



29
30
31
# File 'lib/fronde/org/file.rb', line 29

def project
  @project
end

Instance Method Details

#format(string) ⇒ String

Formats given ~string~ with values of the current Org::File.

This method expects to find percent-tags in the given ~string~ and replace them by their corresponding value.

It reuses the same tags than the ~org-html-format-spec~ method.

*** Format:

  • %a

    the raw author name.

  • %A

    the HTML rendering of the author name, equivalent to ~<span class=“author”>%a</span>~.

  • %d

    the ~:short~ date HTML representation, equivalent to ~<time datetime=“%I”>%i</time>~.

  • %D

    the ~:full~ date and time HTML representation.

  • %F

    the ~link~ HTML tag for the main Atom feed of the current file source.

  • %h

    the declared host/domain name, taken from the Config#settings.

  • %i

    the raw ~:short~ date and time.

  • %I

    the raw ~:iso8601~ date and time.

  • %k

    the document keywords separated by commas.

  • %K

    the HTML list rendering of the keywords.

  • %l

    the lang of the document.

  • %L

    the license information, taken from the Config#settings.

  • %n

    the fronde name and version.

  • %N

    the fronde name and version with a link to the project home on the name.

  • %o

    the theme name (~o~ as in Outfit) of the current file source.

  • %s

    the subtitle of the document (from ~#+subtitle:~).

  • %t

    the title of the document (from ~#+title:~).

  • %u

    the URL to the related published HTML document.

  • %x

    the raw description (~x~ as in eXcerpt) of the document (from ~#+description:~).

  • %X

    the description, enclosed in an HTML ~p~ tag, equivalent to ~<p>%x</p>~.

rubocop:disable Layout/LineLength

Examples:

org_file.format("Article written by %a the %d")
=> "Article written by Alice Smith the Wednesday 3rd July"

Parameters:

  • string (String)

    the template text to edit

Returns:

  • (String)

    the given ~string~ after replacement occurs



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/fronde/org/file.rb', line 172

def format(string)
  project_data = @project.to_h
  # NOTE: The following keycode are reserved by Org itself:
  #       %a (author), %c (creator), %C (input-file), %d (date),
  #       %e (email), %s (subtitle), %t (title), %T (timestamp),
  #       %v (html validation link)
  localized_dates = I18n.with_locale(@data[:lang]) do
    { short: @data[:date].l18n_short_date_string,
      short_html: @data[:date].l18n_short_date_html,
      long_html: @data[:date].l18n_long_date_html }
  end
  string.gsub('%a', @data[:author])
        .gsub('%A', "<span class=\"author\">#{@data[:author]}</span>")
        .gsub('%d', localized_dates[:short_html])
        .gsub('%D', localized_dates[:long_html])
        .gsub('%F', project_data['atom_feed'] || '')
        .gsub('%h', project_data['domain'] || '')
        .gsub('%i', localized_dates[:short])
        .gsub('%I', @data[:date].xmlschema)
        .gsub('%k', @data[:keywords].join(', '))
        .gsub('%K', keywords_to_html)
        .gsub('%l', @data[:lang])
        .gsub('%L', Fronde::CONFIG.get('license', '').gsub(/\s+/, ' ').strip)
        .gsub('%n', "Fronde #{Fronde::VERSION}")
        .gsub('%N', "<a href=\"https://git.umaneti.net/fronde/about/\">Fronde</a> #{Fronde::VERSION}")
        .gsub('%o', project_data['theme'] || '')
        .gsub('%s', @data[:subtitle])
        .gsub('%t', @data[:title])
        .gsub('%u', @data[:url] || '')
        .gsub('%x', @data[:excerpt])
        .gsub('%X', "<p>#{@data[:excerpt]}</p>")
end

#pub_file(absolute: false) ⇒ String

Returns the path to the published version of this document.

By default, this method returns the relative path to the published file. If the ~absolute~ argument is true, it will return the absolute path to the published file.

Parameters:

  • absolute (Boolean) (defaults to: false)

    whether to display absolute or relative published file path (default false)

Returns:

  • (String)

    the document key



121
122
123
124
125
# File 'lib/fronde/org/file.rb', line 121

def pub_file(absolute: false)
  return @data[:pub_file] unless absolute

  "#{@project['folder']}#{@data[:pub_file]}"
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


235
236
237
238
239
240
241
242
# File 'lib/fronde/org/file.rb', line 235

def respond_to_missing?(method_name, include_private = false)
  return true if @data.has_key? method_name

  reader_method = method_name.to_s.delete_suffix('=').to_sym
  return true if @data.has_key? reader_method

  super
end

#timekeyString

Returns a String representation of the document date, which aims

to be used to sort several Org::Files.

The format used for the key is ~%Y%m%d%H%M%S~. If the current Org::File instance does not have a date, this mehod return ~00000000000000~. If the current Org::File instance does not have time information, the date is padded with zeros.

Examples:

with the org header ~#+date: <2019-07-03 Wed 20:52:49>~

org_file.date
=> #<Time: 2019-07-03T20:52:49+02:00...>
org_file.timekey
=> "20190703205349"

with the org header ~#+date: <2019-07-03 Wed>~

org_file.date
=> #<Time: 2019-07-03T00:00:00+02:00...>
org_file.timekey
=> "20190703000000"

with no date header in the org file

org_file.date
=> nil
org_file.timekey
=> "00000000000000"

Returns:

  • (String)

    the document key



106
107
108
109
110
# File 'lib/fronde/org/file.rb', line 106

def timekey
  return '00000000000000' if @data[:date].is_a? NilTime

  @data[:date].strftime('%Y%m%d%H%M%S')
end

#to_hObject



244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/fronde/org/file.rb', line 244

def to_h
  fields = %w[author excerpt keywords lang timekey title url]
  data = fields.to_h { |key| [key, send(key)] }
  data['published_body'] = extract_published_body
  pub_date = @data[:date]
  data['published'] = I18n.with_locale(@data[:lang]) do
    pub_date.l18n_long_date_no_year_string
  end
  data['published_gemini_index'] = pub_date.strftime('%Y-%m-%d')
  data['published_xml'] = pub_date.xmlschema
  data['updated_xml'] = @data[:updated]&.xmlschema
  data
end

#writeInteger

Writes the current Org::File content to the underlying file.

The intermediate parent folders are created if necessary.

Returns:

  • (Integer)

    the length written (as returned by the underlying ~File.write~ method call)



212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/fronde/org/file.rb', line 212

def write
  if ::File.directory? @file
    if @data[:title] == ''
      raise I18n.t('fronde.error.org_file.no_file_or_title')
    end

    @file = ::File.join @file, "#{Slug.slug(@data[:title])}.org"
  else
    FileUtils.mkdir_p ::File.dirname(@file)
  end
  ::File.write @file, @data[:content]
end