defmastership 1.0.5 → 1.0.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/bin/defmastership +33 -22
  4. data/cucumber.yml +1 -1
  5. data/defmastership.gemspec +12 -6
  6. data/features/changeref.feature +82 -129
  7. data/features/definition_checksum.feature +298 -0
  8. data/features/definition_version.feature +204 -0
  9. data/features/export.feature +35 -34
  10. data/features/modify.feature +165 -0
  11. data/features/rename_included_files.feature +121 -0
  12. data/lib/defmastership.rb +17 -3
  13. data/lib/defmastership/batch_modifier.rb +35 -0
  14. data/lib/defmastership/{ref_changer.rb → change_ref_line_modifier.rb} +18 -35
  15. data/lib/defmastership/change_ref_modifier.rb +15 -0
  16. data/lib/defmastership/constants.rb +14 -1
  17. data/lib/defmastership/csv_formatter.rb +22 -17
  18. data/lib/defmastership/csv_formatter_body.rb +19 -11
  19. data/lib/defmastership/csv_formatter_header.rb +15 -10
  20. data/lib/defmastership/definition.rb +14 -3
  21. data/lib/defmastership/definition_parser.rb +46 -0
  22. data/lib/defmastership/document.rb +59 -85
  23. data/lib/defmastership/filters.rb +30 -0
  24. data/lib/defmastership/line_modifier_base.rb +29 -0
  25. data/lib/defmastership/modifier_base.rb +29 -0
  26. data/lib/defmastership/rename_included_files_line_modifier.rb +126 -0
  27. data/lib/defmastership/rename_included_files_modifier.rb +15 -0
  28. data/lib/defmastership/update_def_checksum_line_modifier.rb +38 -0
  29. data/lib/defmastership/update_def_checksum_modifier.rb +21 -0
  30. data/lib/defmastership/update_def_version_line_modifier.rb +58 -0
  31. data/lib/defmastership/update_def_version_modifier.rb +25 -0
  32. data/lib/defmastership/version.rb +1 -1
  33. data/spec/spec_helper.rb +1 -0
  34. data/spec/unit/defmastership/batch_modifier_spec.rb +123 -0
  35. data/spec/unit/defmastership/{ref_changer_spec.rb → change_ref_line_modifier_spec.rb} +48 -26
  36. data/spec/unit/defmastership/change_ref_modifier_spec.rb +76 -0
  37. data/spec/unit/defmastership/comment_filter_spec.rb +8 -4
  38. data/spec/unit/defmastership/csv_formatter_body_spec.rb +88 -82
  39. data/spec/unit/defmastership/csv_formatter_header_spec.rb +68 -22
  40. data/spec/unit/defmastership/csv_formatter_spec.rb +207 -109
  41. data/spec/unit/defmastership/definition_parser_spec.rb +63 -0
  42. data/spec/unit/defmastership/definition_spec.rb +45 -4
  43. data/spec/unit/defmastership/document_spec.rb +236 -35
  44. data/spec/unit/defmastership/rename_included_files_line_modifier_spec.rb +203 -0
  45. data/spec/unit/defmastership/rename_included_files_modifier_spec.rb +67 -0
  46. data/spec/unit/defmastership/update_def_checksum_line_modifier_spec.rb +78 -0
  47. data/spec/unit/defmastership/update_def_checksum_modifier_spec.rb +75 -0
  48. data/spec/unit/defmastership/update_def_version_line_modifier_spec.rb +127 -0
  49. data/spec/unit/defmastership/update_def_version_modifier_spec.rb +80 -0
  50. metadata +44 -9
  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
@@ -0,0 +1,30 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # Contains regexp / action couples
6
+ Filter = Struct.new(:regexp, :event, :consumed_line)
7
+ private_constant :Filter
8
+
9
+ FILTERS_IN_LITERAL = [
10
+ Filter.new(DMRegexp::LITERAL_BLOCK, :code_block_delimiter, false),
11
+ Filter.new(DMRegexp::WHATEVER, :new_line, true)
12
+ ].freeze
13
+ private_constant :FILTERS_IN_LITERAL
14
+
15
+ FILTERS = [
16
+ Filter.new(DMRegexp::VARIABLE_DEF, :new_variable_def, false),
17
+ Filter.new(DMRegexp::VARIABLE_USE, :new_variable_use, false),
18
+ Filter.new(DMRegexp::DEFINITION, :new_definition, true),
19
+ Filter.new(DMRegexp::EREF_CONFIG, :new_eref_setup, true),
20
+ Filter.new(DMRegexp::EREF_DEF, :new_eref_def, false),
21
+ Filter.new(DMRegexp::IREF_DEF, :new_iref_def, false),
22
+ Filter.new(DMRegexp::ATTR_CONFIG, :new_attribute_conf, true),
23
+ Filter.new(DMRegexp::ATTR_SET, :new_attribute_value, false),
24
+ Filter.new(DMRegexp::BLOCK, :block_delimiter, true),
25
+ Filter.new(DMRegexp::LITERAL_BLOCK, :code_block_delimiter, true),
26
+ Filter.new(DMRegexp::EMPTY_LINE, :empty_line, false),
27
+ Filter.new(DMRegexp::WHATEVER, :new_line, true)
28
+ ].freeze
29
+ private_constant :FILTERS
30
+ end
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # Change references from temporary to definitive with multiple RefChangers
6
+ class LineModifierBase
7
+ attr_reader :changes, :config
8
+
9
+ def initialize
10
+ @config = {}
11
+ @changes = []
12
+ end
13
+
14
+ def method_missing(method_name, *args, &block)
15
+ return @config[method_name] if @config[method_name]
16
+
17
+ super
18
+ end
19
+
20
+ def respond_to_missing?(method_name, *args)
21
+ @config[method_name] || super
22
+ end
23
+
24
+ def from_config(config)
25
+ @config.merge!(config)
26
+ self
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # Change references from temporary to definitive with multiple RefChangers
6
+ class ModifierBase
7
+ attr_reader :config, :changes
8
+
9
+ def initialize(config)
10
+ @config = config
11
+ @changes = []
12
+ end
13
+
14
+ def do_modifications(adoc_texts)
15
+ line_modifier = new_line_modifier(@config, adoc_texts)
16
+
17
+ adoc_texts =
18
+ replacements.reduce(adoc_texts) do |texts, method|
19
+ texts.transform_values do |text|
20
+ text.lines.map { |line| line_modifier.public_send(method, line) }.join
21
+ end
22
+ end
23
+
24
+ @config = line_modifier.config
25
+ @changes = line_modifier.changes
26
+ adoc_texts
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,126 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # Change included filenames on one line at a time
6
+ class RenameIncludedFilesLineModifier < LineModifierBase
7
+ LOCAL_FILTERS = [
8
+ Filter.new(DMRegexp::VARIABLE_DEF, :new_variable_def, false),
9
+ Filter.new(DMRegexp::DEFINITION, :new_definition, true),
10
+ Filter.new(DMRegexp::BLOCK, :block_delimiter, true),
11
+ Filter.new(DMRegexp::EMPTY_LINE, :empty_line, false),
12
+ Filter.new(DMRegexp::WHATEVER, :new_line, true)
13
+ ].freeze
14
+ private_constant :LOCAL_FILTERS
15
+
16
+ def self.from_config(config)
17
+ new.from_config(config)
18
+ end
19
+
20
+ def initialize
21
+ super
22
+ @config = {
23
+ from_regexp: '',
24
+ to_template: ''
25
+ }
26
+ @variables = {}
27
+ @definition_parser = DefinitionParser.new(self)
28
+ end
29
+
30
+ def replace(line)
31
+ match = matched?(line)
32
+
33
+ return line unless match
34
+
35
+ new_line =
36
+ line.gsub(complete_regexp_from(from_regexp)) do
37
+ text_with(match, to_template % hmerge(match))
38
+ end
39
+
40
+ rename_file(line, new_line)
41
+
42
+ new_line
43
+ end
44
+
45
+ def add_new_definition(match, _line)
46
+ @config[:reference] = match[:reference]
47
+ end
48
+
49
+ def add_line(_match, _line) end
50
+
51
+ def new_variable_def(match, line)
52
+ @variables[match[:varname].to_sym] = match[:value]
53
+ line
54
+ end
55
+
56
+ private
57
+
58
+ def matched?(line)
59
+ return if line.commented?
60
+
61
+ parse(line)
62
+
63
+ return if @definition_parser.idle?
64
+ return unless line =~ complete_regexp_from(from_regexp)
65
+
66
+ match = Regexp.last_match
67
+
68
+ return if @config[:cancel_if_match] && match[:filename] =~ Regexp.new(cancel_if_match)
69
+
70
+ match
71
+ end
72
+
73
+ def parse(line)
74
+ LOCAL_FILTERS.each do |filter|
75
+ next unless line.match(filter.regexp)
76
+
77
+ line = generate_event(filter.event, Regexp.last_match, line)
78
+
79
+ break if filter.consumed_line
80
+ end
81
+ end
82
+
83
+ def rename_file(from, to)
84
+ @changes << [extract_filename(from), extract_filename(to)]
85
+ File.rename(extract_filename(from), extract_filename(to))
86
+ end
87
+
88
+ def extract_filename(include_statement)
89
+ filename = include_statement
90
+ .gsub(Regexp.new(DMRegexp::INCLUDE_KEYWORD), '')
91
+ .gsub(Regexp.new(DMRegexp::INCLUDE_OPTIONS), '')
92
+
93
+ filename.dup.scan(DMRegexp::VARIABLE_USE) do |_|
94
+ varname = Regexp.last_match[:varname]
95
+ next if @variables[varname.to_sym].nil?
96
+
97
+ filename.gsub!("{#{varname}}", @variables[varname.to_sym])
98
+ end
99
+ filename
100
+ end
101
+
102
+ def complete_regexp_from(from)
103
+ Regexp.new(
104
+ DMRegexp::INCLUDE_KEYWORD + DMRegexp::INCLUDE_PATH +
105
+ "(?<filename>#{from})" + DMRegexp::INCLUDE_OPTIONS
106
+ )
107
+ end
108
+
109
+ def text_with(match, to)
110
+ "include::#{match[:path] || ''}#{to}[#{match[:options]}]"
111
+ end
112
+
113
+ def hmerge(match)
114
+ @config.merge(match.names.map(&:to_sym).zip(match.captures).to_h)
115
+ end
116
+
117
+ def generate_event(event, match, line)
118
+ if respond_to?(event)
119
+ public_send(event, match, line)
120
+ else
121
+ @definition_parser.public_send(event, match, line)
122
+ end
123
+ line
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # Change included filenames
6
+ class RenameIncludedFilesModifier < ModifierBase
7
+ def replacements
8
+ %i[replace]
9
+ end
10
+
11
+ def new_line_modifier(config, _adoc_texts)
12
+ RenameIncludedFilesLineModifier.from_config(config)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # modify one line after another
6
+ class UpdateDefChecksumLineModifier < LineModifierBase
7
+ attr_accessor :document
8
+
9
+ def self.from_config(hash)
10
+ new.from_config(hash)
11
+ end
12
+
13
+ def initialize
14
+ super
15
+ @config = {
16
+ def_type: ''
17
+ }
18
+ end
19
+
20
+ def replace(line)
21
+ match = matched?(line)
22
+
23
+ return line unless match
24
+ return line unless match[:type] == def_type
25
+
26
+ line.gsub(Regexp.new("#{match[:reference]}#{DMRegexp::DEF_VERSION_AND_CHECKSUM}")) do
27
+ "#{match[:reference]}(#{match[:explicit_version]}#{@document.ref_to_def(match[:reference]).sha256})"
28
+ end
29
+ end
30
+
31
+ def matched?(line)
32
+ return if line.commented?
33
+ return unless line =~ DMRegexp::DEFINITION
34
+
35
+ Regexp.last_match
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # Update definition checksum with calculated one
6
+ class UpdateDefChecksumModifier < ModifierBase
7
+ def replacements
8
+ %i[replace]
9
+ end
10
+
11
+ def new_line_modifier(config, adoc_texts)
12
+ document = Document.new
13
+ adoc_texts.each do |adoc_file, _|
14
+ document.parse_file_with_preprocessor(adoc_file)
15
+ end
16
+ line_modifier = UpdateDefChecksumLineModifier.from_config(config)
17
+ line_modifier.document = document
18
+ line_modifier
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # modify one line after another
6
+ class UpdateDefVersionLineModifier < LineModifierBase
7
+ attr_accessor :document, :ref_document
8
+
9
+ def self.from_config(hash)
10
+ new.from_config(hash)
11
+ end
12
+
13
+ def initialize
14
+ super
15
+ @config = {
16
+ def_type: '',
17
+ ref_document: '',
18
+ first_version: ''
19
+ }
20
+ end
21
+
22
+ def replace(line)
23
+ match = matched?(line)
24
+
25
+ return line unless match
26
+ return line unless match[:type] == def_type
27
+
28
+ version_and_checksum = ''
29
+ if match[:explicit_checksum] || version_string(match)
30
+ version_and_checksum = "(#{version_string(match)}#{match[:explicit_checksum]})"
31
+ end
32
+
33
+ line.gsub(Regexp.new("#{match[:reference]}#{DMRegexp::DEF_VERSION_AND_CHECKSUM}")) do
34
+ "#{match[:reference]}#{version_and_checksum}"
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def matched?(line)
41
+ return if line.commented?
42
+ return unless line =~ DMRegexp::DEFINITION
43
+
44
+ Regexp.last_match
45
+ end
46
+
47
+ def version_string(match)
48
+ ref_definition = @ref_document.ref_to_def(match[:reference])
49
+ definition = @document.ref_to_def(match[:reference])
50
+
51
+ return if ref_definition.nil?
52
+ return ref_definition.explicit_version if definition.sha256 == ref_definition.sha256
53
+
54
+ ref_version = @ref_document.ref_to_def(match[:reference]).explicit_version
55
+ ref_version.nil? ? @config[:first_version] : ref_version.next
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # Update definition version if the definition has change since
6
+ # reference document
7
+ class UpdateDefVersionModifier < ModifierBase
8
+ def replacements
9
+ %i[replace]
10
+ end
11
+
12
+ def new_line_modifier(config, adoc_texts)
13
+ document = Document.new
14
+ adoc_texts.each do |adoc_file, _|
15
+ document.parse_file_with_preprocessor(adoc_file)
16
+ end
17
+ ref_document = Document.new
18
+ ref_document.parse_file_with_preprocessor(config[:ref_document])
19
+ line_modifier = UpdateDefVersionLineModifier.from_config(config)
20
+ line_modifier.document = document
21
+ line_modifier.ref_document = ref_document
22
+ line_modifier
23
+ end
24
+ end
25
+ end
@@ -2,6 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module DefMastership
5
- VERSION = '1.0.5'
5
+ VERSION = '1.0.10'
6
6
  public_constant :VERSION
