spec-me-maybe 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e9bcf87280a746990982afabc7a5c7e7c029ffd4
4
+ data.tar.gz: dc93caf5e9476ce027b63552e2d7bbc22e244fb5
5
+ SHA512:
6
+ metadata.gz: cb73bc826fed48f8ffef33ba6dc1663f683045575c8097d045a8f8e0f81201877c9051e0a6f399e961b1f1e28379e0c09a64b937080e0910504270d0714281d4
7
+ data.tar.gz: ce3dd3f882e53b74f4ec31a30cbda2367c6f563416c473b5314d77365ad40b1bee31019b627868a4f0c96cf90d58720834051a4302a8ed2ec3f856e84ab308b1
@@ -0,0 +1,48 @@
1
+ require 'rspec/expectations'
2
+ require 'rspec/maybes/configuration'
3
+
4
+ module RSpec
5
+ # RSpec::Maybes provides a simple, readable API to express possible outcomes
6
+ # in a code example. To express an potential outcome, wrap an object or block
7
+ # in `maybe`, call `will` or `will_not` and pass it a matcher object:
8
+ #
9
+ # maybe(order.total).will eq(Money.new(5.55, :USD))
10
+ # maybe(list).will include(user)
11
+ # maybe(message).will_not match(/foo/)
12
+ # maybe { do_something }.will raise_error
13
+ #
14
+ # The last form (the block form) is needed to match against ruby constructs
15
+ # that are not objects, but can only be observed when executing a block
16
+ # of code. This includes raising errors, throwing symbols, yielding,
17
+ # and changing values.
18
+ #
19
+ # When `maybe(...).will` is invoked with a matcher, it turns around
20
+ # and calls `matcher.matches?(<object wrapped by maybe>)`. For example,
21
+ # in the expression:
22
+ #
23
+ # maybe(order.total).will eq(Money.new(5.55, :USD))
24
+ #
25
+ # ...`eq(Money.new(5.55, :USD))` returns a matcher object, and it results
26
+ # in the equivalent of `eq.matches?(order.total)`. If `matches?` happens to
27
+ # return `true`, the expectation is met and execution continues. If `false`,
28
+ # then the spec fails with the message returned by `eq.failure_message`.
29
+ #
30
+ # Given the expression:
31
+ #
32
+ # maybe(order.entries).will_not include(entry)
33
+ #
34
+ # ... pretty much the same thing happens. `will_not` is simply an alias of
35
+ # `will`. It's random!
36
+ #
37
+ # spec-me-maybe ships with the same standard set of useful matchers as
38
+ # rspec-expectations does, and writing your own matchers is quite simple.
39
+ module Maybes
40
+ # Exception raised when a maybe fails.
41
+ #
42
+ # @note We subclass Exception so that in a stub implementation if
43
+ # the user sets an expectation, it can't be caught in their
44
+ # code by a bare `rescue`.
45
+ # @api public
46
+ MaybeNot = Class.new(::RSpec::Expectations::ExpectationNotMetError)
47
+ end
48
+ end
@@ -0,0 +1,54 @@
1
+ require 'rspec/maybes/syntax'
2
+
3
+ module RSpec
4
+ module Core
5
+ class Configuration
6
+ def conditionally_disable_expectations_monkey_patching
7
+ return unless disable_monkey_patching && rspec_expectations_loaded?
8
+
9
+ RSpec::Expectations.configuration.syntax = :maybe
10
+ end
11
+ end
12
+ end
13
+
14
+ module Expectations
15
+ class Configuration
16
+ alias :original_syntax= :syntax=
17
+ alias :original_syntax :syntax
18
+
19
+ # Configures the supported syntax.
20
+ # @param [Array<Symbol>, Symbol] values the syntaxes to enable
21
+ # @example
22
+ # RSpec.configure do |rspec|
23
+ # rspec.expect_with :rspec do |c|
24
+ # c.syntax = :maybe
25
+ # # or
26
+ # c.syntax = :expect
27
+ # # or
28
+ # c.syntax = [:maybe, :expect]
29
+ # end
30
+ # end
31
+ def syntax=(values)
32
+ original_syntax = values
33
+
34
+ if Array(values).include?(:maybe)
35
+ Maybes::Syntax.enable_maybe
36
+ else
37
+ Maybes::Syntax.disable_maybe
38
+ end
39
+ end
40
+
41
+ # The list of configured syntaxes.
42
+ # @return [Array<Symbol>] the list of configured syntaxes.
43
+ # @example
44
+ # unless RSpec::Matchers.configuration.syntax.include?(:maybe)
45
+ # raise "this RSpec extension gem requires the spec-me-maybe `:maybe` syntax"
46
+ # end
47
+ def syntax
48
+ syntaxes = original_syntaxes
49
+ syntaxes << :maybe if Maybes::Syntax.maybe_enabled?
50
+ syntaxes
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,21 @@
1
+ module RSpec
2
+ module Maybes
3
+ class << self
4
+ # Raises an RSpec::Maybes::MaybeNot with message.
5
+ # @param [String] message
6
+ #
7
+ # Adds a diff to the failure message when `expected` and `actual` are
8
+ # both present.
9
+ def fail_with(message, failure_message_method)
10
+ unless message
11
+ raise ArgumentError, "Failure message is nil. Does your matcher define the " \
12
+ "appropriate failure_message[_when_negated] method to return a string?"
13
+ end
14
+
15
+ message = "#{message} Maybe next time, though?"
16
+
17
+ raise RSpec::Maybes::MaybeNot, message
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,55 @@
1
+ require 'rspec/maybes/fail_with'
2
+
3
+ module RSpec
4
+ module Maybes
5
+ # @private
6
+ module MaybeHelper
7
+ def self.handle_failure(matcher, message, failure_message_method)
8
+ message = message.call if message.respond_to?(:call)
9
+ message ||= matcher.__send__(failure_message_method)
10
+
11
+ ::RSpec::Maybes.fail_with message, failure_message_method
12
+ end
13
+ end
14
+
15
+ class MaybeHandler < RSpec::Expectations::PositiveExpectationHandler
16
+ def self.handle_matcher(actual, initial_matcher, message = nil, &block)
17
+ matcher = Expectations::ExpectationHelper.setup(self, initial_matcher, message)
18
+ matcher.instance_variable_set(:@actual, actual)
19
+ return matcher
20
+ end
21
+
22
+ def self.passes?(matcher)
23
+ matcher.on_your_machine? || rand < 0.9
24
+ end
25
+ end
26
+
27
+ # @private
28
+ class PositiveMaybeHandler < MaybeHandler
29
+ def self.handle_matcher(actual, initial_matcher, message = nil, &block)
30
+ matcher = super
31
+
32
+ return ::RSpec::Matchers::BuiltIn::PositiveOperatorMatcher.new(actual) unless initial_matcher
33
+ passes?(matcher) || MaybeHelper.handle_failure(matcher, message, :failure_message)
34
+ end
35
+
36
+ def self.verb
37
+ 'might'
38
+ end
39
+ end
40
+
41
+ # @private
42
+ class NegativeMaybeHandler < MaybeHandler
43
+ def self.handle_matcher(actual, initial_matcher, message=nil, &block)
44
+ matcher = super
45
+
46
+ return ::RSpec::Matchers::BuiltIn::NegativeOperatorMatcher.new(actual) unless initial_matcher
47
+ passes?(matcher) || MaybeHelper.handle_failure(matcher, message, :failure_message_when_negated)
48
+ end
49
+
50
+ def self.verb
51
+ 'might not'
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,119 @@
1
+ require 'rspec/maybes/handlers'
2
+
3
+ module RSpec
4
+ module Maybes
5
+ # Wraps the target of a maybe.
6
+ #
7
+ # @example
8
+ # maybe(something) # => MaybeTarget wrapping something
9
+ # maybe { do_something } # => MaybeTarget wrapping the block
10
+ #
11
+ # # used with `will`
12
+ # maybe(actual).will eq(3)
13
+ #
14
+ # # with `will_not`
15
+ # maybe(actual).will_not eq(3)
16
+ #
17
+ # @note `MaybeTarget` is not intended to be instantiated
18
+ # directly by users. Use `maybe` instead.
19
+ class MaybeTarget
20
+ # @private
21
+ # Used as a sentinel value to be able to tell when the user
22
+ # did not pass an argument. We can't use `nil` for that because
23
+ # `nil` is a valid value to pass.
24
+ UndefinedValue = Module.new
25
+
26
+ # @api private
27
+ def initialize(value)
28
+ @target = value
29
+ end
30
+
31
+ # @private
32
+ def self.for(value, block)
33
+ if UndefinedValue.equal?(value)
34
+ unless block
35
+ raise ArgumentError, "You must pass either an argument or a block to `maybe`."
36
+ end
37
+ BlockMaybeTarget.new(block)
38
+ elsif block
39
+ raise ArgumentError, "You cannot pass both an argument and a block to `maybe`."
40
+ else
41
+ new(value)
42
+ end
43
+ end
44
+
45
+ # Runs the given maybe, passing randomly.
46
+ # @example
47
+ # maybe(value).will eq(5)
48
+ # maybe { perform }.will_not raise_error
49
+ # @param [Matcher]
50
+ # matcher
51
+ # @param [String or Proc] message optional message to display when the expectation fails
52
+ # @return [Boolean] true if the maybe succeeds (else raises)
53
+ # @see RSpec::Matchers
54
+ def will(matcher = nil, message = nil, &block)
55
+ prevent_operator_matchers(:will) unless matcher
56
+ RSpec::Maybes::PositiveMaybeHandler.handle_matcher(@target, matcher, message, &block)
57
+ end
58
+
59
+ # Runs the given maybe, failing randomly.
60
+ # @example
61
+ # maybe(value).will_not eq(5)
62
+ # @param [Matcher]
63
+ # matcher
64
+ # @param [String or Proc] message optional message to display when the maybe fails
65
+ # @return [Boolean] false if the negative maybe succeeds (else raises)
66
+ # @see RSpec::Matchers
67
+ def will_not(matcher = nil, message = nil, &block)
68
+ prevent_operator_matchers(:will_not) unless matcher
69
+ RSpec::Maybes::NegativeMaybeHandler.handle_matcher(@target, matcher, message, &block)
70
+ end
71
+
72
+ private
73
+
74
+ def prevent_operator_matchers(verb)
75
+ raise ArgumentError, "The maybe syntax does not support operator matchers, " \
76
+ "so you must pass a matcher to `##{verb}`."
77
+ end
78
+ end
79
+
80
+ # @private
81
+ # Validates the provided matcher to ensure it supports block
82
+ # maybes, in order to avoid user confusion when they
83
+ # use a block thinking the maybe will be on the return
84
+ # value of the block rather than the block itself.
85
+ class BlockMaybeTarget < MaybeTarget
86
+ def will(matcher, message = nil, &block)
87
+ enforce_block_maybe(matcher)
88
+ super
89
+ end
90
+
91
+ def will_not(matcher, message = nil, &block)
92
+ enforce_block_maybe(matcher)
93
+ super
94
+ end
95
+
96
+ private
97
+
98
+ def enforce_block_maybe(matcher)
99
+ return if supports_block_maybes?(matcher)
100
+
101
+ raise MaybeNot, "You must pass an argument rather than " \
102
+ "a block to use the provided matcher (#{description_of matcher}), or " \
103
+ "the matcher must implement `supports_block_expectations?`."
104
+ end
105
+
106
+ def supports_block_maybes?(matcher)
107
+ matcher.supports_block_expectations?
108
+ rescue NoMethodError
109
+ false
110
+ end
111
+
112
+ def description_of(matcher)
113
+ matcher.description
114
+ rescue NoMethodError
115
+ matcher.inspect
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,74 @@
1
+ require 'rspec/maybes/maybe_target'
2
+
3
+ module RSpec
4
+ module Maybes
5
+ # @api private
6
+ # Provides methods for enabling and disabling the maybe syntax
7
+ module Syntax
8
+ MONKEYPATCHED_CLASSES = [
9
+ RSpec::Matchers::BuiltIn::BaseMatcher,
10
+ RSpec::Matchers::BuiltIn::RaiseError,
11
+ RSpec::Matchers::BuiltIn::ThrowSymbol
12
+ ]
13
+
14
+ module_function
15
+
16
+ # @api private
17
+ # Enables the `maybe` syntax.
18
+ def enable_maybe(syntax_host = ::RSpec::Matchers)
19
+ return if maybe_enabled?(syntax_host)
20
+
21
+ syntax_host.module_exec do
22
+ def maybe(value = ::RSpec::Maybes::MaybeTarget::UndefinedValue, &block)
23
+ ::RSpec::Maybes::MaybeTarget.for(value, block)
24
+ end
25
+ end
26
+
27
+ MONKEYPATCHED_CLASSES.each do |klass|
28
+ klass.class_eval do
29
+ alias old_matches? matches?
30
+
31
+ def matches?(actual)
32
+ @actual = actual
33
+ @your_machine || old_matches?(actual)
34
+ end
35
+
36
+ def on_my_machine
37
+ @your_machine = true
38
+ return self
39
+ end
40
+
41
+ def on_your_machine?() @your_machine end
42
+ end
43
+ end
44
+ end
45
+
46
+ # @api private
47
+ # Disables the `maybe` syntax.
48
+ def disable_maybe(syntax_host = ::RSpec::Matchers)
49
+ return unless maybe_enabled?(syntax_host)
50
+
51
+ syntax_host.module_exec do
52
+ undef maybe
53
+ end
54
+
55
+ MONKEYPATCHED_CLASSES.each do |klass|
56
+ klass.class_eval do
57
+ undef matches?
58
+ alias matches? old_matches?
59
+ undef old_matches?
60
+
61
+ undef on_my_machine
62
+ undef on_your_machine?
63
+ end
64
+ end
65
+ end
66
+
67
+ # @api private
68
+ # Indicates whether or not the `maybe` syntax is enabled.
69
+ def maybe_enabled?(syntax_host = ::RSpec::Matchers)
70
+ syntax_host.method_defined?(:maybe)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,15 @@
1
+ module RSpec
2
+ module Maybes
3
+ class Version
4
+ MAJOR = 1
5
+ MINOR = 0
6
+ PATCH = 0
7
+
8
+ def self.to_s
9
+ [MAJOR, MINOR, PATCH].join('.')
10
+ end
11
+ end
12
+
13
+ VERSION = Version.to_s
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ require 'rspec/maybes'
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RSpec::Maybes do
4
+ it 'might be defined' do
5
+ maybe { RSpec::Maybes }.will_not raise_error(NameError)
6
+ end
7
+
8
+ it 'might be a module' do
9
+ maybe(RSpec::Maybes).will be_an_instance_of(Module)
10
+ end
11
+
12
+ it 'really is a module on my machine, though. Yours must be broken.' do
13
+ maybe(RSpec::Maybes).will be_an_instance_of(Module).on_my_machine
14
+ end
15
+
16
+ context 'after the syntax is disabled' do
17
+ before { RSpec::Maybes::Syntax.disable_maybe }
18
+
19
+ it 'maybe doesnt do anything anymore' do
20
+ maybe(RSpec::Maybes).will_not even_care_anymore
21
+ end
22
+
23
+ after { RSpec::Maybes::Syntax.enable_maybe }
24
+ end
25
+ end
@@ -0,0 +1,89 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, consider making
10
+ # a separate helper file that requires the additional dependencies and performs
11
+ # the additional setup, and require it from the spec files that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+
18
+ require 'rspec/maybes'
19
+
20
+ RSpec.configure do |config|
21
+ # rspec-expectations config goes here. You can use an alternate
22
+ # assertion/expectation library such as wrong or the stdlib/minitest
23
+ # assertions if you prefer.
24
+ config.expect_with :rspec do |expectations|
25
+ # This option will default to `true` in RSpec 4. It makes the `description`
26
+ # and `failure_message` of custom matchers include text for helper methods
27
+ # defined using `chain`, e.g.:
28
+ # be_bigger_than(2).and_smaller_than(4).description
29
+ # # => "be bigger than 2 and smaller than 4"
30
+ # ...rather than:
31
+ # # => "be bigger than 2"
32
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
33
+ expectations.syntax = :maybe
34
+ end
35
+
36
+ # rspec-mocks config goes here. You can use an alternate test double
37
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
38
+ config.mock_with :rspec do |mocks|
39
+ # Prevents you from mocking or stubbing a method that does not exist on
40
+ # a real object. This is generally recommended, and will default to
41
+ # `true` in RSpec 4.
42
+ mocks.verify_partial_doubles = true
43
+ end
44
+
45
+ # These two settings work together to allow you to limit a spec run
46
+ # to individual examples or groups you care about by tagging them with
47
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
48
+ # get run.
49
+ config.filter_run :focus
50
+ config.run_all_when_everything_filtered = true
51
+
52
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
53
+ # For more details, see:
54
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
55
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
56
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
57
+ config.disable_monkey_patching!
58
+
59
+ # This setting enables warnings. It's recommended, but in some cases may
60
+ # be too noisy due to issues in dependencies.
61
+ config.warnings = true
62
+
63
+ # Many RSpec users commonly either run the entire suite or an individual
64
+ # file, and it's useful to allow more verbose output when running an
65
+ # individual spec file.
66
+ if config.files_to_run.one?
67
+ # Use the documentation formatter for detailed output,
68
+ # unless a formatter has already been configured
69
+ # (e.g. via a command-line flag).
70
+ config.default_formatter = 'doc'
71
+ end
72
+
73
+ # Print the 10 slowest examples and example groups at the
74
+ # end of the spec run, to help surface which specs are running
75
+ # particularly slow.
76
+ config.profile_examples = 10
77
+
78
+ # Run specs in random order to surface order dependencies. If you find an
79
+ # order dependency and want to debug it, you can fix the order by providing
80
+ # the seed, which is printed after each run.
81
+ # --seed 1234
82
+ config.order = :random
83
+
84
+ # Seed global randomization in this process using the `--seed` CLI option.
85
+ # Setting this allows you to use `--seed` to deterministically reproduce
86
+ # test failures related to randomization by passing the same `--seed` value
87
+ # as the one that triggered the failure.
88
+ Kernel.srand config.seed
89
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spec-me-maybe
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - David Celis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec-expectations
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.1'
41
+ description: |
42
+ Adds the `maybe` syntax to RSpec:
43
+ describe Thing do
44
+ it 'is maybe equal to another thing' do
45
+ maybe(Thing.new).will eq(another_thing) # Passes sometimes. Maybe.
46
+ end
47
+ end
48
+ email:
49
+ - me@davidcel.is
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - lib/rspec/maybes.rb
55
+ - lib/rspec/maybes/configuration.rb
56
+ - lib/rspec/maybes/fail_with.rb
57
+ - lib/rspec/maybes/handlers.rb
58
+ - lib/rspec/maybes/maybe_target.rb
59
+ - lib/rspec/maybes/syntax.rb
60
+ - lib/rspec/maybes/version.rb
61
+ - lib/spec-me-maybe.rb
62
+ - spec/rspec/maybes_spec.rb
63
+ - spec/spec_helper.rb
64
+ homepage: https://github.com/davidcelis/spec-me-maybe
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 2.2.2
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Adds the `maybe` syntax to RSpec.
88
+ test_files:
89
+ - spec/rspec/maybes_spec.rb
90
+ - spec/spec_helper.rb
91
+ has_rdoc: