defmastership 1.3.3 → 1.3.4

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -9
  3. data/Rakefile +1 -1
  4. data/defmastership.gemspec +3 -2
  5. data/features/changeref.feature +30 -0
  6. data/features/export.feature +55 -0
  7. data/features/rename_included_files.feature +27 -0
  8. data/features/step_definitions/git_steps.rb +3 -0
  9. data/lib/defmastership/app.rb +31 -3
  10. data/lib/defmastership/export/csv/formatter.rb +8 -60
  11. data/lib/defmastership/export/formatter.rb +88 -0
  12. data/lib/defmastership/export/json/formatter.rb +34 -0
  13. data/lib/defmastership/export/xlsx/formatter.rb +87 -0
  14. data/lib/defmastership/export/yaml/formatter.rb +34 -0
  15. data/lib/defmastership/modifier/change_ref.rb +13 -5
  16. data/lib/defmastership/modifier/modifier_common.rb +4 -4
  17. data/lib/defmastership/modifier/rename_included_files.rb +7 -5
  18. data/lib/defmastership/modifier/update_def.rb +2 -1
  19. data/lib/defmastership/modifier/update_eref_common.rb +2 -1
  20. data/lib/defmastership/modifier/update_iref_checksum.rb +2 -1
  21. data/lib/defmastership/modifier/update_iref_version.rb +2 -1
  22. data/lib/defmastership/version.rb +1 -1
  23. data/spec/unit/defmastership/app_spec.rb +27 -3
  24. data/spec/unit/defmastership/export/csv/formatter_spec.rb +44 -231
  25. data/spec/unit/defmastership/export/formatter_spec.rb +97 -0
  26. data/spec/unit/defmastership/export/json/formatter_spec.rb +85 -0
  27. data/spec/unit/defmastership/export/xlsx/formatter_spec.rb +82 -0
  28. data/spec/unit/defmastership/export/yaml/formatter_spec.rb +85 -0
  29. data/spec/unit/defmastership/modifier/change_ref_spec.rb +54 -48
  30. data/spec/unit/defmastership/modifier/modifier_common_spec.rb +5 -5
  31. data/spec/unit/defmastership/modifier/rename_included_files_spec.rb +66 -62
  32. data/spec/unit/defmastership/modifier/update_def_checksum_spec.rb +5 -5
  33. data/spec/unit/defmastership/modifier/update_def_spec.rb +12 -10
  34. data/spec/unit/defmastership/modifier/update_def_version_spec.rb +9 -7
  35. data/spec/unit/defmastership/modifier/update_eref_checksum_spec.rb +26 -17
  36. data/spec/unit/defmastership/modifier/update_eref_version_spec.rb +34 -22
  37. data/spec/unit/defmastership/modifier/update_iref_checksum_spec.rb +8 -8
  38. data/spec/unit/defmastership/modifier/update_iref_version_spec.rb +11 -11
  39. data/tasks/code_quality.rake +1 -1
  40. metadata +28 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 568d3b059a4327d2b486468b9867230d3547f9f499134c85e6c1d013761373a8
4
- data.tar.gz: 8b9bf9d9abe528e104a3105a5ebd7c9fc83060282e56b81c7dfab8509eaa3b97
3
+ metadata.gz: 7005c6bf64a1de44a7ac2f511070d4233ec8abde7816df47ceb1219c77500732
4
+ data.tar.gz: 219352e005a6e87d02258caacc30ad537e3d644da8dc008b1d4b958e70f33fcc
5
5
  SHA512:
6
- metadata.gz: 21e893b27a124ae1cdd50fa3312f06fa767d87cd44953f3f5b133e29c7bf6c21bd9f53c5683738c27bafa5050159be2f548068433995d15c45b442df9b136ceb
7
- data.tar.gz: d04e16d41f24eee527638d475101080de60115cdaabd8ee48cc2b81084256cb1db6556ca8f5ecf9b123154b45b2b7be77b6af5a8ba56877eaa6ec9338b7d27fe
6
+ metadata.gz: 5a80ed40ddcf6300da7287b30e5e5c10bb4789aca80ef2c927a85056987c6831022e18e2459ac72633b408f05d3ab564292d96611c282f19e73d173534eadf91
7
+ data.tar.gz: 218bad889104732f8ba69f00b0313b7a8327ddffb7ea5bfd2e2fac66b4dd38ae37efacf7f0033be576b32924bececafa4582c02a7cf458bc9c81ed2474cbacbd
data/Gemfile CHANGED
@@ -11,13 +11,13 @@ group :development do
11
11
  # cucumber steps for command line tests