7
7
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  require('bundler/setup')
5
5
  require('aruba/rspec')
6
+ require('aasm/rspec')
6
7
 
7
8
  # formatter = [SimpleCov::Formatter::HTMLFormatter]
8
9
  # SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(formatter)
@@ -0,0 +1,123 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership')
5
+
6
+ module DefMastership
7
+ class TotoClassModifier < ModifierBase
8
+ end
9
+
10
+ class TutuClassModifier < ModifierBase
11
+ end
12
+ end
13
+
14
+ RSpec.describe(DefMastership::BatchModifier) do
15
+ subject(:batchmodifier) do
16
+ described_class.new(config, adoc_texts)
17
+ end
18
+
19
+ let(:config) do
20
+ {
21
+ modifier1: { type: 'toto_class', config: { p: 1 } },
22
+ modifier2: { type: 'toto_class', config: { p: 'whatever1' } },
23
+ modifier3: { type: 'tutu_class', config: { p1: 'whatever2', p2: 'whatever3' } }
24
+ }
25
+ end
26
+ let(:adoc_texts) do
27
+ {
28
+ 'file1.adoc' => 'some text',
29
+ 'file2.adoc' => 'another text'
30
+ }
31
+ end
32
+
33
+ describe '.new' do
34
+ it { is_expected.not_to(be(nil)) }
35
+ it { is_expected.to(have_attributes(config: config)) }
36
+
37
+ it do
38
+ expect(batchmodifier).to(have_attributes(adoc_texts: adoc_texts))
39
+ end
40
+ end
41
+
42
+ describe '#apply' do
43
+ context 'with only one modification' do
44
+ let(:toto1) { instance_double(DefMastership::TotoClassModifier, 'toto1') }
45
+ let(:adoc_texts_modified) do
46
+ {
47
+ 'file1.adoc' => 'some text modified',
48
+ 'file2.adoc' => 'another text'
49
+ }
50
+ end
51
+
52
+ let(:config_modified) do
53
+ {
54
+ modifier1: { type: 'toto_class', config: { p: 'modified_param' } },
55
+ modifier2: { type: 'toto_class', config: { p: 'whatever1' } },
56
+ modifier3: { type: 'tutu_class', config: { p1: 'whatever2', p2: 'whatever3' } }
57
+ }
58
+ end
59
+
60
+ before do
61
+ allow(DefMastership::TotoClassModifier).to(receive(:new).once.and_return(toto1))
62
+ allow(toto1).to(receive(:do_modifications).once.and_return(adoc_texts_modified))
63
+ allow(toto1).to(receive(:config).once.and_return(p: 'modified_param'))
64
+ allow(toto1).to(receive(:changes).once.and_return([%w[from1 to1], %w[from2 to2]]))
65
+ batchmodifier.apply('modifier1')
66
+ end
67
+
68
+ it do
69
+ expect(DefMastership::TotoClassModifier).to(have_received(:new).with(p: 1))
70
+ end
71
+
72
+ it { expect(toto1).to(have_received(:do_modifications).with(adoc_texts)) }
73
+ it { is_expected.to(have_attributes(adoc_texts: adoc_texts_modified)) }
74
+ it { expect(toto1).to(have_received(:config).with(no_args)) }
75
+
76
+ it { is_expected.to(have_attributes(config: config_modified)) }
77
+ it { is_expected.to(have_attributes(changes: [%w[modifier1 from1 to1], %w[modifier1 from2 to2]])) }
78
+ end
79
+
80
+ context 'with two modifications' do
81
+ let(:toto2) { instance_double(DefMastership::TotoClassModifier, 'toto2') }
82
+ let(:tutu3) { instance_double(DefMastership::TutuClassModifier, 'tutu3') }
83
+
84
+ let(:config_modified) do
85
+ {
86
+ modifier1: { type: 'toto_class', config: { p: 1 } },
87
+ modifier2: { type: 'toto_class', config: :whatever },
88
+ modifier3: { type: 'tutu_class', config: :pouet }
89
+ }
90
+ end
91
+
92
+ before do
93
+ allow(DefMastership::TotoClassModifier).to(receive(:new).once.and_return(toto2))
94
+ allow(toto2).to(receive(:do_modifications).once.and_return(:adoc_texts_modified_mod2))
95
+ allow(toto2).to(receive(:config).once.and_return(:whatever))
96
+ allow(DefMastership::TutuClassModifier).to(receive(:new).once.and_return(tutu3))
97
+ allow(tutu3).to(receive(:do_modifications).once.and_return(:adoc_texts_modified_mod3))
98
+ allow(tutu3).to(receive(:config).once.and_return(:pouet))
99
+ allow(toto2).to(receive(:changes).once.and_return([%w[from1 to1]]))
100
+ allow(tutu3).to(receive(:changes).once.and_return([%w[from2 to2]]))
101
+ batchmodifier.apply('modifier2, modifier3')
102
+ end
103
+
104
+ it { expect(DefMastership::TotoClassModifier).to(have_received(:new).with(p: 'whatever1')) }
105
+ it { expect(DefMastership::TutuClassModifier).to(have_received(:new).with(p1: 'whatever2', p2: 'whatever3')) }
106
+ it { expect(toto2).to(have_received(:do_modifications).with(adoc_texts)) }
107
+ it { expect(toto2).to(have_received(:config).with(no_args)) }
108
+ it { expect(tutu3).to(have_received(:do_modifications).with(:adoc_texts_modified_mod2)) }
109
+ it { expect(tutu3).to(have_received(:config).with(no_args)) }
110
+ it { is_expected.to(have_attributes(adoc_texts: :adoc_texts_modified_mod3)) }
111
+ it { is_expected.to(have_attributes(config: config_modified)) }
112
+ it { is_expected.to(have_attributes(changes: [%w[modifier2 from1 to1], %w[modifier3 from2 to2]])) }
113
+ end
114
+
115
+ context 'with wrong modification' do
116
+ it do
117
+ expect { batchmodifier.apply('wrong-modification') }.to(
118
+ raise_error(ArgumentError, 'wrong-modification is not a known modification')
119
+ )
120
+ end
121
+ end
122
+ end
123
+ end