motion-spec 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +8 -8
  2. data/.hound.yml +2 -0
  3. data/.rubocop.yml +3 -0
  4. data/Gemfile.lock +1 -1
  5. data/lib/motion-spec/context.rb +4 -0
  6. data/lib/motion-spec/context_helper/expectation.rb +10 -0
  7. data/lib/motion-spec/context_helper/matchers.rb +95 -0
  8. data/lib/motion-spec/context_helper/should.rb +12 -0
  9. data/lib/motion-spec/error.rb +4 -0
  10. data/lib/motion-spec/expectation.rb +32 -0
  11. data/lib/motion-spec/fail_message_renderer.rb +101 -0
  12. data/lib/motion-spec/matcher/be.rb +16 -0
  13. data/lib/motion-spec/matcher/be_false.rb +15 -0
  14. data/lib/motion-spec/matcher/be_generic.rb +10 -0
  15. data/lib/motion-spec/matcher/be_nil.rb +16 -0
  16. data/lib/motion-spec/matcher/be_true.rb +16 -0
  17. data/lib/motion-spec/matcher/be_within.rb +30 -0
  18. data/lib/motion-spec/matcher/change.rb +35 -0
  19. data/lib/motion-spec/matcher/end_with.rb +22 -0
  20. data/lib/motion-spec/matcher/eq.rb +14 -0
  21. data/lib/motion-spec/matcher/eql.rb +10 -0
  22. data/lib/motion-spec/matcher/have_generic.rb +23 -0
  23. data/lib/motion-spec/matcher/have_items.rb +29 -0
  24. data/lib/motion-spec/matcher/include.rb +20 -0
  25. data/lib/motion-spec/matcher/match.rb +14 -0
  26. data/lib/motion-spec/matcher/match_array.rb +28 -0
  27. data/lib/motion-spec/matcher/raise_error.rb +47 -0
  28. data/lib/motion-spec/matcher/respond_to.rb +40 -0
  29. data/lib/motion-spec/matcher/satisfy.rb +20 -0
  30. data/lib/motion-spec/matcher/single_method.rb +25 -0
  31. data/lib/motion-spec/matcher/start_with.rb +22 -0
  32. data/lib/motion-spec/version.rb +1 -1
  33. data/lib/motion-spec.rb +20 -10
  34. metadata +28 -2
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ODlmZDBkZDQ2ODE2ODhiMzBmZGZiNzM5NmNmMTZlM2NmYmFhYTJiMA==
4
+ MDBmZjcyMjlmMTg2NDcyMWVjN2Q5NDJmZGE3MGZlYzAzMGY1MDhhMA==
5
5
  data.tar.gz: !binary |-
6
- ODIyMWE2MTExNjU3ZGQ4N2FhZjVlZDE5ZjI2ODdkOTBlMDcxNTFkOA==
6
+ M2ExODNlMzdhZWE2YmYwODY5OTBiY2ZhODVjNjg3ZGI1MDdmY2JjNg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- Y2Y5NmUzYzE5NDgzZGE5MDljMDE1MGE0Zjg0OTEyMDQ0NTZlNTk5YTFhYjIy
10
- NTNhNjdmNTA1YjQxZTkzNWNkMDdkZTAzOTkxMjRhM2ZmZTQ1Y2Y2ZTNiOWVj
11
- ODRhNjNmNTc5MDg5OGEyY2M0YTE2YjQ2ZjM0NjUyMWIzMjE1M2U=
9
+ YWVjYjI1YTNhMDQxZmMwMDY3OGIzYTkyNjYzZjIzYWY5Nzk4ZjlhZDI2MjQ5
10
+ ZDhhOTZhNzkwMDMwNGQ0YjlkZTI2NWQ0YmI4NzI3ZjhjY2RmNWYzMjM1MGNk
11
+ MzU0OTA3YmNhOTM3MmE0OTI4MjJjNmVmNmQ5ZDQzODM4NmQzMWI=
12
12
  data.tar.gz: !binary |-
