lax 0.2.1 → 0.2.3

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.
data/README.md CHANGED
@@ -1,30 +1,65 @@
1
1
  lax
2
2
  ===
3
- Lax is an insouciant smidgen of a testing framework that tries to be an invisible wrapper around your ideas about how your code should work.
3
+ Lax is an insouciant smidgen of a testing framework that tries hard to be an invisible wrapper around your ideas about how your code works.
4
4
  ```ruby
5
- Lax.assert do
6
- let number: 1,
7
- string: 'Hi There',
8
- regexp: defer{ /the/ } # lazy evaluation
9
-
10
- number + 1 == 2
11
- string.downcase =~ regexp
5
+ Lax.scope do
6
+ let number: 1, # let defines targets that are appropriately scoped and
7
+ string: 'Hi There', # re-instantiated for each assertion block.
8
+ regexp: lazy{ /the/ } # <- lazy evaluation
12
9
 
13
10
  assert do
14
- let number: 2
15
- number - 1 == 1
11
+ that number + 1 == 2, # these assertions can pass or fail independently
12
+ string.downcase =~ regexp
13
+
14
+ that(regexp.hash).satisfies {|obj| obj.is_a? Fixnum} # you can also easily define your own conditions
16
15
  end
17
- end
18
16
 
19
- Lax::Run[ Lax ] #=> pass, pass, pass
17
+ string { upcase.strip == 'HI THERE' } # you can also make assertions like this
18
+
19
+ before { puts "hiii. i am a callback. i will be run once for each assertion block in my scope." }
20
+
21
+ scope do
22
+ before { puts "i will be run after the before callback in my enclosing scope." }
23
+ before { @this_ivar = 'is visible in assertion blocks' }
24
+ after { puts 'after callbacks also are a thing' }
25
+
26
+
27
+ def self.number_is_even # rspec-like 'shared examples' can be defined like this.
28
+ number { even? }
29
+ end
30
+
31
+ let number: 2,
32
+ nothing: regexp.match('ffff') # compound target
33
+ bool: true
34
+
35
+ number_is_even
36
+
37
+ assert 'documented tests' do # docstrings can optionally be attached to assertion groups.
38
+ that number - 1 == 1,
39
+ string.upcase == 'HI THERE', # string is still in scope
40
+ nothing == nil
41
+ end
42
+ end
43
+
44
+ scope do
45
+ let lax: self,
46
+ open_file: fix(read: "data\nof\nimmediate\ninterest ") # fixtures are also a thing
47
+ assert do
48
+ that lax.respond_to?(:bool) == false, # bool is out of scope
49
+ open_file.read.lines.map(&:strip).size == 4
50
+ end
51
+ end
52
+ end
20
53
 
54
+ Lax::Run[ Lax ] #=> green dots aww yeah
21
55
  ```
22
56
  how come lax is neat
23
57
  --------------------
24
- * Minimal bullshit legalese.
25
- * Easy-to-define custom matchers and hooks.
26
- * Hackable with a tiny code footprint (< 300 SLOC).
27
- * Does not pollute your toplevel namespace or infect the entire Ruby object hierarchy with its code.
58
+ * Minimal legalese.
59
+ * Easy-to-define custom matchers.
60
+ * Built-in Rake task generator for quick setup.
61
+ * Small & hackable is a design goal (< 150 SLOC with plenty of hooks for your code)
62
+ * Does not work by infecting the entire object system with its code - neighbourly!
28
63
 
29
64
  how to make it do it
30
65
  --------------------
@@ -32,7 +67,7 @@ how to make it do it
32
67
  gem install lax
33
68
  cd my/project/root
34
69
  echo "require 'lax/rake_task'; Lax::RakeTask.new" >> Rakefile
35
- # write yr tests in the test directory (default test)
70
+ # write tests in yr test directory (defaults to 'test')
36
71
  rake lax
