metanorma-plugin-lutaml 0.7.30 → 0.7.31

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -8
  3. data/README.adoc +16 -1030
  4. data/docs/usages/enterprise_architect.adoc +583 -0
  5. data/docs/usages/express.adoc +299 -0
  6. data/docs/usages/json_yaml.adoc +1034 -0
  7. data/docs/usages/lutaml-gml.adoc +73 -0
  8. data/docs/usages/lutaml-uml.adoc +73 -0
  9. data/lib/metanorma/plugin/lutaml/asciidoctor/preprocessor.rb +1 -1
  10. data/lib/metanorma/plugin/lutaml/base_structured_text_preprocessor.rb +192 -0
  11. data/lib/metanorma/plugin/lutaml/content.rb +89 -0
  12. data/lib/metanorma/plugin/lutaml/data2_text_preprocessor.rb +45 -0
  13. data/lib/metanorma/plugin/lutaml/express_remarks_decorator.rb +19 -6
  14. data/lib/metanorma/plugin/lutaml/json2_text_preprocessor.rb +43 -0
  15. data/lib/metanorma/plugin/lutaml/liquid/custom_blocks/key_iterator.rb +31 -0
  16. data/lib/metanorma/plugin/lutaml/liquid/custom_filters/loadfile.rb +18 -0
  17. data/lib/metanorma/plugin/lutaml/liquid/custom_filters/replace_regex.rb +14 -0
  18. data/lib/metanorma/plugin/lutaml/liquid/custom_filters/values.rb +13 -0
  19. data/lib/metanorma/plugin/lutaml/liquid/multiply_local_file_system.rb +29 -22
  20. data/lib/metanorma/plugin/lutaml/liquid_drops/gml_dictionary_drop.rb +1 -1
  21. data/lib/metanorma/plugin/lutaml/lutaml_diagram_base.rb +1 -1
  22. data/lib/metanorma/plugin/lutaml/lutaml_diagram_block_macro.rb +2 -1
  23. data/lib/metanorma/plugin/lutaml/lutaml_ea_diagram_block_macro.rb +2 -1
  24. data/lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb +48 -36
  25. data/lib/metanorma/plugin/lutaml/lutaml_figure_inline_macro.rb +2 -1
  26. data/lib/metanorma/plugin/lutaml/lutaml_gml_dictionary_block_macro.rb +3 -1
  27. data/lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb +2 -1
  28. data/lib/metanorma/plugin/lutaml/lutaml_preprocessor.rb +15 -2
  29. data/lib/metanorma/plugin/lutaml/lutaml_table_inline_macro.rb +2 -1
  30. data/lib/metanorma/plugin/lutaml/source_extractor.rb +97 -0
  31. data/lib/metanorma/plugin/lutaml/utils.rb +59 -26
  32. data/lib/metanorma/plugin/lutaml/version.rb +1 -1
  33. data/lib/metanorma/plugin/lutaml/yaml2_text_preprocessor.rb +41 -0
  34. data/lib/metanorma-plugin-lutaml.rb +3 -0
  35. data/metanorma-plugin-lutaml.gemspec +7 -1
  36. metadata +35 -6
  37. data/lib/metanorma/plugin/lutaml/liquid_templates/test.rb +0 -1
  38. /data/lib/metanorma/plugin/lutaml/liquid/{custom_filters.rb → custom_filters/html2adoc.rb} +0 -0
@@ -0,0 +1,73 @@
1
+
2
+ == Usage with LutaML GML Dictionary
3
+
4
+ === Rendering a LutaML GML Dictionary: `lutaml_gml_dictionary`
5
+
6
+ This command allows to render a LutaML GML Dictionary by using Liquid Drop.
7
+
8
+ GmlDictionaryDrop has the following attributes:
9
+
10
+ * name
11
+ * file_name
12
+ * dictionary_entry
13
+
14
+ Each `dictionary_entry` has the following attributes:
15
+
16
+ * name
17
+ * description
18
+
19
+ [source,adoc]
20
+ ----
21
+ lutaml_gml_dictionary::/path/to/dictionary.xml[template="/path/to/template.liquid",context=dict]
22
+ ----
23
+
24
+ The command accepts the options listed below:
25
+
26
+ * `/path/to/dictionary.xml` specifies the path of xml file of the
27
+ GML Dictionary.
28
+
29
+ * `template="/path/to/template.liquid"` specifies the liquid template.
30
+ For example, you can create a liquid template and link it by `template`.
31
+
32
+ * `context=dict` define the context in the template.
33
+
34
+ [source,adoc]
35
+ ----
36
+ [cols="3a,22a"]
37
+ |===
38
+ | Name | {{ dict.file_name }}
39
+
40
+ h| Code h| Description
41
+ {% for entry in dict.dictionary_entry %}
42
+ | {{ entry.name }} | {{ entry.description }}
43
+ {% endfor %}
44
+ |===
45
+
46
+ [.source]
47
+ <<source_link>>
48
+ ----
49
+
50
+ In spite of specifying the path of the template, you can also define an inline
51
+ template within a block by
52
+ `[lutaml_gml_dictionary,"/path/to/dictionary.xml",context=dict]`.
53
+
54
+ [source,adoc]
55
+ ----
56
+ [lutaml_gml_dictionary,"/path/to/dictionary.xml",context=dict]
57
+ --
58
+ {% capture link %}https://www.test.com/{{ dict.file_name }}{% endcapture %}
59
+
60
+ [cols="3a,22a"]
61
+ |===
62
+ | File Name | {{ dict.file_name }}
63
+ h| URL | {{ link }}
64
+ h| Help | Description
65
+ {% for entry in dict.dictionary_entry %}
66
+ | {{ entry.name }} | {{ entry.description }}
67
+ {% endfor %}
68
+ |===
69
+
70
+ [.source]
71
+ <<source_link>>
72
+ --
73
+ ----
@@ -0,0 +1,73 @@
1
+
2
+ == Usage with Lutaml-UML
3
+
4
+ === General
5
+
6
+ The LutaML plugin supports working with LutaML UML files to render UML diagrams
7
+ and class definitions.
8
+
9
+
10
+ === Rendering a LutaML view: `lutaml_diagram`
11
+
12
+ This command allows to quickly render a LutaML view as an image file.
13
+
14
+ Given a file `example.lutaml` file with content:
15
+
16
+ [source,java]
17
+ ----
18
+ diagram MyView {
19
+ title "my diagram"
20
+
21
+ enum AddressClassProfile {
22
+ imlicistAttributeProfile: CharacterString [0..1] {
23
+ definition
24
+ this is multiline with `asciidoc`
25
+ end definition
26
+ }
27
+ }
28
+
29
+ class AttributeProfile {
30
+ +addressClassProfile: CharacterString [0..1]
31
+ imlicistAttributeProfile: CharacterString [0..1] {
32
+ definition this is attribute definition
33
+ }
34
+ }
35
+ }
36
+ ----
37
+
38
+ The `lutaml_diagram` command will add the image to the document.
39
+
40
+ [source,adoc]
41
+ ----
42
+ lutaml_diagram::example.lutaml[]
43
+ ----
44
+
45
+ The `lutaml_diagram` command can also be used to denote a block with an embedded
46
+ LutaML view.
47
+
48
+ For example:
49
+
50
+ [source,java]
51
+ ----
52
+ [lutaml_diagram]
53
+ ....
54
+ diagram MyView {
55
+ title "my diagram"
56
+
57
+ enum AddressClassProfile {
58
+ imlicistAttributeProfile: CharacterString [0..1] {
59
+ definition {
60
+ This is multiline AsciiDoc content.
61
+ }
62
+ }
63
+ }
64
+
65
+ class AttributeProfile {
66
+ +addressClassProfile: CharacterString [0..1]
67
+ imlicistAttributeProfile: CharacterString [0..1] {
68
+ definition this is attribute definition
69
+ }
70
+ }
71
+ }
72
+ ....
73
+ ----
@@ -4,7 +4,7 @@ module Metanorma
4
4
  module Asciidoctor
5
5
  class PreprocessorNoIfdefsReader < ::Asciidoctor::PreprocessorReader
6
6
  def preprocess_conditional_directive(_keyword, _target, _delimiter,
7
- _text)
7
+ _text)
8
8
  false # decline to resolve idefs
9
9
  end
10
10
  end
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+ require "asciidoctor"
5
+ require "asciidoctor/reader"
6
+ require_relative "source_extractor"
7
+ require_relative "utils"
8
+ require "metanorma/plugin/lutaml/asciidoctor/preprocessor"
9
+
10
+ module Metanorma
11
+ module Plugin
12
+ module Lutaml
13
+ # Base class for processing structured data blocks(yaml, json)
14
+ class BaseStructuredTextPreprocessor <
15
+ ::Asciidoctor::Extensions::Preprocessor
16
+ include Utils
17
+
18
+ BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/.freeze
19
+ BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/.freeze
20
+ LOAD_FILE_REGEXP = /{% assign (.*) = (.*) \| load_file %}/.freeze
21
+ INCLUDE_PATH_OPTION = "include_path"
22
+ TEMPLATE_OPTION = "template"
23
+
24
+ def process(document, reader)
25
+ r = Asciidoctor::PreprocessorNoIfdefsReader
26
+ .new(document, reader.lines)
27
+ input_lines = r.readlines
28
+ Metanorma::Plugin::Lutaml::SourceExtractor
29
+ .extract(document, input_lines)
30
+ result_content = processed_lines(document, input_lines.to_enum)
31
+ Asciidoctor::PreprocessorNoIfdefsReader.new(document, result_content)
32
+ end
33
+
34
+ protected
35
+
36
+ def content_from_file(_document, _file_path)
37
+ raise ArgumentError, "Implement `content_from_file` in your class"
38
+ end
39
+
40
+ def content_from_anchor(_document, _file_path)
41
+ raise ArgumentError, "Implement `content_from_anchor` in your class"
42
+ end
43
+
44
+ private
45
+
46
+ def process_text_blocks(document, input_lines)
47
+ line = input_lines.next
48
+ block_match = line.match(/^\[#{config[:block_name]},(.+?)\]/)
49
+ return [line] if block_match.nil?
50
+
51
+ end_mark = input_lines.next
52
+ parse_template(
53
+ document,
54
+ collect_internal_block_lines(document, input_lines, end_mark),
55
+ block_match,
56
+ )
57
+ end
58
+
59
+ def collect_internal_block_lines(document, input_lines, end_mark) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
60
+ current_block = []
61
+ while (block_line = input_lines.next) != end_mark
62
+ if block_line.match?(LOAD_FILE_REGEXP)
63
+ load_file_match = block_line.match(LOAD_FILE_REGEXP)
64
+
65
+ # Add parent folder as argument to loadfile filter
66
+ block_line = "{% assign #{load_file_match[1]} = "\
67
+ "#{load_file_match[2]} | loadfile: " \
68
+ "\"#{document.attributes['docdir']}\" %}"
69
+ end
70
+
71
+ current_block.push(block_line)
72
+ end
73
+ current_block
74
+ end
75
+
76
+ def data_file_type
77
+ @config[:block_name].split("2").first
78
+ end
79
+
80
+ def parse_template(document, current_block, block_match) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
81
+ transformed_liquid_lines = current_block.map do |x|
82
+ transform_line_liquid(x)
83
+ end
84
+
85
+ contexts, include_path, template_path = resolve_context(
86
+ document, block_match
87
+ )
88
+
89
+ parse_context_block(
90
+ document: document,
91
+ context_lines: transformed_liquid_lines,
92
+ contexts: contexts,
93
+ include_path: include_path,
94
+ template_path: template_path,
95
+ )
96
+ rescue StandardError => e
97
+ ::Metanorma::Util.log("Failed to parse #{config[:block_name]} \
98
+ block: #{e.message}", :error)
99
+ []
100
+ end
101
+
102
+ def resolve_context(document, block_match) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
103
+ include_path = nil
104
+ template_path = nil
105
+
106
+ contexts = if block_match[1].include?("=")
107
+ multiple_contexts, include_path, template_path =
108
+ content_from_multiple_contexts(
109
+ document, block_match[1].split(",")
110
+ )
111
+ multiple_contexts
112
+ elsif block_match[1].start_with?("#")
113
+ anchor = block_match[1].split(",").first.strip[1..-1]
114
+ {
115
+ block_match[1].split(",").last.strip =>
116
+ content_from_anchor(document, anchor),
117
+ }
118
+ else
119
+ path = block_match[1].split(",").first.strip
120
+ {
121
+ block_match[1].split(",").last.strip =>
122
+ content_from_file(document, path),
123
+ }
124
+ end
125
+ [contexts, include_path, template_path]
126
+ end
127
+
128
+ def content_from_multiple_contexts(document, context_and_paths) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
129
+ contexts = {}
130
+ include_path = nil
131
+ template_path = nil
132
+
133
+ context_and_paths.each do |context_and_path|
134
+ context_and_path.strip!
135
+ context_name, path = context_and_path.split("=")
136
+
137
+ if context_name == INCLUDE_PATH_OPTION
138
+ include_path = path
139
+ elsif context_name == TEMPLATE_OPTION
140
+ template_path = path
141
+ else
142
+ context_items = content_from_file(document, path)
143
+ contexts[context_name] = context_items
144
+ end
145
+ end
146
+
147
+ [contexts, include_path, template_path]
148
+ end
149
+
150
+ def transform_line_liquid(line) # rubocop:disable Metrics/MethodLength
151
+ if line.match?(BLOCK_START_REGEXP)
152
+ line.gsub!(BLOCK_START_REGEXP, '{% keyiterator \1, \2 %}')
153
+ end
154
+
155
+ if line.strip.match?(BLOCK_END_REGEXP)
156
+ line.gsub!(BLOCK_END_REGEXP, "{% endkeyiterator %}")
157
+ end
158
+ line
159
+ .gsub(/(?<!{){(?!%)([^{}]{1,900})(?<!%)}(?!})/, '{{\1}}')
160
+ .gsub(/[a-z\.]{1,900}\#/, "index")
161
+ .gsub(/{{([^}]{1,900})\s+\+\s+(\d+)\s*?}}/, '{{ \1 | plus: \2 }}')
162
+ .gsub(/{{([^}]{1,900})\s+-\s+(\d+)\s*?}}/, '{{ \1 | minus: \2 }}')
163
+ .gsub(/{{([^}]{1,500})\.values([^}]{0,500})}}/,
164
+ '{% assign custom_value = \1 | values %}{{custom_value\2}}')
165
+ end
166
+
167
+ def parse_context_block( # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
168
+ context_lines:, contexts:, document:,
169
+ include_path: nil, template_path: nil
170
+ )
171
+ if include_path
172
+ include_path = relative_file_path(document, include_path)
173
+ end
174
+
175
+ if template_path
176
+ template_path = relative_file_path(document, template_path)
177
+ end
178
+
179
+ render_result, errors = render_liquid_string(
180
+ template_string: context_lines.join("\n"),
181
+ contexts: contexts,
182
+ document: document,
183
+ include_path: include_path,
184
+ template_path: template_path,
185
+ )
186
+ notify_render_errors(document, errors)
187
+ render_result.split("\n")
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "yaml"
5
+
6
+ module Metanorma
7
+ module Plugin
8
+ module Lutaml
9
+ module Content
10
+ protected
11
+
12
+ # https://ruby-doc.org/stdlib-2.5.1/libdoc/psych/rdoc/Psych.html#method-c-safe_load
13
+ def yaml_content_from_file(resolved_file_path) # rubocop:disable Metrics/MethodLength
14
+ unless File.exist?(resolved_file_path)
15
+ ::Metanorma::Util.log(
16
+ "YAML file referenced in [yaml2text] block not found: " \
17
+ "#{resolved_file_path}", :error
18
+ )
19
+ return
20
+ end
21
+
22
+ YAML.safe_load(
23
+ File.read(resolved_file_path, encoding: "UTF-8"),
24
+ permitted_classes: [Date, Time, Symbol],
25
+ permitted_symbols: [],
26
+ aliases: true,
27
+ )
28
+ end
29
+
30
+ def yaml_content_from_anchor(document, anchor)
31
+ YAML.safe_load(
32
+ document.attributes["source_blocks"][anchor],
33
+ permitted_classes: [Date, Time, Symbol],
34
+ permitted_symbols: [],
35
+ aliases: true,
36
+ )
37
+ end
38
+
39
+ def json_content_from_file(resolved_file_path)
40
+ JSON.parse(File.read(resolved_file_path, encoding: "UTF-8"))
41
+ end
42
+
43
+ def json_content_from_anchor(document, anchor)
44
+ JSON.parse(document.attributes["source_blocks"][anchor])
45
+ end
46
+
47
+ def content_from_file(document, file_path)
48
+ resolved_file_path = relative_file_path(document, file_path)
49
+ load_content_from_file(resolved_file_path)
50
+ end
51
+
52
+ def load_content_from_file(resolved_file_path)
53
+ unless File.exist?(resolved_file_path)
54
+ ::Metanorma::Util
55
+ .log("Failed to load content from file: #{resolved_file_path}",
56
+ :error)
57
+ end
58
+
59
+ if json_file?(resolved_file_path)
60
+ json_content_from_file(resolved_file_path)
61
+ else
62
+ yaml_content_from_file(resolved_file_path)
63
+ end
64
+ end
65
+
66
+ def content_from_anchor(document, anchor)
67
+ source_block = document.attributes["source_blocks"][anchor]
68
+ if json_content?(source_block)
69
+ json_content_from_anchor(document, anchor)
70
+ else
71
+ yaml_content_from_anchor(document, anchor)
72
+ end
73
+ end
74
+
75
+ def json_or_yaml_filepath?(file_path)
76
+ file_path.end_with?(".json", ".yaml", ".yml")
77
+ end
78
+
79
+ def json_file?(file_path)
80
+ file_path.end_with?(".json")
81
+ end
82
+
83
+ def json_content?(content)
84
+ content.start_with?("{", "[")
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "content"
4
+ require_relative "base_structured_text_preprocessor"
5
+
6
+ module Metanorma
7
+ module Plugin
8
+ module Lutaml
9
+ class Data2TextPreprocessor < BaseStructuredTextPreprocessor
10
+ include Content
11
+ # search document for block `data2text`
12
+ # after that take template from block and read file into this template
13
+ # example:
14
+ # [data2text,my_yaml=foobar.yaml,my_json=foobar.json]
15
+ # ----
16
+ # === {foobar.name}
17
+ # {foobar.desc}
18
+ #
19
+ # {my_json.symbol}:: {my_json.symbol_def}
20
+ # ----
21
+ #
22
+ # with content of `foobar.yaml` file equal to:
23
+ # - name: spaghetti
24
+ # desc: wheat noodles of 9mm diameter
25
+ #
26
+ # and content of `foobar.json` file equal to:
27
+ # {
28
+ # "symbol": "SPAG",
29
+ # "symbol_def": "the situation is message like spaghetti",
30
+ # }
31
+ #
32
+ # will produce:
33
+ # === spaghetti
34
+ # wheat noodles of 9mm diameter
35
+ #
36
+ # SPAG:: the situation is message like spaghetti
37
+
38
+ def initialize(config = {})
39
+ super
40
+ @config[:block_name] = "data2text"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -4,7 +4,19 @@ module Metanorma
4
4
  module Plugin
