brutal 0.4.0 → 1.2.0

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: 4b21dc72c3687aa3893272f404e01d0329a528a61caa2b6f5ec251b5de66a3a4
4
- data.tar.gz: 9aeb0ad4c455bb747700dc3af6bdf8957376e100af6e7b11bc6b377218e12426
3
+ metadata.gz: 7a7eb1b01e30dda0f5b204eef32ac2ec59c19384b37500f40587a1a522fce6db
4
+ data.tar.gz: be19e4c8f4741658ef2aea98891b8bf040a250361fe48fee5219b02cc297b10f
5
5
  SHA512:
6
- metadata.gz: 7a818e0951d2993387caf80e699a989ffecca901f43ebf00b430b1de2ce330eb8da486c75800fd936a32b6f9b3286703d5ce4e85995b1a652f945ee9261162d3
7
- data.tar.gz: afeedf7b04fc5be914e400a2b1a2149b0f82fb45f069654f2cc0bcf72e64cc84fc1c906b52c780d5199c2897059e1fc8e6125c6667e32c8a26fd656ae645a0c8
6
+ metadata.gz: 565a5d6628dd7f3904f97343da33539eaddf97c6fa020d2c14736ed84a146c3fe3d0aa7eb6fdfc73a94a3238be3bba40d892f07281d231918022b2c96fb95ce6
7
+ data.tar.gz: 245f56b40a04d626c653e679b3634a5e1f3805a4f356c6f009759cb9e350e675b89e17e699e430fac5ffcb596e83c19190b929b4086b1da42254f2ffdbc7ea60
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2019 Cyril Kato
3
+ Copyright (c) 2020-2021 Cyril Kato
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,84 +1,44 @@
1
1
  # Brutal 💎🔨
2
2
 
