brutal 1.6.0.beta1 → 1.6.0.beta2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 37fdb51264d859c50519c1bfc0f511542eb8bcca0817049e11191977d06cb7b1
4
- data.tar.gz: 54e26e7e3ad8cc403fdb6c1db116186c61d06b0766eb8fa5e96ed7688913872b
3
+ metadata.gz: 2a8a912485598e917360c280db92eee2b3acc53180dd0587b2147ea0eb26e649
4
+ data.tar.gz: 5a7a1f13b748e8deb7d5a1529ca2e11eb35b687aabab84f7b9fc9ebc58d0b174
5
5
  SHA512:
6
- metadata.gz: d42f48f5e24be39950a9e5a1bfb521a84a37402b8cb3cca1eb680767ce63410ab44b836310ba7792af80a8d9c9f803ba30c9e08dff4f1094fde184409f81c95c
7
- data.tar.gz: 40a6cf45ccdc12816d677fd5c8d19ed4c6305ec135c66fc2e56bd11f595291d9c16715b979ff920b1ed36cc90bddfe783db3653fb7f072cbc77ef8a0d760c769
6
+ metadata.gz: ec1ffa0f11a17812ff0000bc7e8b4ba8a04c826e37f9ef5e777681312fcb87962020f034b4802b617471894019f9c046598a012eeb6491c6548f0fef233af66d
7
+ data.tar.gz: 363647b4219053d2433fa198aac832b8f8f630e36d7b9282f0c36c34c2a255e5874ee91e481440be6bea2c87bb7763225ddbd04bfbf0204ad949bea98b5fbb01
data/README.md CHANGED
@@ -38,7 +38,7 @@ It is therefore the responsibility of the developer to analyze the generated beh
38
38
  Add this line to your application's Gemfile:
39
39
 
40
40
  ```ruby
41
- gem "brutal", ">= 1.6.0.beta1", require: false
41
+ gem "brutal", ">= 1.6.0.beta2", require: false
42
42
  ```
43
43
 
44
44
  And then execute:
@@ -53,7 +53,22 @@ Or install it yourself as:
53
53
  gem install brutal --pre
54
54
  ```
55
55
 
56
- ## Command line
56
+ ## Usage
57
+
58
+ ### YAML manifest
59
+
60
+ __Brutal__ needs configuration files in YAML format to know how to write tests.
61
+ Configuration file names are suffixed by `_brutal.yaml` and composed of 7 top-level sections:
62
+
63
+ * `header` - Specifies a block of lines to be executed once before all examples.
64
+ * `before` - Specifies a block of lines to be executed before each example.
65
+ * `subject` - Specifies the template of the code to be declined across contexts.
66
+ * `contexts` - Specifies a list of variables to populate the subject's template.
67
+ * `actuals` - Specifies templates to challenge evaluated subjects & get results.
68
+ * `after` - Specifies a block of lines to be executed after each example.
69
+ * `footer` - Specifies a block of lines to be executed once after all examples.
70
+
71
+ ### Command line
57
72
 
58
73
  The `brutal` command comes with several options you can use to customize Brutal's behavior.
59
74
 
@@ -64,25 +79,13 @@ brutal --help
64
79
  ```
65
80
 
66
81
  ```txt
67
- Usage: #{$PROGRAM_NAME} [options] [files or directories]
82
+ Usage: brutal [options] [files or directories]
68
83
 
69
84
  --format=FORMAT Choose "ruby" (default).
70
85
  --help Display this help.
71
86
  --version Display the version.
72
87
  ```
73
88
 
74
- ## Usage
75
-
76
- __Brutal__ needs configuration files in YAML format to know how to write tests.
77
- Configuration file names are suffixed by `_brutal.yaml` and composed of 4 top-level sections:
78
-
79
- * `header` - Specifies the code to execute before generating the test suite.
80
- * `subject` - Specifies the template of the code to be declined across contexts.
81
- * `contexts` - Specifies a list of variables to populate the subject's template.
82
- * `actuals` - Specifies templates to challenge evaluated subjects & get results.
83
-
84
- When the configuration file is present, the generation of a test suite can be done with the command:
85
-
86
89
  Assuming that in the workspace there is a configuration file named `user_brutal.yaml`, the test suite can be generated via one of these commands:
