defmastership 1.0.1 → 1.0.6

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 +20 -0
  4. data/.rubocop.yml +5 -4
  5. data/Gemfile +1 -0
  6. data/LICENSE +22 -0
  7. data/Rakefile +2 -2
  8. data/bin/defmastership +25 -17
  9. data/cucumber.yml +2 -0
  10. data/defmastership.gemspec +18 -11
  11. data/features/changeref.feature +82 -129
  12. data/features/export.feature +102 -31
  13. data/features/modify.feature +143 -0
  14. data/features/rename_included_files.feature +121 -0
  15. data/features/step_definitions/defmastership_steps.rb +1 -0
  16. data/features/support/env.rb +1 -0
  17. data/lib/defmastership.rb +12 -3
  18. data/lib/defmastership/batch_modifier.rb +33 -0
  19. data/lib/defmastership/{ref_changer.rb → change_ref_line_modifier.rb} +19 -35
  20. data/lib/defmastership/change_ref_modifier.rb +15 -0
  21. data/lib/defmastership/comment_filter.rb +1 -0
  22. data/lib/defmastership/constants.rb +15 -1
  23. data/lib/defmastership/csv_formatter.rb +19 -18
  24. data/lib/defmastership/csv_formatter_body.rb +12 -6
  25. data/lib/defmastership/csv_formatter_header.rb +12 -10
  26. data/lib/defmastership/definition.rb +12 -0
  27. data/lib/defmastership/definition_parser.rb +46 -0
  28. data/lib/defmastership/document.rb +44 -75
  29. data/lib/defmastership/filters.rb +30 -0
  30. data/lib/defmastership/line_modifier_base.rb +29 -0
  31. data/lib/defmastership/modifier_base.rb +29 -0
  32. data/lib/defmastership/rename_included_files_line_modifier.rb +126 -0
  33. data/lib/defmastership/rename_included_files_modifier.rb +30 -0
  34. data/lib/defmastership/version.rb +2 -1
  35. data/spec/spec_helper.rb +2 -0
  36. data/spec/unit/defmastership/batch_modifier_spec.rb +115 -0
  37. data/spec/unit/defmastership/{ref_changer_spec.rb → change_ref_line_modifier_spec.rb} +49 -26
  38. data/spec/unit/defmastership/change_ref_modifier_spec.rb +76 -0
  39. data/spec/unit/defmastership/comment_filter_spec.rb +9 -4
  40. data/spec/unit/defmastership/csv_formatter_body_spec.rb +62 -37
  41. data/spec/unit/defmastership/csv_formatter_header_spec.rb +47 -22
  42. data/spec/unit/defmastership/csv_formatter_spec.rb +67 -105
  43. data/spec/unit/defmastership/definition_parser_spec.rb +63 -0
  44. data/spec/unit/defmastership/definition_spec.rb +31 -4
  45. data/spec/unit/defmastership/document_spec.rb +113 -35
  46. data/spec/unit/defmastership/rename_included_files_line_modifier_spec.rb +203 -0
  47. data/spec/unit/defmastership/rename_included_files_modifier_spec.rb +67 -0
  48. data/spec/unit/defmastership_spec.rb +1 -0
  49. metadata +44 -17
  50. data/Gemfile.lock +0 -140
  51. data/lib/defmastership/batch_changer.rb +0 -40
  52. data/lib/defmastership/project_ref_changer.rb +0 -27
  53. data/spec/unit/defmastership/batch_changer_spec.rb +0 -108
  54. data/spec/unit/defmastership/project_ref_changer_spec.rb +0 -79
@@ -1,40 +1,11 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
1
2
  # frozen_string_literal: true
2
3
 
3
- require('aasm')
4
-
5
4
  module DefMastership
6
5
  # Contains the content of a DefMastership document: mainly definitions
7
- # TODO: make this class smaller by defining a separated parser
8
-
9
- # Contains regexp / action couples
10
- Filter = Struct.new(:regexp, :event, :consumed_line)
11
- private_constant :Filter
12
-
13
- FILTERS_IN_LITERAL = [
14
- Filter.new(DMRegexp::LITERAL_BLOCK, :code_block_delimiter, false),
15
- Filter.new(DMRegexp::WHATEVER, :new_line, true)
16
- ].freeze
17
- private_constant :FILTERS_IN_LITERAL
18
-
19
- FILTERS = [
20
- Filter.new(DMRegexp::VARIABLE_DEF, :new_variable_def, false),
21
- Filter.new(DMRegexp::VARIABLE_USE, :new_variable_use, false),
22
- Filter.new(DMRegexp::DEFINITION, :new_definition, true),
23
- Filter.new(DMRegexp::EREF_CONFIG, :new_eref_setup, true),
24
- Filter.new(DMRegexp::EREF_DEF, :new_eref_def, false),
25
- Filter.new(DMRegexp::IREF_DEF, :new_iref_def, false),
26
- Filter.new(DMRegexp::ATTR_CONFIG, :new_attribute_conf, true),
27
- Filter.new(DMRegexp::ATTR_SET, :new_attribute_value, false),
28
- Filter.new(DMRegexp::BLOCK, :block_delimiter, true),
29
- Filter.new(DMRegexp::LITERAL_BLOCK, :code_block_delimiter, true),
30
- Filter.new(DMRegexp::EMPTY_LINE, :empty_line, false),
31
- Filter.new(DMRegexp::WHATEVER, :new_line, true)
32
- ].freeze
33
- private_constant :FILTERS
34
6
 
35
7
  # Reflects document structure from a definition point of view
36
8
  class Document
37
- include AASM
38
9
  attr_reader :definitions, :labels, :eref, :iref, :attributes, :variables
39
10
 
40
11
  def initialize
@@ -44,110 +15,108 @@ module DefMastership
44
15
  @iref = false
45
16
  @attributes = {}
46
17
  @in_literal = true
47
- @current_line = nil
48
18
  @variables = {}
49
- end
50
-
51
- aasm do
52
- state :idle, initial: true
53
- state :wait_content
54
- state :in_block
55
- state :single_para
56
-
57
- event :new_definition do
58
- transitions from: :idle, to: :wait_content, after: :add_new_definition
59
- end
60
-
61
- event :block_delimiter do
62
- transitions from: :wait_content, to: :in_block
63
- transitions from: %i[in_block idle], to: :idle
64
- transitions from: :single_para, to: :idle
65
- end
66
19
 
67
- event :new_line do
68
- transitions from: :wait_content, to: :single_para, after: :add_line
69
- transitions from: :single_para, to: :single_para, after: :add_line
70
- transitions from: :in_block, to: :in_block, after: :add_line
71
- transitions from: :idle, to: :idle
72
- end
20
+ @definition_parser = DefinitionParser.new(self)
21
+ end
73
22
 
74
- event :empty_line do
75
- transitions from: %i[wait_content single_para idle], to: :idle
76
- transitions from: :in_block, to: :in_block
23
+ def wrong_explicit_checksum?
24
+ @definitions.reduce(false) do |res, definition|
25
+ res || !definition.wrong_explicit_checksum.nil?
77
26
  end
78
27
  end
79
28
 
80
- def code_block_delimiter(_match)
29
+ def code_block_delimiter(_match, line)
81
30
  @in_literal ^= true
31
+ line
82
32
  end
83
33
 
84
- def add_new_definition(match)
34
+ def add_new_definition(match, line)
85
35
  definition = Definition.new(match)
86
36
  @labels.merge(definition.labels)
87
37
  @definitions << definition
38
+ line
88
39
  end
89
40
 
90
- def add_line(_match)
91
- @definitions.last << @current_line
41
+ def add_line(_match, line)
42
+ @definitions.last << line
43
+ line
92
44
  end
93
45
 
94
- def new_eref_setup(match)
46
+ def new_eref_setup(match, line)
95
47
  @eref[match[:refname].to_sym] ||= {}
96
48
 
