mini_sanity 1.0.0 → 1.1.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
  SHA1:
3
- metadata.gz: c5da04d9d5a007087a446a04332d0ffc6384a5d8
4
- data.tar.gz: a26754f66a63338980c31d97461d8a443d868106
3
+ metadata.gz: ba5fd068770843f3044c6dade58282429e1330e5
4
+ data.tar.gz: 1aa0bfd6c7f88f9a0e1d992cd18289c5a9328ac1
5
5
  SHA512:
6
- metadata.gz: d595fc9b17a60fb29ece9f2d553c0549aaa341ce055d16589157e4be2be072b0c28d92c8ea3a35973d6bce0aaf30444b1644f6f3704033e39462eb3289c9d8e7
7
- data.tar.gz: '08db65b91fc28caa65d47a711afb0cb338ad0edfd1a601e78e642bb1846f4e150547612b42f996e77222c9ac27c8a35a86fa437da97a7c12fbc8c7af4cadb005'
6
+ metadata.gz: 1dfe7f149c334cd7ea7eb2330ddf834b72a17bb3009cdd45f42dd8e1347278084a65c835a1d7d438e881a64d42750ab8fda3eefd0fb498a919e76faa38a59bd3
7
+ data.tar.gz: ea9642cd25487cf2f54d990843f79ba98cece1b560811ea791644e2c010707d910fb5def8800a9518bec04ef274b9db7bf9884a1612549888ee6dfe5102f7260
@@ -0,0 +1,32 @@
1
+ ## 1.1.0
2
+
3
+ * Standardized exception error messages
4
+
5
+ * Added sanity check methods:
6
+ * Array#assert_length!
7
+ * Array#refute_length!
8
+ * Enumerable#assert_empty!
9
+ * Object#assert_equal!
10
+ * Object#assert_in!
11
+ * Object#assert_nil!
12
+ * Object#refute_equal!
13
+ * Object#refute_in!
14
+ * Pathname#assert_dir!
15
+ * Pathname#assert_file!
16
+ * Pathname#refute_dir!
17
+ * Pathname#refute_file!
18
+ * String#assert_empty!
19
+ * String#assert_length!
20
+ * String#refute_length!
21
+
22
+ * Added utility methods:
23
+ * Enumerable#first!
24
+ * Regexp#match!
25
+ * String#change
26
+ * String#change!
27
+ * String#match!
28
+
29
+
30
+ ## 1.0.0
31
+
32
+ * Initial release
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # mini_sanity
2
2
 
3
- In-line [sanity checks], written as extensions to core Ruby objects. See
4
- API listing below, or browse the [full documentation].
3
+ In-line [sanity checks], written as extensions to core Ruby objects.
4
+ See API listing below, or browse the [full documentation].
5
5
 
6
6
  [sanity checks]: https://en.wikipedia.org/wiki/Sanity_check
7
7
  [full documentation]: http://www.rubydoc.info/gems/mini_sanity/
8
8
 
9
9
 
10
- # Example
10
+ ## Example
11
11
 
12
12
  ```ruby
13
13
  require "json"
@@ -27,22 +27,55 @@ end.uniq
27
27
  ```
28
28
 
29
29
 
30
- # API
30
+ ## API
31
31
 
32
32
  - [Object](http://www.rubydoc.info/gems/mini_sanity/Object)
33
+ - [#assert_equal!](http://www.rubydoc.info/gems/mini_sanity/Object:assert_equal%21)
34
+ - [#assert_in!](http://www.rubydoc.info/gems/mini_sanity/Object:assert_in%21)
33
35
  - [#assert_instance_of!](http://www.rubydoc.info/gems/mini_sanity/Object:assert_instance_of%21)
34
36
  - [#assert_kind_of!](http://www.rubydoc.info/gems/mini_sanity/Object:assert_kind_of%21)
37
+ - [#assert_nil!](http://www.rubydoc.info/gems/mini_sanity/Object:assert_nil%21)
35
38
  - [#assert_respond_to!](http://www.rubydoc.info/gems/mini_sanity/Object:assert_respond_to%21)
39
+ - [#refute_equal!](http://www.rubydoc.info/gems/mini_sanity/Object:refute_equal%21)
40
+ - [#refute_in!](http://www.rubydoc.info/gems/mini_sanity/Object:refute_in%21)
36
41
  - [#refute_nil!](http://www.rubydoc.info/gems/mini_sanity/Object:refute_nil%21)
42
+ - [Array](http://www.rubydoc.info/gems/mini_sanity/Array)
43
+ - [#assert_length!](http://www.rubydoc.info/gems/mini_sanity/Array:assert_length%21)
44
+ - [#refute_length!](http://www.rubydoc.info/gems/mini_sanity/Array:refute_length%21)
37
45
  - [Enumerable](http://www.rubydoc.info/gems/mini_sanity/Enumerable)
46
+ - [#assert_empty!](http://www.rubydoc.info/gems/mini_sanity/Enumerable:assert_empty%21)
38
47
  - [#refute_empty!](http://www.rubydoc.info/gems/mini_sanity/Enumerable:refute_empty%21)
39
48
  - [String](http://www.rubydoc.info/gems/mini_sanity/String)
49
+ - [#assert_empty!](http://www.rubydoc.info/gems/mini_sanity/String:assert_empty%21)
50
+ - [#assert_length!](http://www.rubydoc.info/gems/mini_sanity/String:assert_length%21)
40
51
  - [#assert_match!](http://www.rubydoc.info/gems/mini_sanity/String:assert_match%21)
41
52
  - [#refute_empty!](http://www.rubydoc.info/gems/mini_sanity/String:refute_empty%21)
53
+ - [#refute_length!](http://www.rubydoc.info/gems/mini_sanity/String:refute_length%21)
42
54
  - [#refute_match!](http://www.rubydoc.info/gems/mini_sanity/String:refute_match%21)
43
55
  - [Pathname](http://www.rubydoc.info/gems/mini_sanity/Pathname)
56
+ - [#assert_dir!](http://www.rubydoc.info/gems/mini_sanity/Pathname:assert_dir%21)
44
57
  - [#assert_exist!](http://www.rubydoc.info/gems/mini_sanity/Pathname:assert_exist%21)
58
+ - [#assert_file!](http://www.rubydoc.info/gems/mini_sanity/Pathname:assert_file%21)
59
+ - [#refute_dir!](http://www.rubydoc.info/gems/mini_sanity/Pathname:refute_dir%21)
45
60
  - [#refute_exist!](http://www.rubydoc.info/gems/mini_sanity/Pathname:refute_exist%21)
61
+ - [#refute_file!](http://www.rubydoc.info/gems/mini_sanity/Pathname:refute_file%21)
62
+
63
+
64
+ ## Util API
65
+
66
+ *mini_sanity* also includes a few optional utility methods which perform
67
+ some function, check an assertion on the result, and raise an error with
68
+ a helpful message if the assertion fails. You must add
69
+ `require "mini_sanity/util"` to your script to access these methods.
70
+
71
+ - [Enumerable](http://www.rubydoc.info/gems/mini_sanity/Enumerable)
72
+ - [#first!](http://www.rubydoc.info/gems/mini_sanity/Enumerable:first%21)
73
+ - [Regexp](http://www.rubydoc.info/gems/mini_sanity/Regexp)
74
+ - [#match!](http://www.rubydoc.info/gems/mini_sanity/Regexp:match%21)
75
+ - [String](http://www.rubydoc.info/gems/mini_sanity/String)
76
+ - [#change](http://www.rubydoc.info/gems/mini_sanity/String:change)
77
+ - [#change!](http://www.rubydoc.info/gems/mini_sanity/String:change%21)
78
+ - [#match!](http://www.rubydoc.info/gems/mini_sanity/String:match%21)
46
79
 
47
80
 
48
81
  ## Installation
@@ -57,6 +90,7 @@ Then require in your Ruby script:
57
90
 
58
91
  ```ruby
59
92
  require "mini_sanity"
93
+ require "mini_sanity/util" # OPTIONAL
60
94
  ```
61
95
 
62
96
 
data/Rakefile CHANGED
@@ -9,6 +9,7 @@ end
9
9
  desc "Launch IRB with this gem pre-loaded"
10
10
  task :irb do
11
11
  require "mini_sanity"
12
+ require "mini_sanity/util"
12
13
  require "irb"
13
14
  ARGV.clear
14
15
  IRB.start
@@ -1,5 +1,6 @@
1
1
  require_relative "mini_sanity/version"
2
2
  require_relative "mini_sanity/error"
3
+ require_relative "mini_sanity/array"
3
4
  require_relative "mini_sanity/enumerable"
4
5
  require_relative "mini_sanity/object"
5
6
  require_relative "mini_sanity/pathname"
@@ -0,0 +1,63 @@
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,12 +1,37 @@
1
1
  module Enumerable
2
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
+
3
28
  # Checks that the Enumerable is not empty, and returns the Enumerable
4
29
  # unmodified. If the Enumerable fails this check, an exception is
5
30
  # raised.
6
31
  #
7
32
  # @example
8
- # [7, 8].refute_empty! # == [7, 8]
9
- # [].refute_empty! # raises exception
33
+ # ["result 1"].refute_empty! # == ["result 1"]
34
+ # [].refute_empty! # raises exception
10
35
  #
11
36
  # @param name [String, Symbol]
12
37
  # optional name to include in the error message
@@ -14,8 +39,12 @@ module Enumerable
14
39
  # @raise [MiniSanity::Error]
15
40
  # if the Enumerable is empty
16
41
  def refute_empty!(name = nil)
17
- if self.empty?
18
- raise MiniSanity::Error.new("#{name || self.class} is empty")
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)
19
48
  end
20
49
  self
21
50
  end
@@ -1,2 +1,11 @@
1
1
  class MiniSanity::Error < RuntimeError
2
+
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
10
+
2
11
  end
@@ -1,11 +1,35 @@
1
1
  class Object
2
2
 
3
+ # Checks that the Object is nil, and returns nil. If the Object fails
4
+ # this check, an exception is raised.
5
+ #
6
+ # @example
7
+ # result = {}
8
+ # result[:error].assert_nil! # == nil
9
+ #
10
+ # result = { error: "something went wrong" }
11
+ # result[:error].assert_nil! # == raises exception
12
+ #
13
+ # @param name [String, Symbol]
14
+ # optional name to include in the error message
15
+ # @return [self]
16
+ # @raise [MiniSanity::Error]
17
+ # if the Object is not nil
18
+ def assert_nil!(name = nil)
19
+ if !self.nil?
20
+ raise MiniSanity::Error.new(name,
21
+ "nil",
22
+ self.inspect)
23
+ end
24
+ self
25
+ end
26
+
3
27
  # Checks that the Object is not nil, and returns the Object
4
28
  # unmodified. If the Object fails this check, an exception is raised.
5
29
  #
6
30
  # @example
7
- # [7, 8].first.refute_nil! # == 7
8
- # [].first.refute_nil! # raises exception
31
+ # ["result 1"].first.refute_nil! # == "result 1"
32
+ # [].first.refute_nil! # raises exception
9
33
  #
10
34
  # @param name [String, Symbol]
11
35
  # optional name to include in the error message
@@ -14,8 +38,105 @@ class Object
14
38
  # if the Object is nil
15
39
  def refute_nil!(name = nil)
16
40
  if self.nil?
17
- message = name ? "#{name} is nil" : "unexpected nil"
18
- raise MiniSanity::Error.new(message)
41
+ raise MiniSanity::Error.new(name,
42
+ "non-nil value",
43
+ "nil")
44
+ end
45
+ self
46
+ end
47
+
48
+ # Checks that the Object equals a given expected value, and returns
49
+ # the Object unmodified. If the Object fails this check, an exception
50
+ # is raised.
51
+ #
52
+ # @example
53
+ # "good".assert_equal!("good") # == "good"
54
+ # "bad".assert_equal!("good") # raises exception
55
+ #
56
+ # @param expect [Object]
57
+ # value to expect
58
+ # @param name [String, Symbol]
59
+ # optional name to include in the error message
60
+ # @return [self]
61
+ # @raise [MiniSanity::Error]
62
+ # if the Object does not equal +expect+
63
+ def assert_equal!(expect, name = nil)
64
+ if self != expect
65
+ raise MiniSanity::Error.new(name,
66
+ expect.inspect,
67
+ self.inspect)
68
+ end
69
+ self
70
+ end
71
+
72
+ # Checks that the Object does not equal a given reject value, and
73
+ # returns the Object unmodified. If the Object fails this check, an
74
+ # exception is raised.
75
+ #
76
+ # @example
77
+ # "good".refute_equal!("bad") # == "good"
78
+ # "bad".refute_equal!("bad") # raises exception
79
+ #
80
+ # @param reject [Object]
81
+ # value to reject
82
+ # @param name [String, Symbol]
83
+ # optional name to include in the error message
84
+ # @return [self]
85
+ # @raise [MiniSanity::Error]
86
+ # if the Object equals +reject+
87
+ def refute_equal!(reject, name = nil)
88
+ if self == reject
89
+ raise MiniSanity::Error.new(name,
90
+ "not #{reject.inspect}",
91
+ self.inspect)
92
+ end
93
+ self
94
+ end
95
+
96
+ # Checks that the Object is included in a given collection, and
97
+ # returns the Object unmodified. If the Object fails this check, an
98
+ # exception is raised.
99
+ #
100
+ # @example
101
+ # "good".assert_in!(["ok", "good", "great"]) # == "good"
102
+ # "bad".assert_in!(["ok", "good", "great"]) # raises exception
103
+ #
104
+ # @param permitted [Enumerable, #include?]
105
+ # collection of permitted values
106
+ # @param name [String, Symbol]
107
+ # optional name to include in the error message
108
+ # @return [self]
109
+ # @raise [MiniSanity::Error]
110
+ # if the Object is not included in +permitted+
111
+ def assert_in!(permitted, name = nil)
112
+ if !permitted.include?(self)
113
+ raise MiniSanity::Error.new(name,
114
+ "value included in #{permitted.inspect}",
115
+ self.inspect)
116
+ end
117
+ self
118
+ end
119
+
120
+ # Checks that the Object is not included in a given collection, and
121
+ # returns the Object unmodified. If the Object fails this check, an
122
+ # exception is raised.
123
+ #
124
+ # @example
125
+ # "good".refute_in!(["bad", "poor", "fail"]) # == "good"
126
+ # "bad".refute_in!(["bad", "poor", "fail"]) # raises exception
127
+ #
128
+ # @param prohibited [Enumerable, #include?]
129
+ # collection of prohibited values
130
+ # @param name [String, Symbol]
131
+ # optional name to include in the error message
132
+ # @return [self]
133
+ # @raise [MiniSanity::Error]
134
+ # if the Object is included in +prohibited+
135
+ def refute_in!(prohibited, name = nil)
136
+ if prohibited.include?(self)
137
+ raise MiniSanity::Error.new(name,
138
+ "value not included in #{prohibited.inspect}",
139
+ self.inspect)
19
140
  end
20
141
  self
21
142
  end
@@ -25,8 +146,8 @@ class Object
25
146
  # is raised.
26
147
  #
27
148
  # @example
28
- # "abc".assert_instance_of!(String) # == "abc"
29
- # "abc".assert_instance_of!(Numeric) # raises exception
149
+ # 123.assert_instance_of!(Numeric) # == 123
150
+ # 123.assert_instance_of!(String) # raises exception
30
151
  #
31
152
  # @param klass [Class]
32
153
  # class to check
@@ -36,9 +157,10 @@ class Object
36
157
  # @raise [MiniSanity::Error]
37
158
  # if the Object is not an instance of +klass+
38
159
  def assert_instance_of!(klass, name = nil)
39
- unless self.instance_of?(klass)
40
- prelude = name ? "#{name} is instance of #{self.class}" : "unexpected #{self.class}"
41
- raise MiniSanity::Error.new("#{prelude}; expected #{klass}")
160
+ if !self.instance_of?(klass)
161
+ raise MiniSanity::Error.new(name,
162
+ "instance of #{klass}",
163
+ "instance of #{self.class}: #{self.inspect}")
42
164
  end
43
165
  self
44
166
  end
@@ -48,8 +170,8 @@ class Object
48
170
  # this check, an exception is raised.
49
171
  #
50
172
  # @example
51
- # 42.assert_kind_of!(Numeric) # == 42
52
- # 42.assert_kind_of!(Float) # raises exception
173
+ # 123.assert_kind_of!(Numeric) # == 123
174
+ # 123.assert_kind_of!(Float) # raises exception
53
175
  #
54
176
  # @param klass [Class]
55
177
  # class to check
@@ -59,9 +181,10 @@ class Object
59
181
  # @raise [MiniSanity::Error]
60
182
  # if the Object is not an instance of +klass+ or its subclasses
61
183
  def assert_kind_of!(klass, name = nil)
62
- unless self.kind_of?(klass)
63
- prelude = name ? "#{name} is instance of #{self.class}" : "unexpected #{self.class}"
64
- raise MiniSanity::Error.new("#{prelude}; expected #{klass} or one of its subclasses")
184
+ if !self.kind_of?(klass)
185
+ raise MiniSanity::Error.new(name,
186
+ "instance of #{klass} or one of its subclasses",
187
+ "instance of #{self.class}: #{self.inspect}")
65
188
  end
66
189
  self
67
190
  end
@@ -82,8 +205,10 @@ class Object
82
205
  # @raise [MiniSanity::Error]
83
206
  # if the Object does not respond to +method_name+
84
207
  def assert_respond_to!(method_name, name = nil)
85
- unless self.respond_to?(method_name)
86
- raise MiniSanity::Error.new("#{name || self.class} does not respond to #{method_name}")
208
+ if !self.respond_to?(method_name)
209
+ raise MiniSanity::Error.new(name,
210
+ "object responding to method #{method_name}",
211
+ "instance of #{self.class}: #{self.inspect}")
87
212
  end
88
213
  self
89
214
  end
@@ -1,6 +1,6 @@
1
1
  class Pathname
2
2
 
3
- # Checks that the file or directory indicated by the Pathname exists,
3
+ # Checks that the Pathname represents an existing file or directory,
4
4
  # and returns the Pathname unmodified. If the Pathname fails this
5
5
  # check, an exception is raised.
6
6
  #
@@ -12,18 +12,19 @@ class Pathname
12
12
  # optional name to include in the error message
13
13
  # @return [self]
14
14
  # @raise [MiniSanity::Error]
15
- # if the file or directory indicated by the Pathname does not exist
15
+ # if the Pathname does not represent an existing file or directory
16
16
  def assert_exist!(name = nil)
17
- unless self.exist?
18
- descriptor = name ? "#{name} (#{self})" : self.to_s
19
- raise MiniSanity::Error.new("#{descriptor} does not exist")
17
+ if !self.exist?
18
+ raise MiniSanity::Error.new(name,
19
+ "existent file or directory",
20
+ "#{self} does not exist")
20
21
  end
21
22
  self
22
23
  end
23
24
 
24
- # Checks that the file or directory indicated by the Pathname does
25
- # not already exist, and returns the Pathname unmodified. If the
26
- # Pathname fails this check, an exception is raised.
25
+ # Checks that the Pathname does not represent an existing file or
26
+ # directory, and returns the Pathname unmodified. If the Pathname
27
+ # fails this check, an exception is raised.
27
28
  #
28
29
  # @example
29
30
  # Pathname.new("/dev/null/nope").refute_exist! # == Pathname.new("/dev/null/nope")
@@ -33,11 +34,100 @@ class Pathname
33
34
  # optional name to include in the error message
34
35
  # @return [self]
35
36
  # @raise [MiniSanity::Error]
36
- # if the file or directory indicated by the Pathname already exists
37
+ # if the Pathname represents an existing file or directory
37
38
  def refute_exist!(name = nil)
38
39
  if self.exist?
39
- descriptor = name ? "#{name} (#{self})" : self.to_s
40
- raise MiniSanity::Error.new("#{descriptor} already exists")
40
+ raise MiniSanity::Error.new(name,
41
+ "non-existent file or directory",
42
+ "#{self} already exists")
43
+ end
44
+ self
45
+ end
46
+
47
+ # Checks that the Pathname represents an existing directory, and
48
+ # returns the Pathname unmodified. If the Pathname fails this check,
49
+ # an exception is raised.
50
+ #
51
+ # @example
52
+ # Pathname.new(__dir__).assert_dir! # == Pathname.new(__dir__)
53
+ # Pathname.new(__FILE__).assert_dir! # == raises exception
54
+ #
55
+ # @param name [String, Symbol]
56
+ # optional name to include in the error message
57
+ # @return [self]
58
+ # @raise [MiniSanity::Error]
59
+ # if the Pathname does not represent an existing directory
60
+ def assert_dir!(name = nil)
61
+ if !self.directory?
62
+ raise MiniSanity::Error.new(name,
63
+ "existent directory",
64
+ "#{self} is not a directory")
65
+ end
66
+ self
67
+ end
68
+
69
+ # Checks that the Pathname does not represent an existing directory,
70
+ # and returns the Pathname unmodified. If the Pathname fails this
71
+ # check, an exception is raised.
72
+ #
73
+ # @example
74
+ # Pathname.new(__FILE__).refute_dir! # == Pathname.new(__FILE__)
75
+ # Pathname.new(__dir__).refute_dir! # raises exception
76
+ #
77
+ # @param name [String, Symbol]
78
+ # optional name to include in the error message
79
+ # @return [self]
80
+ # @raise [MiniSanity::Error]
81
+ # if the Pathname represents an existing directory
82
+ def refute_dir!(name = nil)
83
+ if self.directory?
84
+ raise MiniSanity::Error.new(name,
85
+ "not an existent directory",
86
+ "#{self} is a directory")
87
+ end
88
+ self
89
+ end
90
+
91
+ # Checks that the Pathname represents an existing file, and returns
92
+ # the Pathname unmodified. If the Pathname fails this check, an
93
+ # exception is raised.
94
+ #
95
+ # @example
96
+ # Pathname.new(__FILE__).assert_file! # == Pathname.new(__FILE__)
97
+ # Pathname.new(__dir__).assert_file! # == raises exception
98
+ #
99
+ # @param name [String, Symbol]
100
+ # optional name to include in the error message
101
+ # @return [self]
102
+ # @raise [MiniSanity::Error]
103
+ # if the Pathname does not represent an existing file
104
+ def assert_file!(name = nil)
105
+ if !self.file?
106
+ raise MiniSanity::Error.new(name,
107
+ "existent file",
108
+ "#{self} is not a file")
109
+ end
110
+ self
111
+ end
112
+
113
+ # Checks that the Pathname does not represent an existing file, and
114
+ # returns the Pathname unmodified. If the Pathname fails this check,
115
+ # an exception is raised.
116
+ #
117
+ # @example
118
+ # Pathname.new(__dir__).refute_file! # == Pathname.new(__dir__)
119
+ # Pathname.new(__FILE__).refute_file! # raises exception
120
+ #
121
+ # @param name [String, Symbol]
122
+ # optional name to include in the error message
123
+ # @return [self]
124
+ # @raise [MiniSanity::Error]
125
+ # if the Pathname represents an existing file
126
+ def refute_file!(name = nil)
127
+ if self.file?
128
+ raise MiniSanity::Error.new(name,
129
+ "not an existent file",
130
+ "#{self} is a file")
41
131
  end
42
132
  self
43
133
  end
@@ -1,11 +1,32 @@
1
1
  class String
2
2
 
3
+ # Checks that the String is empty, and returns the String unmodified.
4
+ # If the String fails this check, an exception is raised.
5
+ #
6
+ # @example
7
+ # "".assert_empty! # == ""
8
+ # "bad".assert_empty! # raises exception
9
+ #
10
+ # @param name [String, Symbol]
11
+ # optional name to include in the error message
12
+ # @return [self]
13
+ # @raise [MiniSanity::Error]
14
+ # if the String is not empty
15
+ def assert_empty!(name = nil)
16
+ if !self.empty?
17
+ raise MiniSanity::Error.new(name,
18
+ "empty #{self.class}",
19
+ self.inspect)
20
+ end
21
+ self
22
+ end
23
+
3
24
  # Checks that the String is not empty, and returns the String
4
25
  # unmodified. If the String fails this check, an exception is raised.
5
26
  #
6
27
  # @example
7
- # "abc".refute_empty! # == "abc"
8
- # "".refute_empty! # raises exception
28
+ # "result".refute_empty! # == "result"
29
+ # "".refute_empty! # raises exception
9
30
  #
10
31
  # @param name [String, Symbol]
11
32
  # optional name to include in the error message
@@ -14,7 +35,59 @@ class String
14
35
  # if the String is empty
15
36
  def refute_empty!(name = nil)
16
37
  if self.empty?
17
- raise MiniSanity::Error.new("#{name || self.class} is empty")
38
+ raise MiniSanity::Error.new(name,
39
+ "non-empty #{self.class}",
40
+ self.inspect)
41
+ end
42
+ self
43
+ end
44
+
45
+ # Checks that the String matches a given length, and returns the
46
+ # String unmodified. If the String fails this check, an exception is
47
+ # raised.
48
+ #
49
+ # @example
50
+ # "password".assert_length!(8) # == "password"
51
+ # "long password".assert_length!(8..64) # == "long password"
52
+ # "pass".assert_length!(8..64) # == raises exception
53
+ #
54
+ # @param length [Integer, Range<Integer>]
55
+ # length to match
56
+ # @param name [String, Symbol]
57
+ # optional name to include in the error message
58
+ # @return [self]
59
+ # @raise [MiniSanity::Error]
60
+ # if the String length does not match +length+
61
+ def assert_length!(length, name = nil)
62
+ if !(length === self.length)
63
+ raise MiniSanity::Error.new(name,
64
+ "#{self.class} having #{length} characters",
65
+ self.inspect)
66
+ end
67
+ self
68
+ end
69
+
70
+ # Checks that the String does not match a given length, and returns
71
+ # the String unmodified. If the String fails this check, an exception
72
+ # is raised.
73
+ #
74
+ # @example
75
+ # "password".refute_length!(0) # == "password"
76
+ # "long password".refute_length!(0...8) # == "long password"
77
+ # "pass".refute_length!(0...8) # == raises exception
78
+ #
79
+ # @param length [Integer, Range<Integer>]
80
+ # length to not match
81
+ # @param name [String, Symbol]
82
+ # optional name to include in the error message
83
+ # @return [self]
84
+ # @raise [MiniSanity::Error]
85
+ # if the String length matches +length+
86
+ def refute_length!(length, name = nil)
87
+ if length === self.length
88
+ raise MiniSanity::Error.new(name,
89
+ "#{self.class} not having #{length} characters",
90
+ self.inspect)
18
91
  end
19
92
  self
20
93
  end
@@ -24,8 +97,8 @@ class String
24
97
  # exception is raised.
25
98
  #
26
99
  # @example
27
- # "abc".assert_match!(/b/) # == "abc"
28
- # "abc".assert_match!(/x/) # raises exception
100
+ # "good result".assert_match!(/^good/) # == "good result"
101
+ # "bad result".assert_match!(/^good/) # raises exception
29
102
  #
30
103
  # @param regexp [Regexp]
31
104
  # regular expression to check
@@ -35,9 +108,10 @@ class String
35
108
  # @raise [MiniSanity::Error]
36
109
  # if the String does not match +regexp+
37
110
  def assert_match!(regexp, name = nil)
38
- unless regexp =~ self
39
- descriptor = name ? "#{name} (#{self.inspect})" : self.inspect
40
- raise MiniSanity::Error.new("#{descriptor} does not match #{regexp.inspect}")
111
+ if regexp !~ self
112
+ raise MiniSanity::Error.new(name,
113
+ "#{self.class} matching #{regexp.inspect}",
114
+ self.inspect)
41
115
  end
42
116
  self
43
117
  end
@@ -47,8 +121,8 @@ class String
47
121
  # an exception is raised.
48
122
  #
49
123
  # @example
50
- # "abc".refute_match!(/x/) # == "abc"
51
- # "abc".refute_match!(/b/) # raises exception
124
+ # "good result".refute_match!(/^bad/) # == "good result"
125
+ # "bad result".refute_match!(/^bad/) # raises exception
52
126
  #
53
127
  # @param regexp [Regexp]
54
128
  # regular expression to check
@@ -59,8 +133,9 @@ class String
59
133
  # if the String matches +regexp+
60
134
  def refute_match!(regexp, name = nil)
61
135
  if regexp =~ self
62
- descriptor = name ? "#{name} (#{self.inspect})" : self.inspect
63
- raise MiniSanity::Error.new("#{descriptor} matches #{regexp.inspect}; expected no match")
136
+ raise MiniSanity::Error.new(name,
137
+ "#{self.class} not matching #{regexp.inspect}",
138
+ self.inspect)
64
139
  end
65
140
  self
66
141
  end
@@ -0,0 +1,3 @@
1
+ require_relative "util/enumerable"
2
+ require_relative "util/regexp"
3
+ require_relative "util/string"
@@ -0,0 +1,31 @@
1
+ module Enumerable
2
+
3
+ # Like {https://ruby-doc.org/core/Enumerable.html#method-i-first
4
+ # +Enumerable#first+}, but raises an exception if the Enumerable does
5
+ # not contain the requested number of elements.
6
+ #
7
+ # @example
8
+ # [7, 8, 9].first # == 7
9
+ # [7, 8, 9].first(1) # == [7]
10
+ # [7, 8, 9].first(2) # == [7, 8]
11
+ # [7, 8, 9].first(4) # raises exception
12
+ # [].first # raises exception
13
+ #
14
+ # @param n [Integer]
15
+ # requested number of elements
16
+ # @return [Object, Array]
17
+ # @raise [MiniSanity::Error]
18
+ # if the Enumerable does not contain the requested number of elements
19
+ def first!(n = nil)
20
+ result = n.nil? ? self.first : self.first(n)
21
+
22
+ if (result.nil? && !self.any?{ true }) || (!n.nil? && result.length < n)
23
+ raise MiniSanity::Error.new(nil,
24
+ "Enumerable having at least #{n || 1} elements",
25
+ self.inspect)
26
+ end
27
+
28
+ result
29
+ end
30
+
31
+ end
@@ -0,0 +1,27 @@
1
+ class Regexp
2
+
3
+ # Like {https://ruby-doc.org/core/Regexp.html#method-i-match
4
+ # +Regexp#match+}, but raises an exception if the match fails.
5
+ #
6
+ # @example
7
+ # /^([^@]+)@(.+)$/.match!("user@example.com") # === MatchData
8
+ # /^([^@]+)@(.+)$/.match!("@user") # raises exception
9
+ #
10
+ # @param str [String]
11
+ # string to search
12
+ # @param pos [Integer]
13
+ # position in +str+ to begin the search
14
+ # @return [MatchData]
15
+ # @raise [MiniSanity::Error]
16
+ # if the Regexp does not match +str+
17
+ def match!(str, pos = 0)
18
+ result = self.match(str, pos)
19
+ if result.nil?
20
+ raise MiniSanity::Error.new(nil,
21
+ "String matching #{self.inspect}#{" from position #{pos}" if pos != 0}",
22
+ str.inspect)
23
+ end
24
+ result
25
+ end
26
+
27
+ end
@@ -0,0 +1,77 @@
1
+ class String
2
+
3
+ # Like {https://ruby-doc.org/core/String.html#method-i-match
4
+ # +String#match+}, but raises an exception if the match fails.
5
+ #
6
+ # @example
7
+ # "user@example.com".match!(/^([^@]+)@(.+)$/) # === MatchData
8
+ # "@user".match!(/^([^@]+)@(.+)$/) # raises exception
9
+ #
10
+ # @param pattern [Regexp]
11
+ # pattern to search for
12
+ # @param pos [Integer]
13
+ # position in the String to begin the search
14
+ # @return [MatchData]
15
+ # @raise [MiniSanity::Error]
16
+ # if +pattern+ does not match the String
17
+ def match!(pattern, pos = 0)
18
+ result = self.match(pattern, pos)
19
+ if result.nil?
20
+ raise MiniSanity::Error.new(nil,
21
+ "String matching #{pattern.inspect}#{" from position #{pos}" if pos != 0}",
22
+ self.inspect)
23
+ end
24
+ result
25
+ end
26
+
27
+ # Like {https://ruby-doc.org/core/String.html#method-i-sub-21
28
+ # +String#sub!+}, but raises an exception if no substitution was
29
+ # performed.
30
+ #
31
+ # @example
32
+ # "author: YOUR_NAME".change!(/\bYOUR_NAME\b/, "Me") # == "author: Me"
33
+ # "author: TODO".change!(/\bYOUR_NAME\b/, "Me") # raises exception
34
+ #
35
+ # @param pattern [Regexp, String]
36
+ # pattern to search for
37
+ # @param replacement [String, Hash, &block]
38
+ # substitution value (see +String#sub!+ documentation for full details)
39
+ # @return [String]
40
+ # @raise [MiniSanity::Error]
41
+ # if no substitution was performed
42
+ def change!(pattern, replacement = nil, &replacement_block)
43
+ result = if replacement
44
+ self.sub!(pattern, replacement)
45
+ else
46
+ self.sub!(pattern, &replacement_block)
47
+ end
48
+
49
+ if !result
50
+ raise MiniSanity::Error.new(nil,
51
+ "String matching #{pattern.inspect}",
52
+ self.inspect)
53
+ end
54
+
55
+ result
56
+ end
57
+
58
+ # Like {https://ruby-doc.org/core/String.html#method-i-sub
59
+ # +String#sub+}, but raises an exception if no substitution was
60
+ # performed.
61
+ #
62
+ # @example
63
+ # "author: YOUR_NAME".change(/\bYOUR_NAME\b/, "Me") # == "author: Me"
64
+ # "author: TODO".change(/\bYOUR_NAME\b/, "Me") # raises exception
65
+ #
66
+ # @param pattern [Regexp, String]
67
+ # pattern to search for
68
+ # @param replacement [String, Hash, &block]
69
+ # substitution value (see +String#sub+ documentation for full details)
70
+ # @return [String]
71
+ # @raise [MiniSanity::Error]
72
+ # if no substitution was performed
73
+ def change(pattern, replacement = nil, &replacement_block)
74
+ self.dup.change!(pattern, replacement, &replacement_block)
75
+ end
76
+
77
+ end
@@ -1,3 +1,3 @@
1
1
  module MiniSanity
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_sanity
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.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: 2017-08-26 00:00:00.000000000 Z
11
+ date: 2018-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -75,16 +75,22 @@ extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
77
  - ".travis.yml"
78
+ - CHANGELOG.md
78
79
  - Gemfile
79
80
  - LICENSE.txt
80
81
  - README.md
81
82
  - Rakefile
82
83
  - lib/mini_sanity.rb
84
+ - lib/mini_sanity/array.rb
83
85
  - lib/mini_sanity/enumerable.rb
84
86
  - lib/mini_sanity/error.rb
85
87
  - lib/mini_sanity/object.rb
86
88
  - lib/mini_sanity/pathname.rb
87
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
88
94
  - lib/mini_sanity/version.rb
89
95
  - mini_sanity.gemspec
90
96
  homepage: https://github.com/jonathanhefner/mini_sanity
@@ -107,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
113
  version: '0'
108
114
  requirements: []
109
115
  rubyforge_project:
110
- rubygems_version: 2.4.8
116
+ rubygems_version: 2.6.13
111
117
  signing_key:
112
118
  specification_version: 4
113
119
  summary: In-line sanity checks