defmastership 1.0.4 → 1.0.9

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.gitlab-ci.yml +0 -1
  4. data/.rubocop.yml +1 -1
  5. data/Rakefile +1 -2
  6. data/bin/defmastership +36 -24
  7. data/cucumber.yml +2 -0
  8. data/defmastership.gemspec +14 -8
  9. data/features/changeref.feature +82 -129
  10. data/features/definition_checksum.feature +298 -0
  11. data/features/definition_version.feature +24 -0
  12. data/features/export.feature +49 -31
  13. data/features/modify.feature +165 -0
  14. data/features/rename_included_files.feature +121 -0
  15. data/lib/defmastership.rb +14 -3
  16. data/lib/defmastership/batch_modifier.rb +35 -0
  17. data/lib/defmastership/{ref_changer.rb → change_ref_line_modifier.rb} +18 -35
  18. data/lib/defmastership/change_ref_modifier.rb +15 -0
  19. data/lib/defmastership/constants.rb +14 -1
  20. data/lib/defmastership/csv_formatter.rb +25 -19
  21. data/lib/defmastership/csv_formatter_body.rb +19 -11
  22. data/lib/defmastership/csv_formatter_header.rb +15 -10
  23. data/lib/defmastership/definition.rb +14 -3
  24. data/lib/defmastership/definition_parser.rb +46 -0
  25. data/lib/defmastership/document.rb +59 -85
  26. data/lib/defmastership/filters.rb +30 -0
  27. data/lib/defmastership/line_modifier_base.rb +29 -0
  28. data/lib/defmastership/modifier_base.rb +29 -0
  29. data/lib/defmastership/rename_included_files_line_modifier.rb +126 -0
  30. data/lib/defmastership/rename_included_files_modifier.rb +15 -0
  31. data/lib/defmastership/update_def_checksum_line_modifier.rb +38 -0
  32. data/lib/defmastership/update_def_checksum_modifier.rb +21 -0
  33. data/lib/defmastership/version.rb +1 -1
  34. data/spec/spec_helper.rb +1 -0
  35. data/spec/unit/defmastership/batch_modifier_spec.rb +123 -0
  36. data/spec/unit/defmastership/{ref_changer_spec.rb → change_ref_line_modifier_spec.rb} +48 -26
  37. data/spec/unit/defmastership/change_ref_modifier_spec.rb +76 -0
  38. data/spec/unit/defmastership/comment_filter_spec.rb +8 -4
  39. data/spec/unit/defmastership/csv_formatter_body_spec.rb +88 -82
  40. data/spec/unit/defmastership/csv_formatter_header_spec.rb +68 -22
  41. data/spec/unit/defmastership/csv_formatter_spec.rb +208 -110
  42. data/spec/unit/defmastership/definition_parser_spec.rb +63 -0
  43. data/spec/unit/defmastership/definition_spec.rb +45 -4
  44. data/spec/unit/defmastership/document_spec.rb +236 -35
  45. data/spec/unit/defmastership/rename_included_files_line_modifier_spec.rb +203 -0
  46. data/spec/unit/defmastership/rename_included_files_modifier_spec.rb +67 -0
  47. data/spec/unit/defmastership/update_def_checksum_line_modifier_spec.rb +78 -0
  48. data/spec/unit/defmastership/update_def_checksum_modifier_spec.rb +75 -0
  49. metadata +47 -16
  50. data/Gemfile.lock +0 -140
  51. data/lib/defmastership/batch_changer.rb +0 -41
  52. data/lib/defmastership/project_ref_changer.rb +0 -28
  53. data/spec/unit/defmastership/batch_changer_spec.rb +0 -109
  54. data/spec/unit/defmastership/project_ref_changer_spec.rb +0 -80
@@ -19,8 +19,11 @@ module DefMastership
19
19
  \s*
20
20
  (,\s*\[\s*(?<labels>.*?)\s*\])?\s*\]
21
21
  AFT
22
+
23
+ DEF_VERSION_AND_CHECKSUM = '(\((?<explicit_version>[^~]+)?(?<explicit_checksum>~[[:alnum:]]+)?\))?'
24
+
22
25
  DEFINITION = Regexp.new(
23
- "#{DEF_BEFORE_REF}(?<reference>[\\w:_-]+)#{DEF_AFTER_REF}",
26
+ "#{DEF_BEFORE_REF}(?<reference>[\\w:_-]+)#{DEF_VERSION_AND_CHECKSUM}#{DEF_AFTER_REF}",
24
27
  Regexp::EXTENDED
25
28
  )
26
29
 
@@ -56,6 +59,16 @@ module DefMastership
56
59
 
57
60
  WHATEVER = //.freeze
58
61
 
62
+ INCLUDE_KEYWORD = '\binclude::'
63
+ INCLUDE_PATH = '(?<path>.*/)?'
64
+ INCLUDE_FILENAME = '(?<filename>[^\\/]+)'
65
+ INCLUDE_OPTIONS = '\[(?<options>[\]]*)\]'
66
+
67
+ INCLUDE = Regexp.new(
68
+ INCLUDE_KEYWORD + INCLUDE_PATH + INCLUDE_FILENAME + INCLUDE_OPTIONS,
69
+ Regexp::EXTENDED
70
+ )
71
+
59
72
  public_constant :SINGLE_LINE_COMMENT,
60
73
  :MULTI_LINE_COMMENT_DELIM,
61
74
  :DEF_BEFORE_REF,
@@ -8,36 +8,42 @@ require('defmastership/csv_formatter_body')
8
8
  module DefMastership
9
9
  # to export a CSV file
10
10
  class CSVFormatter
11
- COLUMN_LIST = %w[fixed labels eref iref attributes].freeze
12
- private_constant :COLUMN_LIST
13
-
14
- def initialize(doc)
11
+ def initialize(doc, sep = ',')
15
12
  @doc = doc
16
- @header_formatter = CSVFormatterHeader.new(@doc)
17
- @body_formatter = CSVFormatterBody.new(@doc)
13
+ @sep = sep
18
14
  end
19
15
 
20
16
  def export_to(output_file)
21
- CSV.open(output_file, 'w:ISO-8859-1') do |csv|
22
- csv << header
23
- @doc.definitions.each { |definition| csv << body(definition) }
17
+ column_list = build_column_list
18
+ CSV.open(output_file, 'w:ISO-8859-1', { col_sep: @sep }) do |csv|
19
+ csv << header(column_list)
20
+ @doc.definitions.each { |definition| csv << body(definition, column_list) }
24
21
  end
25
22
  end
26
23
 
27
- def header
28
- header_line =
29
- COLUMN_LIST.map do |part|
30
- @header_formatter.public_send("#{part}_header".to_sym)
31
- end
24
+ private
25
+
26
+ def header(column_list)
27
+ header_formatter = CSVFormatterHeader.new(@doc)
28
+ header_line = column_list.map { |part| header_formatter.public_send(part) }
32
29
  header_line.reduce(:+)
33
30
  end
34
31
 
35
- def body(definition)
36
- body_line =
37
- COLUMN_LIST.map do |part|
38
- @body_formatter.public_send("#{part}_body".to_sym, definition)
39
- end
32
+ def body(definition, column_list)
33
+ body_formatter = CSVFormatterBody.new(@doc)
34
+ body_line = column_list.map { |part| body_formatter.public_send(part, definition) }
40
35
  body_line.reduce(:+)
41
36
  end
37
+
38
+ def build_column_list
39
+ column_list = [:fixed]
40
+ column_list += [:wrong_explicit_checksum] if @doc.wrong_explicit_checksum?
41
+ column_list += [:explicit_version] if @doc.explicit_version?
42
+ column_list += [:labels] unless @doc.labels.empty?
43
+ column_list += [:eref] unless @doc.eref.empty?
44
+ column_list += [:iref] if @doc.iref
45
+ column_list += [:attributes] unless @doc.attributes.empty?
46
+ column_list
47
+ end
42
48
  end
43
49
  end
@@ -10,26 +10,34 @@ module DefMastership
10
10
  @doc = doc
11
11
  end
12
12
 
13
- def fixed_body(definition)
14
- [definition.type, definition.reference, definition.value]
13
+ def fixed(definition)
14
+ [definition.type, definition.reference, definition.value, definition.sha256]
15
15
  end
16
16
 
17
- def labels_body(definition)
18
- @doc.labels.empty? ? [] : [definition.labels.to_a.join("\n")]
17
+ def wrong_explicit_checksum(definition)
18
+ wrong_explicit_checksum = definition.wrong_explicit_checksum
19
+ wrong_explicit_checksum ? [wrong_explicit_checksum] : ['']
19
20
  end
20
21
 
