defmastership 1.0.16 → 1.0.18

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +50 -7
  4. data/.rubocop.yml +14 -6
  5. data/Gemfile +51 -1
  6. data/Rakefile +16 -47
  7. data/bin/defmastership +12 -9
  8. data/config/mutant.yml +23 -3
  9. data/defmastership.gemspec +22 -27
  10. data/features/definition_checksum.feature +31 -1
  11. data/features/export.feature +43 -1
  12. data/features/rename_included_files.feature +28 -0
  13. data/lib/defmastership/batch_modifier.rb +17 -12
  14. data/lib/defmastership/change_ref_modifier.rb +89 -5
  15. data/lib/defmastership/comment_filter.rb +1 -1
  16. data/lib/defmastership/constants.rb +5 -4
  17. data/lib/defmastership/csv_formatter.rb +20 -16
  18. data/lib/defmastership/csv_formatter_body.rb +18 -15
  19. data/lib/defmastership/csv_formatter_header.rb +1 -1
  20. data/lib/defmastership/definition.rb +58 -19
  21. data/lib/defmastership/document.rb +109 -74
  22. data/lib/defmastership/matching_line.rb +17 -0
  23. data/lib/defmastership/modifier.rb +42 -0
  24. data/lib/defmastership/modifier_factory.rb +12 -0
  25. data/lib/defmastership/parsing_state.rb +15 -9
  26. data/lib/defmastership/rename_included_files_modifier.rb +172 -5
  27. data/lib/defmastership/set_join_hack.rb +11 -0
  28. data/lib/defmastership/update_def_checksum_modifier.rb +8 -13
  29. data/lib/defmastership/update_def_modifier.rb +49 -0
  30. data/lib/defmastership/update_def_version_modifier.rb +56 -15
  31. data/lib/defmastership/version.rb +1 -1
  32. data/lib/defmastership.rb +7 -17
  33. data/spec/spec_helper.rb +4 -2
  34. data/spec/unit/{defmastership → def_mastership}/batch_modifier_spec.rb +42 -39
  35. data/spec/unit/{defmastership/change_ref_line_modifier_spec.rb → def_mastership/change_ref_modifier_spec.rb} +44 -66
  36. data/spec/unit/{defmastership → def_mastership}/csv_formatter_body_spec.rb +61 -32
  37. data/spec/unit/{defmastership → def_mastership}/csv_formatter_header_spec.rb +2 -2
  38. data/spec/unit/{defmastership → def_mastership}/csv_formatter_spec.rb +81 -86
  39. data/spec/unit/{defmastership → def_mastership}/definition_parser_spec.rb +2 -2
  40. data/spec/unit/{defmastership → def_mastership}/definition_spec.rb +17 -7
  41. data/spec/unit/{defmastership → def_mastership}/document_spec.rb +108 -53
  42. data/spec/unit/def_mastership/matching_line_spec.rb +37 -0
  43. data/spec/unit/def_mastership/modifier_factory_spec.rb +37 -0
  44. data/spec/unit/def_mastership/modifier_spec.rb +83 -0
  45. data/spec/unit/{defmastership → def_mastership}/parsing_state_spec.rb +16 -16
  46. data/spec/unit/{defmastership/rename_included_files_line_modifier_spec.rb → def_mastership/rename_included_files_modifier_spec.rb} +72 -36
  47. data/spec/unit/{defmastership/comment_filter_spec.rb → def_mastership/string_spec.rb} +1 -1
  48. data/spec/unit/def_mastership/update_def_checksum_modifier_spec.rb +107 -0
  49. data/spec/unit/def_mastership/update_def_modifier_spec.rb +119 -0
  50. data/spec/unit/def_mastership/update_def_version_modifier_spec.rb +159 -0
  51. data/spec/unit/{defmastership_spec.rb → def_mastership_spec.rb} +1 -1
  52. data/tasks/console.rake +8 -0
  53. data/tasks/package.task +9 -0
  54. data/tasks/smelling_code.rake +38 -0
  55. data/tasks/test.rake +45 -0
  56. metadata +37 -145
  57. data/lib/defmastership/change_ref_line_modifier.rb +0 -82
  58. data/lib/defmastership/line_modifier_base.rb +0 -29
  59. data/lib/defmastership/modifier_base.rb +0 -29
  60. data/lib/defmastership/rename_included_files_line_modifier.rb +0 -126
  61. data/lib/defmastership/update_def_checksum_line_modifier.rb +0 -38
  62. data/lib/defmastership/update_def_version_line_modifier.rb +0 -58
  63. data/spec/unit/defmastership/change_ref_modifier_spec.rb +0 -76
  64. data/spec/unit/defmastership/rename_included_files_modifier_spec.rb +0 -67
  65. data/spec/unit/defmastership/update_def_checksum_line_modifier_spec.rb +0 -78
  66. data/spec/unit/defmastership/update_def_checksum_modifier_spec.rb +0 -75
  67. data/spec/unit/defmastership/update_def_version_line_modifier_spec.rb +0 -127
  68. data/spec/unit/defmastership/update_def_version_modifier_spec.rb +0 -80
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # define methods for line modifiers
6
+ module Modifier
7
+ attr_reader :config, :changes
8
+
9
+ def setup_modifier_module(config)
10
+ @config = self.class.default_config.merge(config)
11
+ @changes = []
12
+ end
13
+
14
+ def method_missing(method_name, *args)
15
+ config_method_name = config[method_name]
16
+ return config_method_name if config_method_name
17
+
18
+ super
19
+ end
20
+
21
+ def respond_to_missing?(method_name, *args)
22
+ config.key?(method_name) || super
23
+ end
24
+
25
+ def apply_to_all(texts, method)
26
+ texts.transform_values do |text|
27
+ apply_to_one(text, method)
28
+ end
29
+ end
30
+
31
+ def apply_to_one(text, method)
32
+ text.lines.map { |line| public_send(method, line) }
33
+ .join
34
+ end
35
+
36
+ def do_modifications(adoc_sources)
37
+ self.class.replacement_methods.reduce(adoc_sources) do |texts, method|
38
+ apply_to_all(texts, method)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright (c) 2023 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # build midifers from a piece of configuration
6
+ module ModifierFactory
7
+ def self.from_config(config)
8
+ class_name = "#{config.fetch(:type).split('_').map(&:capitalize).join}Modifier"
9
+ DefMastership.const_get(class_name).new(config.fetch(:config))
10
+ end
11
+ end
12
+ end
@@ -4,22 +4,28 @@
4
4
  module DefMastership
5
5
  # Allow to know if we need to parse the line or simply ignore it
6
6
  class ParsingState
7
+ # mutant:disable (for mutant, aatribute initialization is useless)
7
8
  def initialize
8
9
  @last_disabling_line = nil
9
10
  end
10
11
 
11
12
  def enabled?(line)
12
- return false if line.match(DMRegexp::SINGLE_LINE_COMMENT)
13
+ return false if line.match?(DMRegexp::SINGLE_LINE_COMMENT)
13
14
 
14
- line = line.dup.chomp
15
- if ['....', '----', '////'].include?(line)
16
- if @last_disabling_line == line
17
- @last_disabling_line = nil
18
- elsif @last_disabling_line.nil?
19
- @last_disabling_line = line
20
- end
15
+ line = line.chomp
16
+ possibly_invert_last_disabling_line(line) if ['....', '----', '////'].include?(line)
17
+
18
+ !@last_disabling_line
19
+ end
20
+
21
+ private
22
+
23
+ def possibly_invert_last_disabling_line(line)
24
+ if @last_disabling_line == line
25
+ @last_disabling_line = nil
26
+ elsif !@last_disabling_line
27
+ @last_disabling_line = line
21
28
  end
22
- @last_disabling_line.nil?
23
29
  end
24
30
  end
25
31
  end
@@ -1,15 +1,182 @@
1
1
  # Copyright (c) 2020 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'defmastership/constants'
5
+ require('defmastership/matching_line')
6
+ require 'defmastership/modifier'
7
+
8
+ # defintion of the Rename Included Files Modifier
4
9
  module DefMastership