5
5
  module Lutaml
6
6
  class ExpressRemarksDecorator
7
- RELATIVE_PREFIX_MACRO_REGEXP = /^(link|image|video|audio|include)(:+)?(?![^\/:]+:\/\/|[A-Z]:\/|\/)([^:\[]+)(\[.*\])?$/.freeze
7
+ RELATIVE_PREFIX_MACRO_REGEXP = %r{
8
+ ^ # Start of line
9
+ (link|image|video|audio|include) # Capture group 1: content type
10
+ (:+)? # Capture group 2: optional colons
11
+ (?! # Negative lookahead
12
+ [^\/:]+://| # Don't match URLs (http://, etc.)
13
+ [A-Z]:/| # Don't match Windows paths
14
+ / # Don't match absolute paths
15
+ ) # End negative lookahead
16
+ ([^:\[]+) # Capture group 3: the path/name
17
+ (\[.*\])? # Capture group 4: optional attribute
18
+ $ # End of line
19
+ }x.freeze
8
20
 
9
21
  attr_reader :remark, :options
10
22
 
@@ -21,7 +33,7 @@ module Metanorma
21
33
  result = remark
22
34
  if options["relative_path_prefix"]
23
35
  result = update_relative_paths(result,
24
- options["relative_path_prefix"])
36
+ options["relative_path_prefix"])
25
37
  end
26
38
  result
27
39
  end
@@ -44,10 +56,11 @@ module Metanorma
44
56
  def prefix_relative_paths(line, path_prefix)
45
57
  line.gsub(RELATIVE_PREFIX_MACRO_REGEXP) do |_match|
46
58
  prefixed_path = File.join(path_prefix, $3.strip)
47
- # When we are dealing with a relative path of a template:
48
- # ../path/to/file we need to transform it into
49
- # the absolute one because `image::` macro wont understand it other way
50
- prefixed_path = File.absolute_path(prefixed_path) if prefixed_path.start_with?("../")
59
+ # Transform relative path (../path/to/file) into the absolute path
60
+ # because `image::` macro wont understand it other way
61
+ if prefixed_path.start_with?("../")
62
+ prefixed_path = File.absolute_path(prefixed_path)
63
+ end
51
64
  full_path = File.expand_path(prefixed_path)
52
65
  "#{$1}#{$2}#{full_path}#{$4}"
53
66
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "content"
4
+ require_relative "base_structured_text_preprocessor"
5
+
6
+ module Metanorma
7
+ module Plugin
8
+ module Lutaml
9
+ class Json2TextPreprocessor < BaseStructuredTextPreprocessor
10
+ include Content
11
+ # search document for block `json2text`
12
+ # after that take template from block and read file into this template
13
+ # example:
14
+ # [json2text,foobar.json]
15
+ # ----
16
+ # === {item.name}
17
+ # {item.desc}
18
+ #
19
+ # {item.symbol}:: {item.symbol_def}
20
+ # ----
21
+ #
22
+ # with content of `foobar.json` file equal to:
23
+ # {
24
+ # "name": "spaghetti",
25
+ # "desc": "wheat noodles of 9mm diameter".
26
+ # "symbol": "SPAG",
27
+ # "symbol_def": "the situation is message like spaghetti",
28
+ # }
29
+ #
30
+ # will produce:
31
+ # === spaghetti
32
+ # wheat noodles of 9mm diameter
33
+ #
34
+ # SPAG:: the situation is message like spaghetti
35
+
36
+ def initialize(config = {})
37
+ super
38
+ @config[:block_name] = "json2text"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ module Metanorma
2
+ module Plugin
3
+ module Lutaml
4
+ module Liquid
5
+ module CustomBlocks
6
+ class KeyIterator < ::Liquid::Block
7
+ def initialize(tag_name, markup, tokens)
8
+ super
9
+ @context_name, @var_name = markup.split(",").map(&:strip)
10
+ end
11
+
12
+ def render(context) # rubocop:disable Metrics/MethodLength
13
+ res = ""
14
+ iterator = if context[@context_name].is_a?(Hash)
15
+ context[@context_name].keys
16
+ else
17
+ context[@context_name]
18
+ end
19
+ iterator.each.with_index do |key, index|
20
+ context["index"] = index
21
+ context[@var_name] = key
22
+ res += super
23
+ end
24
+ res
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "../../content"
2
+
3
+ module Metanorma
4
+ module Plugin
5
+ module Lutaml
6
+ module Liquid
7
+ module CustomFilters
8
+ include ::Metanorma::Plugin::Lutaml::Content
9
+
10
+ def loadfile(path, parent_folder = ".")
11
+ resolved_file_path = File.expand_path(path, parent_folder)
12
+ load_content_from_file(resolved_file_path)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Metanorma
2
+ module Plugin
3
+ module Lutaml
4
+ module Liquid
5
+ module CustomFilters
6
+ def replace_regex(text, regex_search, replace_value)
7
+ regex = /#{regex_search}/
8
+ text.to_s.gsub(regex, replace_value)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Metanorma
2
+ module Plugin
3
+ module Lutaml
4
+ module Liquid
5
+ module CustomFilters
6
+ def values(list)
7
+ list.values
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end