rspec-usecases 0.0.12 → 0.0.37

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +2 -0
  3. data/.gitignore +5 -0
  4. data/.rubocop.yml +7 -0
  5. data/Gemfile +19 -10
  6. data/Guardfile +1 -0
  7. data/STORIES.md +25 -4
  8. data/bin/console +1 -1
  9. data/docs/regexp-01.md +56 -0
  10. data/docs/samples.md +62 -0
  11. data/docs/test.debug.txt +93 -0
  12. data/docs/test.json +172 -0
  13. data/docs/test.md +39 -0
  14. data/lib/rspec/usecases.rb +20 -4
  15. data/lib/rspec/usecases/configure.rb +40 -0
  16. data/lib/rspec/usecases/contents/base_content.rb +145 -0
  17. data/lib/rspec/usecases/contents/code.rb +33 -0
  18. data/lib/rspec/usecases/contents/outcome.rb +27 -0
  19. data/lib/rspec/usecases/document.rb +173 -0
  20. data/lib/rspec/usecases/documentor.rb +35 -0
  21. data/lib/rspec/usecases/generator/base_generator.rb +58 -0
  22. data/lib/rspec/usecases/generator/debug_generator.rb +106 -0
  23. data/lib/rspec/usecases/generator/json_generator.rb +39 -0
  24. data/lib/rspec/usecases/generator/markdown_generator.rb +136 -0
  25. data/lib/rspec/usecases/groups/base_group.rb +116 -0
  26. data/lib/rspec/usecases/groups/group.rb +14 -0
  27. data/lib/rspec/usecases/groups/usecase.rb +30 -0
  28. data/lib/rspec/usecases/helpers/uc_file_as_markdown_content.rb +26 -0
  29. data/lib/rspec/usecases/helpers/uc_grab_lines.rb +54 -0
  30. data/lib/rspec/usecases/options/debug_options.rb +33 -0
  31. data/lib/rspec/usecases/options/document_options.rb +24 -0
  32. data/lib/rspec/usecases/options/dynamic_options.rb +102 -0
  33. data/lib/rspec/usecases/options/json_options.rb +32 -0
  34. data/lib/rspec/usecases/options/markdown_options.rb +37 -0
  35. data/lib/rspec/usecases/version.rb +1 -1
  36. data/rspec-usecases.gemspec +6 -0
  37. metadata +45 -9
  38. data/lib/rspec/usecases/content.rb +0 -155
  39. data/lib/rspec/usecases/content_code.rb +0 -42
  40. data/lib/rspec/usecases/content_outcome.rb +0 -30
  41. data/lib/rspec/usecases/usecase.rb +0 -103
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rspec
4
+ module Usecases
5
+ # Documentor
6
+ class Documentor
7
+ # Document that is to be rendered
8
+ attr_reader :document
9
+
10
+ # List of generators selected for rendering
11
+ attr_reader :generators
12
+
13
+ def initialize(root)
14
+ @document = Rspec::Usecases::Document.new(root)
15
+
16
+ build_generators
17
+ end
18
+
19
+ def render
20
+ @generators.each(&:run)
21
+ end
22
+
23
+ private
24
+
25
+ # rubocop:disable Metrics/AbcSize
26
+ def build_generators
27
+ @generators = []
28
+ @generators << Rspec::Usecases::Generator::JsonGenerator.new(document, document.options.json) if document.json?
29
+ @generators << Rspec::Usecases::Generator::DebugGenerator.new(document, document.options.debug) if document.debug?
30
+ @generators << Rspec::Usecases::Generator::MarkdownGenerator.new(document, document.options.markdown) if document.markdown?
31
+ end
32
+ # rubocop:enable Metrics/AbcSize
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rspec
4
+ module Usecases
5
+ # Generators build meta data in various output formats. JSON, Debug, Markdown etc.
6
+ module Generator
7
+ # Base generator contains helper methods
8
+ class BaseGenerator
9
+ attr_accessor :document
10
+ attr_accessor :output
11
+ attr_accessor :options
12
+
13
+ def initialize(document, options = nil)
14
+ @document = document
15
+ @options = options
16
+ @output = ''
17
+ end
18
+
19
+ # Write line of text to the output buffer and then add line feed character
20
+ def write_line(line = nil)
21
+ @output = "#{@output}#{line}\n" unless line == ''
22
+ end
23
+
24
+ # Write line feed character ot output buffer
25
+ def write_lf
26
+ @output = "#{@output}\n"
27
+ end
28
+
29
+ # Print output to console
30
+ def print_output
31
+ puts @output
32
+ end
33
+
34
+ # Write the file, force creation of folder if needed
35
+ def write_file(file)
36
+ FileUtils.mkdir_p(File.dirname(file))
37
+
38
+ File.write(file, @output)
39
+ end
40
+
41
+ # Run the file through prettier and then write back to that file
42
+ def prettier_file(file)
43
+ # npm install -g prettier @prettier/plugin-ruby
44
+
45
+ cmd = "prettier --check #{file} --write #{file}"
46
+
47
+ puts cmd
48
+ system(cmd)
49
+ end
50
+
51
+ # Open the file in vscode
52
+ def open_file_in_vscode(file)
53
+ system("code #{file}")
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rspec
4
+ module Usecases
5
+ # Generators build meta data in various output formats. JSON, Debug, Markdown etc.
6
+ module Generator
7
+ # Debug Generator helps to visualize the data that is collected
8
+ # from use cases
9
+ class DebugGenerator < Rspec::Usecases::Generator::BaseGenerator
10
+ def run
11
+ @key_width = 30
12
+ @indent_size = 0
13
+
14
+ generate
15
+
16
+ print_output if options.printable?
17
+
18
+ return unless options.writable?
19
+
20
+ write_file(options.file)
21
+
22
+ open_file_in_vscode(options.file) if options.openable?
23
+ end
24
+
25
+ def generate
26
+ print_document_header
27
+ print_groups(document.groups)
28
+ end
29
+
30
+ private
31
+
32
+ def print_document_header
33
+ write_line '*' * 100
34
+ kv 'Title', document.title if document.title
35
+ kv 'Description', document.description if document.description
36
+ end
37
+
38
+ def print_groups(groups)
39
+ groups.each { |usecase| print_usecase(usecase) }
40
+ end
41
+
42
+ def print_usecase(usecase)
43
+ print_usecase_header(usecase)
44
+
45
+ indent
46
+ usecase.contents.each { |content| print_usecase_content(content) }
47
+ print_groups(usecase.groups)
48
+ outdent
49
+ end
50
+
51
+ # rubocop:disable Metrics/AbcSize
52
+ def print_usecase_header(usecase)
53
+ write_line '=' * 100
54
+ kv 'Key' , usecase.key if usecase.key
55
+ kv 'Title' , usecase.title if usecase.title
56
+ kv 'Deep Title' , usecase.deep_title if usecase.deep_title
57
+ kv 'Summary' , usecase.summary if usecase.summary
58
+ kv 'Usage' , usecase.usage if usecase.usage
59
+ kv 'Usage Description', usecase.usage_description if usecase.usage_description
60
+ end
61
+ # rubocop:enable Metrics/AbcSize
62
+
63
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
64
+ def print_usecase_content(content)
65
+ write_line '-' * 100
66
+ kv 'Title' , content.title if content.title != ''
67
+ kv 'Type' , content.type if content.type != ''
68
+
69
+ # Used by outcome
70
+ kv 'Note' , content.note if content.respond_to?('note') && content.note != ''
71
+
72
+ # Used by code
73
+ kv 'Code' , content.code if content.respond_to?('code') && content.code != ''
74
+ kv 'Code Type', content.code_type if content.respond_to?('code_type') && content.code_type != ''
75
+ wl content.source if content.respond_to?('source') && content.source != ''
76
+ end
77
+ # rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
78
+
79
+ def wl(value)
80
+ write_line "#{indentation}#{value}"
81
+ end
82
+
83
+ def kv(key, value, key_width = @key_width)
84
+ key_width -= @indent_size
85
+ write_line "#{indentation}#{green(key.to_s.ljust(key_width))}: #{value}"
86
+ end
87
+
88
+ def indentation
89
+ ' ' * @indent_size
90
+ end
91
+
92
+ def green(value)
93
+ "\033[32m#{value}\033[0m"
94
+ end
95
+
96
+ def indent
97
+ @indent_size += 2
98
+ end
99
+
100
+ def outdent
101
+ @indent_size -= 2
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Rspec
6
+ module Usecases
7
+ # Generators build meta data in various output formats. JSON, Debug, Markdown etc.
8
+ module Generator
9
+ # JSON Generator
10
+ class JsonGenerator < Rspec::Usecases::Generator::BaseGenerator
11
+ attr_reader :data
12
+
13
+ def run
14
+ generate
15
+
16
+ print_output if options.printable?
17
+
18
+ return unless options.writable?
19
+
20
+ write_file(options.file)
21
+
22
+ open_file_in_vscode(options.file) if options.openable?
23
+ end
24
+
25
+ def generate
26
+ @data = {
27
+ document: {
28
+ title: document.title,
29
+ description: document.description
30
+ },
31
+ usecases: document.groups.map(&:to_h)
32
+ }
33
+
34
+ @output = JSON.pretty_generate(@data)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rspec
4
+ module Usecases
5
+ # Generators build meta data in various output formats. JSON, Debug, Markdown etc.
6
+ module Generator
7
+ # Markdown generator can build a markdown documentation file
8
+ # based on the document content
9
+ class MarkdownGenerator < Rspec::Usecases::Generator::BaseGenerator
10
+ # rubocop:disable Metrics/AbcSize
11
+ def run
12
+ @key_width = 30
13
+ @indent_size = 0
14
+
15
+ generate
16
+
17
+ print_output if options.printable?
18
+
19
+ return unless options.writable?
20
+
21
+ write_file(options.file)
22
+ prettier_file(options.file) if options.prettier?
23
+
24
+ open_file_in_vscode(options.file) if options.openable?
25
+ end
26
+ # rubocop:enable Metrics/AbcSize
27
+
28
+ def generate
29
+ print_document_header
30
+ print_groups(document.groups)
31
+ end
32
+
33
+ private
34
+
35
+ def print_document_header
36
+ h1 document.title
37
+ write_line document.description
38
+ write_lf
39
+ end
40
+
41
+ def print_groups(groups)
42
+ groups.each { |usecase| print_usecase(usecase) }
43
+ end
44
+
45
+ def print_usecase(usecase)
46
+ h2 usecase.title
47
+ write_lf
48
+ print_summary(usecase)
49
+ print_usage(usecase)
50
+ print_contents(usecase)
51
+ end
52
+
53
+ def print_summary(usecase)
54
+ return unless usecase.summary
55
+
56
+ write_line usecase.summary
57
+ write_lf
58
+ end
59
+
60
+ def print_usage(usecase)
61
+ return if usecase.usage == ''
62
+
63
+ h3 usecase.usage
64
+ write_lf
65
+
66
+ return unless usecase.usage_description
67
+
68
+ write_line usecase.usage_description
69
+ write_lf
70
+ end
71
+
72
+ def print_contents(usecase)
73
+ return if usecase.contents.empty?
74
+
75
+ usecase.contents.each do |content|
76
+ write_line '---' if content.is_hr
77
+
78
+ render_outcome(content) if content.type == 'outcome'
79
+ render_code(content) if content.type == 'code'
80
+ end
81
+
82
+ print_groups(usecase.groups)
83
+ end
84
+
85
+ def render_outcome(content)
86
+ bullet content.title
87
+ write_line content.note if content.note
88
+ end
89
+
90
+ def render_code(content)
91
+ h4 content.title
92
+ # write_line content.note if content.note
93
+ render_code_block(content.source, content.code_type) unless content.source == ''
94
+ end
95
+
96
+ def render_code_block(source, code_type)
97
+ write_line "```#{code_type}"
98
+ write_line source
99
+ write_line '```'
100
+ end
101
+
102
+ def h1(title)
103
+ write_line("# #{title}") if title != ''
104
+ end
105
+
106
+ def h2(title)
107
+ write_line("## #{title}") if title != ''
108
+ end
109
+
110
+ def h3(title)
111
+ write_line("### #{title}") if title != ''
112
+ end
113
+
114
+ def h4(title)
115
+ write_line("#### #{title}") if title != ''
116
+ end
117
+
118
+ def h5(title)
119
+ write_line("##### #{title}") if title != ''
120
+ end
121
+
122
+ def h6(title)
123
+ write_line("###### #{title}") if title != ''
124
+ end
125
+
126
+ def bullet(title)
127
+ write_line("- #{title}") if title != ''
128
+ end
129
+
130
+ def hr
131
+ write_line '---'
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rspec
4
+ module Usecases
5
+ module Groups
6
+ # Base Group
7
+ class BaseGroup
8
+ # key
9
+ attr_reader :key
10
+
11
+ # type of group
12
+ attr_reader :type
13
+
14
+ # title
15
+ attr_reader :title
16
+
17
+ # deep title is constructed by concatenating the chain of parents titles
18
+ # investigate the existing full_title attribute already on example_group
19
+ attr_reader :deep_title
20
+
21
+ # summary
22
+ attr_reader :summary
23
+
24
+ # contents
25
+ attr_reader :contents
26
+
27
+ # Nested groups, this is helpful when grouping
28
+ attr_accessor :groups
29
+
30
+ def initialize(key, type, example_group)
31
+ @key = key
32
+ @type = type
33
+ @deep_title = ''
34
+ @groups = []
35
+
36
+ build_title(example_group)
37
+ build_attributes(example_group)
38
+
39
+ # Loop through the it blocks
40
+ @contents = example_group.examples.map { |example| parse_content(example) }
41
+ end
42
+
43
+ def self.parse(key, example_group)
44
+ # return nil if example_group.description.nil?# || example_group.description.strip.length.zero?
45
+ return nil if example_group.metadata[:group_type].nil?
46
+
47
+ get_instance(key, example_group)
48
+ end
49
+
50
+ def self.get_instance(key, example_group)
51
+ type = example_group.metadata[:group_type].to_s
52
+
53
+ begin
54
+ klass = Module.const_get("Rspec::Usecases::Groups::#{type.capitalize}")
55
+ klass.new(key, type, example_group)
56
+ rescue NameError
57
+ # TODO: Logging
58
+ puts "UNKNOWN GROUP TYPE: #{type}"
59
+ nil
60
+ rescue StandardError => e
61
+ # TODO: Logging
62
+ puts e
63
+ nil
64
+ end
65
+ end
66
+
67
+ def to_h
68
+ {
69
+ key: key,
70
+ title: title,
71
+ deep_title: deep_title,
72
+ summary: summary,
73
+ contents: contents.map(&:to_h),
74
+ groups: groups.map(&:to_h)
75
+ }
76
+ end
77
+
78
+ # Override in child instances for class specific attributes
79
+ def build_attributes(example_group)
80
+ @summary = example_group.metadata[:summary] || ''
81
+ end
82
+
83
+ private
84
+
85
+ def parse_content(example)
86
+ Rspec::Usecases::Contents::BaseContent.parse(example)
87
+ end
88
+
89
+ # Build the title from the rspec example_group, aka describe or context
90
+ #
91
+ # If title attribute is set then this takes priority.
92
+ # If not set, then build the title by looking through the parent objects
93
+ def build_title(example_group)
94
+ # return if title != ''
95
+
96
+ @title = example_group.metadata[:title] || example_group.description
97
+ # .example_group.parent_groups.first&.description
98
+
99
+ build_deep_title(example_group)
100
+ end
101
+
102
+ def build_deep_title(example_group)
103
+ # example_group.parent_groups.reverse[0..-2].map { |g| g.description }
104
+ example_group.parent_groups.reverse[0..-2].each do |group|
105
+ @deep_title = if @deep_title.length.zero?
106
+ group.description
107
+ else
108
+ "#{@deep_title} #{group.description}"
109
+ end
110
+ end
111
+ @deep_title = "#{@deep_title} #{@title}"
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end