5
- # Change included filenames
6
- class RenameIncludedFilesModifier < ModifierBase
7
- def replacements
10
+ LOCAL_FILTERS = [
11
+ Filter.new(DMRegexp::VARIABLE_DEF, :new_variable_def),
12
+ Filter.new(DMRegexp::DEFINITION, :new_definition),
13
+ Filter.new(DMRegexp::BLOCK, :block_delimiter),
14
+ Filter.new(DMRegexp::EMPTY_LINE, :empty_line),
15
+ Filter.new(DMRegexp::WHATEVER, :new_line)
16
+ ].freeze
17
+ private_constant :LOCAL_FILTERS
18
+
19
+ # Change included filenames on one line at a time
20
+ class RenameIncludedFilesModifier
21
+ include Modifier
22
+
23
+ PARSER_ACTIONS = {
24
+ new_variable_def: lambda { |matching_line|
25
+ @variables.merge!(Helper.variable_def_hash(matching_line.match))
26
+ },
27
+ add_line: proc { |_| },
28
+ add_new_definition: lambda { |matching_line|
29
+ config[:reference] = matching_line.match[:reference]
30
+ }
31
+ }.freeze
32
+
33
+ private_constant :PARSER_ACTIONS
34
+
35
+ def self.replacement_methods
8
36
  %i[replace]
9
37
  end
10
38
 
11
- def new_line_modifier(config, _adoc_texts)
12
- RenameIncludedFilesLineModifier.from_config(config)
39
+ def self.default_config
40
+ {
41
+ from_regexp: '',
42
+ to_template: ''
43
+ }
44
+ end
45
+
46
+ def initialize(config)
47
+ @variables = {}
48
+ @definition_parser = DefinitionParser.new(self)
49
+
50
+ setup_modifier_module(config)
51
+ end
52
+
53
+ def method_missing(method_name, *args)
54
+ action = PARSER_ACTIONS[method_name]
55
+ return instance_exec(*args, &action) if action
56
+
57
+ super
58
+ end
59
+
60
+ def respond_to_missing?(method_name, *args)
61
+ PARSER_ACTIONS.key?(method_name) || super
62
+ end
63
+
64
+ def replace(line)
65
+ match = matched?(line)
66
+
67
+ return line unless match
68
+
69
+ new_line = build_new_include_line(match, line)
70
+
71
+ rename_file(line, new_line)
72
+
73
+ new_line
74
+ end
75
+
76
+ private
77
+
78
+ def build_new_include_line(match, line)
79
+ line.sub(Helper.complete_regexp_from(from_regexp)) do
80
+ Helper.text_with(match, to_template % Helper.hmerge(config, match))
81
+ end
82
+ end
83
+
84
+ def matched?(line)
85
+ return false unless concerned_line?(line)
86
+ return false unless line =~ Helper.complete_regexp_from(from_regexp)
87
+
88
+ match = Regexp.last_match
89
+
90
+ return false if config.key?(:cancel_if_match) && match[:filename].match?(cancel_if_match)
91
+
92
+ match
93
+ end
94
+
95
+ def concerned_line?(line)
96
+ return false if line.commented?
97
+
98
+ parse(line)
99
+
100
+ return false if @definition_parser.idle?
101
+
102
+ true
103
+ end
104
+
105
+ def parse(line)
106
+ Helper.apply_filters_until_consumed(line) do |event, match|
107
+ generate_event(event, MatchingLine.new(match))
108
+ end
109
+ end
110
+
111
+ def rename_file(from, to)
112
+ filename_from = Helper.extract_filename(from, @variables)
113
+ filename_to = Helper.extract_filename(to, @variables)
114
+ changes << [filename_from, filename_to]
115
+ File.rename(filename_from, filename_to)
116
+ end
117
+
118
+ def generate_event(event, matching_line)
119
+ if PARSER_ACTIONS.key?(event)
120
+ public_send(event, matching_line)
121
+ else
122
+ @definition_parser.public_send(event, matching_line)
123
+ end
124
+ end
125
+
126
+ # Helper functions
127
+ module Helper
128
+ def self.extract_filename(include_statement, variables)
129
+ filename = filename_from_include_statement(include_statement)
130
+
131
+ filename_replace_all_variables(filename, variables).chomp
132
+ end
133
+
134
+ def self.filename_from_include_statement(include_statement)
135
+ include_statement
136
+ .sub(Regexp.new(DMRegexp::INCLUDE_KEYWORD), '')
137
+ .sub(Regexp.new(DMRegexp::INCLUDE_OPTIONS), '')
138
+ end
139
+
140
+ def self.filename_replace_all_variables(filename, variables)
141
+ filename.scan(DMRegexp::VARIABLE_USE) do
142
+ varname = Regexp.last_match[:varname]
143
+ value = variables.fetch(varname.to_sym)
144
+ filename = filename_replace_one_variable(filename, varname, value)
145
+ end
146
+ filename
147
+ end
148
+
149
+ def self.filename_replace_one_variable(filename, varname, value)
150
+ filename.sub("{#{varname}}", value)
151
+ end
152
+
153
+ def self.complete_regexp_from(from)
154
+ Regexp.new(
155
+ DMRegexp::INCLUDE_KEYWORD + DMRegexp::INCLUDE_PATH +
156
+ "(?<filename>#{from})" + DMRegexp::INCLUDE_OPTIONS
157
+ )
158
+ end
159
+
160
+ def self.text_with(match, to)
161
+ "include::#{match[:path]}#{to}[#{match[:options]}]"
162
+ end
163
+
164
+ def self.hmerge(config, match)
165
+ config.merge(match.names.map(&:to_sym).zip(match.captures).to_h)
166
+ end
167
+
168
+ def self.variable_def_hash(match)
169
+ { match[:varname].to_sym => match[:value] }
170
+ end
171
+
172
+ def self.apply_filters_until_consumed(line)
173
+ LOCAL_FILTERS.each do |filter|
174
+ next unless line.match(filter.regexp)
175
+
176
+ yield(filter.event, Regexp.last_match)
177
+ break
178
+ end
179
+ end
13
180
  end
