rlab-assert 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e6938e62081cbd09fc601ff5d7c00f66e68b1b61
4
+ data.tar.gz: 56a1a0c69cdd1de23185353b272159ea0b493d97
5
+ SHA512:
6
+ metadata.gz: 3ed5a18f1393c4ed0610e37e13acf0e492f3357ac618f0ed66638a15e1afe0fbc490f9a90e868b9a72e487a1a23d91ca89365a52599b8c3ae69c194377876288
7
+ data.tar.gz: e3493df70e1ec449ffa61e2c2e9e7b84ed3fafd017c826748481351c33b701603451647e68310373d33976f6422cce110a09c41ceb735969994ec255b5541ec7
data/.bundle/config ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ BUNDLE_PATH: vendor
3
+ BUNDLE_DISABLE_SHARED_GEMS: '1'
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nassert.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # RLab Assert
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/nassert`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem "rlab-assert"
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install rlab-assert
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it ( https://github.com/[my-github-username]/nassert/fork )
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/tests ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+
5
+ $LOAD_PATH.<< File.expand_path "../../../../src", __FILE__
6
+ $LOAD_PATH.<< File.expand_path "../../lib", __FILE__
7
+
8
+ require "util"
9
+ require "executor"
10
+ require "executor/minitest"
11
+ require "reporters"
12
+ require "test"
13
+
14
+ require "rlab/assert"
15
+
16
+ module Picotest
17
+ class Test
18
+ singleton_class.send :attr, :subclasses
19
+ @subclasses = []
20
+
21
+ class << self
22
+ def extract_tests executor
23
+ subclasses.flat_map do |subclass|
24
+ RLab::Assert::Syntax.infect subclass, :observer => executor
25
+
26
+ test_methods = subclass.instance_methods.grep %r{^test_}
27
+ test_methods.map do |test_method|
28
+ RLab::Test.new executor, "#{subclass}##{test_method}", -> do
29
+ instance = subclass.new
30
+ instance.setup
31
+ instance.public_send test_method
32
+ instance.teardown
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def inherited subclass
39
+ subclasses.push subclass
40
+ end
41
+ end
42
+
43
+ def setup; end
44
+ def teardown; end
45
+ def skip; throw :skip end
46
+ end
47
+ end
48
+
49
+ Dir["tests/**/*.rb"].each &method(:load)
50
+
51
+ RLab::Executor::SingleThreaded.run(
52
+ Picotest::Test.method(:extract_tests),
53
+ RLab::Reporters::Classic.new(:color => true),
54
+ )
@@ -0,0 +1,116 @@
1
+ require "observer"
2
+
3
+ module RLab
4
+ module Assert
5
+ class Assertion
6
+ include Observable
7
+
8
+ attr :fails
9
+ attr :passes
10
+ attr_accessor :source
11
+
12
+ def initialize subject_proc, checks
13
+ @subject_proc = subject_proc
14
+ @checks = checks
15
+ @passes = []
16
+ @fails = []
17
+ @trace = caller_locations
18
+ end
19
+
20
+ def assert
21
+ changed
22
+ perform_checks
23
+ freeze
24
+ raise to_error if failed?
25
+ subject
26
+ ensure
27
+ notify_observers self
28
+ end
29
+
30
+ def build_checks
31
+ @checks.map do |check_name, argument|
32
+ resolve_check check_name, argument
33
+ end
34
+ end
35
+
36
+ def failed?
37
+ fails.any?
38
+ end
39
+
40
+ def file
41
+ @trace[0].path
42
+ end
43
+
44
+ def freeze
45
+ passes.freeze
46
+ fails.freeze
47
+ end
48
+
49
+ def line
50
+ @trace[0].lineno
51
+ end
52
+
53
+ def passed?
54
+ not failed?
55
+ end
56
+
57
+ def perform_checks
58
+ build_checks.each do |check|
59
+ check.evaluate
60
+ ary = if check.passed? then passes else fails end
61
+ ary.push check
62
+ end
63
+ end
64
+
65
+ def resolve_check check_name, argument
66
+ check = Checks.resolve check_name do
67
+ check_name = :include if check_name == :includes
68
+ argument = [check_name, *argument]
69
+ Checks[:predicate]
70
+ end
71
+ check.new subject_thunk, argument
72
+ end
73
+
74
+ def subject
75
+ subject_thunk.call
76
+ end
77
+
78
+ def subject_thunk
79
+ @subject_thunk ||= SubjectThunk.new @subject_proc
80
+ end
81
+
82
+ def to_error
83
+ AssertionFailed.new self
84
+ end
85
+
86
+ def trace
87
+ Assert.filter_trace @trace
88
+ end
89
+
90
+ class SubjectThunk
91
+ def initialize block
92
+ @block = block
93
+ end
94
+
95
+ def call
96
+ return @subject if subject_resolved?
97
+ @subject = @block.call
98
+ end
99
+
100
+ def expect_error
101
+ raise "called after initially fetched" if subject_resolved?
102
+ @block.call
103
+ nothing_raised = true
104
+ rescue => error
105
+ @subject = error
106
+ ensure
107
+ raise NothingRaised.new if nothing_raised
108
+ end
109
+
110
+ def subject_resolved?
111
+ instance_variable_defined? :@subject
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,53 @@
1
+ module RLab
2
+ module Assert
3
+ class Check
4
+ singleton_class.send :attr_reader, :block, :name
5
+
6
+ attr :argument
7
+
8
+ def initialize subject_thunk, argument
9
+ @argument = argument
10
+ @subject_thunk = subject_thunk
11
+ end
12
+
13
+ def evaluate
14
+ self.class.block.call self, @argument
15
+ freeze
16
+ end
17
+
18
+ def expect_error
19
+ @subject_thunk.expect_error
20
+ end
21
+
22
+ def fail message
23
+ passed = negated? ^ yield
24
+ @fail_message = message unless passed
25
+ end
26
+
27
+ def fail_message
28
+ "expected #{Assert.inspect subject} to#{" not" if negated?} #{@fail_message}"
29
+ end
30
+
31
+ def failed?
32
+ @fail_message ? true : false
33
+ end
34
+
35
+ def negated?
36
+ @negated ? true : false
37
+ end
38
+
39
+ def negate
40
+ @negated = !@negated
41
+ end
42
+
43
+ def passed?
44
+ not failed?
45
+ end
46
+
47
+ def subject
48
+ @expected_error or @subject_thunk.call
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ module RLab
2
+ module Assert
3
+ module Checks
4
+ module Registry
5
+ def self.extended base
6
+ base.instance_variable_set :@registry, {}
7
+ end
8
+
9
+ def self.define check_name, block
10
+ klass = Class.new Check
11
+ klass.instance_variable_set :@block, block
12
+ constant_name = RLab::Util.to_camel_case check_name
13
+ const_set constant_name, klass
14
+ klass
15
+ end
16
+
17
+ attr :registry
18
+
19
+ def register check_name, &block
20
+ registry[check_name] = Registry.define check_name, block
21
+ end
22
+
23
+ def resolve check_name, &block
24
+ block ||= -> * do raise MissingCheck.new check_name end
25
+ registry.fetch check_name, &block
26
+ end
27
+ alias_method :[], :resolve
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,75 @@
1
+ module RLab
2
+ module Assert
3
+ module Checks
4
+ extend Registry
5
+
6
+ register :equals do |check, object|
7
+ obj_inspect = Assert.inspect object
8
+
9
+ if Assert.inspect(check.subject) == obj_inspect and not check.negated?
10
+ fail_message = "equal other object (no difference in #inspect output)"
11
+ else
12
+ fail_message = "equal #{obj_inspect}"
13
+ end
14
+
15
+ check.fail fail_message do check.subject == object end
16
+ end
17
+
18
+ register :included_in do |check, list|
19
+ check.fail "be included in #{Assert.inspect list}" do
20
+ list.include? check.subject
21
+ end
22
+ end
23
+
24
+ register :kind_of do |check, type|
25
+ check.fail "be a kind of #{type}" do
26
+ check.subject.kind_of? type
27
+ end
28
+ end
29
+
30
+ register :matches do |check, matcher|
31
+ check.fail "match #{Assert.inspect matcher}" do
32
+ check.subject.match matcher
33
+ end
34
+ end
35
+
36
+ register :predicate do |check, argument|
37
+ name, *args = argument
38
+ method_name = "#{name}?"
39
+ method = check.subject.method method_name
40
+
41
+ if method.arity == 0
42
+ expect_truth = args.all?
43
+ message = "be #{name}"
44
+ result = check.subject.public_send method_name
45
+ result = result ^ !expect_truth
46
+ else
47
+ result = check.subject.public_send method_name, *args
48
+ args = args.map &Assert.method(:inspect)
49
+ message = "#{name} #{args * ', '}"
50
+ end
51
+
52
+ check.fail message do result end
53
+ end
54
+
55
+ register :raises do |check, error_type|
56
+ check.expect_error
57
+ check.fail "be a #{Assert.inspect error_type}" do
58
+ check.subject.is_a? error_type
59
+ end
60
+ end
61
+
62
+ register :responds_to do |check, method_name|
63
+ check.fail "respond to ##{method_name}" do
64
+ check.subject.respond_to? method_name
65
+ end
66
+ end
67
+
68
+ register :truthy do |check, arg|
69
+ check.fail "be #{arg ? "truthy" : "falsey"}" do
70
+ !arg ^ check.subject
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,46 @@
1
+ module RLab
2
+ module Assert
3
+ Error = Class.new StandardError
4
+
5
+ class AssertionFailed < Error
6
+ attr :assertion
7
+
8
+ def initialize assertion
9
+ @assertion = assertion
10
+ end
11
+
12
+ def backtrace
13
+ assertion.trace.map &:to_s
14
+ end
15
+
16
+ def to_s
17
+ failures = assertion.fails.map do |failed_check|
18
+ failed_check.fail_message
19
+ end
20
+ if failures.size > 1
21
+ "Assertion failure:\n\n * #{failures * "\n * "}\n"
22
+ else
23
+ "Assertion failure: #{failures * ", "}"
24
+ end
25
+ end
26
+ end
27
+
28
+ class MissingCheck < Error
29
+ attr :check_name
30
+
31
+ def initialize check_name
32
+ @check_name = check_name
33
+ end
34
+
35
+ def to_s
36
+ "could not resolve check #{check_name.inspect}"
37
+ end
38
+ end
39
+
40
+ class NothingRaised < Error
41
+ def to_s
42
+ "expected subject block to raise an error"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ module RLab
2
+ module Assert
3
+ class MinitestIntegration
4
+ def self.load mt_test
5
+ instance = new mt_test
6
+ instance.load
7
+ end
8
+
9
+ def initialize mt_test
10
+ @mt_test = mt_test
11
+ end
12
+
13
+ def load
14
+ @mt_test.class_eval do
15
+ instance_methods.map(&:to_s).each do |instance_method|
16
+ next unless instance_method.match /^(?:assert|refute)/
17
+ next if instance_method.match /^assertions/
18
+ undef_method instance_method
19
+ end
20
+ end
21
+ Syntax.infect @mt_test, :observer => Observer.new
22
+ end
23
+
24
+ class Observer
25
+ def update assertion
26
+ return unless assertion.failed?
27
+ error = assertion.to_error
28
+ raise Minitest::Assertion, error.message
29
+ end
30
+ end
31
+ end
32
+
33
+ MinitestIntegration.load Minitest::Test
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module RLab
2
+ module Assert
3
+ class Refutation < Assertion
4
+ private
5
+
6
+ def build_checks
7
+ super.each &:negate
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,109 @@
1
+ module RLab
2
+ module Assert
3
+ class Syntax < Module
4
+ MISSING = :__rlab_assert_arg_missing__
5
+
6
+ class << self
7
+ def infect target, params = {}
8
+ assert, refute, observer = RLab::Util.extract_key_args params,
9
+ :method => :assert, :refute => :refute, :observer => nil
10
+ instance = new assert, refute, observer
11
+ if target.is_a? Class
12
+ target.send :include, instance
13
+ else
14
+ target.extend instance
15
+ end
16
+ end
17
+
18
+ # Public: assert is designed to be called a number of different ways,
19
+ # from 0 to 2 positional arguments, and maybe a block. Note that this
20
+ # method is a big nested ball of conditionals because I want it to
21
+ # perform well.
22
+ #
23
+ # subject_or_checks - the first optional argument passed in
24
+ # checks - the second optional argument passed in
25
+ # block - the &block parameter
26
+ #
27
+ # Valid examples:
28
+ #
29
+ # assert :raises => Error do ̡… end
30
+ # assert "foo"
31
+ # assert 3, :included_in => [6, 3]
32
+ # assert [6, 3], :includes => 3
33
+ # assert :equal => 4 do 2 + 2 end
34
+ #
35
+ # Invalid examples:
36
+ #
37
+ # # Can't determine if the block or 2 is the subject
38
+ # assert 2, :equals => 4 do ̒… end
39
+ # # There's no subject at all
40
+ # assert :incuded_in => 4
41
+ #
42
+ # Returns two arguments, the subject, and a checks hash. If the checks
43
+ # would be empty, returns { :truthy => true }. The subject will always be
44
+ # a Proc that gets lazy evaluated when the assertion is checked.
45
+ def decode_assert_arguments subject_or_checks, checks, block
46
+ if checks == MISSING
47
+ if subject_or_checks == MISSING
48
+ missing_subject! unless block
49
+ subject_thunk = block
50
+ checks = { :truthy => true }
51
+ elsif block
52
+ ambiguous_subject! unless subject_or_checks.is_a? Hash
53
+ subject_thunk = block
54
+ checks = subject_or_checks
55
+ else
56
+ subject_thunk = -> do subject_or_checks end
57
+ checks = { :truthy => true }
58
+ end
59
+ else
60
+ ambiguous_subject! if block
61
+ subject_thunk = -> do subject_or_checks end
62
+ end
63
+ [subject_thunk, checks]
64
+ end
65
+
66
+ def ambiguous_subject!
67
+ raise ArgumentError, "cannot supply a block subject *and* a positional subject"
68
+ end
69
+
70
+ def missing_subject!
71
+ raise ArgumentError, "must supply either a positional subject *or* a block subject (but not both)"
72
+ end
73
+ end
74
+
75
+ def initialize assert, refute, observer
76
+ @assert = assert
77
+ @refute = refute
78
+ @observer = observer
79
+ end
80
+
81
+ def refute?
82
+ @refute ? true : false
83
+ end
84
+
85
+ def extended base
86
+ graft base.singleton_class
87
+ end
88
+
89
+ def included base
90
+ graft base
91
+ end
92
+
93
+ def graft base
94
+ method_body = -> method_name, assertion_class, syntax, observer do
95
+ define_method method_name do |arg1 = MISSING, arg2 = MISSING, &block|
96
+ subject_thunk, checks = syntax.decode_assert_arguments arg1, arg2, block
97
+ assertion = assertion_class.new subject_thunk, checks
98
+ assertion.add_observer observer if observer
99
+ assertion.source = self
100
+ assertion.assert
101
+ end
102
+ end
103
+
104
+ base.class_exec @assert, Assertion, self.class, @observer, &method_body
105
+ base.class_exec @refute, Refutation,self.class, @observer, &method_body if refute?
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,5 @@
1
+ module RLab
2
+ module Assert
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "assert/assertion"
2
+ require_relative "assert/check"
3
+ require_relative "assert/checks/registry"
4
+ require_relative "assert/checks"
5
+ require_relative "assert/errors"
6
+ require_relative "assert/refutation"
7
+ require_relative "assert/syntax"
8
+ require_relative "assert/version"
9
+
10
+ module RLab
11
+ module Assert
12
+ def self.filter_trace trace
13
+ assert_root = __FILE__.chomp ".rb"
14
+ trace.drop_while do |location|
15
+ full_path = File.expand_path location.path
16
+ full_path.start_with? assert_root
17
+ end
18
+ end
19
+
20
+ def self.inspect object, truncate = 100
21
+ raw = object.inspect
22
+ return raw if raw.size <= truncate
23
+ "#{raw[0..truncate - 2]} …\""
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path "../lib", __FILE__
3
+ $LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib
4
+ require "rlab/assert/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rlab-assert"
8
+ spec.version = RLab::Assert::VERSION
9
+ spec.authors = ["ntl"]
10
+ spec.email = ["nathanladd+github@gmail.com"]
11
+
12
+ spec.summary = %q{An alternative assert implementation}
13
+ spec.description = %q{An alternative assert implementation designed for straightforward syntax and better debugging}
14
+ spec.homepage = "https://github.com/ntl/rlab-assert"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f| f.match %r{^tests} end
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep %r{^exe/} do |f| File.basename f end
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.9"
22
+ spec.add_development_dependency "minitest"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rlab-assert
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ntl
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-05-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: An alternative assert implementation designed for straightforward syntax
56
+ and better debugging
57
+ email:
58
+ - nathanladd+github@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".bundle/config"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - README.md
67
+ - Rakefile
68
+ - bin/tests
69
+ - lib/rlab/assert.rb
70
+ - lib/rlab/assert/assertion.rb
71
+ - lib/rlab/assert/check.rb
72
+ - lib/rlab/assert/checks.rb
73
+ - lib/rlab/assert/checks/registry.rb
74
+ - lib/rlab/assert/errors.rb
75
+ - lib/rlab/assert/minitest_integration.rb
76
+ - lib/rlab/assert/refutation.rb
77
+ - lib/rlab/assert/syntax.rb
78
+ - lib/rlab/assert/version.rb
79
+ - rlab-assert.gemspec
80
+ homepage: https://github.com/ntl/rlab-assert
81
+ licenses: []
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.4.7
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: An alternative assert implementation
103
+ test_files: []