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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +2 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +7 -0
- data/Gemfile +19 -10
- data/Guardfile +1 -0
- data/STORIES.md +25 -4
- data/bin/console +1 -1
- data/docs/regexp-01.md +56 -0
- data/docs/samples.md +62 -0
- data/docs/test.debug.txt +93 -0
- data/docs/test.json +172 -0
- data/docs/test.md +39 -0
- data/lib/rspec/usecases.rb +20 -4
- data/lib/rspec/usecases/configure.rb +40 -0
- data/lib/rspec/usecases/contents/base_content.rb +145 -0
- data/lib/rspec/usecases/contents/code.rb +33 -0
- data/lib/rspec/usecases/contents/outcome.rb +27 -0
- data/lib/rspec/usecases/document.rb +173 -0
- data/lib/rspec/usecases/documentor.rb +35 -0
- data/lib/rspec/usecases/generator/base_generator.rb +58 -0
- data/lib/rspec/usecases/generator/debug_generator.rb +106 -0
- data/lib/rspec/usecases/generator/json_generator.rb +39 -0
- data/lib/rspec/usecases/generator/markdown_generator.rb +136 -0
- data/lib/rspec/usecases/groups/base_group.rb +116 -0
- data/lib/rspec/usecases/groups/group.rb +14 -0
- data/lib/rspec/usecases/groups/usecase.rb +30 -0
- data/lib/rspec/usecases/helpers/uc_file_as_markdown_content.rb +26 -0
- data/lib/rspec/usecases/helpers/uc_grab_lines.rb +54 -0
- data/lib/rspec/usecases/options/debug_options.rb +33 -0
- data/lib/rspec/usecases/options/document_options.rb +24 -0
- data/lib/rspec/usecases/options/dynamic_options.rb +102 -0
- data/lib/rspec/usecases/options/json_options.rb +32 -0
- data/lib/rspec/usecases/options/markdown_options.rb +37 -0
- data/lib/rspec/usecases/version.rb +1 -1
- data/rspec-usecases.gemspec +6 -0
- metadata +45 -9
- data/lib/rspec/usecases/content.rb +0 -155
- data/lib/rspec/usecases/content_code.rb +0 -42
- data/lib/rspec/usecases/content_outcome.rb +0 -30
- 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
|