12
12
  gem 'aruba', '~> 2.3'
13
13
  # bdd
14
- gem 'cucumber', '~> 10.0'
14
+ gem 'cucumber', '~> 10.2'
15
15
  # code duplication
16
- gem 'flay', '~> 2.13'
16
+ gem 'flay', '~> 2.14'
17
17
  # automatic test run
18
18
  gem 'guard', '~> 2.19'
19
19
  # automatic update invocation
20
- gem 'guard-bundler', '~> 3.0'
20
+ # gem 'guard-bundler', '~> 3.0'
21
21
  # automatic style check
22
22
  gem 'guard-reek', '~> 1.2'
23
23
  # automatic tdd
@@ -31,21 +31,21 @@ group :development do
31
31
  # detect selling code
32
32
  gem 'reek', '~> 6.5'
33
33
  # needed by yard to render documentation
34
- gem 'rdoc', '~> 6.14'
34
+ gem 'rdoc', '~> 7.0'
35
35
  # tdd
36
36
  gem 'rspec', '~> 3.13'
37
37
  # code needs to be clean
38
- gem 'rubocop', '~> 1.77'
38
+ gem 'rubocop', '~> 1.82'
39
39
  # code needs to be clean
40
- gem 'rubocop-performance', '~> 1.25'
40
+ gem 'rubocop-performance', '~> 1.26'
41
41
  # test code needs to be clean
42
- gem 'rubocop-rspec', '~> 3.6'
42
+ gem 'rubocop-rspec', '~> 3.8'
43
43
  # Rakefiles need to be clean
44
44
  gem 'rubocop-rake', '~> 0.7'
45
45
  # Doc need to be clean
46
- gem 'rubocop-yard', '~> 0.10'
46
+ gem 'rubocop-yard', '~> 1.0'
47
47
  # my code needs to be critiqued
48
- gem 'rubycritic', '~> 4.9'
48
+ gem 'rubycritic', '~> 4.11'
49
49
  # What is tdd without code coverage ?
50
50
  gem 'simplecov', '~> 0.22'
51
51
  # to document code
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ task :ci do
10
10
  [
11
11
  'test:spec',
12
12
  'test:features',
13
- :rubocop
13
+ 'quality:all'
14
14
  ].each do |name|
15
15
  puts "\n=== Running #{name}...\n"
16
16
  Rake::Task[name].invoke
@@ -23,10 +23,11 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency('aasm', '~> 5.5')
24
24
  spec.add_dependency('asciidoctor', '~> 2.0')
25
25
  spec.add_dependency('csv', '~> 3.3')
26
- spec.add_dependency('defmastership-core', '~> 1.5.3')
26
+ spec.add_dependency('defmastership-core', '~> 1.5.5')
27
27
  spec.add_dependency('facets', '~> 3.1')
28
- spec.add_dependency('git', '~> 3.1')
28
+ spec.add_dependency('git', '~> 4.0')
29
29
  spec.add_dependency('gli', '~> 2.22')
30
30
  spec.add_dependency('memoist', '~> 0.16')
31
31
  spec.add_dependency('ostruct', '~> 0.6')
32
+ spec.add_dependency('rubyXL', '~> 3.4')
32
33
  end
@@ -348,6 +348,36 @@ Feature: The changeref command
348
348
  | // tag::TOTO-TEMP-XXX1[] Whatever | // tag::TOTO-0123[] Whatever |
349
349
  | /* end::TOTO-TEMP-XXX1[] */ | /* end::TOTO-0123[] */ |
350
350
 
