brutal 0.3.0 → 0.4.0

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: 8e7af479b185bf19e8cb7050360c79d216af2916668e76efb0d7c550e553af4b
4
- data.tar.gz: e917683e2edd247429cb9776444e6a97c10b9930265459a10ac8a3b4dbcf2cf6
3
+ metadata.gz: 4b21dc72c3687aa3893272f404e01d0329a528a61caa2b6f5ec251b5de66a3a4
4
+ data.tar.gz: 9aeb0ad4c455bb747700dc3af6bdf8957376e100af6e7b11bc6b377218e12426
5
5
  SHA512:
6
- metadata.gz: ad95d20234be22ed17de738afa0f1f1e0a5518cbf967fe87f9f1932f571e13d683a454354dd792f07d55010033dfd257b888422a880a4bd6c0f04ed19cf284ed
7
- data.tar.gz: c4e82e9a5036e134e83f86c313277573926fe0773ef3e2e43145d30fb725ba6a7a196f881f090f083589ac447889b7aa10d1d7e450ec550f468792991bffb824
6
+ metadata.gz: 7a818e0951d2993387caf80e699a989ffecca901f43ebf00b430b1de2ce330eb8da486c75800fd936a32b6f9b3286703d5ce4e85995b1a652f945ee9261162d3
7
+ data.tar.gz: afeedf7b04fc5be914e400a2b1a2149b0f82fb45f069654f2cc0bcf72e64cc84fc1c906b52c780d5199c2897059e1fc8e6125c6667e32c8a26fd656ae645a0c8
data/README.md CHANGED
@@ -1,22 +1,77 @@
1
- # Brutal 👹
2
-
3
- > I don't like testing because it's redundant. If we are smart enough, we can avoid it. <br/>
4
- > -- Matz
1
+ # Brutal 💎🔨
5
2
 
