speck 1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NTcxNDI0MDBkZDlkYWQ4OGJjOGI2N2RhYzQwM2Y5NDEyNmQzN2QyNw==
5
+ data.tar.gz: !binary |-
6
+ OTM5MTY0MDJjZDZiNDhlNmI3OWZlMmQ0M2FkNTBmMTgwODFkYThjYw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NzVhMWIzMjk3NDU4ZTg5MGRlOWRkMzI1ODhiZDVlMzI1YzA0Y2ZmZmU1MTkz
10
+ MjVmMjBmMWRjNjBlOTkxZDMwNzI0MWFmOGQ4MDIwNzVhYTlhYTMyOTI4OTQ0
11
+ OTNiNjhlZDI0ZGYzOTU2NGE1YmUwYzRjMGJmMGMxNjI3NjU3Y2E=
12
+ data.tar.gz: !binary |-
13
+ MzIyODQ4MGZlYzRlNTNkMWU4MmRiYWJhZDkzYmE5NGZmN2U3ODVjNjI0Y2U0
14
+ N2Q1ZjJhNmZhMDU5OWYxMzZkMmVkYmYzZGUzMThjMDFkYzc4NmY5YTIxZGMw
15
+ ZTdhMjc5YmQ4YTU4NGJlZWQ2NjBmM2IzZjNlNWE2OWY2MjA0NGE=
@@ -0,0 +1,16 @@
1
+ Copyright (C) 2013 elliottcable
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
4
+ associated documentation files (the "Software"), to deal in the Software without restriction,
5
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
6
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
7
+ furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or substantial
10
+ portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
13
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
15
+ OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,82 @@
1
+ Speck
2
+ =====
3
+ This is a super-light library that attempts to enable a “literate” form of code-testing. This
4
+ library is a part of a suite of tools intended to be used together; alongside its
5
+ [brethren](#suite), it allows for “literate” specifications that look something like this:
6
+
7
+ Speck.new Dog do
8
+ some_breed = Dog::Shetland
9
+
10
+ Dog.new.check { it.breed == Dog::Labrador }
11
+ Dog.new(a_breed).check { it.breed == a_breed }
12
+
13
+ Speck.new Dog.class_method :bark do
14
+ a_dog = Dog.new
15
+ a_dog.bark.check { |rv| rv == 'arf' }
16
+ end
17
+ end
18
+
19
+ Ideas, feature requests, and bugs can be reported on the [GitHub][] issue tracker:
20
+
21
+ <http://github.com/elliottcable/Speck/issues>
22
+
23
+ [GitHub]: http://github.com/
24
+
25
+ Philosophy
26
+ ----------
27
+ If you'll pay attention to the above example, you'll notice we do things a little differently around
28
+ here. The conventions that Speck is designed to enable include:
29
+
30
+ - first and foremost, we want the specification to be *source-code*, that is, we want it to read
31
+ like any Ruby code anywhere else. Our ‘checks’ (called assertions in other environments) simply
32
+ boil down to a `target` and a block to execute *against* that target. This is intended to be very
33
+ idiomatic Ruby-style code.
34
+ - secondary to the former, we also like it when the checks themselves read a bit like an English
35
+ sentence. For example, Slack ([see below](#suite)) uses the [it][] library to make the blocks look
36
+ a little more readable in the usual case.
37
+ - this is especially powerful, because Spark extracts the source-code responsible for each check,
38
+ and hilights it based on the execution of that check. Thus, specification code itself is self-
39
+ documenting output for your test suite.
40
+ - related to that, we tend to abstract the specifics of each check into variables, named in such a
41
+ way as to express the generic form of that specific element. If we're testing that a dog takes a
42
+ breed, but not *which* breed it takes, we place a relevant breed into `some_breed`. Similarly, we
43
+ might put an arbitrary numeric argument into a variable named `some_number` instead of using the
44
+ developer standards of `42` or `1337`. If, however, we were testing specific functionality related
45
+ to handling of the magic number `2`, as opposed to `1` or `3`, then we'd write the `2` directly
46
+ into the check-line.
47
+ - our specification sections directly include *what* they're testing, instead of a description
48
+ thereof in a string. Whether this is an class, an instance method, or something else entirely.
49
+
50
+ Generally speaking, we try to write *code* that self-describes what it's testing, instead of writing
51
+ lots of english sentences in a DSL to redundantly describe the code being tested. (Lookin' at you,
52
+ RSpec 'n friends.)
53
+
54
+ [it]: <http://github.com/elliottcable/it> "A sneakly library to expose iterated elements beautifully"
55
+
56
+ Suite
57
+ -----
58
+ I've intentionally designed Speck to be tiny and modular. Speck itself, here, is three extremely
59
+ brief files. To do more interesting things, and make specks easier to write, I've provided several
60
+ “sister libraries” that expand upon what Speck itself does:
61
+
62
+ - **[Slack][]**: Provides convenience methods for creating specks directly from various objects and
63
+ values, and various other comparators and tools to make *writing* specks easier.
64
+ - **[Spark][]**: Provides a [Rake][] task and other tools that beautifully *runs* your specks.
65
+ - **[Smock][]**: Provides a “mocking and spying” toolkit, for testing intricate code that you can't
66
+ easily decouple enough to test in minutae.
67
+
68
+ In no way are any of these *required* to use Speck, nor do any of them inter-depend upon eachother.
69
+ Mix-and-match as you desire. Or, y'know, write your own.
70
+
71
+ [Slack]: <http://github.com/elliottcable/slack>
72
+ [Spark]: <http://github.com/elliottcable/spark>
73
+ [Smock]: <http://github.com/elliottcable/smock>
74
+
75
+ [Rake]: <http://rake.rubyforge.org> "A Ruby DSL for `make`-like project tasks"
76
+
77
+ License
78
+ -------
79
+ This project is licensed very openly for your use, under a variation of the ‘MIT license.’
80
+ Details are available in [LICENSE][].
81
+
82
+ [LICENSE]: <./blob/master/LICENSE.text>
@@ -0,0 +1,143 @@
1
+ # All library files are required at the bottom, because in this unique case we
2
+ # need `Speck` defined before we can use it to `Speck` anything.
3
+
4
+ class Speck
5
+ VERSION = 1
6
+
7
+ class <<self
8
+
9
+ ##
10
+ # All specks not bound to an environment
11
+ attr_accessor :unbound
12
+ def unbound; @unbound ||= Array.new; end
13
+
14
+ # The current `Speck` execution stack
15
+ #
16
+ # @see #current
17
+ attr_accessor :stack
18
+ def stack; @stack ||= Array.new; end
19
+
20
+ ##
21
+ # Returns the top `Speck` on the execution stack (the one currently in the
22
+ # process of executing)
23
+ #
24
+ # When your `Speck`s are being run, there is a `stack` of `Speck` objects,
25
+ # consisting of the current nesting list of `Speck`s being run.
26
+ def current
27
+ stack.last
28
+ end
29
+
30
+ ##
31
+ # Retreives the `Speck`s defiend for a given object, or, if none are
32
+ # defined, creates a new (empty) `Speck` for it.
33
+ #
34
+ # It’s worth noting that `Module#instance_method` returns a new
35
+ # `UnboundMethod` object every time you call it, even for the same method…
36
+ # so you can’t retreive Specks assigned to `UnboundMethods` via
37
+ # `Module#instance_method` with this method.
38
+ def for object
39
+ specks = Speck::on object
40
+ specks << Speck.new(object) if specks.empty?
41
+ return specks
42
+ end
43
+
44
+ ##
45
+ # Functions like `Speck::for`, without creating a new `Speck` if none are
46
+ # defined.
47
+ #
48
+ # @see `Speck::for`
49
+ def on object
50
+ object.instance_variable_get(NinjaVar) ||
51
+ object.instance_variable_set(NinjaVar, Array.new)
52
+ end
53
+
54
+ end
55
+
56
+ ##
57
+ # This instance variable will be set on target objects to point to the
58
+ # specks for that object
59
+ NinjaVar = :@_specks_
60
+
61
+ ##
62
+ # The block to be executed
63
+ attr_accessor :block
64
+
65
+ ##
66
+ # `Speck`s which consider this `Speck` to be their environment
67
+ attr_accessor :children
68
+ def children; @children ||= Array.new; end
69
+
70
+ ##
71
+ # The `environment` of a `Speck` is another `Speck`, describing some sort of
72
+ # parent. The environment of a `Speck` describing an `UnboundMethod`, for
73
+ # instance, would most likely be a `Speck` describing a `Module` or `Class`
74
+ # on which that method is defined
75
+ attr_accessor :environment
76
+ def environment= object
77
+ (@environment ? @environment.children : Speck.unbound).delete self
78
+
79
+ speck = object.is_a?(Speck) || object.nil? ?
80
+ object : Speck::for(object).first
81
+ @environment = speck
82
+
83
+ (@environment ? @environment.children : Speck.unbound) << self
84
+ end
85
+
86
+ ##
87
+ # The checks involved in the current `Speck`
88
+ attr_accessor :checks
89
+ def checks; @checks ||= Array.new; end
90
+
91
+ ##
92
+ # The `target` of a speck is usually the object which it is intended to
93
+ # describe (and test) the functionality of (Usually, this will be an
94
+ # instance of `Class`, `Module`, `Method` for “class” methods, or
95
+ # `UnboundMethod` for instance methods)
96
+ attr_accessor :target
97
+ def target= object
98
+ Speck::on(@target).delete self if @target and Speck::on(@target).include? self
99
+
100
+ @target = object
101
+
102
+ Speck::on(@target) << self if @target
103
+ end
104
+
105
+ ##
106
+ # Creates a new `Speck`.
107
+ def initialize *environment, &block
108
+ self.target = environment.pop
109
+
110
+ environment = environment.inject do |prev, curr|
111
+ raise Exception::EnvironmentConflict if Speck::for(curr).first.environment and Speck::for(curr).first.environment != Speck::for(prev).first
112
+ Speck::for(curr).first.environment = Speck::for(prev).first
113
+ curr
114
+ end
115
+
116
+ self.environment = environment ? Speck::for(environment).first : Speck.current
117
+ @block = block || lambda {}
118
+ end
119
+
120
+ ##
121
+ # Executes the `Speck`.
122
+ def execute
123
+ Speck.stack << self
124
+ @block.call
125
+ Speck.stack.pop
126
+ end
127
+
128
+
129
+ ##
130
+ # A root class, and container class, for `Speck` exceptions.
131
+ class Exception < StandardError
132
+ # Raised when a `Check` fails
133
+ CheckFailed = Class.new self
134
+
135
+ # Raised when you attempt to stack an environment contrary to the existing
136
+ # environment
137
+ EnvironmentConflict = Class.new self
138
+ end
139
+
140
+ end
141
+
142
+ require 'speck/battery'
143
+ require 'speck/check'
@@ -0,0 +1,28 @@
1
+ class Speck
2
+ ##
3
+ # A `Battery` of `Speck`s is a set of specks which should be executed
4
+ # together, and which interdepend upon other `Speck`s in the battery.
5
+ # `Batteries` are recursive structures; that is, a `Battery` may have sub–
6
+ # `Batteries` for relevant objects.
7
+ class Battery
8
+
9
+ attr_reader :specks
10
+ attr_reader :targets
11
+
12
+ def initialize
13
+ @specks = Array.new
14
+ @targets = Hash.new
15
+ end
16
+
17
+ def << speck
18
+ @specks << speck
19
+ @targets[speck.target] ||= Battery.new
20
+ return self
21
+ end
22
+
23
+ def [] object
24
+ return @targets[object]
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,43 @@
1
+ class Speck
2
+ ##
3
+ # Represents a queued thing to be checked of some sort, within a `Speck`.
4
+ class Check
5
+ ##
6
+ # The block to be executed, determining the success or failure of this
7
+ # particular `Check`. If it accepts an argument, the result of the target
8
+ # block will be passed as that argument.
9
+ attr_accessor :expectation
10
+
11
+ ##
12
+ # The `target` of a `Check` is a block that returns an object to be passed
13
+ # to the `expectation`. It represents the object that the `Check` is
14
+ # intended to, well, check.
15
+ attr_accessor :target
16
+
17
+ ##
18
+ # The status of the `Check`. `nil` indicates the `Check` hasn’t been
19
+ # executed, and `true` or `false` indicate the success of the latest
20
+ # execution
21
+ attr_accessor :status
22
+ def passed?
23
+ status == :passed
24
+ end
25
+
26
+ def initialize(target = nil, &expectation)
27
+ @target = target.respond_to?(:call) ? target : ->{target}
28
+ @expectation = expectation
29
+ Speck.current.checks << self if Speck.current
30
+ end
31
+
32
+ ##
33
+ # Executes this `Check`, raising an error if the expectation returns nil
34
+ # or false.
35
+ def execute
36
+ call = @expectation.arity == 0 ? ->{@target.call; @expectation.call} : ->{@expectation[@target.call]}
37
+ @status = call.call ? :passed : :failed
38
+ raise Exception::CheckFailed unless passed?
39
+ return self
40
+ end
41
+
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: speck
3
+ version: !ruby/object:Gem::Version
4
+ version: '1'
5
+ platform: ruby
6
+ authors:
7
+ - elliottcable [http://ell.io/tt]
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-02-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/speck/battery.rb
20
+ - lib/speck/check.rb
21
+ - lib/speck.rb
22
+ - README.markdown
23
+ - LICENSE.text
24
+ homepage: http://github.com/elliottcable/speck
25
+ licenses:
26
+ - MIT
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 2.0.0
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: ! 'An (extremely light) source-code literate code-specification and -testing
48
+ system. (see: spark, slack)'
49
+ test_files: []
50
+ has_rdoc: