speck 1

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.
@@ -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: