fear 0.11.0 → 1.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.
- checksums.yaml +5 -5
- data/.gitignore +0 -1
- data/.rubocop.yml +18 -0
- data/.travis.yml +0 -3
- data/CHANGELOG.md +12 -1
- data/Gemfile +1 -0
- data/{gemfiles/dry_equalizer_0.2.1.gemfile.lock → Gemfile.lock} +21 -12
- data/README.md +594 -241
- data/Rakefile +166 -219
- data/benchmarks/README.md +1 -0
- data/benchmarks/dry_do_vs_fear_for.txt +11 -0
- data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
- data/benchmarks/factorial.txt +16 -0
- data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
- data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
- data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
- data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
- data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
- data/examples/pattern_extracting.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +96 -0
- data/examples/pattern_matching_number_in_words.rb +54 -0
- data/fear.gemspec +4 -2
- data/lib/fear.rb +21 -4
- data/lib/fear/either.rb +77 -59
- data/lib/fear/either_api.rb +21 -0
- data/lib/fear/empty_partial_function.rb +1 -1
- data/lib/fear/extractor.rb +108 -0
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +8 -0
- data/lib/fear/extractor/any_matcher.rb +15 -0
- data/lib/fear/extractor/array_head_matcher.rb +34 -0
- data/lib/fear/extractor/array_matcher.rb +38 -0
- data/lib/fear/extractor/array_splat_matcher.rb +14 -0
- data/lib/fear/extractor/empty_list_matcher.rb +18 -0
- data/lib/fear/extractor/extractor_matcher.rb +42 -0
- data/lib/fear/extractor/grammar.rb +201 -0
- data/lib/fear/extractor/grammar.treetop +129 -0
- data/lib/fear/extractor/identifier_matcher.rb +16 -0
- data/lib/fear/extractor/matcher.rb +54 -0
- data/lib/fear/extractor/matcher/and.rb +36 -0
- data/lib/fear/extractor/named_array_splat_matcher.rb +15 -0
- data/lib/fear/extractor/pattern.rb +55 -0
- data/lib/fear/extractor/typed_identifier_matcher.rb +24 -0
- data/lib/fear/extractor/value_matcher.rb +17 -0
- data/lib/fear/extractor_api.rb +33 -0
- data/lib/fear/failure.rb +32 -10
- data/lib/fear/for.rb +14 -69
- data/lib/fear/for_api.rb +66 -0
- data/lib/fear/future.rb +414 -0
- data/lib/fear/future_api.rb +19 -0
- data/lib/fear/left.rb +8 -0
- data/lib/fear/none.rb +17 -8
- data/lib/fear/option.rb +55 -49
- data/lib/fear/option_api.rb +38 -0
- data/lib/fear/partial_function.rb +9 -12
- data/lib/fear/partial_function/empty.rb +1 -1
- data/lib/fear/partial_function/guard.rb +8 -20
- data/lib/fear/partial_function/lifted.rb +1 -0
- data/lib/fear/partial_function_class.rb +10 -0
- data/lib/fear/pattern_match.rb +10 -0
- data/lib/fear/pattern_matching_api.rb +35 -11
- data/lib/fear/promise.rb +87 -0
- data/lib/fear/right.rb +8 -0
- data/lib/fear/some.rb +22 -3
- data/lib/fear/success.rb +22 -1
- data/lib/fear/try.rb +82 -67
- data/lib/fear/try_api.rb +31 -0
- data/lib/fear/unit.rb +28 -0
- data/lib/fear/version.rb +1 -1
- data/spec/fear/done_spec.rb +3 -3
- data/spec/fear/either/mixin_spec.rb +15 -0
- data/spec/fear/either_pattern_match_spec.rb +10 -12
- data/spec/fear/extractor/array_matcher_spec.rb +228 -0
- data/spec/fear/extractor/extractor_matcher_spec.rb +151 -0
- data/spec/fear/extractor/grammar_array_spec.rb +23 -0
- data/spec/fear/extractor/identified_matcher_spec.rb +47 -0
- data/spec/fear/extractor/identifier_matcher_spec.rb +66 -0
- data/spec/fear/extractor/pattern_spec.rb +32 -0
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +62 -0
- data/spec/fear/extractor/value_matcher_number_spec.rb +77 -0
- data/spec/fear/extractor/value_matcher_string_spec.rb +86 -0
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +69 -0
- data/spec/fear/extractor_api_spec.rb +113 -0
- data/spec/fear/extractor_spec.rb +59 -0
- data/spec/fear/failure_spec.rb +73 -13
- data/spec/fear/for_spec.rb +35 -35
- data/spec/fear/future_spec.rb +466 -0
- data/spec/fear/guard_spec.rb +4 -4
- data/spec/fear/left_spec.rb +40 -14
- data/spec/fear/none_spec.rb +28 -12
- data/spec/fear/option/mixin_spec.rb +37 -0
- data/spec/fear/option_pattern_match_spec.rb +7 -9
- data/spec/fear/partial_function_spec.rb +25 -3
- data/spec/fear/pattern_match_spec.rb +33 -1
- data/spec/fear/promise_spec.rb +94 -0
- data/spec/fear/right_spec.rb +37 -9
- data/spec/fear/some_spec.rb +32 -6
- data/spec/fear/success_spec.rb +32 -4
- data/spec/fear/try/mixin_spec.rb +17 -0
- data/spec/fear/try_pattern_match_spec.rb +8 -10
- data/spec/spec_helper.rb +1 -1
- metadata +115 -20
- data/Appraisals +0 -32
- data/gemfiles/dry_equalizer_0.1.0.gemfile +0 -8
- data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +0 -82
- data/gemfiles/dry_equalizer_0.2.1.gemfile +0 -8
- data/lib/fear/done.rb +0 -22
- data/spec/fear/option_spec.rb +0 -15
@@ -0,0 +1,129 @@
|
|
1
|
+
# PEG grammar for pattern matching and extracting
|
2
|
+
|
3
|
+
module Fear::Extractor
|
4
|
+
grammar Grammar
|
5
|
+
rule matcher
|
6
|
+
identified_matcher / anonymous_matcher
|
7
|
+
end
|
8
|
+
|
9
|
+
rule identified_matcher
|
10
|
+
identifier space '@' space anonymous_matcher <IdentifiedMatcher>
|
11
|
+
end
|
12
|
+
|
13
|
+
rule anonymous_matcher
|
14
|
+
array / literal / identifier / extractor / type
|
15
|
+
end
|
16
|
+
|
17
|
+
rule array
|
18
|
+
'[' (non_empty_array / array_splat / empty_array) ']' <ArrayLiteral>
|
19
|
+
end
|
20
|
+
|
21
|
+
rule empty_array
|
22
|
+
'' <EmptyArray>
|
23
|
+
end
|
24
|
+
|
25
|
+
rule non_empty_array
|
26
|
+
array_head (array_tail / empty_array) <NonEmptyArray>
|
27
|
+
end
|
28
|
+
|
29
|
+
rule array_tail
|
30
|
+
',' (non_empty_array / array_splat) <ArrayTail>
|
31
|
+
end
|
32
|
+
|
33
|
+
rule array_splat
|
34
|
+
space? (named_array_splat / anonymous_array_splat) space? <ArraySplat>
|
35
|
+
end
|
36
|
+
|
37
|
+
rule array_splat_identifier
|
38
|
+
space? anonymous_array_splat space? <ArraySplat>
|
39
|
+
end
|
40
|
+
|
41
|
+
rule anonymous_array_splat
|
42
|
+
'*' '_'? <AnonymousArraySplat>
|
43
|
+
end
|
44
|
+
|
45
|
+
rule named_array_splat
|
46
|
+
'*' [a-z] [a-z0-9_]* <NamedArraySplat>
|
47
|
+
end
|
48
|
+
|
49
|
+
rule array_head
|
50
|
+
space? anonymous_matcher space? <ArrayHead>
|
51
|
+
end
|
52
|
+
|
53
|
+
rule space
|
54
|
+
[\s]+
|
55
|
+
end
|
56
|
+
|
57
|
+
rule any
|
58
|
+
'_' <AnyIdentifier>
|
59
|
+
end
|
60
|
+
|
61
|
+
rule variable_identifier
|
62
|
+
[a-z_] [a-z0-9_]* <Identifier>
|
63
|
+
end
|
64
|
+
|
65
|
+
rule identifier
|
66
|
+
typed_identifier / any / variable_identifier
|
67
|
+
end
|
68
|
+
|
69
|
+
rule typed_identifier
|
70
|
+
(any / variable_identifier) ' : ' type <TypedIdentifier>
|
71
|
+
end
|
72
|
+
|
73
|
+
rule literal
|
74
|
+
nil / true / false / number / string / symbol
|
75
|
+
end
|
76
|
+
|
77
|
+
rule number
|
78
|
+
float / integer
|
79
|
+
end
|
80
|
+
|
81
|
+
rule integer
|
82
|
+
('+' / '-')? [0-9]+ <IntegerLiteral>
|
83
|
+
end
|
84
|
+
|
85
|
+
rule float
|
86
|
+
('+' / '-')? [0-9]+ '.' [0-9]+ <FloatLiteral>
|
87
|
+
end
|
88
|
+
|
89
|
+
rule symbol
|
90
|
+
':' (string / any / variable_identifier) <SymbolLiteral>
|
91
|
+
end
|
92
|
+
|
93
|
+
rule string
|
94
|
+
double_quoted_string / single_quoted_string
|
95
|
+
end
|
96
|
+
|
97
|
+
rule double_quoted_string
|
98
|
+
'"' ([^"\\] / '\\' . )* '"' <DoubleQuotedStringLiteral>
|
99
|
+
end
|
100
|
+
|
101
|
+
rule single_quoted_string
|
102
|
+
"'" ([^'\\] / '\\' . )* "'" <StringLiteral>
|
103
|
+
end
|
104
|
+
|
105
|
+
rule true
|
106
|
+
'true' <TrueLiteral>
|
107
|
+
end
|
108
|
+
|
109
|
+
rule false
|
110
|
+
'false' <FalseLiteral>
|
111
|
+
end
|
112
|
+
|
113
|
+
rule nil
|
114
|
+
'nil' <NilLiteral>
|
115
|
+
end
|
116
|
+
|
117
|
+
rule extractor
|
118
|
+
type '(' non_empty_array? ')' <ExtractorLiteral>
|
119
|
+
end
|
120
|
+
|
121
|
+
rule type
|
122
|
+
constant ('::' constant)* <TypeLiteral>
|
123
|
+
end
|
124
|
+
|
125
|
+
rule constant
|
126
|
+
[A-Z] [a-zA-Z0-9_]*
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module Extractor
|
5
|
+
# @abstract abstract matcher to inherit from.
|
6
|
+
class Matcher < OpenStruct
|
7
|
+
autoload :And, 'fear/extractor/matcher/and'
|
8
|
+
|
9
|
+
EMPTY_HASH = {}.freeze
|
10
|
+
EMPTY_ARRAY = [].freeze
|
11
|
+
|
12
|
+
# @param node [Fear::Extractor::Grammar::Node]
|
13
|
+
def initialize(node:, **attributes)
|
14
|
+
@input = node.input
|
15
|
+
@input_position = node.interval.first
|
16
|
+
super(attributes)
|
17
|
+
end
|
18
|
+
attr_reader :input_position, :input
|
19
|
+
private :input
|
20
|
+
private :input_position
|
21
|
+
|
22
|
+
def call(arg)
|
23
|
+
call_or_else(arg, &PartialFunction::EMPTY)
|
24
|
+
end
|
25
|
+
|
26
|
+
def and(other)
|
27
|
+
And.new(self, other)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param arg [any]
|
31
|
+
# @yield [arg] if function not defined
|
32
|
+
def call_or_else(arg)
|
33
|
+
if defined_at?(arg)
|
34
|
+
bindings(arg)
|
35
|
+
else
|
36
|
+
yield arg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Shows why matcher has failed. Use it for debugging.
|
41
|
+
# @example
|
42
|
+
# Fear['[1, 2, _]'].failure_reason([1, 3, 4])
|
43
|
+
# # it will show that the second element hasn't match
|
44
|
+
#
|
45
|
+
def failure_reason(other)
|
46
|
+
if defined_at?(other)
|
47
|
+
Fear.none
|
48
|
+
else
|
49
|
+
Fear.some("Expected `#{other.inspect}` to match:\n#{input}\n#{'~' * input_position}^")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module Extractor
|
5
|
+
class Matcher < OpenStruct
|
6
|
+
# Combine two matchers, so both should pass
|
7
|
+
class And < Matcher
|
8
|
+
def initialize(matcher1, matcher2)
|
9
|
+
@matcher1 = matcher1
|
10
|
+
@matcher2 = matcher2
|
11
|
+
end
|
12
|
+
attr_reader :matcher1, :matcher2
|
13
|
+
|
14
|
+
def defined_at?(arg)
|
15
|
+
matcher1.defined_at?(arg) && matcher2.defined_at?(arg)
|
16
|
+
end
|
17
|
+
|
18
|
+
def bindings(arg)
|
19
|
+
matcher1.bindings(arg).merge(matcher2.bindings(arg))
|
20
|
+
end
|
21
|
+
|
22
|
+
def failure_reason(arg)
|
23
|
+
if matcher1.defined_at?(arg)
|
24
|
+
if matcher2.defined_at?(arg)
|
25
|
+
Fear.none
|
26
|
+
else
|
27
|
+
matcher2.failure_reason(arg)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
matcher1.failure_reason(arg)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Fear
|
2
|
+
module Extractor
|
3
|
+
# Match against array splat, and capture rest of an array
|
4
|
+
# E.g. +[1, 2, *tail]+
|
5
|
+
#
|
6
|
+
class NamedArraySplatMatcher < ArraySplatMatcher
|
7
|
+
# @!attribute name
|
8
|
+
# @return [Types::Strict::Symbol]
|
9
|
+
|
10
|
+
def bindings(other)
|
11
|
+
{ name => other }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'lru_redux'
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
module Extractor
|
5
|
+
# Parse pattern. Used within +Fear[]+
|
6
|
+
class Pattern
|
7
|
+
DEFAULT_PATTERN_CACHE_SIZE = 10_000
|
8
|
+
@pattern_cache = LruRedux::Cache.new(ENV.fetch('FEAR_PATTERNS_CACHE_SIZE', DEFAULT_PATTERN_CACHE_SIZE))
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_reader :pattern_cache
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(pattern)
|
15
|
+
@matcher = compile_pattern(pattern)
|
16
|
+
end
|
17
|
+
attr_reader :matcher
|
18
|
+
private :matcher
|
19
|
+
|
20
|
+
private def compile_pattern(pattern)
|
21
|
+
self.class.pattern_cache.getset(pattern) do
|
22
|
+
compile_pattern_without_cache(pattern)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private def compile_pattern_without_cache(pattern)
|
27
|
+
parser = Extractor::GrammarParser.new
|
28
|
+
if (result = parser.parse(pattern))
|
29
|
+
result.to_matcher
|
30
|
+
else
|
31
|
+
raise PatternSyntaxError, syntax_error_message(parser, pattern)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def ===(other)
|
36
|
+
matcher.defined_at?(other)
|
37
|
+
end
|
38
|
+
|
39
|
+
def and_then(other)
|
40
|
+
Fear::PartialFunction::Combined.new(matcher, other)
|
41
|
+
end
|
42
|
+
|
43
|
+
def failure_reason(other)
|
44
|
+
matcher.failure_reason(other).get_or_else { 'It matches' }
|
45
|
+
end
|
46
|
+
|
47
|
+
private def syntax_error_message(parser, pattern)
|
48
|
+
parser.failure_reason =~ /^(Expected .+) after/m
|
49
|
+
"#{Regexp.last_match(1).gsub("\n", '$NEWLINE')}:\n" +
|
50
|
+
pattern.split("\n")[parser.failure_line - 1] + "\n" \
|
51
|
+
"#{'~' * (parser.failure_column - 1)}^\n"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Fear
|
2
|
+
module Extractor
|
3
|
+
# Match and capture identifier with specific type. E.g. +foo : Integer+
|
4
|
+
#
|
5
|
+
class TypedIdentifierMatcher < Matcher
|
6
|
+
# @!attribute identifier
|
7
|
+
# @return [IdentifierMatcher]
|
8
|
+
# @!attribute type
|
9
|
+
# @return [ValueMatcher]
|
10
|
+
|
11
|
+
def defined_at?(other)
|
12
|
+
type.defined_at?(other)
|
13
|
+
end
|
14
|
+
|
15
|
+
def bindings(other)
|
16
|
+
{ identifier.name => other }
|
17
|
+
end
|
18
|
+
|
19
|
+
def failure_reason(other)
|
20
|
+
type.failure_reason(other)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Fear
|
2
|
+
module Extractor
|
3
|
+
# Match against values -- true, false, 1, "foo" etc.
|
4
|
+
class ValueMatcher < Matcher
|
5
|
+
# @!attribute value
|
6
|
+
# @return [Any]
|
7
|
+
|
8
|
+
def defined_at?(arg)
|
9
|
+
value === arg
|
10
|
+
end
|
11
|
+
|
12
|
+
def bindings(_)
|
13
|
+
EMPTY_HASH
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Fear
|
2
|
+
module ExtractorApi
|
3
|
+
# Allows to pattern match and extract matcher variables
|
4
|
+
#
|
5
|
+
# @param pattern [String]
|
6
|
+
# @return [Extractor::Pattern]
|
7
|
+
# @note it is not intended to be used by itself, rather then with partial functions
|
8
|
+
def [](pattern)
|
9
|
+
Extractor::Pattern.new(pattern)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Register extractor for given class
|
13
|
+
# @!method register_extractor(*names, extractor)
|
14
|
+
# @param names [<Class, String>, Class, String] name of a class. You can also pass alias for the name
|
15
|
+
# @param extractor [Proc<any => Fear::Option>] proc taking any argument and returned Option
|
16
|
+
# of extracted value('s)
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# register_extractor(Fear::Some, Fear.case(Fear::Some) { |some| some.get }.lift)
|
20
|
+
#
|
21
|
+
# register_extractor(User, Fear.case(User) { |user|} [user.id, user.email] , )
|
22
|
+
#
|
23
|
+
# @example registering an alias. Alias should be CamelCased string
|
24
|
+
# register_extractor(Fear::Some, 'Some', Fear.case(Fear::Some) { |some| some.get }.lift)
|
25
|
+
#
|
26
|
+
# # no you can extract Fear::Some's using Some alias
|
27
|
+
# m.case(Fear['Some(value : Integer)']) { |value:| value * 2 }
|
28
|
+
#
|
29
|
+
def register_extractor(*args)
|
30
|
+
Extractor.register_extractor(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/fear/failure.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
module Fear
|
2
2
|
class Failure
|
3
3
|
include Try
|
4
|
-
include Dry::Equalizer(:exception)
|
5
4
|
include RightBiased::Left
|
6
5
|
include FailurePatternMatch.mixin
|
6
|
+
EXTRACTOR = proc do |try|
|
7
|
+
if Fear::Failure === try
|
8
|
+
Fear.some([try.exception])
|
9
|
+
else
|
10
|
+
Fear.none
|
11
|
+
end
|
12
|
+
end
|
7
13
|
|
8
14
|
# @param [StandardError]
|
9
15
|
def initialize(exception)
|
@@ -44,22 +50,24 @@ module Fear
|
|
44
50
|
self
|
45
51
|
end
|
46
52
|
|
47
|
-
# @yieldparam [
|
48
|
-
# @yieldreturn [Try]
|
49
|
-
# @return [Try]
|
53
|
+
# @yieldparam [Fear::PatternMatch]
|
54
|
+
# @yieldreturn [Fear::Try]
|
55
|
+
# @return [Fear::Try]
|
50
56
|
def recover_with
|
51
|
-
|
52
|
-
Utils.assert_type!(result, Success, Failure)
|
53
|
-
|
57
|
+
Fear.matcher { |m| yield(m) }
|
58
|
+
.and_then { |result| result.tap { Utils.assert_type!(result, Success, Failure) } }
|
59
|
+
.call_or_else(exception) { self }
|
54
60
|
rescue StandardError => error
|
55
61
|
Failure.new(error)
|
56
62
|
end
|
57
63
|
|
58
|
-
# @yieldparam [
|
64
|
+
# @yieldparam [Fear::PatternMatch]
|
59
65
|
# @yieldreturn [any]
|
60
|
-
# @return [Try]
|
66
|
+
# @return [Fear::Try]
|
61
67
|
def recover
|
62
|
-
|
68
|
+
Fear.matcher { |m| yield(m) }
|
69
|
+
.and_then { |v| Success.new(v) }
|
70
|
+
.call_or_else(exception) { self }
|
63
71
|
rescue StandardError => error
|
64
72
|
Failure.new(error)
|
65
73
|
end
|
@@ -69,6 +77,12 @@ module Fear
|
|
69
77
|
Left.new(exception)
|
70
78
|
end
|
71
79
|
|
80
|
+
# @param other [Any]
|
81
|
+
# @return [Boolean]
|
82
|
+
def ==(other)
|
83
|
+
other.is_a?(Failure) && exception == other.exception
|
84
|
+
end
|
85
|
+
|
72
86
|
# Used in case statement
|
73
87
|
# @param other [any]
|
74
88
|
# @return [Boolean]
|
@@ -79,5 +93,13 @@ module Fear
|
|
79
93
|
super
|
80
94
|
end
|
81
95
|
end
|
96
|
+
|
97
|
+
# @return [String]
|
98
|
+
def inspect
|
99
|
+
"#<Fear::Failure exception=#{exception.inspect}>"
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [String]
|
103
|
+
alias to_s inspect
|
82
104
|
end
|
83
105
|
end
|