6
3
  [![Build Status](https://api.travis-ci.org/fixrb/brutal.svg?branch=master)][travis]
7
4
  [![Gem Version](https://badge.fury.io/rb/brutal.svg)][gem]
8
5
  [![Inline docs](https://inch-ci.org/github/fixrb/brutal.svg?branch=master)][inchpages]
9
6
  [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)][rubydoc]
10
7
 
11
- __Brutal__ is a _code-first_ approach that automates the writing of unit tests.
8
+ > A _code-first_ approach to automate the writing of unit tests.
12
9
 
13
- By being able to generate test cases from the code itself, developers can focus on their creation, save time and energy, for more happiness.
10
+ ## Intro
14
11
 
15
- <p>
16
- <img
17
- src="https://github.com/fixrb/brutal/raw/master/img/Ferdinand_Hodler_-_Woodcutter_-_Google_Art_Project.jpg"
18
- alt="A lumberjack brutally cutting a tree" />
19
- </p>
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
+
14
+ > I don't like tests. It's not DRY.<br/>
15
+ > -- [Matz](https://github.com/matz)
16
+
17
+ ## Purpose
18
+
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
+
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.
24
+
25
+ ## Warning
26
+
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
67
+
68
+ # ------------------------------------------------------------------------------
69
+
70
+ actual = front_object.new('world')
71
+
72
+ - raise unless actual.salute == "Hello world!"
73
+ + raise unless actual.salute == "Hello World!"
74
+ ```
20
75
 
21
76
  ## Installation
22
77
 
@@ -40,7 +95,8 @@ Just type `brutal` in a Ruby project's folder and watch the magic happen.
40
95
 
41
96
  ## Usage
42
97
 
43
- The Brutal YAML file handles 4 keys:
98
+ __Brutal__'s configuration file is `.brutal.yml`, which acts like a meta-spec.
99
+ This YAML file can contains the following keys:
44
100
 
45
101
  * `header` (optional): Some code to execute before the test suite.
46
102
  * `front_object` (required): The front object of the test suite.
@@ -48,9 +104,15 @@ The Brutal YAML file handles 4 keys:
48
104
  * `variables` (required): A hash to generate the subject of each context.
49
105
  * `actual_values` (required): A list of tests to challenge the subject.
50
106
 
107
+ ### Optional parameters
108
+
109
+ It would also be possible to ask for an RSpec template by passing "`rspec`" argument:
110
+
111
+ > brutal rspec
112
+
51
113
  ## Example
52
114
 
53
- Given this `.brutal.yml` config file:
115
+ Given this config file:
54
116
 
55
117
  ```yaml
56
118
  ---
@@ -70,7 +132,7 @@ actual_values:
70
132
  - "%{subject}.length"
71
133
  ```
72
134
 
73
- The `brutal` command would save this Plain Old Ruby in to a `test.rb` file:
135
+ The `brutal` command would generate and write in to a `test.rb` file the following "Plain Old Ruby":
74
136
 
75
137
  ```ruby
76
138
  front_object = "Hello "
@@ -88,7 +150,29 @@ raise unless actual.to_s == "Hello Bob"
88
150
  raise unless actual.length == 9
89
151
  ```
90
152
 
91
- [More examples](examples/) are available.
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' }
161
+
162
+ it { expect(actual.to_s).to eq("Hello Alice") }
163
+ it { expect(actual.length).to eq(11) }
164
+ end
165
+
166
+ context do
167
+ let(:actual) { front_object + 'Bob' }
168
+
169
+ it { expect(actual.to_s).to eq("Hello Bob") }
170
+ it { expect(actual.length).to eq(9) }
171
+ end
172
+ end
173
+ ```
174
+
175
+ More examples are available [here](https://github.com/fixrb/brutal/raw/master/examples/).
92
176
 
93
177
  ## Rake integration example
94
178
 
@@ -115,23 +199,10 @@ end
115
199
 
116
200
  __Brutal__ follows [Semantic Versioning 2.0](https://semver.org/).
117
201
 
118
- ## Contributing
119
-
120
- Bug reports and pull requests are welcome on GitHub at https://github.com/fixrb/brutal. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/fixrb/brutal/blob/master/CODE_OF_CONDUCT.md).
121
-
122
202
  ## License
123
203
 
124
204
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
125
205
 
126
- ## Code of Conduct
127
-
128
- Everyone interacting in the GreatGuardian project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fixrb/brutal/blob/master/CODE_OF_CONDUCT.md).
129
-
130
- [gem]: https://rubygems.org/gems/brutal
131
- [travis]: https://travis-ci.org/fixrb/brutal
132
- [inchpages]: https://inch-ci.org/github/fixrb/brutal
133
- [rubydoc]: https://rubydoc.info/gems/brutal/frames
134
-
135
206
  ***
136
207
 
137
208
  <p>
@@ -140,3 +211,8 @@ Everyone interacting in the GreatGuardian project's codebases, issue trackers, c
140
211
  src="https://github.com/fixrb/brutal/raw/master/img/sashite.png"
141
212
  alt="Sashite" /></a>
142
213
  </p>
214
+
215
+ [gem]: https://rubygems.org/gems/brutal
216
+ [travis]: https://travis-ci.org/fixrb/brutal
217
+ [inchpages]: https://inch-ci.org/github/fixrb/brutal
218
+ [rubydoc]: https://rubydoc.info/gems/brutal/frames
data/bin/brutal CHANGED
@@ -24,20 +24,22 @@ front_object = front_object.chomp if front_object.is_a?(::String)
24
24
 
25
25
  require_relative ::File.join('..', 'lib', 'brutal')
26
26
 
27
- scaffold = case ARGV.fetch(0, nil)
28
- when nil
29
- ::Brutal::ScaffoldGenerator::Por
30
- else
31
- abort "#{ARGV[0].inspect} not (yet) supported!"
32
- end
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
33
35
 
34
36
  eval(header) # rubocop:disable Security/Eval
35
37
 
36
38
  doc = [
37
39
  header,
38
40
  scaffold.new(front_object, subject, *actual_values, **variables).to_s
39
- ].reject(&:empty?).join("\n")
41
+ ].reject(&:empty?).join("\n\n")
40
42
 
41
- file = ::File.open('test.rb', 'w')
43
+ file = ::File.open(file_name, 'w')
42
44
  file.write(doc)
43
45
  file.close
@@ -20,7 +20,7 @@ module Brutal
20
20
 
21
21
  test_params = Array(values_arr[0]).product(*Array(values_arr[1..-1]))
22
22
 
23
- blank_line +
23
+ blank_line.gsub(/\A\n/, '') +
24
24
  "front_object = #{front_object_str}\n" +
25
25
  blank_line +
26
26
  test_params.map do |values|
@@ -30,7 +30,7 @@ module Brutal
30
30
 
31
31
  actual_str = format(inspect(subject), **attributes)
32
32
 
33
- string = "actual = #{actual_str}\n"
33
+ string = "actual = #{actual_str}\n\n"
34
34
  actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
35
35
 
36
36
  actual_values.each do |actual_value|
@@ -0,0 +1,55 @@
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
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: 0.3.0
4
+ version: 0.4.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-24 00:00:00.000000000 Z
11
+ date: 2019-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: '2.1'
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.0'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.9'
97
- description: Scaffolds test cases from the code itself.
97
+ description: A code-first approach to automate the writing of unit tests.
98
98
  email: contact@cyril.email
99
99
  executables:
100
100
  - brutal
@@ -107,6 +107,7 @@ files:
107
107
  - lib/brutal.rb
108
108
  - lib/brutal/scaffold_generator/base.rb
109
109
  - lib/brutal/scaffold_generator/por.rb
110
+ - lib/brutal/scaffold_generator/rspec.rb
110
111
  homepage: https://github.com/fixrb/brutal
111
112
  licenses:
112
113
  - MIT
@@ -129,5 +130,5 @@ requirements: []
129
130
  rubygems_version: 3.1.2
130
131
  signing_key:
131
132
  specification_version: 4
132
- summary: Scaffolds test cases from the code itself.
133
+ summary: A code-first approach to automate the writing of unit tests.
133
134
  test_files: []