13
- NTY2NTUzNmNlM2M3MDIyMjRlYTU5YjUwMTgyNGZhYzcwMDgxOTNjNmQ2Njky
14
- OTUyZjg5MGE2YWQxMWE5MTk4OWNjY2Q4OWUxYzllZjlhY2JhYTYzZmUyOTZm
15
- NzA1NTgyYjg1YjkzNWFmMzIzYjEwZjQ4ZDAxMjAxN2Q5ZDhiMGI=
13
+ MTg0YzkzNGYwZDZlYWYwNTlmMGNlYmQyODYwNTI5ZmVmYmM2YmQ5NWVlZWI1
14
+ MGExNWNlNmQyNmM4ZGQ5MDgwMTNlMzNjYzZlOTViZGU1ZTQ5ZmExNWZjZGFk
15
+ M2ZjZmMxY2U3ZjY5OTJkN2ZhMWZiN2NjNjJmMDk0MWQ5OWEwNzI=
data/.hound.yml ADDED
@@ -0,0 +1,2 @@
1
+ ruby:
2
+ config_file: .rubocop.yml
data/.rubocop.yml CHANGED
@@ -27,6 +27,9 @@ Metrics/ClassLength:
27
27
  Enabled: true
28
28
  Max: 100
29
29
 
30
+ Metrics/LineLength:
31
+ Max: 120
32
+
30
33
  Metrics/ModuleLength:
31
34
  Description: 'Avoid modules longer than 100 lines of code.'
32
35
  Enabled: true
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- motion-spec (0.2.0)
4
+ motion-spec (0.3.0)
5
5
  motion-require (>= 0.0.6)
6
6
 
7
7
  GEM
@@ -1,6 +1,10 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module MotionSpec
3
3
  class Context
4
+ include ContextHelper::Matchers
5
+ include ContextHelper::Should
6
+ include ContextHelper::Expectation
7
+
4
8
  attr_reader :name, :block
5
9
 
6
10
  def initialize(name, before = nil, after = nil, &block)
@@ -0,0 +1,10 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module ContextHelper
4
+ module Expectation
5
+ def expect(subject = nil, &block)
6
+ MotionSpec::Expectation.new(subject, &block)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,95 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module ContextHelper
4
+ module Matchers
5
+ def be_nil
6
+ MotionSpec::Matcher::BeNil.new
7
+ end
8
+
9
+ def be_true
10
+ MotionSpec::Matcher::BeTrue.new
11
+ end
12
+
13
+ def be_false
14
+ MotionSpec::Matcher::BeFalse.new
15
+ end
16
+
17
+ def raise_error(exception_class = Exception, message = '')
18
+ MotionSpec::Matcher::RaiseError.new(exception_class, message)
19
+ end
20
+ alias_method :raise_exception, :raise_error
21
+
22
+ def eql(value)
23
+ MotionSpec::Matcher::Eql.new(value)
24
+ end
25
+
26
+ def be(value)
27
+ MotionSpec::Matcher::Be.new(value)
28
+ end
29
+ alias_method :equal, :be
30
+
31
+ def eq(value)
32
+ MotionSpec::Matcher::Eq.new(value)
33
+ end
34
+
35
+ def match(regex)
36
+ MotionSpec::Matcher::Match.new(regex)
37
+ end
38
+
39
+ def match_array(array)
40
+ MotionSpec::Matcher::MatchArray.new(array)
41
+ end
42
+ alias_method :contain_exactly, :match_array
43
+
44
+ def include(*values)
45
+ MotionSpec::Matcher::Include.new(*values)
46
+ end
47
+
48
+ def have(number)
49
+ MotionSpec::Matcher::HaveItems.new(number)
50
+ end
51
+
52
+ def satisfy(&block)
53
+ MotionSpec::Matcher::Satisfy.new(&block)
54
+ end
55
+
56
+ def respond_to(method_name)
57
+ MotionSpec::Matcher::RespondTo.new(method_name)
58
+ end
59
+
60
+ def start_with(substring)
61
+ MotionSpec::Matcher::StartWith.new(substring)
62
+ end
63
+
64
+ def end_with(substring)
65
+ MotionSpec::Matcher::EndWith.new(substring)
66
+ end
67
+
68
+ def change(&change_block)
69
+ MotionSpec::Matcher::Change.new(change_block)
70
+ end
71
+
72
+ def be_within(range)
73
+ MotionSpec::Matcher::BeWithin.new(range)
74
+ end
75
+
76
+ def method_missing(method_name, *args, &block)
77
+ string_method_name = method_name.to_s
78
+ match_be = string_method_name.match(/^be_(.*)/)
79
+
80
+ if match_be
81
+ return MotionSpec::Matcher::BeGeneric.new(match_be[1], *args)
82
+ end
83
+
84
+ match_have = string_method_name.match(/^have_(.*)/)
85
+
86
+ if match_have
87
+ return MotionSpec::Matcher::HaveGeneric.new(match_have[1], *args)
88
+ end
89
+
90
+ super
91
+ # raise "method name not found #{method_name}"
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,12 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module ContextHelper
4
+ module Should
5
+ def should(*args, &block)
6
+ return it('should ' + args.first, &block) if Counter[:depth] == 0
7
+
8
+ super(*args, &block)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -8,4 +8,8 @@ module MotionSpec
8
8
  super message