87
90
 
88
91
  ```sh
@@ -101,17 +104,19 @@ or even:
101
104
  brutal
102
105
  ```
103
106
 
104
- This would create a `user_brutal.rb` file containing the test suite.
107
+ This would create a `test_user.rb` file containing the test suite.
105
108
 
106
109
  Assuming now that in the workspace there are a large number of configuration files named in the `spec/` folder, the complete test suite could be generated recursively via this command:
107
110
 
108
111
  ```sh
109
- brutal spec/ # => generate tests from each configuration file matching ./spec/**/*_brutal.yaml in to ./spec/**/*_brutal.rb
112
+ brutal spec/
110
113
  ```
111
114
 
115
+ This would create one test file per configuration file matching `./spec/**/*_brutal.yaml` in to `./spec/**/test_*.rb`.
116
+
112
117
  ### Some examples
113
118
 
114
- <https://github.com/fixrb/brutal/blob/v1.6.0.beta1/examples/>
119
+ <https://github.com/fixrb/brutal/tree/main/examples/>
115
120
 
116
121
  ## Rake integration example
117
122
 
@@ -119,7 +124,7 @@ Generated test suite files could be matched as follows:
119
124
 
120
125
  ```ruby
121
126
  Rake::TestTask.new do |t|
122
- t.pattern = "**/*_brutal.rb"
127
+ t.pattern = "**/test_*.rb"
123
128
  end
124
129
  ```
125
130
 
data/bin/brutal CHANGED
@@ -2,13 +2,17 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative File.join("..", "lib", "brutal", "command_line_arguments_parser")
5
- format, pathnames = Brutal::CommandLineArgumentsParser.new(*ARGV).call
5
+
6
+ formats, pathnames = Brutal::CommandLineArgumentsParser.new(*ARGV).call
6
7
 
7
8
  require_relative File.join("..", "lib", "brutal")
8
- generator = Brutal.new(format: format)
9
9
 
10
- pathnames.each do |pathname|
11
- Dir.chdir(pathname.dirname) do
12
- generator.call(pathname.basename)
10
+ formats.each do |format|
11
+ generator = Brutal.new(format)
12
+
13
+ pathnames.each do |pathname|
14
+ Dir.chdir(pathname.dirname) do
15
+ generator.call(pathname.basename)
16
+ end
13
17
  end
14
18
  end
@@ -1,64 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("manifest", "file", "name")
4
+
3
5
  require "pathname"
4
6
 
5
7
  class Brutal
6
8
  # Accept an arbitrary number of arguments passed from the command-line.
7
9
  class CommandLineArgumentsParser
8
- DEFAULT_FORMAT = "ruby"
9
- FILE_SUFFIX = "_brutal.yaml"
10
- FILE_PATTERN = ::File.join("**", "*#{FILE_SUFFIX}")
11
- CURRENT_EXECUTION_CONTEXT = "."
10
+ MANIFEST_FILENAME_SUFFIX = Manifest::File::Name::SUFFIX
11
+ MANIFEST_FILENAME_PATTERN = ::File.join("**", "*#{MANIFEST_FILENAME_SUFFIX}")
12
+ CURRENT_DIRECTORY_CONTEXT = "."
13
+ GEM_NAME = "brutal"
14
+ HELP_OPTION = "--help"
15
+ VERSION_OPTION = "--version"
16
+ RUBY_FORMAT_OPTION = "--format=ruby"
17
+ DEFAULT_FORMAT_OPTION = RUBY_FORMAT_OPTION
18
+
19
+ FORMAT_OPTIONS = {
20
+ RUBY_FORMAT_OPTION => :Ruby
21
+ }.freeze
22
+
23
+ DEFAULT_FORMAT = FORMAT_OPTIONS.fetch(DEFAULT_FORMAT_OPTION)
24
+ DEFAULT_FORMATS = [DEFAULT_FORMAT].freeze
12
25
 