37
72
  ```
38
73
 
data/lib/lax.rb CHANGED
@@ -1,4 +1,138 @@
1
- Object::Lax = Class.new(Array)
2
- Lax::SOURCE = File.new(File.expand_path('../lax/source.rb', __FILE__)).read
3
- Lax.class_eval Lax::SOURCE
1
+ class Lax < Array
2
+ VERSION = '0.2.3'
3
+
4
+ Lazy = Class.new Proc
5
+ Run = ->(lax=Lax, fin=->(n){n}) do
6
+ fin.call lax.select {|l| l.included_modules.include? AssertionGroup}.map(&:new).flatten
7
+ end
8
+ Assertion = Struct.new(:pass, :source, :doc, :exception)
9
+
10
+ @lings = []
11
+ extend Enumerable
12
+ def self.inherited(ling)
13
+ @lings << ling
14
+ ling.lings = []
15
+ end
16
+
17
+ class << self
18
+ attr_accessor :lings, :src, :doc
19
+
20
+ def each(&b)
21
+ yield self
22
+ lings.each {|c| c.each(&b)}
23
+ end
24
+
25
+ def let(h)
26
+ h.each do |key, value|
27
+ val = (Lazy===value) ? value : lazy{value}
28
+ define_singleton_method(key) do |&b|
29
+ b ? assert { that val.call.instance_exec(&b) } : val.call
30
+ end
31
+ define_method(key) do
32
+ (@_memo||={}).has_key?(key)? @_memo[key] : @_memo[key] = val.call
33
+ end
34
+ end
35
+ end
36
+
37
+ def lazy
38
+ Lazy.new
39
+ end
40
+
41
+ def fix(hash)
42
+ Struct.new(*hash.keys).new *hash.values
43
+ end
44
+
45
+ def before(&bef)
46
+ ->(m) { define_method(:before) do |*a|
47
+ m.bind(self).call *a
48
+ instance_exec(*a, &bef)
49
+ end }.call instance_method :before
50
+ end
51
+
52
+ def assert(doc=nil,&spec)
53
+ scope do
54
+ @doc, @src = doc, spec.source_location
55
+ include AssertionGroup
56
+ before(&spec)
57
+ end
58
+ end
59
+
60
+ def scope(&b)
61
+ Class.new(self, &b)
62
+ end
63
+
64
+ def after(&aft)
65
+ ->(m) { define_method(:after) do |*a|
66
+ instance_exec(*a, &aft)
67
+ m.bind(self).call *a
68
+ end }.call instance_method :after
69
+ end
70
+
71
+ def matcher(sym,&p)
72
+ define_method(sym) { satisfies &p}
73
+ end
74
+ end
75
+
76
+ def before(*a); end
77
+ def after(*a); end
78
+
79
+ module AssertionGroup
80
+ def fix(hash)
81
+ self.class.fix hash
82
+ end
83
+
84
+ def that(*as)
85
+ concat as.map {|a| assert a}
86
+ end
87
+
88
+ def satisfies
89
+ push assert yield pop
90
+ end
91
+
92
+ def assert(v,x=nil)
93
+ Assertion.new !!v, self.class.src, self.class.doc, x
94
+ end
95
+
96
+ def initialize
97
+ before
98
+ rescue => e
99
+ push assert(false, e)
100
+ ensure
101
+ after self
102
+ end
103
+ end
104
+
105
+ module RakeTask
106
+ def self.new(opts = {})
107
+ require 'rake'
108
+ extend Rake::DSL
109
+ o = {dir: :test, name: :lax}.merge(opts)
110
+ namespace o[:name] do
111
+ task(:load) { Dir["./#{o[:dir]}/**/*.rb"].each {|f| load f} }
112
+ task(:run) do
113
+ Lax.after &Output::DOTS
114
+ Run[ Lax, ->(n){Output::FAILURES[n]; Output::SUMMARY[n]} ]
115
+ end
116
+ end
117
+ task o[:name] => ["#{o[:name]}:load", "#{o[:name]}:run"]
118
+ end
119
+ end
120
+
121
+ module Output
122
+ DOTS = ->(tc) {
123
+ tc.each {|c| print c.pass ? "\x1b[32m.\x1b[0m" : "\x1b[31mX\x1b[0m"}
124
+ }
125
+
126
+ SUMMARY = ->(cs) {
127
+ puts "pass: #{cs.select(&:pass).size}\nfail: #{cs.reject(&:pass).size}"
128
+ }
129
+ FAILURES = ->(cs) {
130
+ puts
131
+ cs.reject(&:pass).each do |f|
132
+ puts " failure in #{f.doc || 'an undocumended node'} at #{f.source*?:}"
133
+ puts " raised #{f.exception.class} : #{f.exception.message}" if f.exception
134
+ end
135
+ }
136
+ end
137
+ end
4
138
 
@@ -2,25 +2,42 @@ require 'spec_helper'
2
2
 
3
3
  describe Lax do
4
4
 
5
- let :simple_case do
6
- Lax.assert do
7
- let number: 19,
8
- string: 'asdf',
9
- symbol: :symbol
5
+ context 'a simple case' do
6
+ let :simple_case do
7
+ Lax.scope do
8
+ let number: 19,
9
+ string: 'asdf',
10
+ symbol: :symbol
10
11
 
11
- number.odd? == true
12
- number == 19
13
- string == 'asdf'
14
- number == 20
15
- string.upcase == 'ASDF'
16
- symbol.to_s == 'symbol'
12
+ assert do
13
+ that number.odd? == true,
14
+ number == 19,
15
+ string == 'asdf',
16
+ number == 20,
17
+ string.upcase == 'ASDF',
18
+ symbol.to_s == 'symbol'
19
+ end
20
+ end
17
21
  end
22
+
23
+ subject { simple_case.lings.last.new }
24
+ it { should have(6).things }
25
+ specify { subject.select(&:pass).should have(5).things }
26
+ specify { subject.reject(&:pass).should have(1).things }
18
27
  end
19
28
 
20
- subject { simple_case.new }
21
- it { should have(6).things }
22
- specify { subject.select(&:pass?).should have(5).things }
23
- specify { subject.reject(&:pass?).should have(1).things }
29
+ context 'compound targets' do
30
+ let :comp do
31
+ Lax.scope do
32
+ let number: 21
33
+ let thirty: number + 9
34
+ assert { that thirty == 30 }
35
+ end
36
+ end
37
+ subject { comp.lings.last.new }
38
+ it { should have(1).thing }
39
+ specify { subject.first.pass.should == true }
40
+ end
24
41
 
25
42
  end
26
43
 
data/spec/spec_helper.rb CHANGED
@@ -6,5 +6,4 @@ RSpec.configure do |config|
6
6
  config.color_enabled = true
7
7
  end
8
8
 
9
- Lax.config.run.hooks.after = Lax::Hook.noop # suppress output
10
9
 
@@ -1,20 +1,38 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Lax do
4
- subject { Lax }
4
+ let(:lax) { Class.new(Lax) }
5
5
 
6
6
  describe '::let' do
7
- before do
8
- Lax.let number: 1
9
- Lax.number == 1
10
- end
11
- subject { Lax.instance_methods - Lax.superclass.instance_methods }
12
- it { should have(1).thing }
7
+ before { lax.let number: 1 }
8
+ specify { lax.methods.should include :number }
9
+ specify { lax.instance_methods.should include :number }
10
+ specify { lax.number.should == 1 }
11
+ specify { lax.new.number.should == 1 }
13
12
  end
14
13
 
15
14
  describe '#initialize' do
16
- subject { Lax.reboot.new }
15
+ subject { lax.new }
17
16
  it { should be_empty }
18
17
  end
18
+
19
+ describe '::scope' do
20
+ subject { Lax.scope }
21
+ specify { Lax.lings.should include subject }
22
+ its(:superclass) { should == Lax }
23
+ its(:new) { should be_empty }
24
+ end
25
+
26
+ describe '::assert' do
27
+ subject do
28
+ Lax.scope do
29
+ let number: 22
30
+ assert('hahawow') { that number == 22 }
31
+ end.lings.last
32
+ end
33
+ specify { subject.superclass.superclass.should be Lax }
34
+ its(:doc) { should == 'hahawow' }
35
+ its(:new) { should have(1).thing }
36
+ end
19
37
  end
20
38
 
data/test/control.rb CHANGED
@@ -1,28 +1,77 @@
1
- Lax.assert do
1
+ Lax.scope do
2
2
  let number: 1,
3
- string: 'asdf',
4
- symbol: :a_sym,
5
- regexp: _{/asd/}
3
+ string: 'asdf',
4
+ symbol: :a_sym,
5
+ regexp: lazy{/asd/}
6
6
 
7
- assert do
8
- number == 1
9
- assert do
7
+ scope do
8
+ assert { that number == 1 }
9
+ scope do
10
10
  let number: 2
11
- number == 2
12
-
13
- string.upcase.downcase == 'asdf'
14
- string =~ regexp
11
+ assert do
12
+ that number == 2,
13
+ number.even?,
14
+ string.upcase.downcase == 'asdf',
15
+ string =~ regexp
16
+ end
15
17
  end
16
18
  end
17
19
  end
18
- Lax.assert do
20
+
21
+ Lax.scope do
19
22
  let number: 1,
20
- string: 'Hi There',
21
- regexp: defer{ /the/ }
22
- number + 1 == 2
23
- string.downcase =~ regexp
23
+ string: 'Hi There',
24
+ regexp: lazy{ /the/ } # lazy evaluation
25
+
26
+ string {upcase == 'HI THERE'}
27
+
24
28
  assert do
25
- let number: 2
26
- number - 1 == 1
29
+ that number + 1 == 2,
30
+ string.downcase =~ regexp
31
+ end
32
+
33
+ # before { puts "i will be run once for each assert block in my scope" }
34
+ # after { puts "are stackable" }
35
+
36
+ scope do
37
+
38
+ def self.number_is_even
39
+ number { even? }
40
+ end
41
+
42
+ let number: 2,
43
+ nothing: regexp.match('ffff'),
44
+ bool: true
45
+ before { @qqq=9}
46
+
47
+ number_is_even
48
+
49
+ assert 'documented tests' do
50
+ that number + @qqq == 11,
51
+ number - 1 == 1,
52
+ string.upcase == 'HI THERE', # string is in scope
53
+ nothing == nil
54
+ end
55
+ end
56
+
57
+ scope do
58
+ let lax: self,
59
+ open_file: fix(read: "data\nof\nimmediate\ninterest ") # fixtures
60
+ assert do
61
+ that lax.respond_to?(:bool) == false # bool is out of scope
62
+ that open_file.read.lines.map(&:strip).size == 4
63
+ end
27
64
  end
28
65
  end
66
+
67
+ Lax.scope do
68
+ let lax: Lax
69
+ assert do
70
+ group = lax.scope do
71
+ let altitude: 10000
72
+ assert { that altitude > 1000 }
73
+ end.lings.first.new
74
+ that group.size==1
75
+ end
76
+ end
77
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lax
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-22 00:00:00.000000000 Z
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -35,17 +35,12 @@ extra_rdoc_files: []
35
35
  files:
36
36
  - lax.gemspec
37
37
  - lib/lax.rb
38
- - lib/lax/rake_task.rb
39
- - lib/lax/source.rb
40
38
  - README.md
41
39
  - LICENSE
42
40
  - test/control.rb
43
41
  - spec/spec_helper.rb
44
42
  - spec/acceptance/acceptance_spec.rb
45
- - spec/unit/hook_spec.rb
46
- - spec/unit/target_spec.rb
47
43
  - spec/unit/lax_spec.rb
48
- - spec/unit/fixture/hashable_spec.rb
49
44
  homepage: http://github.com/gwentacle/lax
50
45
  licenses:
51
46
  - MIT/X11
@@ -75,7 +70,4 @@ test_files:
75
70
  - test/control.rb
76
71
  - spec/spec_helper.rb
77
72
  - spec/acceptance/acceptance_spec.rb
78
- - spec/unit/hook_spec.rb
79
- - spec/unit/target_spec.rb
80
73
  - spec/unit/lax_spec.rb
81
- - spec/unit/fixture/hashable_spec.rb
data/lib/lax/rake_task.rb DELETED
@@ -1,20 +0,0 @@
1
- require 'rake'
2
- require 'lax'
3
- class Lax
4
- module RakeTask
5
- class << self
6
- include Rake::DSL
7
- def new(opts = {})
8
- o = Lax.config.task.merge opts
9
- namespace o[:name] do
10
- task(:load) { Dir["./#{o[:dir]}/**/*.rb"].each {|f| load f} }
11
- task(:run) do
12
- Lax::Run[ Lax ]
13
- end
14
- end
15
- task o[:name] => ["#{o[:name]}:load", "#{o[:name]}:run"]
16
- end
17
- end
18
- end
19
- end
20
-
data/lib/lax/source.rb DELETED
@@ -1,288 +0,0 @@
1
- VERSION = '0.2.1'
2
-
3
- class Assertion < Struct.new :name, :subject, :condition, :src, :matcher, :args, :hooks
4
- def pass?
5
- memoize(:pass) { condition.call value }
6
- end
7
-
8
- def value
9
- memoize(:value) { subject.call }
10
- end
11
-
12
- def validate
13
- memoize(:validate) do
14
- hooks.before.call self
15
- pass?
16
- self.tap { hooks.after.call self }
17
- end
18
- end
19
-
20
- private
21
- def memoize(key)
22
- @memo ||= {}
23
- @memo.has_key?(key) ? @memo[key] : @memo[key] = yield
24
- end
25
-
26
- class Xptn < Struct.new :assertion, :exception
27
- attr_accessor :name, :src, :matcher, :args
28
-
29
- def pass?
30
- false
31
- end
32
-
33
- def value
34
- nil
35
- end
36
-
37
- def initialize(a, x)
38
- super
39
- %w{name src matcher args}.each {|m| send "#{m}=", a.send(m)}
40
- end
41
- end
42
- end
43
-
44
- module Fixture
45
- def self.new(hash)
46
- klass = Struct.new(*hash.keys)
47
- klass.send :include, self
48
- klass.new *hash.values
49
- end
50
-
51
- module Hashable
52
- def self.new(hashable)
53
- hash = hashable.to_hash
54
- klass = Struct.new(*hash.keys)
55
- klass.send :include, self, Fixture
56
- klass.new(*hash.values.map do |val|
57
- (Hash===val) ? new(val) : val
58
- end)
59
- end
60
-
61
- def to_hash
62
- Hash[
63
- members.zip entries.map {|e| e.kind_of?(Hashable) ? e.to_hash : e }
64
- ]
65
- end
66
-
67
- def merge(hashable)
68
- Hashable.new to_hash.merge hashable
69
- end
70
- end
71
- end
72
-
73
- class Target < BasicObject
74
- def self.define_matcher(sym, &p)
75
- define_method(sym) do |*a,&b|
76
- p ?
77
- satisfies(sym) do |o|
78
- p[*a.map {|v| resolve v},&b][o]
79
- end :
80
- satisfies(sym,*a) do |o|
81
- o.__send__ sym,*a.map {|v| resolve v},&b
82
- end
83
- end
84
- end
85
-
86
- def self.define_predicate(sym)
87
- if sym =~ /(.*)(\?|_?p)$/
88
- define_method($1) { satisfies($1) {|o| o.__send__ sym} }
89
- else
90
- raise ArgumentError, "#{sym} does not appear to be a predicate"
91
- end
92
- end
93
-
94
- %w{== === != =~ !~ < > <= >=}.each {|m| define_matcher m}
95
- %w{odd? even? is_a? kind_of? include?}.each {|m| define_predicate m}
96
-
97
- def initialize(node, subj, name, src)
98
- @node, @subj, @name, @src = node, subj, name, src
99
- end
100
-
101
- def satisfies(matcher=nil, *args, &cond)
102
- assert!(cond, *[ matcher, args ])
103
- end
104
-
105
- def method_missing(sym, *args, &blk)
106
- Target.new @node, ->{@subj.call.__send__(sym, *args, &blk)}, @name, @src
107
- end
108
-
109
- def __val__
110
- @subj.call
111
- end
112
-
113
- private
114
- def assert!(cond, matcher=nil, args=nil)
115
- name, subj, src, hooks = @name, @subj, @src, @node.hooks
116
- ord = @node.instance_methods.size.to_s
117
- @node.send(:include, ::Module.new do
118
- define_method(ord) do
119
- ::Lax::Assertion.new name, subj, cond, src, matcher, args, hooks
120
- end
121
- end)
122
- end
123
-
124
- def resolve(v)
125
- ::Lax::Target === v ? v.__val__ : v
126
- end
127
-
128
- end
129
-
130
- module Run
131
- def self.[](lax)
132
- hook = lax.config.run.hooks
133
- hook.start[ as = lax.map(&:new).flatten ]
134
- as.map do |assertion|
135
- hook.before[ assertion ]
136
- validate_protect(assertion).tap {|v| hook.after[v]}
137
- end.tap {|vs| hook.finish[vs]}
138
- end
139
-
140
- private
141
- def self.validate_protect(a)
142
- begin
143
- a.validate
144
- rescue => e
145
- Assertion::Xptn.new(a, e)
146
- end
147
- end
148
- end
149
-
150
- class Hook < Proc
151
- class << self
152
- def _resolve(hook)
153
- if hook.is_a? Hook
154
- hook
155
- elsif hook.is_a? Proc
156
- new &hook
157
- elsif hook.is_a?(Symbol) and self.respond_to?(hook)
158
- send hook
159
- else
160
- raise NameError, "Unable to resolve hook `#{hook}'"
161
- end
162
- end
163
-
164
- def noop
165
- new {|*a|}
166
- end
167
-
168
- def output
169
- new {|tc| print tc.pass? ? "\x1b[32m.\x1b[0m" : "\x1b[31mX\x1b[0m"}
170
- end
171
-
172
- # Returns a hook for generating terminal output from test cases.
173
- def summary
174
- new {|cs| puts "\nFinished #{cs.size} tests with #{cs.reject(&:pass?).size} failures"}
175
- end
176
-
177
- # Returns a hook for generating terminal output from test cases.
178
- def failures
179
- new do |cs|
180
- cs.reject(&:pass?).each do |f|
181
- puts " #{f.src}\n " <<
182
- "#{f.exception ?
183
- "(raised an unhandled #{f.exception.class})" :
184
- "(got #{f.subject})"}"
185
- end
186
- end
187
- end
188
-
189
- def define(sym, &p)
190
- define_singleton_method(sym) {new &p}
191
- end
192
- end
193
-
194
- def <<(hook)
195
- Hook.new {|*a,&b| call(Hook._resolve(hook)[*a,&b])}
196
- end
197
-
198
- def +(hook)
199
- Hook.new {|*a,&b| call(*a,&b); Hook._resolve(hook)[*a,&b]}
200
- end
201
- end
202
-
203
- CONFIG = Fixture::Hashable.new(
204
- task: { dir: :test, name: :lax },
205
- node: {
206
- hooks: {
207
- before: Hook.noop,
208
- after: Hook.noop
209
- }
210
- },
211
- run: {
212
- hooks: {
213
- start: Hook.noop,
214
- before: Hook.noop,
215
- after: Hook.output,
216
- finish: Hook.summary
217
- }
218
- }
219
- )
220
-
221
- @hooks = CONFIG.node.hooks
222
- @children = []
223
-
224
- def self.inherited(child)
225
- @children << child
226
- child.hooks = @hooks.dup
227
- child.children = []
228
- end
229
-
230
- extend Enumerable
231
-
232
- class << self
233
- attr_accessor :hooks, :children
234
-
235
- def reboot(suppress_warning = true)
236
- (stderr, $stderr = $stderr, StringIO.new) if suppress_warning
237
- Object.const_set :Lax, Class.new(Array)
238
- Lax.const_set :SOURCE, SOURCE
239
- Lax.class_eval SOURCE
240
- ($stderr = stderr) if suppress_warning
241
- Lax
242
- end
243
-
244
- def config
245
- block_given? ? yield(CONFIG) : CONFIG
246
- end
247
-
248
- def matcher(sym, &b)
249
- Target.define_matcher(sym, &b)
250
- end
251
-
252
- def hook(sym, &b)
253
- Hook.define(sym, &b)
254
- end
255
-
256
- def each(&b)
257
- yield self
258
- children.each {|c| c.each(&b)}
259
- end
260
-
261
- def let(h)
262
- h.each do |key, value|
263
- val = value.is_a?(Hook) ? value : ->{value}
264
- define_singleton_method(key) do
265
- Target.new(self, val, key, caller[0])
266
- end
267
- end
268
- end
269
-
270
- def defer(&v)
271
- Hook.new(&v)
272
- end
273
- alias _ defer
274
-
275
- def fix(hash)
276
- Fixture.new(hash)
277
- end
278
-
279
- def assert(*vals, &b)
280
- Class.new(self).tap {|node| node.class_eval(&b)}
281
- end
282
- end
283
-
284
- def initialize
285
- ks = methods - self.class.superclass.instance_methods
286
- ks.map {|k| send k}.each {|k| self << k}
287
- end
288
-
@@ -1,27 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Lax::Fixture::Hashable do
4
- let(:hash) { { name: 'phyllis', fears: { mild: ['spiders'], severe: ['manatees'] } } }
5
- let(:config) { Lax::Fixture::Hashable.new hash }
6
-
7
- describe '::new' do
8
- specify { ->{Lax::Fixture::Hashable.new}.should raise_error ArgumentError }
9
- specify { [:name, :fears].each {|msg| config.should respond_to msg } }
10
- specify { config.name.should == 'phyllis' }
11
- specify { config.fears.should be_a_kind_of Lax::Fixture::Hashable }
12
- end
13
-
14
- describe '#merge' do
15
- subject { config.merge manners: 'impeccable' }
16
- it { should be_a_kind_of Lax::Fixture::Hashable }
17
- specify { subject.name.should == 'phyllis' }
18
- specify { subject.manners.should == 'impeccable' }
19
- specify { subject.fears.should be_a_kind_of Lax::Fixture::Hashable }
20
- end
21
-
22
- describe '#to_hash' do
23
- subject { config.to_hash }
24
- it { should == hash }
25
- end
26
- end
27
-
@@ -1,40 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Lax::Hook do
4
- let(:one) { Lax::Hook.new {1} }
5
- specify { one.should be_a_kind_of Proc }
6
-
7
- describe '#<<' do
8
- let(:doubler) { Lax::Hook.new {|n| 2*n} }
9
- subject { doubler << one }
10
- its(:call) { should == 2 }
11
- end
12
-
13
- describe '#+' do
14
- let(:thing) { Object.new }
15
- let(:hash) { Lax::Hook.new { thing.hash } }
16
- subject { hash + one }
17
- its(:call) { should == 1 }
18
- specify do
19
- thing.should_receive :hash
20
- subject.call
21
- end
22
- end
23
-
24
- describe '::_resolve' do
25
- let(:resolve) { Lax::Hook.method :_resolve }
26
- context 'given a hook' do
27
- let(:hook) { Lax::Hook.new {:surprise!} }
28
- subject { resolve[hook] }
29
- it { should == hook }
30
- end
31
-
32
- context 'given a symbol' do
33
- let(:a_hook) { :noop }
34
- let(:random_sym) { :asdfqwer }
35
- specify { resolve[a_hook].call.should == nil }
36
- specify { -> {resolve[random_sym]}.should raise_error NameError }
37
- end
38
- end
39
- end
40
-
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Lax::Target do
4
- let(:node) { Lax.assert { let num: 1 } }
5
-
6
- describe 'establishing a target' do
7
- subject { node.num }
8
- specify { (Lax::Target === subject).should == true }
9
- specify { subject.__val__.should == 1 }
10
- end
11
-
12
- context 'when specifying a condition' do
13
- before { node.num == 1234 }
14
- specify { node.new.should have(1).thing }
15
- describe 'the entailed assertion' do
16
- subject { node.new.first }
17
- it { should be_an_instance_of Lax::Assertion }
18
- its(:subject) { should be_an_instance_of Proc }
19
- its(:name) { should == :num }
20
- its(:matcher) { should == '==' }
21
- its(:pass?) { should == false }
22
- end
23
- end
24
- end
25
-