brutal 1.1.1 → 1.3.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: 98d43784db59dbf4d8263ec4730d302832e7e5edc46ebafc1a13d95935e9b697
4
- data.tar.gz: e2d37b31d5b37387437e6ac80afb11b5b1a6d104cb677629ec3aafa9aae153af
3
+ metadata.gz: 7f98c650c2e97438b0cedcebdb5b01da84af29f7cbc0c324a4b3416b3da68114
4
+ data.tar.gz: 696e8e96639a62e046f138c10f3d5181a3265c90bb10306481bc0d2b2fd9d3d0
5
5
  SHA512:
6
- metadata.gz: d3af04c68e89e7bdd965163066db2b99a4e3df78846ea6f33a0a89b9fe443e477376a6108a31c8b69d86d45f04459991d503f56c345b5089b7233a22b0d831bd
7
- data.tar.gz: 55e326bf5cdcba338c63d7e57a8f75378f9869fe0f986867a86ece479850dd78745a2a568c3e0b89c8080f343e977b17d42b714e80dbbe3543b980204fd67c4d
6
+ metadata.gz: b6279a503eba6120d29cd8855fab48c725f46671bd8efa7d6fd73158e68d0cf6de9fed01e4f5ae83cf04417b0551ab9598d6c615d25b164fbefec1d3b7ce262f
7
+ data.tar.gz: 8aebd74fd0a2c9bda6b418980dd627645f9b1c85f3e92e753ba2c03bd642d0dd63393dfd8923ef25e470269e3b6645fa3428a54cd7b2128ca53ee2b5c9e5de63
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
- The MIT License (MIT)
1
+ # The MIT License
2
2
 
3
- Copyright (c) 2020 Cyril Kato
3
+ Copyright (c) 2020-2022 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,53 +1,57 @@
1
1
  # Brutal 💎🔨
2
2
 
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=master)][travis]
5
- [![Gem Version](https://badge.fury.io/rb/brutal.svg)][gem]
6
- [![Inline docs](https://inch-ci.org/github/fixrb/brutal.svg?branch=master)][inchpages]
7
- [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)][rubydoc]
3
+ [![Version](https://img.shields.io/github/v/tag/fixrb/brutal?label=Version&logo=github)](https://github.com/fixrb/brutal/tags)
4
+ [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/fixrb/brutal/main)
5
+ [![Ruby](https://github.com/fixrb/brutal/workflows/Ruby/badge.svg?branch=main)](https://github.com/fixrb/brutal/actions?query=workflow%3Aruby+branch%3Amain)
6
+ [![RuboCop](https://github.com/fixrb/brutal/workflows/RuboCop/badge.svg?branch=main)](https://github.com/fixrb/brutal/actions?query=workflow%3Arubocop+branch%3Amain)
7
+ [![License](https://img.shields.io/github/license/fixrb/brutal?label=License&logo=github)](https://github.com/fixrb/brutal/raw/main/LICENSE.md)
8
8
 
9
9
  > A _code-first_ approach to automate the writing of unit tests.
10
10
 
11
11
  ## Intro
12
12
 
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.")
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.")
14
14
 
15
- > I don't like tests. It's not DRY.<br/>
15
+ > I don't like tests. It's not DRY.
16
16
  > -- [Matz](https://github.com/matz)
17
17
 
18
18
  ## Overview
19
19
 
20
- Let __Brutal__ shape for you in no time the actual behavior of your code through as many combinations of contexts as needed.
20
+ Let __Brutal__ craft for you in no time a (potentially huge) framework-less vanilla Ruby file describing the actual behavior of your code across as many context combinations as necessary.
21
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.
22
+ By delegating to __Brutal__ the repetitive (and redundant) task of writing tests, you will be able to focus on your core business: the code itself.
23
+
24
+ ![Brutal-Driven Development](https://github.com/fixrb/brutal/raw/main/img/brutal-driven-development.jpg)
23
25
 
24
26
  ## Warning
25
27
 
26
- __Brutal__ development process does not prevent from bugs.
28
+ The _Brutal-Driven Development_ process does not prevent bugs from appearing in the code.
29
+
30
+ A generated test suite acts as a _picture of the code's behavior_. Therefore, if the code is wrong, the picture of the code's behavior will also be wrong.
27
31
 
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.
32
+ The mere fact that all expectations are true does not mean that the code behaves as it should.
31
33
 
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_.
34
+ It is therefore the responsibility of the developer to analyze the generated behavioral pictures to ensure that the code reacts as it is supposed to according to the contexts in which it is evaluated.
35
35
 
36
36
  ## Installation
37
37
 
38
38
  Add this line to your application's Gemfile:
39
39
 
40
40
  ```ruby
41
- gem 'brutal'
41
+ gem "brutal"
42
42
  ```
43
43
 
44
44
  And then execute:
45
45
 
46
- $ bundle install
46
+ ```sh
47
+ bundle install
48
+ ```
47
49
 
48
50
  Or install it yourself as:
49
51
 
50
- $ gem install brutal
52
+ ```sh
53
+ gem install brutal
54
+ ```
51
55
 
52
56
  ## Quick Start
53
57
 
@@ -55,18 +59,22 @@ Just type `brutal` in a Ruby project's folder and watch the magic happen.
55
59
 
56
60
  ## Usage
57
61
 
58
- The `brutal.yml` file is a manifest you can use to define your __Brutal__ meta-spec.
59
- It has 4 top-level sections:
62
+ __Brutal__ needs a configuration file, it's a kind of manifest, or a meta-spec if you prefer.
63
+ This file is composed of 4 top-level sections:
60
64
 
61
65
  * `header` - Specifies the code to execute before generating the test suite.
62
66
  * `subject` - Specifies the template of the code to be declined across contexts.
63
67
  * `contexts` - Specifies a list of variables to populate the subject's template.
64
68
  * `actuals` - Specifies templates to challenge evaluated subjects & get results.
65
69
 
70
+ By default, this file is called `.brutal.yml`, but it would be possible to call it differently by passing it as an argument to the brutal command.
71
+
72
+ Currently, only the YAML format is supported.
73
+
66
74
  ### Getting started
67
75
 
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:
76
+ 1. Create a `.brutal.yml` file in your application's root directory.
77
+ The following example `.brutal.yml` defines the shape of a Hello test suite:
70
78
 
71
79
  ```yaml
72
80
  ---
@@ -111,7 +119,7 @@ raise if actual.length != 9
111
119
 
112
120
  ### More examples
113
121
 
114
- https://github.com/fixrb/brutal/raw/master/examples/
122
+ https://github.com/fixrb/brutal/raw/main/examples/
115
123
 
116
124
  ## Rake integration example
117
125
 
@@ -119,10 +127,14 @@ A generated `test.rb` file could be matched as follows:
119
127
 
120
128
  ```ruby
121
129
  Rake::TestTask.new do |t|
122
- t.pattern = 'test.rb'
130
+ t.pattern = "test.rb"
123
131
  end
124
132
  ```
125
133
 
134
+ ## Test suite
135
+
136
+ __Brutal__'s test set is brutally self-generated here: [./test.rb](https://github.com/fixrb/brutal/blob/main/test.rb)
137
+
126
138
  ## Contact
127
139
 
128
140
  * Source code: https://github.com/fixrb/brutal
@@ -133,19 +145,11 @@ __Brutal__ follows [Semantic Versioning 2.0](https://semver.org/).
133
145
 
134
146
  ## License
135
147
 
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).
148
+ The [gem](https://rubygems.org/gems/brutal) is available as open source under the terms of the [MIT License](https://github.com/fixrb/brutal/raw/main/LICENSE.md).
137
149
 
138
150
  ***
139
151
 
140
- <p>
141
- This project is sponsored by:<br />
142
- <a href="https://sashite.com/"><img
143
- src="https://github.com/fixrb/brutal/raw/master/img/sashite.png"
144
- alt="Sashite" /></a>
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
152
+ This project is sponsored by [Sashité](https://github.com/sashite/):
153
+
154
+ ![Sashité logo](https://github.com/fixrb/brutal/raw/main/img/sponsor/dark/en/sashite.png#gh-dark-mode-only "Sashité")
155
+ ![Sashité logo](https://github.com/fixrb/brutal/raw/main/img/sponsor/light/en/sashite.png#gh-light-mode-only "Sashité")
data/bin/brutal CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative File.join('..', 'lib', 'brutal')
4
+ require_relative File.join("..", "lib", "brutal")
5
5
 
6
- Brutal.generate!
6
+ Brutal.generate! ARGV.fetch(0, Brutal::File::DEFAULT_CONFIG_FILENAME)
@@ -5,20 +5,25 @@ module Brutal
5
5
  #
6
6
  # @since 1.0.0
7
7
  class Configuration
8
+ ACTUALS_KEY = "actuals"
9
+ CONTEXTS_KEY = "contexts"
10
+ HEADER_KEY = "header"
11
+ SUBJECT_KEY = "subject"
12
+
8
13
  DEFAULT_ACTUALS = [].freeze
9
14
  DEFAULT_CONTEXTS = {}.freeze
10
- DEFAULT_HEAD = '# Brutal test suite'
11
- DEFAULT_SUBJECT = ''
15
+ DEFAULT_HEADER = "# Brutal test suite"
16
+ DEFAULT_SUBJECT = ""
12
17
 
13
18
  # Load the configuration parameters.
14
19
  #
15
20
  # @param params [Hash] Receive the 4 top-level section parameters.
16
21
  def self.load(params)
17
22
  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)
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)
22
27
  )
23
28
  end
24
29
 
@@ -41,7 +46,7 @@ module Brutal
41
46
  raise ::TypeError, header.inspect unless header.is_a?(::String)
42
47
  raise ::TypeError, subject.inspect unless subject.is_a?(::String)
43
48
 
44
- @actuals = actuals
49
+ @actuals = actuals.sort
45
50
  @contexts = contexts
46
51
  @header = header
47
52
  @subject = subject
@@ -1,19 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Brutal
4
- # Brutal::File
5
- #
6
- # @since 1.1.0
7
4
  module File
8
5
  # Brutal::File::Read
9
6
  #
10
7
  # @since 1.1.0
11
8
  class Read
12
- NAME = '.brutal.yml'
13
-
14
9
  attr_reader :name
15
10
 
16
- def initialize(name = NAME)
11
+ def initialize(name)
17
12
  @name = name
18
13
  end
19
14
 
@@ -1,24 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Brutal
4
- # Brutal::File
5
- #
6
- # @since 1.1.0
7
4
  module File
8
5
  # Brutal::File::Write
9
6
  #
10
7
  # @since 1.1.0
11
8
  class Write
12
- NAME = 'test.rb'
13
-
14
9
  attr_reader :name
15
10
 
16
- def initialize(name = NAME)
11
+ def initialize(name)
17
12
  @name = name
18
13
  end
19
14
 
20
15
  def call(scaffold)
21
- file = ::File.open(path, 'w')
16
+ file = ::File.open(path, "w")
22
17
  file.write(scaffold)
23
18
 
24
19
  true
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ %w[
4
+ read
5
+ write
6
+ ].each { |filename| require_relative(File.join("file", filename)) }
7
+
8
+ module Brutal
9
+ # Brutal::File
10
+ module File
11
+ DEFAULT_CONFIG_FILENAME = ".brutal.yml"
12
+ DEFAULT_GENERATED_FILENAME = "test.rb"
13
+
14
+ def self.generated_filename(filename)
15
+ return DEFAULT_GENERATED_FILENAME if filename == DEFAULT_CONFIG_FILENAME
16
+
17
+ filename.gsub(/.[^.]+\z/, ".rb")
18
+ end
19
+ end
20
+ end
@@ -19,9 +19,9 @@ module Brutal
19
19
 
20
20
  # Initialize a new scaffold generator.
21
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?
22
+ warn("Empty subject!") if subject.empty?
23
+ warn("Empty actual values!") if actuals.empty?
24
+ warn("Empty contexts!") if contexts.empty?
25
25
 
26
26
  eval(header) # rubocop:disable Security/Eval
27
27
 
@@ -41,8 +41,6 @@ module Brutal
41
41
  # Return a string representation.
42
42
  #
43
43
  # @return [String]
44
- #
45
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
46
44
  def to_s
47
45
  "#{header.chomp}\n#{blank_line}" + combinations_values.map do |values|
48
46
  attributes = context_names.each_with_index.inject({}) do |h, (name, i)|
@@ -61,19 +59,18 @@ module Brutal
61
59
  actual = eval(actual_str) # rubocop:disable Security/Eval, Lint/UselessAssignment
62
60
 
63
61
  actuals.each do |actual_value|
64
- result_str = format(actual_value, subject: 'actual')
62
+ result_str = format(actual_value, subject: "actual")
65
63
  string += "raise if #{result_str} != #{eval(result_str).inspect}\n" # rubocop:disable Security/Eval
66
64
  end
67
65
 
68
66
  string
69
67
  end.join(blank_line)
70
68
  end
71
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
72
69
 
73
70
  def blank_line
74
- "\n" \
75
- "# #{('-' * 78)}\n" \
76
- "\n"
71
+ "\n" \
72
+ "# #{'-' * 78}\n" \
73
+ "\n"
77
74
  end
78
75
 
79
76
  def context_names
data/lib/brutal/yaml.rb CHANGED
@@ -1,14 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
3
+ require "yaml"
4
4
 
5
5
  module Brutal
6
6
  # Brutal::Yaml
7
7
  #
8
8
  # @since 1.1.0
9
9
  module Yaml
10
+ FILENAME_EXTENSIONS = %w[
11
+ yaml
12
+ yml
13
+ ].freeze
14
+
10
15
  def self.parse(yaml)
11
16
  ::YAML.safe_load(yaml, symbolize_names: false)
12
17
  end
18
+
19
+ def self.parse?(filename)
20
+ filename_extension = filename.split(".")[1..][-1]
21
+ FILENAME_EXTENSIONS.include?(filename_extension)
22
+ end
13
23
  end
14
24
  end
data/lib/brutal.rb CHANGED
@@ -2,23 +2,32 @@
2
2
 
3
3
  %w[
4
4
  configuration
5
- file/read
6
- file/write
5
+ file
7
6
  scaffold
8
7
  yaml
9
- ].each { |file_name| require_relative(File.join('brutal', file_name)) }
8
+ ].each { |filename| require_relative(File.join("brutal", filename)) }
10
9
 
11
10
  # The Brutal namespace.
12
11
  module Brutal
13
- def self.generate!
14
- yaml = File::Read.new.call
15
- hash = Yaml.parse(yaml)
12
+ def self.generate!(filename)
13
+ file = File::Read.new(filename).call
14
+
15
+ hash = if Yaml.parse?(filename)
16
+ Yaml.parse(file)
17
+ else
18
+ raise ::ArgumentError, "Unrecognized extension. " \
19
+ "Impossible to parse #{filename.inspect}."
20
+ end
21
+
16
22
  conf = Configuration.load(hash)
23
+
17
24
  ruby = Scaffold.new(conf.header,
18
25
  conf.subject,
19
26
  *conf.actuals,
20
27
  **conf.contexts)
21
28
 
22
- File::Write.new.call(ruby)
29
+ new_filename = File.generated_filename(filename)
30
+
31
+ File::Write.new(new_filename).call(ruby)
23
32
  end
24
33
  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.1.1
4
+ version: 1.3.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: 2020-09-08 00:00:00.000000000 Z
11
+ date: 2022-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-gitlab-security
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-md
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rubocop-performance
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,20 @@ dependencies:
52
80
  - - ">="
53
81
  - !ruby/object:Gem::Version
54
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rake
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'
55
97
  - !ruby/object:Gem::Dependency
56
98
  name: rubocop-thread_safety
57
99
  requirement: !ruby/object:Gem::Requirement
@@ -106,6 +148,7 @@ files:
106
148
  - bin/brutal
107
149
  - lib/brutal.rb
108
150
  - lib/brutal/configuration.rb
151
+ - lib/brutal/file.rb
109
152
  - lib/brutal/file/read.rb
110
153
  - lib/brutal/file/write.rb
111
154
  - lib/brutal/scaffold.rb
@@ -113,7 +156,8 @@ files:
113
156
  homepage: https://github.com/fixrb/brutal
114
157
  licenses:
115
158
  - MIT
116
- metadata: {}
159
+ metadata:
160
+ rubygems_mfa_required: 'true'
117
161
  post_install_message:
118
162
  rdoc_options: []
119
163
  require_paths:
@@ -129,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
173
  - !ruby/object:Gem::Version
130
174
  version: '0'
131
175
  requirements: []
132
- rubygems_version: 3.1.2
176
+ rubygems_version: 3.1.6
133
177
  signing_key:
134
178
  specification_version: 4
135
179
  summary: A code-first approach to automate the writing of unit tests.