21
- def eref_body(definition)
22
+ def explicit_version(definition)
23
+ explicit_version = definition.explicit_version
24
+ explicit_version ? [explicit_version] : ['']
25
+ end
26
+
27
+ def labels(definition)
28
+ [definition.labels.to_a.join("\n")]
29
+ end
30
+
31
+ def eref(definition)
22
32
  @doc.eref.map { |key, _| definition.eref[key].join("\n") }
23
33
  end
24
34
 
25
- def iref_body(definition)
26
- @doc.iref ? [definition.iref.join("\n")] : []
35
+ def iref(definition)
36
+ [definition.iref.join("\n")]
27
37
  end
28
38
 
29
- def attributes_body(definition)
30
- @doc.attributes.map do |key, _|
31
- definition.attributes[key]
32
- end
39
+ def attributes(definition)
40
+ @doc.attributes.map { |key, _| definition.attributes[key] }
33
41
  end
34
42
  end
35
43
  end
@@ -10,26 +10,31 @@ module DefMastership
10
10
  @doc = doc
11
11
  end
12
12
 
13
- def fixed_header
14
- %w[Type Reference Value]
13
+ def fixed
14
+ %w[Type Reference Value Checksum]
15
15
  end
16
16
 
17
- def labels_header
17
+ def wrong_explicit_checksum
18
+ @doc.wrong_explicit_checksum? ? ['Wrong explicit checksum'] : []
19
+ end
20
+
21
+ def explicit_version
22
+ @doc.explicit_version? ? ['Version'] : []
23
+ end
24
+
25
+ def labels
18
26
  @doc.labels.empty? ? [] : %w[Labels]
19
27
  end
20
28
 
21
- def eref_header
22
- @doc.eref.map do |_, ref|
23
- ref[:prefix] +
24
- (ref[:url].nil? || ref[:url] == 'none' ? '' : " #{ref[:url]}")
25
- end
29
+ def eref
30
+ @doc.eref.map { |_, ref| ref[:prefix] }
26
31
  end
27
32
 
28
- def iref_header
33
+ def iref
29
34
  @doc.iref ? ['Internal links'] : []
30
35
  end
31
36
 
32
- def attributes_header
37
+ def attributes
33
38
  @doc.attributes.map { |_, value| value }
34
39
  end
35
40
  end
@@ -1,21 +1,24 @@
1
1
  # Copyright (c) 2020 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'digest'
5
+
4
6
  module DefMastership
5
7
  # DefMastership definition: contains all data of a definition
6
8
  class Definition
7
- attr_reader :type, :reference, :lines, :labels, :eref, :iref, :attributes
9
+ attr_reader :type, :reference, :lines, :labels, :eref, :iref, :attributes, :explicit_version
8
10
 
9
11
  def initialize(match)
10
12
  @type = match[:type]
11
13
  @reference = match[:reference]
12
14
  @lines = []
13
15
  @labels = Set.new
14
- labels = match[:labels]
15
- @labels.merge(labels.split(/\s*,\s*/).to_set) if labels
16
+ @labels.merge(match[:labels].split(/\s*,\s*/).to_set) if match[:labels]
16
17
  @eref = Hash.new([])
17
18
  @iref = []
18
19
  @attributes = {}
20
+ @explicit_checksum = match[:explicit_checksum]
21
+ @explicit_version = match[:explicit_version]
19
22
  end
20
23
 
21
24
  def <<(new_line)
@@ -27,6 +30,14 @@ module DefMastership
27
30
  @lines.join("\n")
28
31
  end
29
32
 
33
+ def sha256
34
+ "~#{Digest::SHA2.new(256).hexdigest(value).split(//).last(8).join}"
35
+ end
36
+
37
+ def wrong_explicit_checksum
38
+ @explicit_checksum if @explicit_checksum != sha256
39
+ end
40
+
30
41
  def add_eref(refname, extrefs)
31
42
  @eref[refname] = extrefs.strip.split(/\s*,\s*/)
32
43
  end
@@ -0,0 +1,46 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('aasm')
5
+
6
+ module DefMastership
7
+ # DefMastership definition: contains all data of a definition
8
+ class DefinitionParser
9
+ include AASM
10
+
11
+ def initialize(document)
12
+ @document = document
13
+ end
14
+
15
+ aasm do
16
+ state :idle, initial: true
17
+ state :wait_content
18
+ state :in_block
19
+ state :single_para
20
+
21
+ event :new_definition do
22
+ transitions from: :idle, to: :wait_content, after: ->(*args) { @document.add_new_definition(*args) }
23
+ end
24
+
25
+ event :block_delimiter do
26
+ transitions from: :wait_content, to: :in_block
27
+ transitions from: %i[in_block idle single_para], to: :idle
28
+ end
29
+
30
+ event :new_line do
31
+ transitions from: %i[wait_content single_para],
32
+ to: :single_para,
33
+ after: ->(*args) { @document.add_line(*args) }
34
+ transitions from: :in_block,
35
+ to: :in_block,
36
+ after: ->(*args) { @document.add_line(*args) }
37
+ transitions from: :idle, to: :idle
38
+ end
39
+
40
+ event :empty_line do
41
+ transitions from: %i[wait_content single_para idle], to: :idle
42
+ transitions from: :in_block, to: :in_block
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,41 +1,13 @@
1
1
  # Copyright (c) 2020 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
- require('aasm')
4
+ require('asciidoctor')
5
5
 
6
6
  module DefMastership
7
7
  # Contains the content of a DefMastership document: mainly definitions
8
- # TODO: make this class smaller by defining a separated parser
9
-
10
- # Contains regexp / action couples
11
- Filter = Struct.new(:regexp, :event, :consumed_line)
12
- private_constant :Filter
13
-
14
- FILTERS_IN_LITERAL = [
15
- Filter.new(DMRegexp::LITERAL_BLOCK, :code_block_delimiter, false),
16
- Filter.new(DMRegexp::WHATEVER, :new_line, true)
17
- ].freeze
18
- private_constant :FILTERS_IN_LITERAL
19
-
20
- FILTERS = [
21
- Filter.new(DMRegexp::VARIABLE_DEF, :new_variable_def, false),
22
- Filter.new(DMRegexp::VARIABLE_USE, :new_variable_use, false),
23
- Filter.new(DMRegexp::DEFINITION, :new_definition, true),
24
- Filter.new(DMRegexp::EREF_CONFIG, :new_eref_setup, true),
25
- Filter.new(DMRegexp::EREF_DEF, :new_eref_def, false),
26
- Filter.new(DMRegexp::IREF_DEF, :new_iref_def, false),
27
- Filter.new(DMRegexp::ATTR_CONFIG, :new_attribute_conf, true),
28
- Filter.new(DMRegexp::ATTR_SET, :new_attribute_value, false),
29
- Filter.new(DMRegexp::BLOCK, :block_delimiter, true),
30
- Filter.new(DMRegexp::LITERAL_BLOCK, :code_block_delimiter, true),
31
- Filter.new(DMRegexp::EMPTY_LINE, :empty_line, false),
32
- Filter.new(DMRegexp::WHATEVER, :new_line, true)
33
- ].freeze
34
- private_constant :FILTERS
35
8
 
36
9
  # Reflects document structure from a definition point of view
37
10
  class Document
38
- include AASM
39
11
  attr_reader :definitions, :labels, :eref, :iref, :attributes, :variables
40
12
 
41
13
  def initialize
@@ -45,110 +17,112 @@ module DefMastership
45
17
  @iref = false
46
18
  @attributes = {}
47
19
  @in_literal = true
48
- @current_line = nil
49
20
  @variables = {}
21
+ @definition_parser = DefinitionParser.new(self)
50
22
  end
51
23
 
52
- aasm do
53
- state :idle, initial: true
54
- state :wait_content
55
- state :in_block
56
- state :single_para
24
+ def parse(lines)
25
+ lines.reject(&:commented?).each do |line|
26
+ (@in_literal ? FILTERS : FILTERS_IN_LITERAL).each do |filter|
27
+ next unless line.match(filter.regexp)
57
28
 
58
- event :new_definition do
59
- transitions from: :idle, to: :wait_content, after: :add_new_definition
60
- end
29
+ line = generate_event(filter.event, Regexp.last_match, line)
61
30
 
62
- event :block_delimiter do
63
- transitions from: :wait_content, to: :in_block
64
- transitions from: %i[in_block idle], to: :idle
65
- transitions from: :single_para, to: :idle
31
+ break if filter.consumed_line
32
+ end
66
33
  end
34
+ end
35
+
36
+ def parse_file_with_preprocessor(adoc_file)
37
+ parse(Asciidoctor.load_file(adoc_file, safe: :unsafe, parse: false).reader.read_lines)
38
+ end
67
39
 
68
- event :new_line do
69
- transitions from: :wait_content, to: :single_para, after: :add_line
70
- transitions from: :single_para, to: :single_para, after: :add_line
71
- transitions from: :in_block, to: :in_block, after: :add_line
72
- transitions from: :idle, to: :idle
40
+ def wrong_explicit_checksum?
41
+ @definitions.reduce(false) do |res, definition|
42
+ res || !definition.wrong_explicit_checksum.nil?
73
43
  end