13
26
  attr_reader :pathnames
14
27
 
15
28
  def initialize(*args)
16
- @any_path = false
29
+ args.each do |arg|
30
+ help! if arg == HELP_OPTION
31
+ version! if arg == VERSION_OPTION
32
+ end
33
+
34
+ @formats = []
17
35
  @pathnames = []
36
+
37
+ args << CURRENT_DIRECTORY_CONTEXT unless any_path_given?(*args)
18
38
  args.each { |arg| parse!(arg) }
19
- parse!(CURRENT_EXECUTION_CONTEXT) unless any_path?
20
39
  end
21
40
 
22
41
  def call
23
- [format, pathnames]
42
+ [formats, pathnames]
24
43
  end
25
44
 
26
45
  private
27
46
 
28
- def any_path?
29
- @any_path
30
- end
31
-
32
- def format
33
- @format || DEFAULT_FORMAT
47
+ def formats
48
+ @formats.empty? ? DEFAULT_FORMATS : @formats
34
49
  end
35
50
 
36
51
  def parse!(arg)
37
52
  case arg
38
- when "--format=ruby"
39
- format!("Ruby")
40
- when "--help"
41
- help!
42
- when "--version"
43
- version!
53
+ when RUBY_FORMAT_OPTION
54
+ @formats << FORMAT_OPTIONS.fetch(RUBY_FORMAT_OPTION)
44
55
  else
45
- pathname = ::Pathname.new(arg)
46
- load!(pathname)
56
+ load!(::Pathname.new(arg))
47
57
  end
48
58
  end
49
59
 
50
- def format!(name)
51
- raise ::ArgumentError, "Format already filled in." unless format.nil?
52
-
53
- @format = name
54
- end
55
-
56
60
  def help!
57
- puts help_command_output
61
+ puts help_message
58
62
  exit
59
63
  end
60
64
 
61
- def help_command_output
65
+ def help_message
62
66
  <<~TXT
63
67
  Usage: #{$PROGRAM_NAME} [options] [files or directories]
64
68
 
@@ -69,21 +73,31 @@ class Brutal
69
73
  end
70
74
 
71
75
  def load!(pathname)
72
- @any_path = true
73
-
74
76
  if pathname.directory?
75
- pathname.glob(FILE_PATTERN).each { |filename| load!(filename) }
77
+ pathname.glob(MANIFEST_FILENAME_PATTERN).each { |filename| load!(filename) }
76
78
  elsif pathname.file?
77
- if pathname.to_s.end_with?(FILE_SUFFIX)
78
- @pathnames << pathname
79
- else
80
- warn "Skipping #{pathname} because not suffixed with #{FILE_SUFFIX}."
81
- end
79
+ load_file!(pathname)
82
80
  else
83
81
  raise ::ArgumentError, "#{pathname} is neither a file nor a directory."
84
82
  end
85
83
  end
86
84
 
85
+ def load_file!(pathname)
86
+ if pathname.fnmatch?(MANIFEST_FILENAME_PATTERN)
87
+ @pathnames << pathname
88
+ else
89
+ warn "Skipping #{pathname} because not matched against #{MANIFEST_FILENAME_PATTERN}."
90
+ end
91
+ end
92
+
93
+ def any_path_given?(*args)
94
+ path_args(*args).any?
95
+ end
96
+
97
+ def path_args(*args)
98
+ args - FORMAT_OPTIONS.keys
99
+ end
100
+
87
101
  def version!
88
102
  abort "Gem not found on the system. Unknown version." if not_loaded_spec?
89
103
 
@@ -92,7 +106,7 @@ class Brutal
92
106
  end
