metanorma-plugin-datastruct 0.3.9 → 0.3.10

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b1a1aff3342ca19d9bad692c321719cc381a1d74d98b2827c23bb1da7f6d2de
4
- data.tar.gz: 3c5f60aba996ac9e1f8924439e60d453c847da10189025917334fbcb200d1d85
3
+ metadata.gz: ddd2e0f19eb24c1c23dd1445ecdf17734b4b70263d1098e9446454c6e5bbddc6
4
+ data.tar.gz: 346f50de2a3a8a36a1dbc7ab89141226ec5ae5133fc0664bb106c7a01fd7356e
5
5
  SHA512:
6
- metadata.gz: 4e69b0df873ef7d4bb9db7fa7d998c8eb5ee943d14d153e472368087ee55afbcd62db101f3791f530f5cc7f7619eff5514ef92a66a8ea8b2ea5a7ef58e94a66e
7
- data.tar.gz: f3746f6e9d3e917dd2ac0e861eb837d8fc6d665699737e41244c427b54112863dd29e5134b23ea3f3b2d7b228f93840ab29935c5da08c471638e7a75e1268ef3
6
+ metadata.gz: 67bab763402f9e0d651effa3fa6e76228331459dd67e4b2faec2b6bb411490aaf7a5751cbddcd4302a9d8962e9412e2de6c0431ff5e9f0222687c3dc88a9c140
7
+ data.tar.gz: 6a87d9f07929323519f1cc4ea9402df25918eb5ec464115be321abe695b4f579f10fac1c72822abccb8bd293656b8660acb47386bcbd76685b120966b652aa45
@@ -2,6 +2,9 @@
2
2
  # See https://github.com/metanorma/cimas
3
3
  name: rake
4
4
 
5
+ permissions:
6
+ contents: read
7
+
5
8
  on:
6
9
  push:
7
10
  branches: [ master, main ]
@@ -2,6 +2,11 @@
2
2
  # See https://github.com/metanorma/cimas
3
3
  name: release
4
4
 
5
+ permissions:
6
+ contents: write
7
+ packages: write
8
+ id-token: write
9
+
5
10
  on:
6
11
  workflow_dispatch:
7
12
  inputs:
@@ -22,4 +27,3 @@ jobs:
22
27
  secrets:
23
28
  rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
24
29
  pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
25
-
data/Gemfile CHANGED
@@ -1,13 +1,20 @@
1
- Encoding.default_external = Encoding::UTF_8
2
- Encoding.default_internal = Encoding::UTF_8
3
-
4
1
  source "https://rubygems.org"
5
- git_source(:github) { |repo| "https://github.com/#{repo}" }
6
2
 
3
+ # Specify your gem's dependencies in metanorma-plugin-datastruct.gemspec
7
4
  gemspec
8
5
 
