brutal 1.6.0.beta1 → 1.6.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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