mini_sanity 1.1.0 → 2.0.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.
@@ -1,11 +1,21 @@
1
- class MiniSanity::Error < RuntimeError
1
+ module MiniSanity
2
+ class Error < RuntimeError
2
3
 
3
- def initialize(name, expected, actual)
4
- super(
5
- "\n#{name || "value"} violates expectations\n" \
6
- " expected: #{expected}\n" \
7
- " actual: #{actual}\n"
8
- )
9
- end
4
+ def initialize(message, details = {})
5
+ super([
6
+ message,
7
+ *details.compact.map{|name, value| "#{name}:\n #{value}" }
8
+ ].join("\n\n"))
9
+ end
10
+
11
+ # @!visibility private
12
+ def self.describe_block(&block)
13
+ if (symbol_name = block.to_s[/\(&:(.+)\)>$/, 1])
14
+ "&:#{symbol_name}"
15
+ elsif block&.source_location
16
+ "block@#{block.source_location.join(":")}"
17
+ end
18
+ end
10
19
 
20
+ end
11
21
  end
@@ -0,0 +1,57 @@
1
+ require_relative "error"
2
+
3
+
4
+ class String
5
+
6
+ # Like {https://docs.ruby-lang.org/en/master/String.html#method-i-match
7
+ # +String#match+}, but raises an exception if the match fails.
8
+ #
9
+ # @example
10
+ # "user@example.com".match!(/^([^@]+)@(.+)$/) # === MatchData
11
+ # "@user".match!(/^([^@]+)@(.+)$/) # raises exception
12
+ #
13
+ # @param pattern [Regexp]
14
+ # Pattern to search for
15
+ # @param pos [Integer]
16
+ # Position in the String to search from
17
+ # @return [MatchData]
18
+ # @raise [MiniSanity::Error]
19
+ # if +pattern+ does not match the String
20
+ def match!(pattern, pos = 0)
21
+ result = self.match(pattern, pos)
22
+
23
+ if result.nil?
24
+ raise MiniSanity::Error.new("String does not match pattern", {
25
+ "String" => self.inspect,
26
+ "Relevant portion (from position #{pos})" => (self[pos..].inspect if pos != 0),
27
+ "Pattern" => pattern.inspect,
28
+ })
29
+ end
30
+
31
+ result
32
+ end
33
+
34
+ end
35
+
36
+
37
+ class Regexp
38
+
39
+ # Like {https://docs.ruby-lang.org/en/master/Regexp.html#method-i-match
40
+ # +Regexp#match+}, but raises an exception if the match fails.
41
+ #
42
+ # @example
43
+ # /^([^@]+)@(.+)$/.match!("user@example.com") # === MatchData
44
+ # /^([^@]+)@(.+)$/.match!("@user") # raises exception
45
+ #
46
+ # @param str [String]
47
+ # String to search
48
+ # @param pos [Integer]
49
+ # Position in +str+ to search from
50
+ # @return [MatchData]
51
+ # @raise [MiniSanity::Error]
52
+ # if the Regexp does not match +str+
53
+ def match!(str, pos = 0)
54
+ str.match!(self, pos)
55
+ end
56
+
57
+ end
@@ -0,0 +1,70 @@
1
+ require_relative "error"
2
+
3
+
4
+ class Enumerator
5
+
6
+ # Iterates the Enumerator with a given +block+, and checks that the
7
+ # result is an Enumerable that has one or more elements. Raises an
8
+ # exception if this check fails. Otherwise, returns the Enumerable
9
+ # result.
10
+ #
11
+ # @example
12
+ # [1, 2, 3].select.results!(&:odd?) # == [1, 3]
13
+ # [2, 4, 6].select.results!(&:odd?) # raises exception
14
+ #
15
+ # @return [Enumerable]
16
+ # @raise [ArgumentError]
17
+ # if no +block+ is provided
18
+ # @raise [MiniSanity::Error]
19
+ # if iterating does not result in an Enumerable, or if the resulting
20
+ # Enumerable has no elements
21
+ def results!(&block)
22
+ raise ArgumentError, "Enumerator#results! requires a block" unless block
23
+
24
+ results = self.each(&block)
25
+
26
+ if !results.is_a?(Enumerable)
27
+ raise MiniSanity::Error.new("Result from Enumerator with block is not an Enumerable", {
28
+ "Enumerator" => self.inspect,
29
+ "Block" => MiniSanity::Error.describe_block(&block),
30
+ "Result" => results.inspect,
31
+ })
32
+ elsif !results.any?{ true }
33
+ raise MiniSanity::Error.new("No results from Enumerator with block", {
34
+ "Enumerator" => self.inspect,
35
+ "Block" => MiniSanity::Error.describe_block(&block),
36
+ })
37
+ end
38
+
39
+ results
40
+ end
41
+
42
+ # Iterates the Enumerator with a given +block+, and checks that the
43
+ # result is not nil. Raises an exception if the result is nil.
44
+ # Otherwise, returns the non-nil result.
45
+ #
46
+ # @example
47
+ # [1, 2, 3].find.result!(&:even?) # == 2
48
+ # [1, 3, 5].find.result!(&:even?) # raises exception
49
+ #
50
+ # @return [Object]
51
+ # @raise [ArgumentError]
52
+ # if no +block+ is provided
53
+ # @raise [MiniSanity::Error]
54
+ # if iterating results in a nil value
55
+ def result!(&block)
56
+ raise ArgumentError, "Enumerator#result! requires a block" unless block
57
+
58
+ result = self.each(&block)
59
+
60
+ if result.nil?
61
+ raise MiniSanity::Error.new("Nil result from Enumerator with block", {
62
+ "Enumerator" => self.inspect,
63
+ "Block" => MiniSanity::Error.describe_block(&block),
64
+ })
65
+ end
66
+
67
+ result
68
+ end
69
+
70
+ end
@@ -1,3 +1,3 @@
1
1
  module MiniSanity
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,27 +1,26 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "mini_sanity/version"
1
+ require_relative "lib/mini_sanity/version"
5
2
 