9
9
  end
10
10
  end
11
+
12
+ class FailedExpectation < RuntimeError; end
13
+
14
+ class InvalidMatcher < RuntimeError; end
11
15
  end
@@ -0,0 +1,32 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ class Expectation
4
+ def initialize(subject, &subject_block)
5
+ @subject = subject
6
+ @subject_block = subject_block
7
+ end
8
+
9
+ def to(matcher)
10
+ fail(matcher, false) unless matcher_passes(matcher)
11
+ assert
12
+ end
13
+
14
+ def not_to(matcher)
15
+ fail(matcher, true) if matcher_passes(matcher)
16
+ assert
17
+ end
18
+ alias_method :to_not, :not_to
19
+
20
+ def matcher_passes(matcher)
21
+ matcher.matches?(@subject, &@subject_block)
22
+ end
23
+
24
+ def fail(matcher, negated)
25
+ raise matcher.fail!(@subject, negated, &@subject_block)
26
+ end
27
+
28
+ def assert
29
+ true.should == true
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,101 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ class FailMessageRenderer
4
+ def self.expectation(negated)
5
+ "#{negated ? ' not' : ''} expected"
6
+ end
7
+
8
+ def self.message_for_be_false(negated, subject)
9
+ "#{subject.inspect}#{expectation(negated)} to be false"
10
+ end
11
+
12
+ def self.message_for_be_true(negated, subject)
13
+ "#{subject.inspect}#{expectation(negated)} to be true"
14
+ end
15
+
16
+ def self.message_for_be_nil(negated, subject)
17
+ "#{subject.inspect}#{expectation(negated)} to be nil"
18
+ end
19
+
20
+ def self.message_for_be(negated, subject, method_name, values)
21
+ message = "#{subject.inspect} ##{method_name}"
22
+ message += "(#{values.map(&:inspect).join(', ')})" unless values.empty?
23
+ message += "#{expectation(negated)} to return true"
24
+ message
25
+ end
26
+
27
+ def self.message_for_be_within(negated, subject, range, center_value)
28
+ "#{subject.inspect}#{expectation(negated)} to be within #{range} of #{center_value}"
29
+ end
30
+
31
+ def self.message_for_change(negated, change_amount, value_diff)
32
+ message = "Block#{expectation(negated)} to change value"
33
+ message += " by #{change_amount}" if change_amount
34
+ message += " but changed by #{value_diff}" if change_amount && !negated
35
+ message
36
+ end
37
+
38
+ def self.message_for_end_with(negated, subject, end_string)
39
+ "#{subject.inspect}#{expectation(negated)} to end with #{end_string.inspect}"
40
+ end
41
+
42
+ def self.message_for_start_with(negated, subject, start_string)
43
+ "#{subject.inspect}#{expectation(negated)} to start with #{start_string.inspect}"
44
+ end
45
+
46
+ def self.message_for_be_equal(negated, subject, value)
47
+ "#{subject.inspect}#{expectation(negated)} to be same object as #{value.inspect}"
48
+ end
49
+
50
+ def self.message_for_be_eq(negated, subject, value)
51
+ "#{subject.inspect}#{expectation(negated)} to be == to #{value.inspect}"
52
+ end
53
+
54
+ def self.message_for_have_generic(negated, subject, method_name, values)
55
+ message = "#{subject.inspect} #has_#{method_name}?"
56
+ message += "(#{values.map(&:inspect).join(', ')})" unless values.empty?
57
+ message += "#{expectation(negated)} to return true"
58
+ message
59
+ end
60
+
61
+ def self.message_for_have_items(negated, subject, expected_number_of_items, actual_number_of_items, key_type_name)
62
+ message = "#{subject.inspect}#{expectation(negated)} to have #{expected_number_of_items} #{key_type_name}"
63
+ message += " but had #{actual_number_of_items}" unless negated
64
+ message
65
+ end
66
+
67
+ def self.message_for_include(negated, subject, values)
68
+ values_message = values.size == 1 ? values.first : values
69
+ message = "#{subject.inspect}#{expectation(negated)} to include #{values_message.inspect}"
70
+ message
71
+ end
72
+
73
+ def self.message_for_match_array(negated, subject_array, expected_array)
74
+ message = "#{subject_array.inspect}#{expectation(negated)} to match array"
75
+ message += " #{expected_array.inspect}"
76
+ message
77
+ end
78
+
79
+ def self.message_for_match(negated, subject, match)
80
+ "#{subject.inspect}#{expectation(negated)} to match #{match.inspect}"
81
+ end
82
+
83
+ def self.message_for_raise_error(negated, show_class, error_class, show_message, error_message, rescued_exception)
84
+ message = "Block#{expectation(negated)} to raise error"
85
+ message += " of type #{error_class}" if show_class
86
+ message += " with message matching #{error_message.inspect}" if show_message
87
+ message += " but was #{rescued_exception.inspect}" if rescued_exception && !negated
88
+ message
89
+ end
90
+
91
+ def self.message_for_respond_to(negated, subject, method_name, number_of_args)
92
+ message = "#{subject.inspect}#{expectation(negated)} to respond to ##{method_name}"
93
+ message += " with #{number_of_args} arguments" if number_of_args
94
+ message
95
+ end
96
+
97
+ def self.message_for_satisfy(negated)
98
+ "Block#{expectation(negated)} to satisfy condition"
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class Be < SingleMethod
5
+ def initialize(value)
6
+ super(:equal?, value)
7
+ end
8
+
9
+ def fail_message(subject, negated)
10
+ FailMessageRenderer.message_for_be_equal(
11
+ negated, subject, @values.first
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class BeFalse
5
+ def matches?(value)
6
+ !value
7
+ end
8
+
9
+ def fail!(subject, negated)
10
+ message = FailMessageRenderer.message_for_be_false(negated, subject)
11
+ raise FailedExpectation.new(message)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class BeGeneric < SingleMethod
5
+ def initialize(method_name, *values)
6
+ super("#{method_name}?", *values)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class BeNil
5
+ def matches?(value)
6
+ value == nil
7
+ end
8
+
9
+ def fail!(subject, negated)
10
+ raise FailedExpectation.new(
11
+ FailMessageRenderer.message_for_be_nil(negated, subject)
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class BeTrue
5
+ def matches?(value)
6
+ value == true
7
+ end
8
+
9
+ def fail!(subject, negated)
10
+ raise FailedExpectation.new(
11
+ FailMessageRenderer.message_for_be_true(negated, subject)
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class BeWithin
5
+ INVALID_MATCH_ERROR = 'be_within matcher incomplete. Missing .of value'
6
+
7
+ def initialize(range)
8
+ @range = range
9
+ end
10
+
11
+ def of(center_value)
12
+ @center_value = center_value
13
+ self
14
+ end
15
+
16
+ def matches?(subject)
17
+ raise InvalidMatcher.new(INVALID_MATCH_ERROR) unless @center_value
18
+ (subject - @center_value).abs <= @range
19
+ end
20
+
21
+ def fail!(subject, negated)
22
+ raise FailedExpectation.new(
23
+ FailMessageRenderer.message_for_be_within(
24
+ negated, subject, @range, @center_value
25
+ )
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class Change
5
+ def initialize(change_block)
6
+ @change_block = change_block
7
+ end
8
+
9
+ def by(amount)
10
+ @change_amount = amount
11
+ self
12
+ end
13
+
14
+ def matches?(subject, &expectation_block)
15
+ old_value = @change_block.call
16
+ expectation_block.call
17
+ new_value = @change_block.call
18
+ if @change_amount
19
+ @value_diff = new_value - old_value
20
+ @value_diff == @change_amount
21
+ else
22
+ new_value != old_value
23
+ end
24
+ end
25
+
26
+ def fail!(subject, negated)
27
+ raise FailedExpectation.new(
28
+ FailMessageRenderer.message_for_change(
29
+ negated, @change_amount, @value_diff
30
+ )
31
+ )
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class EndWith
5
+ def initialize(end_string)
6
+ @end_string = end_string
7
+ end
8
+
9
+ def matches?(subject)
10
+ subject[-@end_string.size..-1] == @end_string
11
+ end
12
+
13
+ def fail!(subject, negated)
14
+ raise FailedExpectation.new(
15
+ FailMessageRenderer.message_for_end_with(
16
+ negated, subject, @end_string
17
+ )
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class Eq < SingleMethod
5
+ def initialize(value)
6
+ super(:==, value)
7
+ end
8
+
9
+ def fail_message(subject, negated)
10
+ FailMessageRenderer.message_for_be_eq(negated, subject, @values.first)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class Eql < SingleMethod
5
+ def initialize(value)
6
+ super(:eql?, value)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class HaveGeneric
5
+ def initialize(method_name, *args)
6
+ @method_name = method_name
7
+ @args = args
8
+ end
9
+
10
+ def matches?(subject)
11
+ subject.send("has_#{@method_name}?", *@args)
12
+ end
13
+
14
+ def fail!(subject, negated)
15
+ raise FailedExpectation.new(
16
+ FailMessageRenderer.message_for_have_generic(
17
+ negated, subject, @method_name, @args
18
+ )
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class HaveItems
5
+ def initialize(number_of_items)
6
+ @number_of_items = number_of_items
7
+ end
8
+
9
+ def matches?(value)
10
+ value.size == @number_of_items
11
+ end
12
+
13
+ [:items, :item, :keys, :values].each do |key_type_name|
14
+ define_method(key_type_name) do
15
+ @key_type_name = key_type_name
16
+ self
17
+ end
18
+ end
19
+
20
+ def fail!(subject, negated)
21
+ raise FailedExpectation.new(
22
+ FailMessageRenderer.message_for_have_items(
23
+ negated, subject, @number_of_items, subject.size, @key_type_name
24
+ )
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class Include
5
+ def initialize(*values)
6
+ @values = *values
7
+ end
8
+
9
+ def matches?(subject)
10
+ @values.all? { |v| subject.include?(v) }
11
+ end
12
+
13
+ def fail!(subject, negated)
14
+ raise FailedExpectation.new(
15
+ FailMessageRenderer.message_for_include(negated, subject, @values)
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class Match < SingleMethod
5
+ def initialize(value)
6
+ super(:match, value)
7
+ end
8
+
9
+ def fail_message(subject, negated)
10
+ FailMessageRenderer.message_for_match(negated, subject, @values.first)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class MatchArray
5
+ def initialize(expected_array)
6
+ @expected_array = expected_array
7
+ end
8
+
9
+ def matches?(subject_array)
10
+ return false unless subject_array.size == @expected_array.size
11
+ array_copy = subject_array.dup
12
+ @expected_array.all? do |item|
13
+ has = array_copy.include?(item)
14
+ array_copy.delete(item) if has
15
+ has
16
+ end
17
+ end
18
+
19
+ def fail!(subject_array, negated)
20
+ raise FailedExpectation.new(
21
+ FailMessageRenderer.message_for_match_array(
22
+ negated, subject_array, @expected_array
23
+ )
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,47 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class RaiseError
5
+ def initialize(error_class = Exception, message = '')
6
+ @error_class = error_class.is_a?(Class) ? error_class : Exception
7
+ @error_message = (error_class.is_a?(String) || error_class.is_a?(Regexp)) ? error_class : message
8
+ end
9
+
10
+ def matches?(value, &block)
11
+ block.call
12
+ false
13
+ rescue Exception => e
14
+ @rescued_exception = e
15
+ exception_matches(e)
16
+ end
17
+
18
+ def exception_matches(exception)
19
+ return false unless exception.is_a?(@error_class)
20
+
21
+ is_match = case @error_message
22
+ when String
23
+ exception.message.include?(@error_message)
24
+ when Regexp
25
+ @error_message.match(exception.message)
26
+ else
27
+ false
28
+ end
29
+
30
+ return false unless is_match
31
+
32
+ true
33
+ end
34
+
35
+ def fail!(subject, negated)
36
+ show_class = @error_class != Exception
37
+ show_message = !@error_message.is_a?(String) || !@error_message.empty?
38
+ raise FailedExpectation.new(
39
+ FailMessageRenderer.message_for_raise_error(
40
+ negated, show_class, @error_class, show_message, @error_message,
41
+ @rescued_exception
42
+ )
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class RespondTo
5
+ def initialize(method_name)
6
+ @method_name = method_name
7
+ end
8
+
9
+ def with(number_of_args)
10
+ @number_of_args = number_of_args
11
+ self
12
+ end
13
+
14
+ def arguments
15
+ self
16
+ end
17
+ alias_method :argument, :arguments
18
+
19
+ def matches?(subject)
20
+ valid = true
21
+
22
+ valid &&= subject.respond_to?(@method_name)
23
+
24
+ if valid && @number_of_args
25
+ valid &&= subject.method(@method_name).arity == @number_of_args
26
+ end
27
+
28
+ valid
29
+ end
30
+
31
+ def fail!(subject, negated)
32
+ raise FailedExpectation.new(
33
+ FailMessageRenderer.message_for_respond_to(
34
+ negated, subject, @method_name, @number_of_args
35
+ )
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class Satisfy
5
+ def initialize(&condition_block)
6
+ @condition_block = condition_block
7
+ end
8
+
9
+ def matches?(*values)
10
+ @condition_block.call(*values)
11
+ end
12
+
13
+ def fail!(subject, negated)
14
+ raise FailedExpectation.new(
15
+ FailMessageRenderer.message_for_satisfy(negated)
16
+ )
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class SingleMethod
5
+ def initialize(method_name, *values)
6
+ @values = values
7
+ @method_name = method_name
8
+ end
9
+
10
+ def matches?(subject)
11
+ subject.send(@method_name, *@values)
12
+ end
13
+
14
+ def fail!(subject, negated)
15
+ raise FailedExpectation.new(fail_message(subject, negated))
16
+ end
17
+
18
+ def fail_message(subject, negated = false)
19
+ FailMessageRenderer.message_for_be(
20
+ negated, subject, @method_name, @values
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ module Matcher
4
+ class StartWith
5
+ def initialize(start_string)
6
+ @start_string = start_string
7
+ end
8
+
9
+ def matches?(subject)
10
+ subject[0...@start_string.size] == @start_string
11
+ end
12
+
13
+ def fail!(subject, negated)
14
+ raise FailedExpectation.new(
15
+ FailMessageRenderer.message_for_start_with(
16
+ negated, subject, @start_string
17
+ )
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  module MotionSpec
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/motion-spec.rb CHANGED
@@ -7,16 +7,16 @@ require 'motion-require'
7
7
 
8
8
  # Proper load order of all the classes/modules
9
9
  ###
10
- def require_lib_file(file)
11
- case file
10
+ def require_lib_files(files)
11
+ case files
12
12
  when String
13
- files = expanded_file_path(file)
14
- files = Dir.glob(files) if file.include? '*'
13
+ file_paths = expanded_file_path(files)
14
+ file_paths = Dir.glob(file_paths) if files.include? '*'
15
15
  when Array
16
- files = file.map { |f| expanded_file_path(f) }
16
+ file_paths = files.map { |f| expanded_file_path(f) }
17
17
  end
18
18
 
19
- Motion::Require.all(files)
19
+ Motion::Require.all(file_paths)
20
20
  end
21
21
 
22
22
  def expanded_file_path(file)
@@ -24,16 +24,26 @@ def expanded_file_path(file)
24
24
  end
25
25
 
26
26
  # Let's start off with what version we're running
27
- require_lib_file('version')
27
+ require_lib_files('version')
28
28
 
29
29
  # Load the output before the core so the core knows how to print
30
- require_lib_file('output/*')
30
+ require_lib_files('output/*')
31
+
32
+ # Add on to the context of specs
33
+ require_lib_files('context_helper/*')
31
34
 
32
35
  # All the other core modules in the proper order
33
- require_lib_file(%w(core error specification platform context should))
36
+ require_lib_files(%w(
37
+ core error specification platform context should expectation
38
+ fail_message_renderer
39
+ ))
40
+
41
+ # Load expectation matchers
42
+ require_lib_files('matcher/single_method')
43
+ require_lib_files('matcher/*')
34
44
 
35
45
  # Monkeypatch core objects to respond to test methods
36
- require_lib_file('extensions/*')
46
+ require_lib_files('extensions/*')
37
47
 
38
48
  # FIXME : Need better detection for iPhone Simulator
39
49
  if defined?(UIDevice) &&
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Bender
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-04 00:00:00.000000000 Z
11
+ date: 2015-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: motion-require
@@ -47,6 +47,7 @@ extra_rdoc_files: []
47
47
  files:
48
48
  - .codeclimate.yml
49
49
  - .gitignore
50
+ - .hound.yml
50
51
  - .rubocop.yml
51
52
  - .travis.yml
52
53
  - Gemfile
@@ -57,14 +58,39 @@ files:
57
58
  - app/app_delegate.rb
58
59
  - lib/motion-spec.rb
59
60
  - lib/motion-spec/context.rb
61
+ - lib/motion-spec/context_helper/expectation.rb
62
+ - lib/motion-spec/context_helper/matchers.rb
63
+ - lib/motion-spec/context_helper/should.rb
60
64
  - lib/motion-spec/core.rb
61
65
  - lib/motion-spec/error.rb
66
+ - lib/motion-spec/expectation.rb
62
67
  - lib/motion-spec/extensions/boolean.rb
63
68
  - lib/motion-spec/extensions/exception.rb
64
69
  - lib/motion-spec/extensions/kernel.rb
65
70
  - lib/motion-spec/extensions/numeric.rb
66
71
  - lib/motion-spec/extensions/object.rb
67
72
  - lib/motion-spec/extensions/proc.rb
73
+ - lib/motion-spec/fail_message_renderer.rb
74
+ - lib/motion-spec/matcher/be.rb
75
+ - lib/motion-spec/matcher/be_false.rb
76
+ - lib/motion-spec/matcher/be_generic.rb
77
+ - lib/motion-spec/matcher/be_nil.rb
78
+ - lib/motion-spec/matcher/be_true.rb
79
+ - lib/motion-spec/matcher/be_within.rb
80
+ - lib/motion-spec/matcher/change.rb
81
+ - lib/motion-spec/matcher/end_with.rb
82
+ - lib/motion-spec/matcher/eq.rb
83
+ - lib/motion-spec/matcher/eql.rb
84
+ - lib/motion-spec/matcher/have_generic.rb
85
+ - lib/motion-spec/matcher/have_items.rb
86
+ - lib/motion-spec/matcher/include.rb
87
+ - lib/motion-spec/matcher/match.rb
88
+ - lib/motion-spec/matcher/match_array.rb
89
+ - lib/motion-spec/matcher/raise_error.rb
90
+ - lib/motion-spec/matcher/respond_to.rb
91
+ - lib/motion-spec/matcher/satisfy.rb
92
+ - lib/motion-spec/matcher/single_method.rb
93
+ - lib/motion-spec/matcher/start_with.rb
68
94
  - lib/motion-spec/output/colorized.rb
69
95
  - lib/motion-spec/output/fast.rb
70
96
  - lib/motion-spec/output/knock.rb