93
107
 
94
108
  def loaded_spec
95
- ::Gem.loaded_specs["brutal"]
109
+ ::Gem.loaded_specs[GEM_NAME]
96
110
  end
97
111
 
98
112
  def not_loaded_spec?
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Brutal
4
+ module Format
5
+ class Ruby
6
+ module Filename
7
+ # Brutal Ruby format file prefix.
8
+ PREFIX = "test_"
9
+
10
+ # Brutal Ruby format file suffix.
11
+ SUFFIX = ".rb"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,33 +1,59 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("ruby", "filename")
4
+
3
5
  class Brutal
4
6
  module Format
5
7
  # Ruby format class
6
8
  class Ruby
9
+ # Whitespace character.
10
+ SPACE = " "
11
+
12
+ # Hyphen-minus character.
13
+ HYPHEN_MINUS = "-"
14
+
15
+ # Two spaces per indentation level.
16
+ INDENTATION = SPACE * 2
17
+
7
18
  # Specifies templates to challenge evaluated subjects & get results.
8
19
  attr_reader :actuals
9
20
 
10
21
  # Specifies a list of variables to populate the subject's template.
11
22
  attr_reader :contexts
12
23
 
13
- # Specifies the code to execute before generating the test suite.
24
+ # Specifies a block of lines to be executed once before all examples.
14
25
  attr_reader :header
15
26
 
27
+ # Specifies a block of lines to be executed before each example.
28
+ attr_reader :before
29
+
16
30
  # Specifies the template of the code to be declined across contexts.
17
31
  attr_reader :subject
18
32
 
33
+ # Specifies a block of lines to be executed after each example.
34
+ attr_reader :after
35
+
36
+ # Specifies a block of lines to be executed once after all examples.
37
+ attr_reader :footer
38
+
19
39
  # Initialize a new scaffold generator.
20
- def initialize(header, subject, *actuals, **contexts)
21
- warn("Empty subject!") if subject.empty?
22
- warn("Empty actual values!") if actuals.empty?
23
- warn("Empty contexts!") if contexts.empty?
40
+ def initialize(header, before, subject, after, footer, *actuals, **contexts)
41
+ header = "# Brutal test suite" if header.empty?
42
+ before = "# Starting an example" if before.empty?
43
+ after = "# Finishing an example" if after.empty?
44
+ footer = "# End of the brutal test" if footer.empty?
24
45
 
25
- eval(header) # rubocop:disable Security/Eval
46
+ warn("Empty subject!") if subject.empty?
47
+ warn("Empty actual values!") if actuals.empty?
48
+ warn("Empty contexts!") if contexts.empty?
26
49
 
27
50
  @header = header
51
+ @before = before
28
52
  @subject = subject
29
53
  @actuals = actuals
30
54
  @contexts = contexts
55
+ @after = after
56
+ @footer = footer
31
57
  end
32
58
 
33
59
  # Return a Ruby string that can be evaluated.
@@ -41,7 +67,11 @@ class Brutal
41
67
  #
42
68
  # @return [String]
43
69
  def to_s
44
- ruby_lines.join(separator_ruby_code)
70
+ eval(header) # rubocop:disable Security/Eval
71
+
72
+ ruby_lines.compact.join(separator_code)
73
+ ensure
74
+ eval(footer) # rubocop:disable Security/Eval
45
75
  end
46
76
 
47
77
  def attributes(*values)
@@ -63,13 +93,13 @@ class Brutal
63
93
  end
64
94
 
65
95
  def ruby_lines
66
- [header_ruby_code] + actual_ruby_codes
96
+ [header_code] + actual_codes + [footer_code]
67
97
  end
68
98
 
69
- def actual_ruby_codes
99
+ def actual_codes
70
100
  combinations_values.map do |values|
71
101
  actual_str = format(inspect(subject), **attributes(*values))
72
- string = actual_ruby_code(actual_str)
102
+ string = actual_code(actual_str)
73
103
  actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
74
104
 
75
105
  actuals.each do |actual_value|
@@ -81,32 +111,52 @@ class Brutal
81
111
  end
82
112
  end
83
113
 
84
- def actual_ruby_code(actual_str)
85
- <<~RUBY_CODE
114
+ def actual_code(actual_str)
115
+ <<~CODE
116
+ #{before_code}
86
117
  actual = begin
87
- #{actual_str.gsub(/^/, ' ')}
118
+ #{actual_str.gsub(/^/, INDENTATION)}
88
119
  end
89
120
 
90
- RUBY_CODE
121
+ #{after_code}
122
+ CODE
91
123
  end
92
124
 
93
- def header_ruby_code
94
- <<~RUBY_CODE
125
+ def header_code
126
+ <<~CODE
95
127
  #{header.chomp}
96
- RUBY_CODE
128
+ CODE
129
+ end
130
+
131
+ def before_code
132
+ <<~CODE
133
+ #{before.chomp}
134
+ CODE
135
+ end
136
+
137
+ def after_code
138
+ <<~CODE
139
+ #{after.chomp}
140
+ CODE
141
+ end
142
+
143
+ def footer_code
144
+ <<~CODE
145
+ #{footer.chomp}
146
+ CODE
97
147
  end
98
148
 
99
- def separator_ruby_code
100
- <<~RUBY_CODE
149
+ def separator_code
150
+ <<~CODE
101
151
 
102
- #{thematic_break_ruby_code}
103
- RUBY_CODE
152
+ #{thematic_break_code}
153
+ CODE
104
154
  end
105
155
 
106
- def thematic_break_ruby_code
107
- <<~RUBY_CODE
108
- # #{'-' * 78}
109
- RUBY_CODE
156
+ def thematic_break_code
157
+ <<~CODE
158
+ # #{HYPHEN_MINUS * 78}
159
+ CODE
110
160
  end
111
161
  end
112
162
  end
data/lib/brutal/format.rb CHANGED
@@ -1,16 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- %w[
4
- ruby
5
- ].each { |filename| require_relative(File.join("format", filename)) }
3
+ Dir[File.join(File.dirname(__FILE__), "format", "*.rb")].sort.each do |fname|
4
+ require_relative fname
5
+ end
6
6
 
7
7
  class Brutal
8
- # Brutal::Format
8
+ # A collection of formatter classes.
9
9
  module Format
10
- SUPPORT = {
11
- "ruby" => Ruby
12
- }.freeze
13
-
14
- DEFAULT = SUPPORT.keys.sort.fetch(-1)
15
10
  end