351
+ Scenario: Change definitions in subfolders, modify tags in included files
352
+ Given a file named "modifications.yml" with:
353
+ """
354
+ ---
355
+ :toto:
356
+ :type: change_ref
357
+ :config:
358
+ :from_regexp: TOTO-TEMP-[X\d]{4}
359
+ :to_template: TOTO-%<next_ref>04d
360
+ :next_ref: 123
361
+ """
362
+ And a directory named "any_path"
363
+ And a file named "any_path/thedoc.adoc" with:
364
+ """
365
+ [define, requirement, TOTO-TEMP-XXX1]
366
+ --
367
+ include::target[TOTO-TEMP-XXX1 ]
368
+ --
369
+ """
370
+ And a file named "any_path/target" with:
371
+ """
372
+ # tag::TOTO-TEMP-XXX1[]
373
+ """
374
+ When I successfully run `defmastership modify --modifications toto any_path/thedoc.adoc`
375
+ Then the stdout should not contain anything
376
+ And the file named "any_path/target" should contain:
377
+ """
378
+ # tag::TOTO-0123[]
379
+ """
380
+
351
381
  Scenario: Do not change definitions when in literal
352
382
  Given a file named "modifications.yml" with:
353
383
  """
@@ -528,3 +528,58 @@ Feature: The export command
528
528
  ....",~7eb3c490
529
529
  """
530
530
  And the stdout should not contain anything
531
+
532
+ Scenario: Export one definition to xslx
533
+ Given a file named "toto.adoc" with:
534
+ """
535
+ [define, requirement, TOTO-0001]
536
+ --
537
+ Exemple of multiline requirement.
538
+ Second line.
539
+ --
540
+ """
541
+ When I successfully run `defmastership export --format xlsx toto.adoc`
542
+ Then the file "toto.xlsx" should exist
543
+
544
+ Scenario: Export one definition to json
545
+ Given a file named "toto.adoc" with:
546
+ """
547
+ [define, requirement, TOTO-0001]
548
+ --
549
+ Exemple of multiline requirement.
550
+ Second line.
551
+ --
552
+ """
553
+ When I successfully run `defmastership export --format json toto.adoc`
554
+ Then the file "toto.json" should contain:
555
+ """
556
+ [
557
+ {
558
+ "Type": "requirement",
559
+ "Reference": "TOTO-0001",
560
+ "Value": "Exemple of multiline requirement.\nSecond line.",
561
+ "Checksum": "~b86dcbde"
562
+ }
563
+ ]
564
+ """
565
+
566
+ Scenario: Export one definition to yaml
567
+ Given a file named "toto.adoc" with:
568
+ """
569
+ [define, requirement, TOTO-0001]
570
+ --
571
+ Exemple of multiline requirement.
572
+ Second line.
573
+ --
574
+ """
575
+ When I successfully run `defmastership export --format yaml toto.adoc`
576
+ Then the file "toto.yaml" should contain:
577
+ """
578
+ ---
579
+ - :Type: requirement
580
+ :Reference: TOTO-0001
581
+ :Value: |-
582
+ Exemple of multiline requirement.
583
+ Second line.
584
+ :Checksum: "~b86dcbde"
585
+ """
@@ -56,6 +56,33 @@ Feature: The rename_included_files command
56
56
  And the file "any_path/one_file.png" should not exist
57
57
  And the file "any_path/TOTO-WHATEVER-123_one_file.png" should exist
58
58
 
59
+ Scenario: change the filename of a file included in a definition (sub directory)
60
+ Given a file named "modifications.yml" with:
61
+ """
62
+ ---
63
+ :rename_included_png:
64
+ :type: rename_included_files
65
+ :config:
66
+ :from_regexp: (?<origin>.*\.png)
67
+ :to_template: "%<reference>s_%<origin>s"
68
+ """
69
+ And a directory named "any_path"
70
+ And a file named "any_path/thedoc.adoc" with:
71
+ """
72
+ [define, requirement, TOTO-WHATEVER-123]
73
+ include::one_file.png[]
74
+ """
75
+ And an empty file named "any_path/one_file.png"
76
+ When I successfully run `defmastership modify --modifications rename_included_png any_path/thedoc.adoc`
77
+ Then the stdout should not contain anything
78
+ And the file "any_path/thedoc.adoc" should contain:
79
+ """
80
+ [define, requirement, TOTO-WHATEVER-123]
81
+ include::TOTO-WHATEVER-123_one_file.png[]
82
+ """
83
+ And the file "any_path/one_file.png" should not exist
84
+ And the file "any_path/TOTO-WHATEVER-123_one_file.png" should exist
85
+
59
86
  Scenario: change the filename with options in include macro