14
181
  end
15
182
  end
@@ -0,0 +1,11 @@
1
+ # Copyright (c) 2024 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ if RUBY_VERSION < '3.0'
5
+ # Ruby 2.7 do not implement join for Set
6
+ class Set
7
+ def join(*args)
8
+ to_a.join(*args)
9
+ end
10
+ end
11
+ end
@@ -1,21 +1,16 @@
1
1
  # Copyright (c) 2020 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'defmastership/constants'
5
+ require 'defmastership/update_def_modifier'
6
+
4
7
  module DefMastership
5
- # Update definition checksum with calculated one
6
- class UpdateDefChecksumModifier < ModifierBase
7
- def replacements
8
- %i[replace]
9
- end
8
+ # modify one line after another
9
+ class UpdateDefChecksumModifier < UpdateDefModifier
10
+ private
10
11
 
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
12
+ def reference_replacement(reference, match)
13
+ "#{reference}(#{match[:explicit_version]}#{document.ref_to_def(reference).sha256_short})"
19
14
  end
20
15
  end
21
16
  end
@@ -0,0 +1,49 @@
1
+ # Copyright (c) 2024 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # absttrac class for modififier that need o update defintion references
6
+ class UpdateDefModifier
7
+ include Modifier
8
+
9
+ attr_reader :document
10
+
11
+ def self.default_config
12
+ {
13
+ def_type: ''
14
+ }
15
+ end
16
+
17
+ def self.replacement_methods
18
+ %i[replace_reference]
19
+ end
20
+
21
+ def self.reference_regexp(reference)
22
+ Regexp.new("#{reference}#{DMRegexp::DEF_VERSION_AND_CHECKSUM}")
23
+ end
24
+
25
+ def initialize(config)
26
+ @document = Document.new
27
+
28
+ setup_modifier_module(config)
29
+ end
30
+
31
+ def do_modifications(adoc_sources)
32
+ adoc_sources.each_key do |adoc_file|
33
+ document.parse_file_with_preprocessor(adoc_file)
34
+ end
35
+
36
+ super(adoc_sources)
37
+ end
38
+
39
+ def replace_reference(line)
40
+ match = line.match(DMRegexp::DEFINITION)
41
+
42
+ return line unless match
43
+ return line unless match[:type] == def_type
44
+
45
+ reference = match[:reference]
46
+ line.sub(self.class.reference_regexp(reference), reference_replacement(reference, match))
47
+ end
48
+ end
49
+ end
@@ -1,25 +1,66 @@
1
1
  # Copyright (c) 2020 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'defmastership/constants'
5
+ require 'defmastership/update_def_modifier'
6
+
4
7
  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]
8
+ # modify one line after another
9
+ class UpdateDefVersionModifier < UpdateDefModifier
10
+ def self.default_config
11
+ {
12
+ def_type: '',
13
+ ref_document: '',
14
+ first_version: ''
15
+ }
16
+ end
17
+
18
+ def initialize(config)
19
+ @ref_document = Document.new
20
+
21
+ super(config)
22
+ end
23
+
24
+ def do_modifications(adoc_sources)
25
+ @ref_document.parse_file_with_preprocessor(config.fetch(:ref_document))
26
+
27
+ super(adoc_sources)
28
+ end
29
+
30
+ private
31
+
32
+ def reference_replacement(reference, match)
33
+ "#{reference}#{version_and_checksum_str(match)}"
10
34
  end
11
35
 
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)
36
+ def version_and_checksum_str(match)
37
+ explicit_checksum = match[:explicit_checksum]
38
+ version = version_string(match)
39
+ return unless explicit_checksum || version
40
+
41
+ "(#{version}#{explicit_checksum})"
42
+ end
43
+
44
+ def version_string(match)
45
+ ref_definition = Helper.def_from_match(@ref_document, match)
46
+ definition = Helper.def_from_match(document, match)
47
+ return unless ref_definition
48
+
49
+ Helper.ref_version(ref_definition, definition, config.fetch(:first_version))
50
+ end
51
+
52
+ # Helper functions
53
+ module Helper
54
+ def self.def_from_match(doc, match)
55
+ doc.ref_to_def(match[:reference])
56
+ end
57
+
58
+ def self.ref_version(ref_definition, definition, first_version)
59
+ new_ref_version = ref_definition.explicit_version
60
+ return new_ref_version if definition.sha256_short == ref_definition.sha256_short
61
+
62
+ new_ref_version ? new_ref_version.next : first_version
16
63
  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
64
  end
24
65
  end
25
66
  end
@@ -2,6 +2,6 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module DefMastership
5
- VERSION = '1.0.16'
5
+ VERSION = '1.0.18'
6
6
  public_constant :VERSION
7
7
  end
data/lib/defmastership.rb CHANGED
@@ -5,27 +5,17 @@ require('defmastership/version')
5
5
 
6
6
  # Add requires for other files you add to your project here, so
7
7
  # you just need to require this one file in your bin file
8
+ require('defmastership/batch_modifier')
9
+ require('defmastership/change_ref_modifier')
10
+ require('defmastership/comment_filter')
8
11
  require('defmastership/constants')
9
- require('defmastership/parsing_state')
12
+ require('defmastership/csv_formatter')
10
13
  require('defmastership/definition')
11
14
  require('defmastership/definition_parser')
12
- require('defmastership/filters')
13
15
  require('defmastership/document')
14
- require('defmastership/comment_filter')
15
- require('defmastership/csv_formatter')
16
-
17
- require('defmastership/modifier_base')
18
- require('defmastership/line_modifier_base')
19
- require('defmastership/batch_modifier')
20
-
21
- require('defmastership/change_ref_modifier')
22
- require('defmastership/change_ref_line_modifier')
23
-
16
+ require('defmastership/filters')
17
+ require('defmastership/modifier_factory')
18
+ require('defmastership/parsing_state')
24
19
  require('defmastership/rename_included_files_modifier')
25
- require('defmastership/rename_included_files_line_modifier')
26
-
27
20
  require('defmastership/update_def_checksum_modifier')
28
- require('defmastership/update_def_checksum_line_modifier')
29
-
30
21
  require('defmastership/update_def_version_modifier')
31
- require('defmastership/update_def_version_line_modifier')
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  # Copyright (c) 2020 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
- require('bundler/setup')
5
- require('aruba/rspec')
6
4
  require('aasm/rspec')
5
+ require('aruba/rspec')
7
6
 
8
7
  # formatter = [SimpleCov::Formatter::HTMLFormatter]
9
8
  # SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(formatter)
@@ -18,8 +17,11 @@ SimpleCov.start do
18
17
 
19
18
  add_filter 'config'
20
19
  add_filter 'vendor'
20
+ add_filter 'set_join_hack'
21
21
 
22
22
  minimum_coverage 100
23
+
24
+ enable_coverage :branch
23
25
  end
24
26
 
25
27
  RSpec.configure do |config|