9
- begin
10
- eval_gemfile("Gemfile.devel")
11
- rescue StandardError
12
- nil
13
- end
6
+ eval_gemfile("Gemfile.devel") if File.exist?("Gemfile.devel")
7
+
8
+ gem "canon"
9
+ gem "metanorma", github: "metanorma/metanorma", branch: "main"
10
+ gem "metanorma-standoc", github: "metanorma/metanorma-standoc", branch: "main"
11
+ gem "rake", "~> 13"
12
+ gem "rspec"
13
+ gem "rubocop"
14
+ gem "rubocop-performance"
15
+ gem "rubocop-rake"
16
+ gem "rubocop-rspec"
17
+ gem "simplecov"
18
+ gem "timecop"
19
+ gem "vcr"
20
+ gem "webmock"
data/Gemfile.devel ADDED
@@ -0,0 +1,2 @@
1
+ gem "metanorma-plugin-lutaml", git: "https://github.com/metanorma/metanorma-plugin-lutaml", branch: "main"
2
+ gem "ogc-gml", "~> 1.1.0"
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+
5
+ module Liquid
6
+ module CustomBlocks
7
+ class KeyIterator < Block
8
+ def initialize(tag_name, markup, tokens)
9
+ super
10
+ @context_name, @var_name = markup.split(",").map(&:strip)
11
+ end
12
+
13
+ def render(context)
14
+ collection = context[@context_name]
15
+ items = enumerable_items(collection)
16
+ result = +""
17
+ items.each.with_index do |item, index|
18
+ context["index"] = index
19
+ context[@var_name] = item
20
+ result << super
21
+ end
22
+ result
23
+ end
24
+
25
+ private
26
+
27
+ def enumerable_items(collection)
28
+ case collection
29
+ when Hash then collection.keys
30
+ else collection
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+
5
+ module Liquid
6
+ module CustomBlocks
7
+ class NestedContextBlock < Block
8
+ def initialize(tag_name, markup, tokens)
9
+ super
10
+ @context_file_variable, @context_name = markup.split(",").map(&:strip)
11
+ end
12
+
13
+ def render(context)
14
+ context_file = context[@context_file_variable].to_s.strip
15
+ context[@context_name] = load_content(context_file)
16
+ super
17
+ end
18
+
19
+ private
20
+
21
+ def load_content(_file_path)
22
+ raise NotImplementedError
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require_relative "nested_context_block"
5
+
6
+ module Liquid
7
+ module CustomBlocks
8
+ class WithJsonNestedContext < NestedContextBlock
9
+ private
10
+
11
+ def load_content(file_path)
12
+ JSON.parse(File.read(file_path, encoding: "utf-8"))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require_relative "nested_context_block"
5
+
6
+ module Liquid
7
+ module CustomBlocks
8
+ class WithYamlNestedContext < NestedContextBlock
9
+ private
10
+
11
+ def load_content(file_path)
12
+ YAML.safe_load(
13
+ File.read(file_path, encoding: "utf-8"),
14
+ permitted_classes: [Date, Time],
15
+ aliases: true,
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ module Liquid
2
+ module CustomFilters
3
+ def values(list)
4
+ list.values
5
+ end
6
+ end
7
+ end
@@ -3,54 +3,52 @@
3
3
  require "liquid"
4
4
  require "asciidoctor"
5
5
  require "asciidoctor/reader"
6
- require_relative "liquid/custom_blocks/key_iterator"
7
- require_relative "liquid/custom_filters/values"
8
- require_relative "liquid/custom_filters/replace_regex"
9
- require_relative "liquid/custom_filters/loadfile"
6
+ require "liquid/custom_blocks/key_iterator"
7
+ require "liquid/custom_blocks/with_yaml_nested_context"
8
+ require "liquid/custom_blocks/with_json_nested_context"
9
+ require "liquid/custom_filters/values"
10
+ require_relative "path_resolver"
10
11
  require_relative "source_extractor"
11
12
 
12
- module Asciidoctor
13
- class PreprocessorNoIfdefsReader < PreprocessorReader
14
- def preprocess_conditional_directive(_keyword, _target, _delimiter, _text)
15
- false # decline to resolve idefs
16
- end
17
- end
18
- end
19
-
20
13
  module Metanorma
21
14
  module Plugin
22
15
  module Datastruct
23
- # Base class for processing structured data blocks(yaml, json)
24
16
  class BaseStructuredTextPreprocessor <
25
17
  Asciidoctor::Extensions::Preprocessor
18
+ include PathResolver
19
+
26
20
  BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/.freeze
27
21
  BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/.freeze
28
- LOAD_FILE_REGEXP = /{% assign (.*) = (.*) \| load_file %}/.freeze
22
+
23
+ def initialize(config = {})
24
+ super
25
+ register_liquid_extensions
26
+ end
29
27
 
30
28
  def process(document, reader)
31
- r = ::Asciidoctor::PreprocessorNoIfdefsReader
32
- .new document, reader.lines
33
- input_lines = r.readlines
34
- Metanorma::Plugin::Datastruct::SourceExtractor.extract(
35
- document,
36
- input_lines,
37
- )
38
- Asciidoctor::PreprocessorNoIfdefsReader
39
- .new(document, processed_lines(document, input_lines.to_enum))
29
+ input_lines = reader.readlines.to_enum
30
+ Asciidoctor::Reader.new(processed_lines(document, input_lines))
40
31
  end
41
32
 
42
33
  protected
43
34
 
44
35
  def content_from_file(_document, _file_path)
45
- raise ArgumentError, "Implement `content_from_file` in your class"
46
- end
47
-
48
- def content_from_anchor(_document, _file_path)
49
- raise ArgumentError, "Implement `content_from_anchor` in your class"
36
+ raise NotImplementedError,
37
+ "Implement `content_from_file` in your subclass"
50
38
  end
51
39
 
52
40
  private
53
41
 
42
+ def register_liquid_extensions
43
+ env = Liquid::Environment.default
44
+ env.register_tag("keyiterator", Liquid::CustomBlocks::KeyIterator)
45
+ env.register_tag("with_yaml_nested_context",
46
+ Liquid::CustomBlocks::WithYamlNestedContext)
47
+ env.register_tag("with_json_nested_context",
48
+ Liquid::CustomBlocks::WithJsonNestedContext)
49
+ env.register_filter(Liquid::CustomFilters)
50
+ end
51
+
54
52
  def processed_lines(document, input_lines)
55
53
  result = []
56
54
  loop do
@@ -59,19 +57,9 @@ module Metanorma
59
57
  result
60
58
  end
61
59
 
62
- def relative_file_path(document, file_path)
63
- docfile_directory = File.dirname(
64
- document.attributes["docfile"] || ".",
65
- )
66
- document
67
- .path_resolver
68
- .system_path(file_path, docfile_directory)
69
- end
70
-
71
60
  def process_text_blocks(document, input_lines)
72
61
  line = input_lines.next
73
- block_match = line.match(/^\[#{config[:block_name]},(.+?),(.+?)\]/) ||
74
- line.match(/^\[#{config[:block_name]},(.+?)\]/)
62
+ block_match = line.match(/^\[#{config[:block_name]},(.+?),(.+?)\]/)
75
63
  return [line] if block_match.nil?
76
64
 
77
65
  end_mark = input_lines.next
@@ -82,73 +70,58 @@ module Metanorma
82
70
  block_match)
83
71
  end
84
72
 
85
- def collect_internal_block_lines(document, input_lines, end_mark) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
73
+ def collect_internal_block_lines(document, input_lines, end_mark)
86
74
  current_block = []
75
+ nested_marks = []
87
76
  while (block_line = input_lines.next) != end_mark
88
- if block_line.match?(LOAD_FILE_REGEXP)
89
- load_file_match = block_line.match(LOAD_FILE_REGEXP)
90
-
91
- # Add parent folder as argument to loadfile filter
92
- block_line = "{% assign #{load_file_match[1]} = "\
93
- "#{load_file_match[2]} | loadfile: " \
94
- "\"#{document.attributes['docdir']}\" %}"
77
+ if nested_match = block_line
78
+ .match(/^\[#{config[:block_name]},(.+?),(.+?)\]/)
79
+ current_block
80
+ .push(*nested_context_tag(document,
81
+ nested_match[1],
82
+ nested_match[2]).split("\n"))
83
+ next nested_marks.push(input_lines.next)
95
84
  end
96
85
 
86
+ if nested_marks.include?(block_line)
87
+ current_block.push("{% endwith_#{data_file_type}_nested_context %}")
88
+ next nested_marks.delete(block_line)
89
+ end
97
90
  current_block.push(block_line)
98
91
  end
99
92
  current_block
100
93
  end
101
94
 
102
95
  def data_file_type
103
- @config[:block_name].split("2").first
96
+ config[:block_name].split("2").first
104
97
  end
105
98
 
106
- def parse_template(document, current_block, block_match) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
107
- transformed_liquid_lines = current_block.map do |x|
108
- transform_line_liquid(x)
109
- end
110
-
111
- contexts = if block_match[1].include?("=")
112
- content_from_multiple_contexts(
113
- document, block_match
114
- )
115
- elsif block_match[1].start_with?("#")
116
- {
117
- block_match[2].strip =>
118
- content_from_anchor(document, block_match[1][1..-1]),
119
- }
120
- else
121
- {
122
- block_match[2].strip =>
123
- content_from_file(document, block_match[1]),
124
- }
125
- end
99
+ def nested_context_tag(document, file_path, context_name)
100
+ absolute_file_path = relative_file_path(document, file_path)
101
+ <<~TEMPLATE
102
+ {% capture nested_file_path %}
103
+ #{absolute_file_path}
104
+ {% endcapture %}
105
+ {% with_#{data_file_type}_nested_context nested_file_path, #{context_name} %}
106
+ TEMPLATE
107
+ end
126
108
 
109
+ def parse_template(document, current_block, block_match)
110
+ transformed_liquid_lines = current_block
111
+ .map(&method(:transform_line_liquid))
112
+ context_items = content_from_file(document, block_match[1])
127
113
  parse_context_block(document: document,
128
114
  context_lines: transformed_liquid_lines,
129
- contexts: contexts)
115
+ context_items: context_items,
116
+ context_name: block_match[2].strip)
130
117
  rescue StandardError => e
131
- ::Metanorma::Util.log("Failed to parse #{config[:block_name]} \
132
- block: #{e.message}", :error)
118
+ document.logger
119
+ .warn("Failed to parse #{config[:block_name]} \
120
+ block: #{e.message}")
133
121
  []
134
122
  end
135
123
 
136
- def content_from_multiple_contexts(document, block_match) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
137
- contexts = {}
138
- (1..block_match.size - 1).each do |i|
139
- context_and_paths = block_match[i].strip
140
- context_and_paths.split(",").each do |context_and_path|
141
- context_and_path.strip!
142
- context_name, path = context_and_path.split("=")
143
- context_items = content_from_file(document, path)
144
- contexts[context_name] = context_items
145
- end
146
- end
147
-
148
- contexts
149
- end
150
-
151
- def transform_line_liquid(line) # rubocop:disable Metrics/MethodLength
124
+ def transform_line_liquid(line)
152
125
  if line.match?(BLOCK_START_REGEXP)
153
126
  line.gsub!(BLOCK_START_REGEXP, '{% keyiterator \1, \2 %}')
154
127
  end
@@ -158,51 +131,39 @@ module Metanorma
158
131
  end
159
132
  line
160
133
  .gsub(/(?<!{){(?!%)([^{}]+)(?<!%)}(?!})/, '{{\1}}')
161
- .gsub(/[a-z\.]+\#/, "index")
134
+ .gsub(/[a-z.]+\#/, "index")
162
135
  .gsub(/{{(.+)\s+\+\s+(\d+)\s*?}}/, '{{ \1 | plus: \2 }}')
163
136
  .gsub(/{{(.+)\s+-\s+(\d+)\s*?}}/, '{{ \1 | minus: \2 }}')
164
137
  .gsub(/{{(.+)\.values(.*?)}}/,
165
138
  '{% assign custom_value = \1 | values %}{{custom_value\2}}')
166
139
  end
167
140
 
168
- def parse_context_block(context_lines:, contexts:, document:)
141
+ def parse_context_block(context_lines:,
142
+ context_items:,
143
+ context_name:,
144
+ document:)
169
145
  render_result, errors = render_liquid_string(
170
146
  template_string: context_lines.join("\n"),
171
- contexts: contexts,
147
+ context_items: context_items,
148
+ context_name: context_name,
172
149
  document: document,
173
150
  )
174
151
  notify_render_errors(document, errors)
175
152
  render_result.split("\n")
176
153
  end
177
154
 
178
- def render_liquid_string(template_string:, contexts:, document:) # rubocop:disable Metrics/MethodLength
179
- liquid_template = ::Liquid::Template
180
- .parse(template_string, environment: create_liquid_environment)
181
-
182
- # Allow includes for the template
155
+ def render_liquid_string(template_string:, context_items:,
156
+ context_name:, document:)
157
+ liquid_template = Liquid::Template.parse(template_string)
183
158
  liquid_template.registers[:file_system] =
184
159
  ::Liquid::LocalFileSystem.new(relative_file_path(document, ""))
185
-
186
- rendered_string = liquid_template.render(
187
- contexts,
188
- strict_variables: false,
189
- error_mode: :warn,
190
- )
160
+ rendered_string = liquid_template
161
+ .render(context_name => context_items,
162
+ strict_variables: true,
163
+ error_mode: :warn)
191
164
  [rendered_string, liquid_template.errors]
192
165
  end
193
166
 
194
- def create_liquid_environment
195
- ::Liquid::Environment.new.tap do |liquid_env|
196
- liquid_env.register_tag(
197
- "keyiterator",
198
- ::Metanorma::Plugin::Datastruct::Liquid::CustomBlocks::KeyIterator, # rubocop:disable Layout/LineLength
199
- )
200
- liquid_env.register_filter(
201
- ::Metanorma::Plugin::Datastruct::Liquid::CustomFilters,
202
- )
203
- end
204
- end
205
-
206
167
  def notify_render_errors(document, errors)
207
168
  errors.each do |error_obj|
208
169
  document
@@ -2,19 +2,21 @@
2
2
 
3
3
  require "json"
4
4
  require "yaml"
5
+ require_relative "path_resolver"
5
6
 
6
7
  module Metanorma
7
8
  module Plugin
8
9
  module Datastruct
9
10
  module Content
11
+ include PathResolver
12
+
10
13
  protected
11
14
 
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
15
+ def yaml_content_from_file(resolved_file_path)
14
16
  unless File.exist?(resolved_file_path)
15
17
  ::Metanorma::Util.log(
16
18
  "YAML file referenced in [yaml2text] block not found: " \
17
- "#{resolved_file_path}", :error
19
+ "#{resolved_file_path}", :error,
18
20
  )
19
21
  return
20
22
  end
@@ -27,23 +29,10 @@ module Metanorma
27
29
  )
28
30
  end
29
31
 
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
32
  def json_content_from_file(resolved_file_path)
40
33
  JSON.parse(File.read(resolved_file_path, encoding: "UTF-8"))
41
34
  end
42
35
 
43
- def json_content_from_anchor(document, anchor)
44
- JSON.parse(document.attributes["source_blocks"][anchor])
45
- end
46
-
47
36
  def content_from_file(document, file_path)
48
37
  resolved_file_path = relative_file_path(document, file_path)
49
38
  load_content_from_file(resolved_file_path)
@@ -63,26 +52,9 @@ module Metanorma
63
52
  end
64
53
  end
65
54
 
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
55
  def json_file?(file_path)
80
56
  file_path.end_with?(".json")
81
57
  end
82
-
83
- def json_content?(content)
84
- content.start_with?("{", "[")
85
- end
86
58
  end
87
59
  end
88
60
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Metanorma
4
+ module Plugin
5
+ module Datastruct
6
+ module PathResolver
7
+ def relative_file_path(document, file_path)
8
+ docfile_directory = File.dirname(
9
+ document.attributes["docfile"] || ".",
10
+ )
11
+ document
12
+ .path_resolver
13
+ .system_path(file_path, docfile_directory)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,20 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "path_resolver"
4
+
1
5
  module Metanorma
2
6
  module Plugin
3
7
  module Datastruct
4
8
  class SourceExtractor
5
- # example:
6
- # - [[abc]]
7
- ANCHOR_REGEX_1 = /^\[\[(?<id>[^\]]*)\]\]\s*$/.freeze
8
-
9
- # examples:
10
- # - [#abc]
11
- # - [source#abc,ruby]
12
- ANCHOR_REGEX_2 = /^\[[^#,]*#(?<id>[^,\]]*)[,\]]/.freeze
9
+ include PathResolver
13
10
 
14
- # examples:
15
- # - [id=abc]
16
- # - [source,id="abc"]
17
- ANCHOR_REGEX_3 = /^\[(?:.+,)?id=['"]?(?<id>[^,\]'"]*)['"]?[,\]]/.freeze
11
+ ANCHOR_PATTERNS = [
12
+ /^\[\[(?<id>[^\]]*)\]\]\s*$/,
13
+ /^\[[^#,]*#(?<id>[^,\]]*)[,\]]/,
14
+ /^\[(?:.+,)?id=['"]?(?<id>[^,\]'"]*)['"]?[,\]]/,
15
+ ].freeze
18
16
 
19
17
  def initialize(document, input_lines)
20
18
  @document = document
@@ -27,17 +25,17 @@ module Metanorma
27
25
  new(document, input_lines).extract
28
26
  end
29
27
 
30
- def extract # rubocop:disable Metrics/AbcSize
28
+ def extract
31
29
  lines = @input_lines.to_enum
32
30
 
33
31
  loop do
34
32
  line = lines.next
35
33
 
36
34
  if /^embed::|^include::/.match?(line.strip)
37
- file_lines = read(filename(@document, line)) or next
35
+ file_lines = read(filename(line)) or next
38
36
  SourceExtractor.extract(@document, file_lines)
39
37
  elsif m = match_anchor(line)
40
- @document.attributes["source_blocks"][m[:id]] = read_section lines
38
+ @document.attributes["source_blocks"][m[:id]] = read_section(lines)
41
39
  end
42
40
  end
43
41
  end
@@ -45,42 +43,29 @@ module Metanorma
45
43
  private
46
44
 
47
45
  def match_anchor(line)
48
- line.match(ANCHOR_REGEX_1) ||
49
- line.match(ANCHOR_REGEX_2) ||
50
- line.match(ANCHOR_REGEX_3)
51
- end
52
-
53
- def readlines_safe(file)
54
- return [] if file.eof?
55
-
56
- file.readlines
46
+ ANCHOR_PATTERNS.each do |pattern|
47
+ match = line.match(pattern)
48
+ return match if match
49
+ end
50
+ nil
57
51
  end
58
52
 
59
53
  def read(inc_path)
60
- inc_path or return nil
61
- ::File.open inc_path, "r" do |fd|
62
- readlines_safe(fd).map(&:chomp)
54
+ return nil unless inc_path
55
+
56
+ File.open(inc_path, "r") do |fd|
57
+ fd.eof? ? [] : fd.readlines.map(&:chomp)
63
58
  end
64
59
  end
65
60
 
66
- def filename(document, line)
61
+ def filename(line)
67
62
  m = /(^include::|^embed::)([^\[]+)\[/.match(line)
68
63
  return nil unless m
69
64
 
70
- file_path = relative_file_path(document, m[2])
71
-
65
+ file_path = relative_file_path(@document, m[2])
72
66
  File.exist?(file_path) ? file_path : nil
73
67
  end
74
68
 
75
- def relative_file_path(document, file_path)
76
- docfile_directory = File.dirname(
77
- document.attributes["docfile"] || ".",
78
- )
79
- document
80
- .path_resolver
81
- .system_path(file_path, docfile_directory)
82
- end
83
-
84
69
  def read_section(lines)
85
70
  m = lines.next.match(/^--+/)
86
71
  return "" unless m
@@ -1,7 +1,7 @@
1
1
  module Metanorma
2
2
  module Plugin
3
3
  module Datastruct
4
- VERSION = "0.3.9".freeze
4
+ VERSION = "0.3.10".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -8,33 +8,18 @@ module Metanorma
8
8
  module Datastruct
9
9
  class Yaml2TextPreprocessor < BaseStructuredTextPreprocessor
10
10
  include Content
11
- # search document for block `yaml2text`
12
- # after that take template from block and read file into this template
13
- # example:
14
- # [yaml2text,foobar.yaml]
15
- # ----
16
- # === {item.name}
17
- # {item.desc}
18
- #
19
- # {item.symbol}:: {item.symbol_def}
20
- # ----
21
- #
22
- # with content of `foobar.yaml` file equal to:
23
- # - name: spaghetti
24
- # desc: wheat noodles of 9mm diameter
25
- # symbol: SPAG
26
- # symbol_def: the situation is message like spaghetti at a kid's
27
- #
28
- # will produce:
29
- # === spaghetti
30
- # wheat noodles of 9mm diameter
31
- #
32
- # SPAG:: the situation is message like spaghetti at a kid's meal
33
11
 
34
12
  def initialize(config = {})
35
13
  super
36
14
  @config[:block_name] = "yaml2text"
37
15
  end
16
+
17
+ protected
18
+
19
+ def content_from_file(document, file_path)
20
+ resolved = relative_file_path(document, file_path)
21
+ yaml_content_from_file(resolved)
22
+ end
38
23
  end
39
24
  end
40
25
  end
@@ -15,8 +15,7 @@ Gem::Specification.new do |spec|
15
15
  spec.license = "BSD-2-Clause"
16
16
 
17
17
  # Specify which files should be added to the gem when it is released.
18
- # The `git ls-files -z` loads the files in the RubyGem that have been added
19
- # into git.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
19
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
20
  `git ls-files -z`.split("\x0").reject do |f|
22
21
  f.match(%r{^(test|spec|features)/})
@@ -26,24 +25,9 @@ Gem::Specification.new do |spec|
26
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
26
  spec.require_paths = ["lib"]
28
27
 
29
- spec.required_ruby_version = ">= 2.7.0" # rubocop:disable Gemspec/RequiredRubyVersion
30
-
31
28
  spec.add_dependency "asciidoctor", "~> 2.0.0"
32
29
  spec.add_dependency "isodoc"
30
+ spec.add_dependency "liquid", ">= 4"
33
31
  spec.add_dependency "relaton-cli"
34
-
35
- spec.add_development_dependency "byebug"
36
- spec.add_development_dependency "equivalent-xml"
37
- spec.add_development_dependency "metanorma"
38
- spec.add_development_dependency "metanorma-standoc"
39
- spec.add_development_dependency "rake", "~> 13"
40
- spec.add_development_dependency "rspec", "~> 3.6"
41
- spec.add_development_dependency "rubocop", "~> 1.58"
42
- spec.add_development_dependency "rubocop-performance", "~> 1.19"
43
- spec.add_development_dependency "simplecov", "~> 0.15"
44
- spec.add_development_dependency "timecop", "~> 0.9"
45
- spec.add_development_dependency "vcr", "~> 6.1.0"
46
- spec.add_development_dependency "webmock"
47
- spec.add_development_dependency "xml-c14n"
48
- spec.metadata["rubygems_mfa_required"] = "false"
32
+ spec.metadata["rubygems_mfa_required"] = "true"
49
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-plugin-datastruct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-05-14 00:00:00.000000000 Z
11
+ date: 2026-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -39,195 +39,27 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: relaton-cli
42
+ name: liquid
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '4'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: byebug
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: equivalent-xml
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: metanorma
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: metanorma-standoc
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: rake
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '13'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '13'
125
- - !ruby/object:Gem::Dependency
126
- name: rspec
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '3.6'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '3.6'
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '1.58'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '1.58'
153
- - !ruby/object:Gem::Dependency
154
- name: rubocop-performance
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '1.19'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '1.19'
167
- - !ruby/object:Gem::Dependency
168
- name: simplecov
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: '0.15'
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '0.15'
181
- - !ruby/object:Gem::Dependency
182
- name: timecop
183
- requirement: !ruby/object:Gem::Requirement
184
- requirements:
185
- - - "~>"
186
- - !ruby/object:Gem::Version
187
- version: '0.9'
188
- type: :development
189
- prerelease: false
190
- version_requirements: !ruby/object:Gem::Requirement
191
- requirements:
192
- - - "~>"
193
- - !ruby/object:Gem::Version
194
- version: '0.9'
195
- - !ruby/object:Gem::Dependency
196
- name: vcr
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - "~>"
200
- - !ruby/object:Gem::Version
201
- version: 6.1.0
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - "~>"
207
- - !ruby/object:Gem::Version
208
- version: 6.1.0
209
- - !ruby/object:Gem::Dependency
210
- name: webmock
211
- requirement: !ruby/object:Gem::Requirement
212
- requirements:
213
- - - ">="
214
- - !ruby/object:Gem::Version
215
- version: '0'
216
- type: :development
217
- prerelease: false
218
- version_requirements: !ruby/object:Gem::Requirement
219
- requirements:
220
- - - ">="
221
- - !ruby/object:Gem::Version
222
- version: '0'
54
+ version: '4'
223
55
  - !ruby/object:Gem::Dependency
224
- name: xml-c14n
56
+ name: relaton-cli
225
57
  requirement: !ruby/object:Gem::Requirement
226
58
  requirements:
227
59
  - - ">="
228
60
  - !ruby/object:Gem::Version
229
61
  version: '0'
230
- type: :development
62
+ type: :runtime
231
63
  prerelease: false
232
64
  version_requirements: !ruby/object:Gem::Requirement
233
65
  requirements:
@@ -249,20 +81,23 @@ files:
249
81
  - ".rubocop.yml"
250
82
  - CODE_OF_CONDUCT.md
251
83
  - Gemfile
84
+ - Gemfile.devel
252
85
  - LICENSE
253
86
  - README.adoc
254
87
  - Rakefile
255
88
  - bin/console
256
89
  - bin/setup
90
+ - lib/liquid/custom_blocks/key_iterator.rb
91
+ - lib/liquid/custom_blocks/nested_context_block.rb
92
+ - lib/liquid/custom_blocks/with_json_nested_context.rb
93
+ - lib/liquid/custom_blocks/with_yaml_nested_context.rb
94
+ - lib/liquid/custom_filters/values.rb
257
95
  - lib/metanorma-plugin-datastruct.rb
258
96
  - lib/metanorma/plugin/datastruct/base_structured_text_preprocessor.rb
259
97
  - lib/metanorma/plugin/datastruct/content.rb
260
98
  - lib/metanorma/plugin/datastruct/data2_text_preprocessor.rb
261
99
  - lib/metanorma/plugin/datastruct/json2_text_preprocessor.rb
262
- - lib/metanorma/plugin/datastruct/liquid/custom_blocks/key_iterator.rb
263
- - lib/metanorma/plugin/datastruct/liquid/custom_filters/loadfile.rb
264
- - lib/metanorma/plugin/datastruct/liquid/custom_filters/replace_regex.rb
265
- - lib/metanorma/plugin/datastruct/liquid/custom_filters/values.rb
100
+ - lib/metanorma/plugin/datastruct/path_resolver.rb
266
101
  - lib/metanorma/plugin/datastruct/source_extractor.rb
267
102
  - lib/metanorma/plugin/datastruct/version.rb
268
103
  - lib/metanorma/plugin/datastruct/yaml2_text_preprocessor.rb
@@ -271,7 +106,7 @@ homepage: https://github.com/metanorma/metanorma-plugin-datastruct
271
106
  licenses:
272
107
  - BSD-2-Clause
273
108
  metadata:
274
- rubygems_mfa_required: 'false'
109
+ rubygems_mfa_required: 'true'
275
110
  post_install_message:
276
111
  rdoc_options: []
277
112
  require_paths:
@@ -280,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
280
115
  requirements:
281
116
  - - ">="
282
117
  - !ruby/object:Gem::Version
283
- version: 2.7.0
118
+ version: '0'
284
119
  required_rubygems_version: !ruby/object:Gem::Requirement
285
120
  requirements:
286
121
  - - ">="
@@ -1,31 +0,0 @@
1
- module Metanorma
2
- module Plugin
3
- module Datastruct
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
@@ -1,18 +0,0 @@
1
- require_relative "../../content"
2
-
3
- module Metanorma
4
- module Plugin
5
- module Datastruct
6
- module Liquid
7
- module CustomFilters
8
- include ::Metanorma::Plugin::Datastruct::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
@@ -1,14 +0,0 @@
1
- module Metanorma
2
- module Plugin
3
- module Datastruct
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
@@ -1,13 +0,0 @@
1
- module Metanorma
2
- module Plugin
3
- module Datastruct
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