6
3
  Gem::Specification.new do |spec|
7
4
  spec.name = "mini_sanity"
8
5
  spec.version = MiniSanity::VERSION
9
6
  spec.authors = ["Jonathan Hefner"]
10
- spec.email = ["jonathan.hefner@gmail.com"]
7
+ spec.email = ["jonathan@hefner.pro"]
11
8
 
12
9
  spec.summary = %q{In-line sanity checks}
13
10
  spec.homepage = "https://github.com/jonathanhefner/mini_sanity"
14
11
  spec.license = "MIT"
12
+ spec.required_ruby_version = ">= 2.6"
15
13
 
16
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
- f.match(%r{^(test|spec|features)/})
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+ spec.metadata["source_code_uri"] = spec.homepage
16
+ spec.metadata["changelog_uri"] = spec.metadata["source_code_uri"] + "/blob/master/CHANGELOG.md"
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(__dir__) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
22
  end
19
23
  spec.bindir = "exe"
20
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
25
  spec.require_paths = ["lib"]
22
-
23
- spec.add_development_dependency "bundler", "~> 1.15"
24
- spec.add_development_dependency "rake", "~> 10.0"
25
- spec.add_development_dependency "minitest", "~> 5.0"
26
- spec.add_development_dependency "yard", "~> 0.9"
27
26
  end
metadata CHANGED
@@ -1,74 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_sanity
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Hefner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-11 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.15'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.15'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '5.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '5.0'
55
- - !ruby/object:Gem::Dependency
56
- name: yard
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '0.9'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '0.9'
11
+ date: 2020-02-02 00:00:00.000000000 Z
12
+ dependencies: []
69
13
  description:
70
14
  email:
71
- - jonathan.hefner@gmail.com
15
+ - jonathan@hefner.pro
72
16
  executables: []
73
17
  extensions: []
74
18
  extra_rdoc_files: []
@@ -81,22 +25,20 @@ files:
81
25
  - README.md
82
26
  - Rakefile
83
27
  - lib/mini_sanity.rb
84
- - lib/mini_sanity/array.rb
85
- - lib/mini_sanity/enumerable.rb
28
+ - lib/mini_sanity/assert.rb
29
+ - lib/mini_sanity/change.rb
86
30
  - lib/mini_sanity/error.rb
87
- - lib/mini_sanity/object.rb
88
- - lib/mini_sanity/pathname.rb
89
- - lib/mini_sanity/string.rb
90
- - lib/mini_sanity/util.rb
91
- - lib/mini_sanity/util/enumerable.rb
92
- - lib/mini_sanity/util/regexp.rb
93
- - lib/mini_sanity/util/string.rb
31
+ - lib/mini_sanity/match.rb
32
+ - lib/mini_sanity/results.rb
94
33
  - lib/mini_sanity/version.rb
95
34
  - mini_sanity.gemspec
96
35
  homepage: https://github.com/jonathanhefner/mini_sanity
97
36
  licenses:
98
37
  - MIT
99
- metadata: {}
38
+ metadata:
39
+ homepage_uri: https://github.com/jonathanhefner/mini_sanity
40
+ source_code_uri: https://github.com/jonathanhefner/mini_sanity
41
+ changelog_uri: https://github.com/jonathanhefner/mini_sanity/blob/master/CHANGELOG.md
100
42
  post_install_message:
101
43
  rdoc_options: []
102
44
  require_paths:
@@ -105,15 +47,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
47
  requirements:
106
48
  - - ">="
107
49
  - !ruby/object:Gem::Version
108
- version: '0'
50
+ version: '2.6'
109
51
  required_rubygems_version: !ruby/object:Gem::Requirement
110
52
  requirements:
111
53
  - - ">="
112
54
  - !ruby/object:Gem::Version
113
55
  version: '0'
114
56
  requirements: []
115
- rubyforge_project:
116
- rubygems_version: 2.6.13
57
+ rubygems_version: 3.1.2
117
58
  signing_key:
118
59
  specification_version: 4
119
60
  summary: In-line sanity checks
@@ -1,63 +0,0 @@
1
- class Array
2
-
3
- # Checks that the Array matches a given length, and returns the Array
4
- # unmodified. If the Array fails this check, an exception is
5
- # raised.
6
- #
7
- # @example
8
- # coord = [0, 0, 0]
9
- # coord.assert_length(3)! # == [0, 0, 0]
10
- #
11
- # coord = [0, 0]
12
- # coord.assert_length(3)! # raises exception
13
- #
14
- # coord = [0, 0]
15
- # coord.assert_length(2..3)! # == [0, 0]
16
- #
17
- # @param length [Integer, Range<Integer>]
18
- # length to match
19
- # @param name [String, Symbol]
20
- # optional name to include in the error message
21
- # @return [self]
22
- # @raise [MiniSanity::Error]
23
- # if the Array length does not match +length+
24
- def assert_length!(length, name = nil)
25
- if !(length === self.length)
26
- raise MiniSanity::Error.new(name,
27
- "#{self.class} having #{length} elements",
28
- self.inspect)
29
- end
30
- self
31
- end
32
-
33
- # Checks that the Array does not match a given length, and returns the
34
- # Array unmodified. If the Array fails this check, an exception is
35
- # raised.
36
- #
37
- # @example
38
- # some = ["one"]
39
- # some.refute_length!(0) # == ["one"]
40
- #
41
- # some = []
42
- # some.refute_length(0)! # raises exception
43
- #
44
- # many = ["one", "many"]
45
- # many.refute_length!(0..1) # == ["one", "many"]
46
- #
47
- # @param length [Integer, Range<Integer>]
48
- # length to not match
49
- # @param name [String, Symbol]
50
- # optional name to include in the error message
51
- # @return [self]
52
- # @raise [MiniSanity::Error]
53
- # if the Array length matches +length+
54
- def refute_length!(length, name = nil)
55
- if length === self.length
56
- raise MiniSanity::Error.new(name,
57
- "#{self.class} not having #{length} elements",
58
- self.inspect)
59
- end
60
- self
61
- end
62
-
63
- end
@@ -1,52 +0,0 @@
1
- module Enumerable
2
-
3
- # Checks that the Enumerable is empty, and returns the Enumerable
4
- # unmodified. If the Enumerable fails this check, an exception is
5
- # raised.
6
- #
7
- # @example
8
- # errors = []
9
- # errors.assert_empty! # == []
10
- #
11
- # errors = ["something went wrong"]
12
- # errors.assert_empty! # raises exception
13
- #
14
- # @param name [String, Symbol]
15
- # optional name to include in the error message
16
- # @return [self]
17
- # @raise [MiniSanity::Error]
18
- # if the Enumerable is not empty
19
- def assert_empty!(name = nil)
20
- if self.any?{ true }
21
- raise MiniSanity::Error.new(name,
22
- "empty #{self.class}",
23
- self.inspect)
24
- end
25
- self
26
- end
27
-
28
- # Checks that the Enumerable is not empty, and returns the Enumerable
29
- # unmodified. If the Enumerable fails this check, an exception is
30
- # raised.
31
- #
32
- # @example
33
- # ["result 1"].refute_empty! # == ["result 1"]
34
- # [].refute_empty! # raises exception
35
- #
36
- # @param name [String, Symbol]
37
- # optional name to include in the error message
38
- # @return [self]
39
- # @raise [MiniSanity::Error]
40
- # if the Enumerable is empty
41
- def refute_empty!(name = nil)
42
- # NOTE use #any? instead of #none? because Array#none? seems to be
43
- # significantly slower than Array#any? (and likewise for Hash)
44
- if !self.any?{ true }
45
- raise MiniSanity::Error.new(name,
46
- "non-empty #{self.class}",
47
- self.inspect)
48
- end
49
- self
50
- end
51
-
52
- end