16
11
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Brutal
4
+ class Manifest
5
+ class File
6
+ module Name
7
+ # Suffix for configuration file names.
8
+ SUFFIX = "_brutal.yaml"
9
+
10
+ # Suffix pattern for configuration file names.
11
+ SUFFIX_PATTERN = "*#{SUFFIX}"
12
+
13
+ # Suffix regex for configuration file names.
14
+ SUFFIX_REGEX = /#{SUFFIX}\z/.freeze
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative File.join("file", "name")
4
+
5
+ require "yaml"
6
+
7
+ class Brutal
8
+ class Manifest
9
+ # YAML manifest file parser.
10
+ class File
11
+ attr_reader :yaml
12
+
13
+ def initialize(pathname)
14
+ raise ::ArgumentError unless pathname.fnmatch?(Name::SUFFIX_PATTERN)
15
+
16
+ @yaml = pathname.read
17
+ end
18
+
19
+ def parse
20
+ ::YAML.safe_load(yaml, symbolize_names: false)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative File.join("manifest", "file")
4
+
5
+ class Brutal
6
+ # Brutal YAML manifest file parser.
7
+ class Manifest
8
+ # The _actuals_ top-level section key.
9
+ ACTUALS_KEY = "actuals"
10
+
11
+ # The _contexts_ top-level section key.
12
+ CONTEXTS_KEY = "contexts"
13
+
14
+ # The _header_ top-level section key.
15
+ HEADER_KEY = "header"
16
+
17
+ # The _before_ top-level section key.
18
+ BEFORE_KEY = "before"
19
+
20
+ # The _subject_ top-level section key.
21
+ SUBJECT_KEY = "subject"
22
+
23
+ # The _after_ top-level section key.
24
+ AFTER_KEY = "after"
25
+
26
+ # The _footer_ top-level section key.
27
+ FOOTER_KEY = "footer"
28
+
29
+ # Default _actuals_ collection.
30
+ DEFAULT_ACTUALS = [].freeze
31
+
32
+ # Default _contexts_ collection.
33
+ DEFAULT_CONTEXTS = {}.freeze
34
+
35
+ # Default _header_ code to evaluate.
36
+ DEFAULT_HEADER = ""
37
+
38
+ # Default _before_ code to evaluate.
39
+ DEFAULT_BEFORE = ""
40
+
41
+ # Default _after_ code to evaluate.
42
+ DEFAULT_AFTER = ""
43
+
44
+ # Default _footer_ code to evaluate.
45
+ DEFAULT_FOOTER = ""
46
+
47
+ # Parse a file at `pathname`. Returns the YAML manifest instance.
48
+ def self.parse_file(pathname)
49
+ load(File.new(pathname).parse)
50
+ end
51
+
52
+ # Load the configuration parameters.
53
+ #
54
+ # @param params [Hash] Receive the 7 top-level section parameters.
55
+ def self.load(params)
56
+ new(
57
+ actuals: params.fetch(ACTUALS_KEY, DEFAULT_ACTUALS),
58
+ contexts: params.fetch(CONTEXTS_KEY, DEFAULT_CONTEXTS),
59
+ header: params.fetch(HEADER_KEY, DEFAULT_HEADER),
60
+ before: params.fetch(BEFORE_KEY, DEFAULT_BEFORE),
61
+ subject: params.fetch(SUBJECT_KEY),
62
+ after: params.fetch(AFTER_KEY, DEFAULT_AFTER),
63
+ footer: params.fetch(FOOTER_KEY, DEFAULT_FOOTER)
64
+ )
65
+ end
66
+
67
+ # Specifies templates to challenge evaluated subjects & get results.
68
+ attr_reader :actuals
69
+
70
+ # Specifies a list of variables to populate the subject's template.
71
+ attr_reader :contexts
72
+
73
+ # Specifies a block of lines to be executed once before all examples.
74
+ attr_reader :header
75
+
76
+ # Specifies a block of lines to be executed before each example.
77
+ attr_reader :before
78
+
79
+ # Specifies the template of the code to be declined across contexts.
80
+ attr_reader :subject
81
+
82
+ # Specifies a block of lines to be executed after each example.
83
+ attr_reader :after
84
+
85
+ # Specifies a block of lines to be executed once after all examples.
86
+ attr_reader :footer
87
+
88
+ # Initialize a new configuration.
89
+ def initialize(actuals:, contexts:, header:, before:, subject:, after:, footer:)
90
+ raise ::TypeError, actuals.inspect unless actuals.is_a?(::Array)
91
+ raise ::TypeError, contexts.inspect unless contexts.is_a?(::Hash)
92
+ raise ::TypeError, header.inspect unless header.is_a?(::String)
93
+ raise ::TypeError, before.inspect unless before.is_a?(::String)
94
+ raise ::TypeError, subject.inspect unless subject.is_a?(::String)
95
+ raise ::TypeError, after.inspect unless after.is_a?(::String)
96
+ raise ::TypeError, footer.inspect unless footer.is_a?(::String)
97
+
98
+ @actuals = actuals
99
+ @contexts = contexts
100
+ @header = header
101
+ @before = before
102
+ @subject = subject
103
+ @after = after
104
+ @footer = footer
105
+ end
106
+ end
107
+ end
data/lib/brutal.rb CHANGED
@@ -1,50 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  %w[
4
- configuration
5
- file
6
4
  format
7
- yaml
5
+ manifest
8
6
  ].each { |filename| require_relative(File.join("brutal", filename)) }