44
+ end
74
45
 
75
- event :empty_line do
76
- transitions from: %i[wait_content single_para idle], to: :idle
77
- transitions from: :in_block, to: :in_block
46
+ def explicit_version?
47
+ @definitions.reduce(false) do |res, definition|
48
+ res || !definition.explicit_version.nil?
78
49
  end
79
50
  end
80
51
 
81
- def code_block_delimiter(_match)
52
+ def code_block_delimiter(_match, line)
82
53
  @in_literal ^= true
54
+ line
83
55
  end
84
56
 
85
- def add_new_definition(match)
57
+ def add_new_definition(match, line)
86
58
  definition = Definition.new(match)
87
59
  @labels.merge(definition.labels)
88
60
  @definitions << definition
61
+ line
89
62
  end
90
63
 
91
- def add_line(_match)
92
- @definitions.last << @current_line
64
+ def ref_to_def(ref)
65
+ @definitions.find { |definition| definition.reference == ref }
93
66
  end
94
67
 
95
- def new_eref_setup(match)
96
- @eref[match[:refname].to_sym] ||= {}
68
+ def add_line(_match, line)
69
+ @definitions.last << line
70
+ line
71
+ end
97
72
 
98
- @eref[match[:refname].to_sym][match[:symb].to_sym] =
99
- match[:value]
73
+ def new_eref_setup(match, line)
74
+ @eref[match[:refname].to_sym] ||= {}
75
+ @eref[match[:refname].to_sym][match[:symb].to_sym] = match[:value]
76
+ line
100
77
  end
101
78
 
102
- def new_eref_def(match)
103
- @definitions.last.add_eref(
104
- match[:refname].to_sym,
105
- match[:extrefs]
106
- )
79
+ def new_eref_def(match, line)
80
+ @definitions.last.add_eref(match[:refname].to_sym, match[:extrefs])
81
+ line
107
82
  end
108
83
 
109
- def new_iref_def(_match)
84
+ def new_iref_def(_match, line)
110
85
  @iref = true
111
- @current_line.scan(DMRegexp::IREF_DEF) do |_|
86
+ line.scan(DMRegexp::IREF_DEF) do |_|
112
87
  @definitions.last.add_iref(Regexp.last_match[:intref])
113
88
  end
89
+ line
114
90
  end
115
91
 
116
- def new_attribute_conf(match)
92
+ def new_attribute_conf(match, line)
117
93
  @attributes[match[:attr].to_sym] = match[:prefix]
94
+ line
118
95
  end
119
96
 
120
- def new_attribute_value(match)
121
- @definitions.last.set_attribute(
122
- match[:attr].to_sym,
123
- match[:value]
124
- )
97
+ def new_attribute_value(match, line)
98
+ @definitions.last.set_attribute(match[:attr].to_sym, match[:value])
99
+ line
125
100
  end
126
101
 
127
- def new_variable_def(match)
102
+ def new_variable_def(match, line)
128
103
  @variables[match[:varname].to_sym] = match[:value]
104
+ line
129
105
  end
130
106
 
131
- def new_variable_use(_match)
132
- @current_line.scan(DMRegexp::VARIABLE_USE) do |_|
107
+ def new_variable_use(_match, line)
108
+ line.scan(DMRegexp::VARIABLE_USE) do |_|
133
109
  varname = Regexp.last_match[:varname]
134
110
  next if @variables[varname.to_sym].nil?
135
111
 
136
- @current_line = @current_line.gsub(
137
- "{#{varname}}", @variables[varname.to_sym]
138
- )
112
+ line = line.gsub("{#{varname}}", @variables[varname.to_sym])
139
113
  end
114
+ line
140
115
  end
141
116
 
142
- def parse(lines)
143
- lines.reject(&:commented?).each do |line|
144
- @current_line = line
145
- (@in_literal ? FILTERS : FILTERS_IN_LITERAL).each do |filter|
146
- next unless line.match(filter.regexp)
117
+ private
147
118
 
148
- public_send(filter.event, Regexp.last_match)
149
- break if filter.consumed_line
150
- end
119
+ def generate_event(event, match, line)
120
+ if respond_to?(event)
121
+ line = public_send(event, match, line)
122
+ else
123
+ @definition_parser.public_send(event, match, line)
151
124
  end
125
+ line
152
126
  end
153
127
  end
154
128
  end