60
87
  Given a file named "modifications.yml" with:
61
88
  """
@@ -9,6 +9,9 @@ end
9
9
 
10
10
  Given('I add and commit the {string} file') do |filename|
11
11
  git = Git.open(Aruba.config.home_directory)
12
+
13
+ git.config('user.name', 'Bob Léponge')
14
+ git.config('user.email', 'bob.léponge@example.com')
12
15
  git.add(filename)
13
16
  git.commit('whatever')
14
17
  end
@@ -6,6 +6,9 @@ require('defmastership/batch_modifier')
6
6
  require('defmastership/config_preserver')
7
7
  require('defmastership/document')
8
8
  require('defmastership/export/csv/formatter')
9
+ require('defmastership/export/json/formatter')
10
+ require('defmastership/export/xlsx/formatter')
11
+ require('defmastership/export/yaml/formatter')
9
12
  require('defmastership/version')
10
13
  require('gli')
11
14
 
@@ -24,9 +27,36 @@ module Defmastership
24
27
  def self.configure_export_flags(command)
25
28
  command.flag(%i[separator sep s], default_value: ',', desc: 'CSV separator')
26
29
  command.flag(%i[output-file o], desc: 'CSV output filename')
30
+ command.flag(%i[format f], desc: 'Output format', default_value: 'csv')
27
31
  command.switch(%i[no-fail], desc: 'Exit success even in case of wrong explicit checksum')
28
32
  end
29
33
 
34
+ # Helper method
35
+ def self.do_the_export(my_doc, options, first_adoc_file)
36
+ format = options.fetch('format')
37
+ formatter = create_formatter(my_doc, format, options)
38
+ output_file = determine_output_file(options, first_adoc_file, format)
39
+
40
+ formatter.export_to(output_file)
41
+ end
42
+
43
+ class << self
44
+ private
45
+
46
+ # Responsibility: Create the correct formatter instance with its specific options.
47
+ def create_formatter(doc, format, options)
48
+ formatter_class = Object.const_get("Defmastership::Export::#{format.upcase}::Formatter")
49
+ formatter_options = format == 'xlsx' ? {} : { separator: options.fetch(:separator) }
50
+
51
+ formatter_class.new(doc, **formatter_options)
52
+ end
53
+
54
+ # Responsibility: Determine the final output filename.
55
+ def determine_output_file(options, first_adoc_file, format)
56
+ options.fetch(:'output-file') || first_adoc_file.sub(/(?<=\.)adoc$/, format)
57
+ end
58
+ end
59
+
30
60
  desc 'Export the definition database in CSV'
31
61
  arg 'asciidoctor_file'
32
62
  arg 'asciidoctor_file', %i[optional multiple]
@@ -38,9 +68,7 @@ module Defmastership
38
68
  my_doc = Defmastership::Document.new
39
69
  args.each { |adoc_file| my_doc.parse_file_with_preprocessor(adoc_file) }
40
70
 
41
- output_file = options[:'output-file'] || args.first.sub(/\.adoc$/, '.csv')
42
-
43
- Defmastership::Export::CSV::Formatter.new(my_doc, options['separator']).export_to(output_file)
71
+ App.do_the_export(my_doc, options, args.first)
44
72
 
45
73
  if my_doc.wrong_explicit_checksum?
46
74
  my_doc.definitions.each do |definition|
@@ -1,9 +1,7 @@
1
1
  # Copyright (c) 2020 Jerome Arbez-Gindre
2
2
  # frozen_string_literal: true
3
3
 
4
- require('csv')
5
- require('defmastership/export/body_formatter')
6
- require('defmastership/export/header_formatter')
4
+ require('defmastership/export/formatter')
7
5
 
8
6
  module Defmastership
9
7
  # Module to host export classes
@@ -11,17 +9,17 @@ module Defmastership
11
9
  # Module to host CSV export classes
12
10
  module CSV
13
11
  # to export a CSV file
14
- class Formatter
12
+ class Formatter < Defmastership::Export::Formatter
15
13
  # @param doc [Document] the document to export
16
- # @param sep [String] the CSV separator
17
- def initialize(doc, sep)
18
- @doc = doc
19
- @sep = sep
14
+ # @param separator [String] the CSV separator
15
+ def initialize(doc, separator: ',')
16
+ @sep = separator
17
+ super(doc)
20
18
  end
21
19
 
22
20
  # Export the document to a CSV file
23
21
  #
24
- # @param output_file [Strinf] filename for the export
22
+ # @param output_file [String] filename for the export
25
23
  def export_to(output_file)
26
24
  column_list = build_column_list
27
25
  ::CSV.open(output_file, 'w:ISO-8859-1', col_sep: @sep) do |csv|
@@ -32,58 +30,8 @@ module Defmastership
32
30
 
33
31
  private
34
32
 
35
- # Helper functions
36
- module Helper
37
- # @return [Array<Symbol>] the array of methods for columns inclusion
38
- #
39
- # @param column_spec [MethodSpec] the method to include or not with its guard
40
- # @param doc [Document] the Document to export
41
- def self.column_method(column_spec, doc)
42
- column_spec.guard.call(doc) ? [column_spec.column_method] : []
43
- end
44
-
45
- # 2-uplet with one method to include or not depending of a lambda guard
46
- MethodSpec = Struct.new(:column_method, :guard)
47
- public_constant :MethodSpec
48
- end
49
- private_constant :Helper
50
-
51
- COLUMNS_METHODS_SPECIFICATIONS =
52
- [
53
- Helper::MethodSpec.new(:type, ->(_) { true }),
54
- Helper::MethodSpec.new(:reference, ->(_) { true }),
55
- Helper::MethodSpec.new(:summary, lambda(&:summaries?)),
56
- Helper::MethodSpec.new(:value, ->(_) { true }),
57
- Helper::MethodSpec.new(:checksum, ->(_) { true }),
58
- Helper::MethodSpec.new(:wrong_explicit_checksum, lambda(&:wrong_explicit_checksum?)),
59
- Helper::MethodSpec.new(:explicit_version, lambda(&:explicit_version?)),
60
- Helper::MethodSpec.new(:labels, ->(doc) { !doc.labels.empty? }),
61
- Helper::MethodSpec.new(:eref, ->(doc) { !doc.eref.empty? }),
62
- Helper::MethodSpec.new(:iref, lambda(&:iref)),
63
- Helper::MethodSpec.new(:attributes, ->(doc) { !doc.attributes.empty? })
64
- ].freeze
65
- private_constant :COLUMNS_METHODS_SPECIFICATIONS
66
-
67
33
  def export_definitions_in(csv, column_list)
68
- @doc.definitions.each { |definition| csv << body(definition, column_list) }
69
- end
70
-
71
- def header(column_list)
72
- header_formatter = HeaderFormatter.new(@doc)
73
- header_line = column_list.map { |part| header_formatter.public_send(part) }
74
- header_line.flatten
75
- end
76
-
77
- def body(definition, column_list)
78
- body_formatter = BodyFormatter.new(@doc, definition)
79
- body_line = column_list.map { |part| body_formatter.public_send(part) }
80
- body_line.flatten
81
- end
82
-
83
- def build_column_list
84
- COLUMNS_METHODS_SPECIFICATIONS.reduce([]) do |acc, column|
85
- acc + Helper.column_method(column, @doc)
86
- end
34
+ doc.definitions.each { |definition| csv << body(definition, column_list) }
87
35
  end
88
36
  end
89
37
  end
@@ -0,0 +1,88 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership/export/body_formatter')
5
+ require('defmastership/export/header_formatter')
6
+
7
+ module Defmastership
8
+ # Module to host export classes
9
+ module Export
10
+ # to export a CSV file
11
+ class Formatter
12
+ attr_reader :doc
13
+
14
+ # @param doc [Document] the document to export
15
+ def initialize(doc)
16
+ @doc = doc
17
+ end
18
+
19
+ # Export the document to a CSV file
20
+ #
21
+ # @param _output_file [String] filename for the export
22
+ def export_to(_output_file)
23
+ raise(NotImplementedError, "#{self.class} has not implemented the 'export_to' method")
24
+ end
25
+
26
+ # Build content of the header from the list of columns
27
+ #
28
+ # @param column_list [Array<Symbol>] List of columns to include
29
+ # @return [Array<String>] List of colums values
30
+ def header(column_list)
31
+ header_formatter = HeaderFormatter.new(doc)
32
+ header_line = column_list.map { |part| header_formatter.public_send(part) }
33
+ header_line.flatten
34
+ end
35
+
36
+ # Build content of a row from the list of columns
37
+ #
38
+ # @param definition [Definition] sourec of data
39
+ # @param column_list [Array<Symbol>] List of columns to include
40
+ # @return [Array<String>] List of colums values
41
+ def body(definition, column_list)
42
+ body_formatter = BodyFormatter.new(doc, definition)
43
+ body_line = column_list.map { |part| body_formatter.public_send(part) }
44
+ body_line.flatten
45
+ end
46
+
47
+ private
48
+
49
+ # Helper functions
50
+ module Helper
51
+ # @return [Array<Symbol>] the array of methods for columns inclusion
52
+ #
53
+ # @param column_spec [MethodSpec] the method to include or not with its guard
54
+ # @param doc [Document] the Document to export
55
+ def self.column_method(column_spec, doc)
56
+ column_spec.guard.call(doc) ? [column_spec.column_method] : []
57
+ end
58
+
59
+ # 2-uplet with one method to include or not depending of a lambda guard
60
+ MethodSpec = Struct.new(:column_method, :guard)
61
+ public_constant :MethodSpec
62
+ end
63
+ public_constant :Helper
64
+
65
+ COLUMNS_METHODS_SPECIFICATIONS =
66
+ [
67
+ Helper::MethodSpec.new(:type, ->(_) { true }),
68
+ Helper::MethodSpec.new(:reference, ->(_) { true }),
69
+ Helper::MethodSpec.new(:summary, lambda(&:summaries?)),
70
+ Helper::MethodSpec.new(:value, ->(_) { true }),
71
+ Helper::MethodSpec.new(:checksum, ->(_) { true }),
72
+ Helper::MethodSpec.new(:wrong_explicit_checksum, lambda(&:wrong_explicit_checksum?)),
73
+ Helper::MethodSpec.new(:explicit_version, lambda(&:explicit_version?)),
74
+ Helper::MethodSpec.new(:labels, ->(doc) { !doc.labels.empty? }),
75
+ Helper::MethodSpec.new(:eref, ->(doc) { !doc.eref.empty? }),
76
+ Helper::MethodSpec.new(:iref, lambda(&:iref)),
77
+ Helper::MethodSpec.new(:attributes, ->(doc) { !doc.attributes.empty? })
78
+ ].freeze
79
+ private_constant :COLUMNS_METHODS_SPECIFICATIONS
80
+
81
+ def build_column_list
82
+ COLUMNS_METHODS_SPECIFICATIONS.reduce([]) do |acc, column|
83
+ acc + Helper.column_method(column, doc)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership/export/formatter')
5
+ require('json')
6
+
7
+ module Defmastership
8
+ # Module to host export classes
9
+ module Export
10
+ # Module to host JSON export classes
11
+ module JSON
12
+ # to export a JSON file
13
+ class Formatter < Defmastership::Export::Formatter
14
+ # @param doc [Document] the document to export
15
+ # @param _options [Hash{Symbol => Object}] unused options
16
+ def initialize(doc, _options = {})
17
+ super(doc)
18
+ end
19
+
20
+ # Export the document to a JSON file
21
+ # @param output_file [String] filename for the export
22
+ def export_to(output_file)
23
+ column_list = build_column_list
24
+ header_column_list = header(column_list).map(&:to_sym)
25
+ definitions =
26
+ doc.definitions.map do |definition|
27
+ header_column_list.zip(body(definition, column_list)).to_h
28
+ end
29
+ File.write(output_file, ::JSON.pretty_generate(definitions))
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership/export/body_formatter')
5
+ require('defmastership/export/header_formatter')
6
+ require('memoist')
7
+ require('rubyXL')
8
+
9
+ module Defmastership
10
+ # Module to host export classes
11
+ module Export
12
+ # Module to host XLSX export classes
13
+ module XLSX
14
+ # to export a XSLX file
15
+ class Formatter < Defmastership::Export::Formatter
16
+ # @param doc [Document] the document to export
17
+ # @param [Hash{Symbol => Object}] _options
18
+ def initialize(doc, _options = {})
19
+ super(doc)
20
+ end
21
+
22
+ # Export the document to a XSLX file
23
+ #
24
+ # @param output_file [String] filename for the export
25
+ def export_to(output_file)
26
+ workbook = RubyXL::Workbook.new
27
+ column_list = build_column_list
28
+ xlsx_data = XLSXData.new(self, workbook, doc, column_list)
29
+
30
+ # Delegate the entire process to the XLSXData object
31
+ xlsx_data.export_to(output_file, doc.definitions)
32
+ end
33
+ end
34
+
35
+ # Encapsulate the data clump
36
+ class XLSXData
37
+ extend Memoist
38
+
39
+ attr_reader :column_list
40
+
41
+ # @param formatter [XLSX::Formatter] the concerned formatter
42
+ # @param workbook [XLSXData] the workbook to save
43
+ # @param doc [Document] the document to export
44
+ # @param column_list [Array<Symbol>] the list of columns to export
45
+ def initialize(formatter, workbook, doc, column_list)
46
+ @formatter = formatter
47
+ @workbook = workbook
48
+ @doc = doc
49
+ @column_list = column_list
50
+ end
51
+
52
+ # Build an write the exported Excel Spreasheet
53
+ #
54
+ # @param output_file [String] filename for the export
55
+ # @param definitions [Array<Definition>] the list of definitions
56
+ def export_to(output_file, definitions)
57
+ add_header(@formatter.header(@column_list))
58
+
59
+ definitions.each_with_index do |definition, def_index|
60
+ add_row(@formatter.body(definition, @column_list), def_index + 1)
61
+ end
62
+
63
+ @workbook.write(output_file)
64
+ end
65
+
66
+ private
67
+
68
+ def add_header(header_data)
69
+ header_data.each_with_index do |val, index|
70
+ worksheet.add_cell(0, index, val)
71
+ end
72
+ end
73
+
74
+ def add_row(row_data, row_index)
75
+ row_data.each_with_index do |val, index|
76
+ worksheet.add_cell(row_index, index, val)
77
+ end
78
+ end
79
+
80
+ def worksheet
81
+ @workbook.worksheets.first
82
+ end
83
+ memoize :worksheet
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ require('defmastership/export/formatter')
5
+ require('yaml')
6
+
7
+ module Defmastership
8
+ # Module to host export classes
9
+ module Export
10
+ # Module to host YAML export classes
11
+ module YAML
12
+ # to export a YAML file
13
+ class Formatter < Defmastership::Export::Formatter
14
+ # @param doc [Document] the document to export
15
+ # @param _options [Hash{Symbol => Object}] unused options
16
+ def initialize(doc, _options = {})
17
+ super(doc)
18
+ end
19
+
20
+ # Export the document to a YAML file
21
+ # @param output_file [String] filename for the export
22
+ def export_to(output_file)
23
+ column_list = build_column_list
24
+ header_column_list = header(column_list).map(&:to_sym)
25
+ definitions =
26
+ doc.definitions.map do |definition|
27
+ header_column_list.zip(body(definition, column_list)).to_h
28
+ end
29
+ File.write(output_file, ::YAML.dump(definitions))
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end