brutal 0.3.0 → 1.1.1

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: 8e7af479b185bf19e8cb7050360c79d216af2916668e76efb0d7c550e553af4b
4
- data.tar.gz: e917683e2edd247429cb9776444e6a97c10b9930265459a10ac8a3b4dbcf2cf6
3
+ metadata.gz: 98d43784db59dbf4d8263ec4730d302832e7e5edc46ebafc1a13d95935e9b697
4
+ data.tar.gz: e2d37b31d5b37387437e6ac80afb11b5b1a6d104cb677629ec3aafa9aae153af
5
5
  SHA512:
6
- metadata.gz: ad95d20234be22ed17de738afa0f1f1e0a5518cbf967fe87f9f1932f571e13d683a454354dd792f07d55010033dfd257b888422a880a4bd6c0f04ed19cf284ed
7
- data.tar.gz: c4e82e9a5036e134e83f86c313277573926fe0773ef3e2e43145d30fb725ba6a7a196f881f090f083589ac447889b7aa10d1d7e450ec550f468792991bffb824
6
+ metadata.gz: d3af04c68e89e7bdd965163066db2b99a4e3df78846ea6f33a0a89b9fe443e477376a6108a31c8b69d86d45f04459991d503f56c345b5089b7233a22b0d831bd
7
+ data.tar.gz: 55e326bf5cdcba338c63d7e57a8f75378f9869fe0f986867a86ece479850dd78745a2a568c3e0b89c8080f343e977b17d42b714e80dbbe3543b980204fd67c4d
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 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,22 +1,37 @@
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
 
3
+ [![RuboCop Status](https://github.com/fixrb/brutal/workflows/RuboCop/badge.svg)][workflow_rubocop]
6
4
  [![Build Status](https://api.travis-ci.org/fixrb/brutal.svg?branch=master)][travis]
7
5
  [![Gem Version](https://badge.fury.io/rb/brutal.svg)][gem]
8
6
  [![Inline docs](https://inch-ci.org/github/fixrb/brutal.svg?branch=master)][inchpages]
9
7
  [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)][rubydoc]
10
8
 
11
- __Brutal__ is a _code-first_ approach that automates the writing of unit tests.
9
+ > A _code-first_ approach to automate the writing of unit tests.
12
10
 
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.
11
+ ## Intro
14
12
 
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>
13
+ [![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.")
14
+
15
+ > I don't like tests. It's not DRY.<br/>
16
+ > -- [Matz](https://github.com/matz)
17
+
18
+ ## Overview
19
+
20
+ Let __Brutal__ shape for you in no time the actual behavior of your code through as many combinations of contexts as needed.
21
+
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.
23
+
24
+ ## Warning
25
+
26
+ __Brutal__ development process does not prevent from bugs.
27
+
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.
31
+
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_.
20
35
 
21
36
  ## Installation
22
37
 
@@ -40,59 +55,67 @@ Just type `brutal` in a Ruby project's folder and watch the magic happen.
40
55
 
41
56
  ## Usage
42
57
 
43
- The Brutal YAML file handles 4 keys:
58
+ The `brutal.yml` file is a manifest you can use to define your __Brutal__ meta-spec.
59
+ It has 4 top-level sections:
44
60
 
45
- * `header` (optional): Some code to execute before the test suite.
46
- * `front_object` (required): The front object of the test suite.
47
- * `subject` (required): The object of each context.
48
- * `variables` (required): A hash to generate the subject of each context.
49
- * `actual_values` (required): A list of tests to challenge the subject.
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.
50
65
 
51
- ## Example
66
+ ### Getting started
52
67
 
53
- Given this `.brutal.yml` 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:
54
70
 
55
71
  ```yaml
56
72
  ---
57
- front_object: |
58
- "Hello "
59
-
60
73
  subject: |
61
- %{front_object} + %{string}
74
+ "Hello " + "%{string}"
62
75
 
63
- variables:
76
+ contexts:
64
77
  string:
65
- - "'Alice'"
66
- - "'Bob'"
78
+ - Alice
79
+ - Bob
67
80
 
68
- actual_values:
81
+ actuals:
69
82
  - "%{subject}.to_s"
70
83
  - "%{subject}.length"
71
84
  ```
72
85
 
73
- The `brutal` command would save this Plain Old Ruby in to a `test.rb` file:
86
+ 2. Run the `brutal` command from the same directory.
87
+
88
+ 3. Read the generated `test.rb` file in the same directory:
74
89
 
75
90
  ```ruby
76
- front_object = "Hello "
91
+ # Brutal test suite
77
92
 
78
93
  # ------------------------------------------------------------------------------
79
94
 
80
- actual = front_object + 'Alice'
81
- raise unless actual.to_s == "Hello Alice"
82
- raise unless actual.length == 11
95
+ actual = begin
96
+ "Hello " + "Alice"
97
+ end
98
+
99
+ raise if actual.to_s != "Hello Alice"
100
+ raise if actual.length != 11
83
101
 
84
102
  # ------------------------------------------------------------------------------
85
103
 
86
- actual = front_object + 'Bob'
87
- raise unless actual.to_s == "Hello Bob"
88
- raise unless actual.length == 9
104
+ actual = begin
105
+ "Hello " + "Bob"
106
+ end
107
+
108
+ raise if actual.to_s != "Hello Bob"
109
+ raise if actual.length != 9
89
110
  ```
90
111
 
91
- [More examples](examples/) are available.
112
+ ### More examples
113
+
114
+ https://github.com/fixrb/brutal/raw/master/examples/
92
115
 
93
116
  ## Rake integration example
94
117
 
95
- The generated brutal test suite `test.rb` file can be declared as follows:
118
+ A generated `test.rb` file could be matched as follows:
96
119
 
97
120
  ```ruby
98
121
  Rake::TestTask.new do |t|
@@ -102,35 +125,15 @@ end
102
125
 
103
126
  ## Contact
104
127
 
105
- * Home page: https://github.com/fixrb/brutal
106
- * Bugs/issues: https://github.com/fixrb/brutal/issues
107
-
108
- ## Rubies
109
-
110
- * [MRI](https://www.ruby-lang.org/)
111
- * [Rubinius](https://rubinius.com/)
112
- * [JRuby](https://www.jruby.org/)
128
+ * Source code: https://github.com/fixrb/brutal
113
129
 
114
130
  ## Versioning
115
131
 
116
132
  __Brutal__ follows [Semantic Versioning 2.0](https://semver.org/).
117
133
 
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
134
  ## License
123
135
 
124
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
125
-
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
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).
134
137
 
135
138
  ***
136
139
 
@@ -140,3 +143,9 @@ Everyone interacting in the GreatGuardian project's codebases, issue trackers, c
140
143
  src="https://github.com/fixrb/brutal/raw/master/img/sashite.png"
141
144
  alt="Sashite" /></a>
142
145
  </p>
146
+
147
+ [workflow_rubocop]: https://github.com/fixrb/brutal/actions?query=workflow%3ARuboCop
148
+ [gem]: https://rubygems.org/gems/brutal
149
+ [travis]: https://travis-ci.org/fixrb/brutal
150
+ [inchpages]: https://inch-ci.org/github/fixrb/brutal
151
+ [rubydoc]: https://rubydoc.info/gems/brutal/frames
data/bin/brutal CHANGED
@@ -1,43 +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 = case ARGV.fetch(0, nil)
28
- when nil
29
- ::Brutal::ScaffoldGenerator::Por
30
- else
31
- abort "#{ARGV[0].inspect} not (yet) supported!"
32
- end
33
-
34
- eval(header) # rubocop:disable Security/Eval
35
-
36
- doc = [
37
- header,
38
- scaffold.new(front_object, subject, *actual_values, **variables).to_s
39
- ].reject(&:empty?).join("\n")
40
-
41
- file = ::File.open('test.rb', 'w')
42
- file.write(doc)
43
- file.close
6
+ Brutal.generate!
@@ -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
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.3.0
4
+ version: 1.1.1
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: 2020-09-08 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.0'
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.0'
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-performance
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rubocop-performance
56
+ name: rubocop-thread_safety
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -70,31 +70,31 @@ dependencies:
70
70
  name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '0.17'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '0.17'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: yard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '0.9'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '0.9'
97
- description: Scaffolds test cases from the code itself.
96
+ version: '0'
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
@@ -105,8 +105,11 @@ files:
105
105
  - README.md
106
106
  - bin/brutal
107
107
  - lib/brutal.rb
108
- - lib/brutal/scaffold_generator/base.rb
109
- - lib/brutal/scaffold_generator/por.rb
108
+ - lib/brutal/configuration.rb
109
+ - lib/brutal/file/read.rb
110
+ - lib/brutal/file/write.rb
111
+ - lib/brutal/scaffold.rb
112
+ - lib/brutal/yaml.rb
110
113
  homepage: https://github.com/fixrb/brutal
111
114
  licenses:
112
115
  - MIT
@@ -119,7 +122,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
122
  requirements:
120
123
  - - ">="
121
124
  - !ruby/object:Gem::Version
122
- version: '0'
125
+ version: 2.7.0
123
126
  required_rubygems_version: !ruby/object:Gem::Requirement
124
127
  requirements:
125
128
  - - ">="
@@ -129,5 +132,5 @@ requirements: []
129
132
  rubygems_version: 3.1.2
130
133
  signing_key:
131
134
  specification_version: 4
132
- summary: Scaffolds test cases from the code itself.
135
+ summary: A code-first approach to automate the writing of unit tests.
133
136
  test_files: []
@@ -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 +
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"
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