9
7
 
10
8
  # The Brutal namespace.
11
9
  class Brutal
12
- attr_reader :format
10
+ attr_reader :engine
13
11
 
14
- def initialize(format: Format::DEFAULT)
15
- @format = String(format)
12
+ def initialize(format)
13
+ @engine = Format.const_get(format)
16
14
  end
17
15
 
18
16
  def call(pathname)
19
- hash = parse(pathname)
20
- conf = Configuration.load(hash)
21
- code = scaffold(conf)
22
- write(pathname, code)
23
- end
24
-
25
- def scaffold(conf)
26
- engine = Format::SUPPORT.fetch(format) do
27
- raise ::NotImplementedError, "#{format.inspect} format is not supported."
28
- end
29
-
30
- engine.new(conf.header, conf.subject, *conf.actuals, **conf.contexts)
17
+ manifest = Manifest.parse_file(pathname)
18
+ scaffold = brutalizer(manifest)
19
+ pathname = new_pathname(pathname)
20
+ pathname.write(scaffold)
31
21
  end
32
22
 
33
23
  private
34
24
 
35
- def parse(pathname)
36
- return Yaml.parse(read(pathname)) if Yaml.parse?(pathname)
25
+ def brutalizer(conf)
26
+ engine.new(conf.header, conf.before, conf.subject, conf.after, conf.footer, *conf.actuals, **conf.contexts)
27
+ end
37
28
 
38
- raise ::ArgumentError, "Unrecognized extension. " \
39
- "Impossible to parse #{pathname.inspect}."
29
+ def new_pathname(pathname)
30
+ pathname.dirname + "#{new_prefix}#{pathname.basename.sub(Manifest::File::Name::SUFFIX_REGEX, new_suffix)}"
40
31
  end
41
32
 
42
- def read(pathname)
43
- File::Read.new(pathname).call
33
+ def new_prefix
34
+ engine.const_get(:Filename).const_get(:PREFIX)
44
35
  end
45
36
 
46
- def write(pathname, ruby)
47
- new_pathname = File.generated_pathname(pathname)
48
- File::Write.new(new_pathname).call(ruby)
37
+ def new_suffix
38
+ engine.const_get(:Filename).const_get(:SUFFIX)
49
39
  end
50
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brutal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0.beta1
4
+ version: 1.6.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-01 00:00:00.000000000 Z
11
+ date: 2022-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,20 +108,6 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: simplecov
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
111
  - !ruby/object:Gem::Dependency
126
112
  name: yard
127
113
  requirement: !ruby/object:Gem::Requirement
@@ -148,13 +134,12 @@ files:
148
134
  - bin/brutal
149
135
  - lib/brutal.rb
150
136
  - lib/brutal/command_line_arguments_parser.rb
151
- - lib/brutal/configuration.rb
152
- - lib/brutal/file.rb
153
- - lib/brutal/file/read.rb
154
- - lib/brutal/file/write.rb
155
137
  - lib/brutal/format.rb
156
138
  - lib/brutal/format/ruby.rb
157
- - lib/brutal/yaml.rb
139
+ - lib/brutal/format/ruby/filename.rb
140
+ - lib/brutal/manifest.rb
141
+ - lib/brutal/manifest/file.rb
142
+ - lib/brutal/manifest/file/name.rb
158
143
  homepage: https://github.com/fixrb/brutal
159
144
  licenses:
160
145
  - MIT
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Brutal
4
- # Brutal::Configuration
5
- #
6
- # @since 1.0.0
7
- class Configuration
8
- ACTUALS_KEY = "actuals"
9
- CONTEXTS_KEY = "contexts"
10
- HEADER_KEY = "header"
11
- SUBJECT_KEY = "subject"
12
-
13
- DEFAULT_ACTUALS = [].freeze
14
- DEFAULT_CONTEXTS = {}.freeze
15
- DEFAULT_HEADER = "# Brutal test suite"
16
- DEFAULT_SUBJECT = ""
17
-
18
- # Load the configuration parameters.
19
- #
20
- # @param params [Hash] Receive the 4 top-level section parameters.
21
- def self.load(params)
22
- new(
23
- actuals: params.fetch(ACTUALS_KEY, DEFAULT_ACTUALS),
24
- contexts: params.fetch(CONTEXTS_KEY, DEFAULT_CONTEXTS),
25
- header: params.fetch(HEADER_KEY, DEFAULT_HEADER),
26
- subject: params.fetch(SUBJECT_KEY, DEFAULT_SUBJECT)
27
- )
28
- end
29
-
30
- # Specifies templates to challenge evaluated subjects & get results.
31
- attr_reader :actuals
32
-
33
- # Specifies a list of variables to populate the subject's template.
34
- attr_reader :contexts
35
-
36
- # Specifies the code to execute before generating the test suite.
37
- attr_reader :header
38
-
39
- # Specifies the template of the code to be declined across contexts.
40
- attr_reader :subject
41
-
42
- # Initialize a new configuration.
43
- def initialize(actuals:, contexts:, header:, subject:)
44
- raise ::TypeError, actuals.inspect unless actuals.is_a?(::Array)
45
- raise ::TypeError, contexts.inspect unless contexts.is_a?(::Hash)
46
- raise ::TypeError, header.inspect unless header.is_a?(::String)
47
- raise ::TypeError, subject.inspect unless subject.is_a?(::String)
48
-
49
- @actuals = actuals.sort
50
- @contexts = contexts
51
- @header = header
52
- @subject = subject
53
- end
54
- end
55
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Brutal
4
- module File
5
- # Brutal::File::Read
6
- #
7
- # @since 1.1.0
8
- class Read
9
- attr_reader :name
10
-
11
- def initialize(name)
12
- @name = name
13
- end
14
-
15
- def call
16
- ::File.read(path)
17
- rescue ::Errno::ENOENT => _e
18
- abort "File #{path} not found!"
19
- end
20
-
21
- protected
22
-
23
- def path
24
- ::File.join(::Dir.pwd, name)
25
- end
26
- end
27
- end
28
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Brutal
4
- module File
5
- # Brutal::File::Write
6
- #
7
- # @since 1.1.0
8
- class Write
9
- attr_reader :name
10
-
11
- def initialize(name)
12
- @name = name
13
- end
14
-
15
- def call(scaffold)
16
- file = ::File.open(path, "w")
17
- file.write(scaffold)
18
-
19
- true
20
- ensure
21
- file.close
22
- end
23
-
24
- protected
25
-
26
- def path
27
- ::File.join(::Dir.pwd, name)
28
- end
29
- end
30
- end
31
- end
data/lib/brutal/file.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- %w[
4
- read
5
- write
6
- ].each { |filename| require_relative(File.join("file", filename)) }
7
-
8
- class Brutal
9
- # Brutal::File
10
- module File
11
- RUBY_EXTENSION = ".rb"
12
-
13
- def self.generated_pathname(pathname)
14
- pathname.sub_ext(RUBY_EXTENSION)
15
- end
16
- end
17
- end
data/lib/brutal/yaml.rb DELETED
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "yaml"
4
-
5
- class Brutal
6
- # Brutal::Yaml
7
- module Yaml
8
- FILENAME_EXTENSION = ".yaml"
9
-
10
- def self.parse(yaml)
11
- ::YAML.safe_load(yaml, symbolize_names: false)
12
- end
13
-
14
- def self.parse?(pathname)
15
- filename_extension = pathname.extname
16
- filename_extension.eql?(FILENAME_EXTENSION)
17
- end
18
- end
19
- end