97
49
  @eref[match[:refname].to_sym][match[:symb].to_sym] =
98
50
  match[:value]
51
+ line
99
52
  end
100
53
 
101
- def new_eref_def(match)
54
+ def new_eref_def(match, line)
102
55
  @definitions.last.add_eref(
103
56
  match[:refname].to_sym,
104
57
  match[:extrefs]
105
58
  )
59
+ line
106
60
  end
107
61
 
108
- def new_iref_def(_match)
62
+ def new_iref_def(_match, line)
109
63
  @iref = true
110
- @current_line.scan(DMRegexp::IREF_DEF) do |_|
64
+ line.scan(DMRegexp::IREF_DEF) do |_|
111
65
  @definitions.last.add_iref(Regexp.last_match[:intref])
112
66
  end
67
+ line
113
68
  end
114
69
 
115
- def new_attribute_conf(match)
70
+ def new_attribute_conf(match, line)
116
71
  @attributes[match[:attr].to_sym] = match[:prefix]
72
+ line
117
73
  end
118
74
 
119
- def new_attribute_value(match)
75
+ def new_attribute_value(match, line)
120
76
  @definitions.last.set_attribute(
121
77
  match[:attr].to_sym,
122
78
  match[:value]
123
79
  )
80
+ line
124
81
  end
125
82
 
126
- def new_variable_def(match)
83
+ def new_variable_def(match, line)
127
84
  @variables[match[:varname].to_sym] = match[:value]
85
+ line
128
86
  end
129
87
 
130
- def new_variable_use(_match)
131
- @current_line.scan(DMRegexp::VARIABLE_USE) do |_|
88
+ def new_variable_use(_match, line)
89
+ new_line = line.dup
90
+ line.scan(DMRegexp::VARIABLE_USE) do |_|
132
91
  varname = Regexp.last_match[:varname]
133
92
  next if @variables[varname.to_sym].nil?
134
93
 
135
- @current_line = @current_line.gsub(
136
- "{#{varname}}", @variables[varname.to_sym]
137
- )
94
+ new_line.gsub!("{#{varname}}", @variables[varname.to_sym])
138
95
  end
96
+ new_line
139
97
  end
140
98
 
141
99
  def parse(lines)
142
100
  lines.reject(&:commented?).each do |line|
143
- @current_line = line
144
101
  (@in_literal ? FILTERS : FILTERS_IN_LITERAL).each do |filter|
145
102
  next unless line.match(filter.regexp)
146
103
 
147
- public_send(filter.event, Regexp.last_match)
104
+ line = generate_event(filter.event, Regexp.last_match, line)
105
+
148
106
  break if filter.consumed_line
149
107
  end
150
108
  end
151
109
  end
110
+
111
+ private
112
+
113
+ def generate_event(event, match, line)
114
+ if respond_to?(event)
115
+ line = public_send(event, match, line)
116
+ else
117
+ @definition_parser.public_send(event, match, line)
118
+ end
119
+ line
120
+ end
152
121
  end
153
122
  end
@@ -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 = line_modifier_class.from_config(@config)
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,30 @@
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 do_modifications(adoc_texts)
8
+ line_modifier = line_modifier_class.from_config(@config)
9
+
10
+ adoc_texts =
11
+ replacements.reduce(adoc_texts) do |texts, method|
12
+ texts.transform_values do |text|
13
+ text.lines.map { |line| line_modifier.public_send(method, line) }.join
14
+ end
15
+ end
16
+
17
+ @config = line_modifier.config
18
+ @changes = line_modifier.changes
19
+ adoc_texts
20
+ end
21
+
22
+ def replacements
23
+ %i[replace]
24
+ end
25
+
26
+ def line_modifier_class
27
+ RenameIncludedFilesLineModifier
28
+ end
29
+ end
30
+ end
@@ -1,6 +1,7 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module DefMastership
4
- VERSION = '1.0.1'
5
+ VERSION = '1.0.6'
5
6
  public_constant :VERSION
6
7
  end