3
- [![Build Status](https://api.travis-ci.org/fixrb/brutal.svg?branch=master)][travis]
3
+ [![RuboCop Status](https://github.com/fixrb/brutal/workflows/RuboCop/badge.svg)][workflow_rubocop]
4
+ [![Build Status](https://api.travis-ci.org/fixrb/brutal.svg?branch=main)][travis]
4
5
  [![Gem Version](https://badge.fury.io/rb/brutal.svg)][gem]
5
- [![Inline docs](https://inch-ci.org/github/fixrb/brutal.svg?branch=master)][inchpages]
6
+ [![Inline docs](https://inch-ci.org/github/fixrb/brutal.svg?branch=main)][inchpages]
6
7
  [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)][rubydoc]
7
8
 
8
9
  > A _code-first_ approach to automate the writing of unit tests.
9
10
 
10
11
  ## Intro
11
12
 
12
- [![I Hate Tests](https://github.com/fixrb/brutal/raw/master/img/rubyhack-2019-ruby3-what-s-missing-by-yukihiro-matsumoto.jpg)](https://www.youtube.com/embed/cmOt9HhszCI?start=1732&end=1736 "I don't like tests. It's not DRY.")
13
+ [![I Hate Tests](https://github.com/fixrb/brutal/raw/main/img/rubyhack-2019-ruby3-what-s-missing-by-yukihiro-matsumoto.jpg)](https://www.youtube.com/embed/cmOt9HhszCI?start=1732&end=1736 "I don't like tests. It's not DRY.")
13
14
 
14
15
  > I don't like tests. It's not DRY.<br/>
15
16
  > -- [Matz](https://github.com/matz)
16
17
 
17
- ## Purpose
18
+ ## Overview
18
19
 
19
- Take a break and let __Brutal__ shape for you the actual behavior of your code against as many combinations of challenges as needed.
20
+ Let __Brutal__ shape for you in no time the actual behavior of your code through as many combinations of contexts as needed.
20
21
 
21
- Without giving the power to test everything, it makes it easy to generate in no time a set of tests for all relevant contexts.
22
-
23
- By delegating to __Brutal__ the repetitive and redundant task of writing tests, you'll be able to focus on your core business: writing code.
22
+ By delegating to __Brutal__ the repetitive (and redundant) task of writing tests, you'll be able to focus on your core business: the code itself.
24
23
 
25
24
  ## Warning
26
25
 
27
- __Brutal__ does not prevent from bugs.
28
- As a picture of the behavior of the code, its generated tests would be wrong if the code is wrong.
29
-
30
- This is why it is important to carefully read the generated test suite, to ensure that it describes the behavior of the code as it is supposed to behave.
31
-
32
- However, when the `brutal` command is executed successfully,
33
- we can consider that both __Brutal__'s configuration file (`.brutal.yml`) and evaluated code as syntactically correct.
34
-
35
- In the context of a versioned project, to avoid regressions,
36
- the integrity of the behavior of the code can easily be checked by re-generating a picture to be compared with the previous one.
37
- Here is an example with [The Greeter class](https://github.com/fixrb/brutal/raw/master/examples/the_greeter_class/) code:
38
-
39
- ```sh
40
- git diff
41
- ```
42
-
43
- The code:
44
-
45
- ```diff
46
- # The Greeter class
47
- class Greeter
48
- def initialize(name)
49
- - @name = name
50
- + @name = name.capitalize
51
- end
52
-
53
- def salute
54
- "Hello #{@name}!"
55
- end
56
- end
57
- ```
58
-
59
- The generated test of the code:
60
-
61
- ```diff
62
- require './greeter'
63
-
64
- # ------------------------------------------------------------------------------
65
-
66
- front_object = Greeter
26
+ __Brutal__ development process does not prevent from bugs.
67
27
 
68
- # ------------------------------------------------------------------------------
28
+ As a _picture of the behavior of the code_,
29
+ a generated test suite is wrong as long as the code is wrong,
30
+ regardless of whether all true expectations.
69
31
 
70
- actual = front_object.new('world')
71
-
72
- - raise unless actual.salute == "Hello world!"
73
- + raise unless actual.salute == "Hello World!"
74
- ```
32
+ However, this document becomes relevant when it shows that the code behaves as it is supposed to.
33
+ It is therefore important to read it well.
34
+ This is the price for _Brutal-Driven Development_.
75
35
 
76
36
  ## Installation
77
37
 
78
38
  Add this line to your application's Gemfile:
79
39
 
80
40
  ```ruby
81
- gem 'brutal'
41
+ gem "brutal"
82
42
  ```
83
43
 
84
44
  And then execute:
@@ -95,105 +55,77 @@ Just type `brutal` in a Ruby project's folder and watch the magic happen.
95
55
 
96
56
  ## Usage
97
57
 
98
- __Brutal__'s configuration file is `.brutal.yml`, which acts like a meta-spec.
99
- This YAML file can contains the following keys:
100
-
101
- * `header` (optional): Some code to execute before the test suite.
102
- * `front_object` (required): The front object of the test suite.
103
- * `subject` (required): The object of each context.
104
- * `variables` (required): A hash to generate the subject of each context.
105
- * `actual_values` (required): A list of tests to challenge the subject.
106
-
107
- ### Optional parameters
58
+ The `brutal.yml` file is a manifest you can use to define your __Brutal__ meta-spec.
59
+ It has 4 top-level sections:
108
60
 
109
- It would also be possible to ask for an RSpec template by passing "`rspec`" argument:
61
+ * `header` - Specifies the code to execute before generating the test suite.
62
+ * `subject` - Specifies the template of the code to be declined across contexts.
63
+ * `contexts` - Specifies a list of variables to populate the subject's template.
64
+ * `actuals` - Specifies templates to challenge evaluated subjects & get results.
110
65
 
111
- > brutal rspec
66
+ ### Getting started
112
67
 
113
- ## Example
114
-
115
- Given this config file:
68
+ 1. Create a `brutal.yml` file in your application's root directory.
69
+ The following example `brutal.yml` defines the shape of a Hello test suite:
116
70
 
117
71
  ```yaml
118
72
  ---
119
- front_object: |
120
- "Hello "
121
-
122
73
  subject: |
123
- %{front_object} + %{string}
74
+ "Hello " + "%{string}"
124
75
 
125
- variables:
76
+ contexts:
126
77
  string:
127
- - "'Alice'"
128
- - "'Bob'"
78
+ - Alice
79
+ - Bob
129
80
 
130
- actual_values:
81
+ actuals:
131
82
  - "%{subject}.to_s"
132
83
  - "%{subject}.length"
133
84
  ```
134
85
 
135
- The `brutal` command would generate and write in to a `test.rb` file the following "Plain Old Ruby":
86
+ 2. Run the `brutal` command from the same directory.
136
87
 
137
- ```ruby
138
- front_object = "Hello "
139
-
140
- # ------------------------------------------------------------------------------
88
+ 3. Read the generated `test.rb` file in the same directory:
141
89
 
142
- actual = front_object + 'Alice'
143
- raise unless actual.to_s == "Hello Alice"
144
- raise unless actual.length == 11
90
+ ```ruby
91
+ # Brutal test suite
145
92
 
146
93
  # ------------------------------------------------------------------------------
147
94
 
148
- actual = front_object + 'Bob'
149
- raise unless actual.to_s == "Hello Bob"
150
- raise unless actual.length == 9
151
- ```
152
-
153
- And the `brutal rspec` command would generate and write in to a `test_spec.rb` file the following spec:
154
-
155
- ```ruby
156
- RSpec.describe do
157
- let(:front_object) { "Hello " }
158
-
159
- context do
160
- let(:actual) { front_object + 'Alice' }
95
+ actual = begin
96
+ "Hello " + "Alice"
97
+ end
161
98
 
162
- it { expect(actual.to_s).to eq("Hello Alice") }
163
- it { expect(actual.length).to eq(11) }
164
- end
99
+ raise if actual.to_s != "Hello Alice"
100
+ raise if actual.length != 11
165
101
 
166
- context do
167
- let(:actual) { front_object + 'Bob' }
102
+ # ------------------------------------------------------------------------------
168
103
 
169
- it { expect(actual.to_s).to eq("Hello Bob") }
170
- it { expect(actual.length).to eq(9) }
171
- end
104
+ actual = begin
105
+ "Hello " + "Bob"
172
106
  end
107
+
108
+ raise if actual.to_s != "Hello Bob"
109
+ raise if actual.length != 9
173
110
  ```
174
111
 
175
- More examples are available [here](https://github.com/fixrb/brutal/raw/master/examples/).
112
+ ### More examples
113
+
114
+ https://github.com/fixrb/brutal/raw/main/examples/
176
115
 
177
116
  ## Rake integration example
178
117
 
179
- The generated brutal test suite `test.rb` file can be declared as follows:
118
+ A generated `test.rb` file could be matched as follows:
180
119
 
181
120
  ```ruby
182
121
  Rake::TestTask.new do |t|
183
- t.pattern = 'test.rb'
122
+ t.pattern = "test.rb"
184
123
  end
185
124
  ```
186
125
 
187
126
  ## Contact
188
127
 
189
- * Home page: https://github.com/fixrb/brutal
190
- * Bugs/issues: https://github.com/fixrb/brutal/issues
191
-
192
- ## Rubies
193
-
194
- * [MRI](https://www.ruby-lang.org/)
195
- * [Rubinius](https://rubinius.com/)
196
- * [JRuby](https://www.jruby.org/)
128
+ * Source code: https://github.com/fixrb/brutal
197
129
 
198
130
  ## Versioning
199
131
 
@@ -201,17 +133,18 @@ __Brutal__ follows [Semantic Versioning 2.0](https://semver.org/).
201
133
 
202
134
  ## License
203
135
 
204
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
136
+ The [gem](https://rubygems.org/gems/brutal) is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
205
137
 
206
138
  ***
207
139
 
208
140
  <p>
209
141
  This project is sponsored by:<br />
210
142
  <a href="https://sashite.com/"><img
211
- src="https://github.com/fixrb/brutal/raw/master/img/sashite.png"
143
+ src="https://github.com/fixrb/brutal/raw/main/img/sashite.png"
212
144
  alt="Sashite" /></a>
213
145
  </p>
214
146
 
147
+ [workflow_rubocop]: https://github.com/fixrb/brutal/actions?query=workflow%3ARuboCop
215
148
  [gem]: https://rubygems.org/gems/brutal
216
149
  [travis]: https://travis-ci.org/fixrb/brutal
217
150
  [inchpages]: https://inch-ci.org/github/fixrb/brutal
data/bin/brutal CHANGED
@@ -1,45 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'yaml'
4
+ require_relative File.join("..", "lib", "brutal")
5
5
 
6
- FILE_NAME = '.brutal.yml'
7
- CONF_PATH = ::File.join(::Dir.pwd, FILE_NAME)
8
-
9
- abort "File #{CONF_PATH} not found!" unless ::File.exist?(CONF_PATH)
10
-
11
- conf = ::YAML.load_file(CONF_PATH)
12
-
13
- header = conf.fetch('header', '').to_s.chomp
14
- front_object = conf.fetch('front_object')
15
- subject = conf.fetch('subject')
16
- variables = conf.fetch('variables', {})
17
- actual_values = conf.fetch('actual_values')
18
-
19
- raise ::TypeError unless subject.is_a?(::String)
20
- raise ::TypeError unless variables.is_a?(::Hash)
21
- raise ::TypeError unless actual_values.is_a?(::Array)
22
-
23
- front_object = front_object.chomp if front_object.is_a?(::String)
24
-
25
- require_relative ::File.join('..', 'lib', 'brutal')
26
-
27
- scaffold, file_name = case ARGV.fetch(0, nil)
28
- when nil
29
- [::Brutal::ScaffoldGenerator::Por, 'test.rb']
30
- when 'rspec'
31
- [::Brutal::ScaffoldGenerator::RSpec, 'test_spec.rb']
32
- else
33
- abort "#{ARGV[0].inspect} not (yet) supported!"
34
- end
35
-
36
- eval(header) # rubocop:disable Security/Eval
37
-
38
- doc = [
39
- header,
40
- scaffold.new(front_object, subject, *actual_values, **variables).to_s
41
- ].reject(&:empty?).join("\n\n")
42
-
43
- file = ::File.open(file_name, 'w')
44
- file.write(doc)
45
- file.close
6
+ Brutal.generate!
data/lib/brutal.rb CHANGED
@@ -1,11 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Main namespace
4
- #
5
- # @api public
3
+ %w[
4
+ configuration
5
+ file/read
6
+ file/write
7
+ scaffold
8
+ yaml
9
+ ].each { |file_name| require_relative(File.join("brutal", file_name)) }
10
+
11
+ # The Brutal namespace.
6
12
  module Brutal
7
- end
13
+ def self.generate!
14
+ yaml = File::Read.new.call
15
+ hash = Yaml.parse(yaml)
16
+ conf = Configuration.load(hash)
17
+ ruby = Scaffold.new(conf.header,
18
+ conf.subject,
19
+ *conf.actuals,
20
+ **conf.contexts)
8
21
 
9
- Dir[File.join File.dirname(__FILE__), 'brutal', 'scaffold_generator', '*.rb'].each do |fname|
10
- require_relative fname
22
+ File::Write.new.call(ruby)
23
+ end
11
24
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brutal
4
+ # Brutal::Configuration
5
+ #
6
+ # @since 1.0.0
7
+ class Configuration
8
+ DEFAULT_ACTUALS = [].freeze
9
+ DEFAULT_CONTEXTS = {}.freeze
10
+ DEFAULT_HEAD = "# Brutal test suite"
11
+ DEFAULT_SUBJECT = ""
12
+
13
+ # Load the configuration parameters.
14
+ #
15
+ # @param params [Hash] Receive the 4 top-level section parameters.
16
+ def self.load(params)
17
+ new(
18
+ actuals: params.fetch("actuals", DEFAULT_ACTUALS),
19
+ contexts: params.fetch("contexts", DEFAULT_CONTEXTS),
20
+ header: params.fetch("header", DEFAULT_HEAD),
21
+ subject: params.fetch("subject", DEFAULT_SUBJECT)
22
+ )
23
+ end
24
+
25
+ # Specifies templates to challenge evaluated subjects & get results.
26
+ attr_reader :actuals
27
+
28
+ # Specifies a list of variables to populate the subject's template.
29
+ attr_reader :contexts
30
+
31
+ # Specifies the code to execute before generating the test suite.
32
+ attr_reader :header
33
+
34
+ # Specifies the template of the code to be declined across contexts.
35
+ attr_reader :subject
36
+
37
+ # Initialize a new configuration.
38
+ def initialize(actuals:, contexts:, header:, subject:)
39
+ raise ::TypeError, actuals.inspect unless actuals.is_a?(::Array)
40
+ raise ::TypeError, contexts.inspect unless contexts.is_a?(::Hash)
41
+ raise ::TypeError, header.inspect unless header.is_a?(::String)
42
+ raise ::TypeError, subject.inspect unless subject.is_a?(::String)
43
+
44
+ @actuals = actuals.sort
45
+ @contexts = contexts
46
+ @header = header
47
+ @subject = subject
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brutal
4
+ # Brutal::File
5
+ #
6
+ # @since 1.1.0
7
+ module File
8
+ # Brutal::File::Read
9
+ #
10
+ # @since 1.1.0
11
+ class Read
12
+ NAME = ".brutal.yml"
13
+
14
+ attr_reader :name
15
+
16
+ def initialize(name = NAME)
17
+ @name = name
18
+ end
19
+
20
+ def call
21
+ ::File.read(path)
22
+ rescue ::Errno::ENOENT => _e
23
+ abort("File #{path} not found!")
24
+ end
25
+
26
+ protected
27
+
28
+ def path
29
+ ::File.join(::Dir.pwd, name)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brutal
4
+ # Brutal::File
5
+ #
6
+ # @since 1.1.0
7
+ module File
8
+ # Brutal::File::Write
9
+ #
10
+ # @since 1.1.0
11
+ class Write
12
+ NAME = "test.rb"
13
+
14
+ attr_reader :name
15
+
16
+ def initialize(name = NAME)
17
+ @name = name
18
+ end
19
+
20
+ def call(scaffold)
21
+ file = ::File.open(path, "w")
22
+ file.write(scaffold)
23
+
24
+ true
25
+ ensure
26
+ file.close
27
+ end
28
+
29
+ protected
30
+
31
+ def path
32
+ ::File.join(::Dir.pwd, name)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brutal
4
+ # Brutal::Scaffold
5
+ #
6
+ # @since 1.0.0
7
+ class Scaffold
8
+ # Specifies templates to challenge evaluated subjects & get results.
9
+ attr_reader :actuals
10
+
11
+ # Specifies a list of variables to populate the subject's template.
12
+ attr_reader :contexts
13
+
14
+ # Specifies the code to execute before generating the test suite.
15
+ attr_reader :header
16
+
17
+ # Specifies the template of the code to be declined across contexts.
18
+ attr_reader :subject
19
+
20
+ # Initialize a new scaffold generator.
21
+ def initialize(header, subject, *actuals, **contexts)
22
+ warn("Empty subject!") if subject.empty?
23
+ warn("Empty actual values!") if actuals.empty?
24
+ warn("Empty contexts!") if contexts.empty?
25
+
26
+ eval(header) # rubocop:disable Security/Eval
27
+
28
+ @header = header
29
+ @subject = subject
30
+ @actuals = actuals
31
+ @contexts = contexts
32
+ end
33
+
34
+ # Return a Ruby string that can be evaluated.
35
+ def inspect(object)
36
+ return object.to_s unless object.is_a?(::String)
37
+
38
+ object.strip
39
+ end
40
+
41
+ # Return a string representation.
42
+ #
43
+ # @return [String]
44
+ #
45
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
46
+ def to_s
47
+ "#{header.chomp}\n#{blank_line}" + combinations_values.map do |values|
48
+ attributes = context_names.each_with_index.inject({}) do |h, (name, i)|
49
+ h.merge(name.to_sym => inspect(values.fetch(i)))
50
+ end
51
+
52
+ actual_str = format(inspect(subject), **attributes)
53
+
54
+ string = <<~CODE
55
+ actual = begin
56
+ #{actual_str.gsub(/^/, ' ')}
57
+ end
58
+
59
+ CODE
60
+
61
+ actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
62
+
63
+ actuals.each do |actual_value|
64
+ result_str = format(actual_value, subject: "actual")
65
+ string += "raise if #{result_str} != #{eval(result_str).inspect}\n" # rubocop:disable Security/Eval
66
+ end
67
+
68
+ string
69
+ end.join(blank_line)
70
+ end
71
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
72
+
73
+ def blank_line
74
+ "\n" \
75
+ "# #{'-' * 78}\n" \
76
+ "\n"
77
+ end
78
+
79
+ def context_names
80
+ contexts.keys.sort
81
+ end
82
+
83
+ def contexts_values
84
+ context_names.map { |context_name| contexts.fetch(context_name) }
85
+ end
86
+
87
+ def combinations_values
88
+ Array(contexts_values[0]).product(*Array(contexts_values[1..]))
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Brutal
6
+ # Brutal::Yaml
7
+ #
8
+ # @since 1.1.0
9
+ module Yaml
10
+ def self.parse(yaml)
11
+ ::YAML.safe_load(yaml, symbolize_names: false)
12
+ end
13
+ end
14
+ end
metadata CHANGED
@@ -1,45 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brutal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-28 00:00:00.000000000 Z
11
+ date: 2021-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.1'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2.1'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '13.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '13.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rubocop
42
+ name: rubocop-md
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -66,34 +66,62 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-thread_safety
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: simplecov
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
- - - "~>"
101
+ - - ">="
74
102
  - !ruby/object:Gem::Version
75
- version: '0.17'
103
+ version: '0'
76
104
  type: :development
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
- - - "~>"
108
+ - - ">="
81
109
  - !ruby/object:Gem::Version
82
- version: '0.17'
110
+ version: '0'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: yard
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
- - - "~>"
115
+ - - ">="
88
116
  - !ruby/object:Gem::Version
89
- version: '0.9'
117
+ version: '0'
90
118
  type: :development
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
- - - "~>"
122
+ - - ">="
95
123
  - !ruby/object:Gem::Version
96
- version: '0.9'
124
+ version: '0'
97
125
  description: A code-first approach to automate the writing of unit tests.
98
126
  email: contact@cyril.email
99
127
  executables:
@@ -105,9 +133,11 @@ files:
105
133
  - README.md
106
134
  - bin/brutal
107
135
  - lib/brutal.rb
108
- - lib/brutal/scaffold_generator/base.rb
109
- - lib/brutal/scaffold_generator/por.rb
110
- - lib/brutal/scaffold_generator/rspec.rb
136
+ - lib/brutal/configuration.rb
137
+ - lib/brutal/file/read.rb
138
+ - lib/brutal/file/write.rb
139
+ - lib/brutal/scaffold.rb
140
+ - lib/brutal/yaml.rb
111
141
  homepage: https://github.com/fixrb/brutal
112
142
  licenses:
113
143
  - MIT
@@ -120,14 +150,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
150
  requirements:
121
151
  - - ">="
122
152
  - !ruby/object:Gem::Version
123
- version: '0'
153
+ version: 2.7.0
124
154
  required_rubygems_version: !ruby/object:Gem::Requirement
125
155
  requirements:
126
156
  - - ">="
127
157
  - !ruby/object:Gem::Version
128
158
  version: '0'
129
159
  requirements: []
130
- rubygems_version: 3.1.2
160
+ rubygems_version: 3.1.4
131
161
  signing_key:
132
162
  specification_version: 4
133
163
  summary: A code-first approach to automate the writing of unit tests.
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Brutal
4
- module ScaffoldGenerator
5
- # Base class
6
- class Base
7
- # @api private
8
- attr_reader :front_object_str, :front_object, :subject, :actual_values, :variables
9
-
10
- # Initialize a new scaffold generator
11
- def initialize(front_object, subject, *actual_values, **variables)
12
- raise 'Empty actual values!' if actual_values.empty?
13
- raise 'Empty variables!' if variables.empty?
14
-
15
- @front_object_str = inspect(front_object)
16
- @front_object = eval(@front_object_str) # rubocop:disable Security/Eval
17
- @subject = subject
18
- @actual_values = actual_values
19
- @variables = variables
20
- end
21
-
22
- # Return a Ruby string that can be evaluated.
23
- def inspect(object)
24
- return object.to_s unless object.is_a?(::String)
25
-
26
- object.strip
27
- end
28
- end
29
- end
30
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base'
4
-
5
- module Brutal
6
- module ScaffoldGenerator
7
- # Plain Old Ruby.
8
- #
9
- # @api private
10
- #
11
- class Por < Base
12
- # Return a string representation
13
- #
14
- # @return [String]
15
- #
16
- # @api public
17
- def to_s
18
- names = variables.keys.sort
19
- values_arr = names.map { |name| variables.fetch(name) }
20
-
21
- test_params = Array(values_arr[0]).product(*Array(values_arr[1..-1]))
22
-
23
- blank_line.gsub(/\A\n/, '') +
24
- "front_object = #{front_object_str}\n" +
25
- blank_line +
26
- test_params.map do |values|
27
- attributes = names.each_with_index.inject(front_object: 'front_object') do |h, (name, i)|
28
- h.merge(name.to_sym => inspect(values.fetch(i)))
29
- end
30
-
31
- actual_str = format(inspect(subject), **attributes)
32
-
33
- string = "actual = #{actual_str}\n\n"
34
- actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
35
-
36
- actual_values.each do |actual_value|
37
- result_str = format(actual_value, subject: 'actual')
38
- string += "raise unless #{result_str} == #{eval(result_str).inspect}\n" # rubocop:disable Security/Eval
39
- end
40
-
41
- string
42
- end.join(blank_line)
43
- end
44
-
45
- def blank_line
46
- "\n" \
47
- "# #{('-' * 78)}\n" \
48
- "\n"
49
- end
50
- end
51
- end
52
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'base'
4
-
5
- module Brutal
6
- module ScaffoldGenerator
7
- # Plain Old Ruby.
8
- #
9
- # @api private
10
- #
11
- class RSpec < Base
12
- # Return a string representation
13
- #
14
- # @return [String]
15
- #
16
- # @api public
17
- def to_s
18
- names = variables.keys.sort
19
- values_arr = names.map { |name| variables.fetch(name) }
20
-
21
- test_params = Array(values_arr[0]).product(*Array(values_arr[1..-1]))
22
-
23
- "RSpec.describe do\n" \
24
- " let(:front_object) { #{front_object_str} }\n" \
25
- "\n" +
26
- test_params.map do |values|
27
- string = " context do\n"
28
-
29
- attributes = names.each_with_index.inject(front_object: 'front_object') do |h, (name, i)|
30
- h.merge(name.to_sym => inspect(values.fetch(i)))
31
- end
32
-
33
- actual_str = format(inspect(subject), **attributes)
34
-
35
- string += " let(:actual) { #{actual_str} }\n\n"
36
- actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
37
-
38
- actual_values.each do |actual_value|
39
- result_str = format(actual_value, subject: 'actual')
40
- string += " it { expect(#{result_str}).to eq(#{eval(result_str).inspect}) }\n" # rubocop:disable Security/Eval
41
- end
42
-
43
- string += " end\n"
44
-
45
- string
46
- end.join(blank_line) +
47
- "end\n"
48
- end
49
-
50
- def blank_line
51
- "\n"
52
- end
53
- end
54
- end
55
- end