anaphoric_case 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ report/*
6
+ .yardoc
7
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in anaphoric_case.gemspec
4
+ #
5
+ gem 'rake','0.9.1'
6
+ gem 'pry','0.9.4pre1'
7
+ gem 'rspec'
8
+ gem 'simplecov'
9
+ gem 'rspec-prof'
10
+ gem 'i18n'
11
+ gem 'ruby-debug19'
12
+
13
+ #gemspec
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ #Anaphoric Case
2
+
3
+ Provides an anaphoric if, and anaphoric case-like construct as kernel methods.
4
+
5
+ ###Examples:
6
+
7
+ English: If the dog is on fire, put it out!
8
+
9
+ Ruby: If the dog is on fire, put the dog out!
10
+
11
+ This is all well and good provided dog is a simple reference, but if the dog
12
+ is something more complicated, you wind up either having to do an assign
13
+ in the if condition, or assign to a temporary variable before you extinguish
14
+ Fido.
15
+
16
+ This is similar to the use case for the andand gem. It's especially handy
17
+ when the dog being on fire is not a simple binary condition. If Rin-tin-tin
18
+ can summon help depending upon his dire situation, like if dog.fire also says
19
+ which *part* of the dog is on fire, or where he is drowning at.
20
+
21
+ # Listen for sounds of distress
22
+ if dog.fire
23
+ owner.tell(dog.fire)
24
+ elsif dog.drowning
25
+ owner.tell(dog.drowning)
26
+ elsif dog.hungry
27
+ owner.tell(dog.hungry)
28
+ end
29
+
30
+ An anaphoric if doesn't need to call `dog.fire` again in the executed block.
31
+
32
+ aif(dog.fire) { |it| owner.tell(it) }
33
+
34
+ If you have multiple conditions, you probably want to use the switch/on construct
35
+
36
+ owner.tell(switch do
37
+ on dog.fire
38
+ on dog.drowing
39
+ on dog.hungry
40
+ end)
41
+
42
+ Here, the dog will tell his owner the first condition he encounters. `switch` can
43
+ also behave like a regular case statement (albiet with fallthrough) if you like.
44
+
45
+ switch dog.name do
46
+ on /Rover/ { |it| "Come on over #{it}"}
47
+ on /Fido/ { |it| "Give #{it} a bone"}
48
+ on /Rin-Tin-Tin/ { |it| "#{it} is frequently mistaken for Lassie"}
49
+ end
50
+
51
+ If the switch parameter takes a block, it will be passed into the block as an optional
52
+ block parameter. In addition, the `on` method will yield the parameter object of the
53
+ `switch` method, rather than it's own parameter.
54
+
55
+ If `switch` is called with an explicit receiver, it acts somewhat like `tap` in that the
56
+ block is executed in the context of the receiver.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = FileList['spec/**/*_spec.rb']
9
+ spec.rspec_opts = "-d"
10
+ end
11
+
12
+ RSpec::Core::RakeTask.new(:spec_with_report) do |spec|
13
+ spec.fail_on_error = false
14
+ spec.pattern = FileList['spec/**/*_spec.rb']
15
+ spec.rspec_opts = "--format html --out report/tests/report.html"
16
+ end
17
+
18
+ desc "Run all specs, profile the code, and generate a coverage report"
19
+ task :report do
20
+ Dir.mkdir "report" unless File.exists? "report"
21
+ Dir.mkdir "report/profile" unless File.exists? "report/profile"
22
+ Dir.mkdir "report/tests" unless File.exists? "report/tests"
23
+ File.open "report/index.html","w" do |f|
24
+ f.write <<-HTML
25
+ <html>
26
+ <body>
27
+ <h1> Status Report </h1>
28
+ <p>
29
+ <a href="coverage/index.html"> Coverage </a>
30
+ </p>
31
+ <p>
32
+ <a href="profile/profile.graph.html"> Graph Speed Profile </a><br/>
33
+ <a href="profile/profile.stack.html"> Speed Profile </a>
34
+ </p>
35
+ <p>
36
+ <a href="test/report.html"> Test Report </a>
37
+ </p>
38
+ </body>
39
+ </html>
40
+ HTML
41
+ end
42
+ ENV["REPORT"] = "1"
43
+ Rake::Task[:spec_with_report].invoke
44
+ ENV["REPORT"] = ""
45
+ end
46
+
47
+ desc "Delete the report directory"
48
+ task :clear_report do
49
+ `rm -rf report`
50
+ end
51
+
52
+ task :default => :spec
53
+
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "anaphoric_case/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "anaphoric_case"
7
+ s.version = AnaphoricCase::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Stephen Prater"]
10
+ s.email = ["me@stephenprater.com"]
11
+ s.homepage = "http://github.com/stephenprater/anaphoric_case"
12
+ s.summary = %q{Provides a simple anaphoric case statement (called "switch/on")}
13
+ s.description = %q{You have twenty or so methods, and you want to call the first one that returns something other than nil,
14
+ If the dog is on fire, put it out.}
15
+
16
+ s.rubyforge_project = "anaphoric_case"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.require_paths = ["lib"]
21
+
22
+
23
+ s.add_development_dependency('rspec')
24
+ s.add_development_dependency('simplecov')
25
+ s.add_development_dependency('rspec-prof')
26
+ s.add_development_dependency('i18n')
27
+ end
@@ -0,0 +1,3 @@
1
+ module AnaphoricCase
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,137 @@
1
+ require 'pry'
2
+
3
+ module AnaphoricCase
4
+ @__nest = 0
5
+ class << self
6
+ # @private
7
+ attr_accessor :__nest
8
+
9
+ def switch_stack
10
+ Thread.current[:__switch_stack] ||= []
11
+ end
12
+ end
13
+ end
14
+
15
+ module Kernel
16
+ # aif - anaphoric if.
17
+ #
18
+ # English is nice, in that if you want to make a conditional, you can say
19
+ # "if the dog is on fire, then put it out!" to say the equivalent thing in Ruby
20
+ # you say "if the dog is on fire, then put the dog out." - which is fine, if something
21
+ # of a hassle sometimes. The "it" in the first example is an anaphor -
22
+ #
23
+ # @param [Object] result - any object, although it generally take the form of an expression.
24
+ # @return [Object, FalseClass] returns the results of the block if the paramater was
25
+ # truthy (ie, it wasn't `nil` or `false`) or FalseClass if it wasn't
26
+ # @yield [Object] yields the parameter into a block if it's truthy, the block can optionally return
27
+ # a different value, which will become the return value of #aif
28
+ def aif result = true, &block
29
+ if result
30
+ unless block.nil? then result = block.call(*[result].slice(0,block.arity)) end
31
+ return result
32
+ end
33
+ false
34
+ end
35
+
36
+ # switch - anaphoric case construct
37
+ #
38
+ # this is basically a form of sugar over a whole list of || operators or +or+ statements
39
+ # @example
40
+ # thing = switch do
41
+ # on object.quick_method_that_might_return_nil
42
+ # on object.medium_method_that_might_return_nil
43
+ # on object.slow_method_that_might_return_nil
44
+ # on { raise 'everything returned nil!' }
45
+ # end
46
+ # # thing will be equal to results of the first method that
47
+ # # didn't return nil
48
+ #
49
+ # This prevents you from either writing a difficult to read list of || operators, or
50
+ # having to construct lazily evaluated list of methods and parameters in order to do
51
+ # the cheapest thing.
52
+ # @param [Object] object -
53
+ # parameter of all +on+ calls will be compared to this object using +===+
54
+ # @yield A block during which the +on+ method will be available - the block is required.
55
+ # The block is always executed in the context of the receiver of the +switch+ method
56
+ # so most of the time this is +self+ but if you call +switch+ with an explicit receiver
57
+ # it acts somewhat like the {Object#tap} method
58
+ # @raise [ArgumentError] I tried to tell you the callable or block was required
59
+ # @return [Object, FalseClase] the results of the first call to +on+ that returned
60
+ # anything truthy, or of its block
61
+ def switch object = nil, &block
62
+ block = block.dup # enable cross thread sharing of blocks
63
+
64
+ AnaphoricCase.__nest += 1
65
+
66
+ raise ArgumentError, "switch requires a block" unless block_given?
67
+
68
+ class << self
69
+ def on result = true, &block
70
+ # the current switch block in this thread
71
+ it = AnaphoricCase.switch_stack.last.instance_eval { @it }
72
+
73
+ begin
74
+ if it and (result === it or result == true)
75
+ result = Kernel.aif it, &block
76
+ throw :result, result if result
77
+ elsif result and not it
78
+ result = Kernel.aif result, &block
79
+ throw :result, result if result
80
+ end
81
+ rescue ArgumentError => e
82
+ if e.message =~ /throw :result/
83
+ raise NameError, "on without associated switch"
84
+ else
85
+ raise e
86
+ end
87
+ end
88
+ false
89
+ end
90
+ end
91
+
92
+ block.instance_eval do
93
+ @it = object
94
+ end
95
+ AnaphoricCase.switch_stack << block
96
+
97
+ res = catch :result do
98
+ if block.arity > 0
99
+ self.instance_exec(object, &block)
100
+ else
101
+ self.instance_eval(&block)
102
+ end
103
+ end
104
+ res ? res : false
105
+
106
+ ensure
107
+ AnaphoricCase.__nest -= 1
108
+ Thread.current[:__switch_stack].pop if object
109
+ if AnaphoricCase.__nest == 0
110
+ class << self
111
+ #you can get here without the on method being defined,
112
+ #so rescue this silently if so.
113
+ remove_method :on rescue nil
114
+ end
115
+ end
116
+ end
117
+
118
+ # on
119
+ #
120
+ # the +on+ method is available only in the {#switch} block - it basically
121
+ # functions exactly like the aif method.
122
+ #
123
+ # The first +on+ method whose argument is truthy will execute it's block and
124
+ # cause switch to return the value of the block.
125
+ # @see #aif
126
+ # @see #switch
127
+ # @param [Object] result - any object, normally an expression
128
+ # it defaults to true, so you can use an +on+ without an argument as a default clause
129
+ # @raise [NameError] if called from outside of a switch block or across
130
+ # the stack rewinding barrier
131
+ # @yield [Object] yields the parameter into the block, which can optionally
132
+ # return a different value. <br/> if the block of an +on+ returns +nil+ or +false+,
133
+ # evaluation will continue at the next call to +on+. If the block is ommitted
134
+ # the parameter passed to +on+ will be returned (by {#switch})
135
+ def on result=true; super; end
136
+ remove_method :on
137
+ end
@@ -0,0 +1,454 @@
1
+ require 'spec_helper'
2
+
3
+ require 'anaphoric_case'
4
+ require 'timeout'
5
+
6
+ describe "it is an anaphoric case" do
7
+
8
+ before :all do
9
+ class Harness
10
+ def initialize
11
+ @array = [1,2,3,4,5]
12
+ @hash = { :bacon => "cheese", :pie => "sky", :snoopy => "pizza" }
13
+ @string = "That is quite a mustache you've got there, sheriff."
14
+ @snitch = 0
15
+ end
16
+
17
+ def count
18
+ @array
19
+ end
20
+
21
+ def flavors thing
22
+ @hash[thing]
23
+ end
24
+
25
+ def compliment
26
+ @string
27
+ end
28
+
29
+ def snitch
30
+ @snitch
31
+ end
32
+
33
+ def narc
34
+ @snitch += 1
35
+ if @string == "I committed regicide"
36
+ true
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ def cover_evidence
43
+ @string = "I committed regicide"
44
+ false
45
+ end
46
+ end
47
+ end
48
+
49
+ before :each do
50
+ @test = Harness.new
51
+ end
52
+
53
+ profile :all do
54
+
55
+ it "provides a simple aif method" do
56
+ res = nil
57
+ aif(5 + 4) { |it| res = it }
58
+ res.should == 9
59
+
60
+ res = nil
61
+ res = aif(5 + 4) { 'okay!' }
62
+ res.should == 'okay!'
63
+
64
+ res = aif(5 < 4) { 'monkey' }
65
+ res.should == false
66
+ end
67
+
68
+ it "should return the first object which is truthy" do
69
+ res = switch do
70
+ on 1
71
+ on false
72
+ on nil
73
+ end
74
+ res.should == 1
75
+
76
+ res = switch do
77
+ on false
78
+ on 2
79
+ on nil
80
+ end
81
+
82
+ res.should == 2
83
+
84
+ res = switch do
85
+ on false
86
+ on nil
87
+ on :bob
88
+ end
89
+ res.should == :bob
90
+
91
+ res = switch do
92
+ on false
93
+ on [1,2,3,4,5]
94
+ end
95
+ res.should == [1,2,3,4,5]
96
+
97
+ end
98
+
99
+ it "is lazy" do
100
+ res = switch do
101
+ on @test.narc
102
+ on @test.cover_evidence
103
+ on @test.narc
104
+ on @test.compliment
105
+ end
106
+ res.should == true
107
+ @test.snitch.should == 2
108
+ end
109
+
110
+ it "can execute anaphoric blocks using on" do
111
+ res = switch do
112
+ on(false) { |it| it.blah_blah } #this would raise an error if it was ever called
113
+ on(1) { |it| it + 1 }
114
+ end
115
+ res.should == 2
116
+ end
117
+
118
+ it "can have an else clause by way of on with no parameters" do
119
+ res = switch do
120
+ on false
121
+ on nil
122
+ on { 5 }
123
+ end
124
+ res.should == 5
125
+
126
+ res = switch do
127
+ on 1
128
+ on { 1 }
129
+ end
130
+ res.should == 1
131
+ end
132
+
133
+ it "on blocks which return falsey cause evaulation to continue" do
134
+ res = switch do
135
+ on { nil }
136
+ on { :turtle }
137
+ end
138
+ res.should == :turtle
139
+ end
140
+
141
+ it "can execute within an object" do
142
+ test_test = proc do
143
+ switch do
144
+ on(count.length > 5) { count }
145
+ on(count.length < 5) { count }
146
+ on(count.length == 5) { :five }
147
+ end
148
+ end
149
+
150
+ @test.instance_eval(&test_test).should == :five
151
+ @test.count.slice!(0,3)
152
+ @test.instance_eval(&test_test).should == [4,5]
153
+ @test.count.concat [1,1,1,1]
154
+ @test.instance_eval(&test_test).should == [4,5,1,1,1,1]
155
+ end
156
+
157
+ it "can look in an object if it's not within it" do
158
+ res = switch do
159
+ on(@test.flavors :lime)
160
+ on(@test.flavors :snoopy)
161
+ on(@test.flavors :mushrooms)
162
+ end
163
+ res.should == "pizza"
164
+ end
165
+
166
+ it "can't call on from outside of switch block" do
167
+ lambda { on }.should raise_error NameError
168
+
169
+ # ensure the on method is defined the next time
170
+ # we call it
171
+ flag = false
172
+ t1 = Thread.new do
173
+ switch do
174
+ on false
175
+ flag = true
176
+ sleep 0.1
177
+ on true
178
+ end
179
+ flag = false
180
+ end
181
+
182
+ Timeout.timeout(1) { loop until flag == true }
183
+
184
+ # should transform the uncaught :throw error into a NameError
185
+ (self.respond_to? :on).should be true #it's defined in the thread
186
+ lambda { on }.should raise_error NameError, "on without associated switch"
187
+
188
+ loop until flag == false
189
+ (self.respond_to? :on).should be false
190
+ lambda { on }.should raise_error NameError
191
+ end
192
+
193
+ it "can raise past the (internal) throw" do
194
+ lambda do
195
+ switch do
196
+ on { |a,b,c| raise ArgumentError }
197
+ end
198
+ end.should raise_error ArgumentError
199
+ end
200
+
201
+ it "can nest safely" do
202
+ res = switch do
203
+ on(@test.compliment =~ /mustache/) do |it|
204
+ switch do
205
+ on(@test.compliment =~ /baron/) { "The Barons Mustache"}
206
+ on(@test.compliment =~ /sheriff/) { "The Sheriff's Mustache" }
207
+ end
208
+ end
209
+ on(@test.count == 5)
210
+ end
211
+ res.should == "The Sheriff's Mustache"
212
+
213
+ res = switch do
214
+ on do |it|
215
+ switch do
216
+ on { nil }
217
+ end
218
+ end
219
+ on { 5 }
220
+ end
221
+ res.should == 5
222
+ end
223
+
224
+ it "can be called with explicit receiver" do
225
+ # this makes it act a little bit like "tap"
226
+ res = @test.switch do
227
+ on (flavors :lime) { |it| it.blah } #would raise
228
+ on (flavors :snoopy)
229
+ on { raise 'terribly awry'}
230
+ end
231
+
232
+ res.should == "pizza"
233
+ end
234
+
235
+ it "can act like a regular case statement if called with a parameter" do
236
+ test = lambda do |test_obj|
237
+ res = switch test_obj do
238
+ on(/baron/) { |it| "'#{it.chomp('.')},' said the queen."}
239
+ on(/sheriff/) { |it| "'#{it.chomp('.')},' I said."}
240
+ on
241
+ end
242
+ end
243
+
244
+ test.call("That's a nice mustache sheriff.").should == "'That's a nice mustache sheriff,' I said."
245
+ test.call("That's a nice mustache baron.").should == "'That's a nice mustache baron,' said the queen."
246
+ test.call("I hate mustache's").should == "I hate mustache's"
247
+ end
248
+
249
+ it "can act like a regular case statement nested" do
250
+ remember = @test.compliment.dup
251
+ res = switch @test.compliment do
252
+ on /sheriff/ do |it|
253
+ # its is @test.compliment
254
+ switch it do
255
+ #it is STILL @test.compliment
256
+ on(/mustache/) { |thing| false }
257
+ #return false to fall through
258
+ end
259
+ end
260
+ # here it should STILL be @test.compliment
261
+ # which means this should NOT match
262
+ on(/baron/) { |it| it.blah }
263
+ # but this should.
264
+ on(/sheriff/) { |it| it + "okay" }
265
+ end
266
+ res.should == remember + "okay"
267
+ end
268
+
269
+ it "can be called both with and without a parameter" do
270
+ res = switch do
271
+ # there is no default __it__
272
+ on @test.compliment =~ /sheriff/ do |it|
273
+ # it here is "43" the place where sheriff occures
274
+ switch it do |ot|
275
+ on(ot > 43) { raise 'ohnoes' }
276
+ on(ot < 43) { raise 'ohnoes again'}
277
+ # this will signal completion
278
+ on(ot == 43) { 'okay!' }
279
+ end
280
+ end
281
+ # so this will not run
282
+ on(@test.compliment =~ /baron/) { |it| it.blah }
283
+ end
284
+
285
+ res.should == 'okay!'
286
+
287
+ res = switch @test.compliment do
288
+ # this will match
289
+ on /mustache/ do |it|
290
+ switch do
291
+ # this should not match, but it's truthy
292
+ on /poor/
293
+ end
294
+ end
295
+ end
296
+
297
+ #so the result of the entire block is the last truthy thing
298
+ res.should == /poor/
299
+
300
+ res = switch @test.compliment do
301
+ on /mustache/ do |it|
302
+ # this will CLOSE around it.
303
+ switch do
304
+ on(it =~ /sheriff/) { 'yes it is' }
305
+ on true
306
+ end
307
+ end
308
+ on(/baron/) { true }
309
+ end
310
+ res.should == 'yes it is'
311
+
312
+
313
+ # can switch eval contexts each time
314
+
315
+ res = switch "this" do
316
+ on /this/ do
317
+ switch "that" do
318
+ on /that/ do
319
+ switch "thing" do
320
+ on /thing/ do
321
+ "foogle bear"
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end
328
+
329
+ res.should == "foogle bear"
330
+ end
331
+
332
+ it "nests in threads" do
333
+ res1, res2 = nil,nil
334
+
335
+ t1 = Thread.new do
336
+ res1 = switch "this" do
337
+ on /this/ do
338
+ switch "that" do
339
+ on(/that/) { "that" }
340
+ end
341
+ end
342
+ end
343
+ end
344
+
345
+ t2 = Thread.new do
346
+ res2 = switch "weasel" do
347
+ on /weasel/ do
348
+ switch "monkey" do
349
+ on(/monkey/) { "monkey" }
350
+ end
351
+ end
352
+ end
353
+ end
354
+
355
+ Timeout.timeout 1 do
356
+ loop do
357
+ t = [t1.status, t2.status]
358
+ t.delete(false)
359
+ break if t.empty?
360
+ end
361
+ end
362
+
363
+ res1.should == "that"
364
+ res2.should == "monkey"
365
+ end
366
+
367
+ it "reusing blocks with params works across threads" do
368
+ thing = proc do
369
+ on(/Pestilence/) { |it| sleep 0.1; "#{it} made you cough." } #yep, mess it up
370
+ on(/Death/) { |it| "#{it} killed you." }
371
+ on(/Famine/) { |it| "#{it} made you hungry."}
372
+ on(/War/) { |it| "#{it} was loud." }
373
+ end
374
+
375
+ res1 = switch "War in Iraq", &thing
376
+ res1.should == "War in Iraq was loud."
377
+
378
+ res2, res3,res4 = nil, nil, nil
379
+
380
+ t1 = Thread.new do
381
+ res2 = switch "Famine in Ireland", &thing
382
+ end
383
+
384
+ t2 = Thread.new do
385
+ res3 = switch "Death at a Funeral", &thing
386
+ end
387
+
388
+ t3 = Thread.new do
389
+ res4 = switch "Pestilence at the presschool", &thing
390
+ end
391
+
392
+ Timeout.timeout 1 do
393
+ loop do
394
+ t = [t1.status, t2.status, t3.status]
395
+ t.delete(false)
396
+ break if t.empty?
397
+ end
398
+ end
399
+
400
+ res2.should == "Famine in Ireland made you hungry."
401
+ res3.should == "Death at a Funeral killed you."
402
+ res4.should == "Pestilence at the presschool made you cough."
403
+ end
404
+
405
+ it "threads?" do
406
+ res1, res2, res3 = nil, nil, nil
407
+
408
+ t1 = Thread.new do
409
+ res1 = switch do
410
+ on(@test.flavors :lime)
411
+ on(@test.flavors :snoopy)
412
+ on(@test.flavors :bacon)
413
+ end
414
+ end
415
+
416
+ t2 = Thread.new do
417
+ res2 = switch do
418
+ on(@test.count.length == 6)
419
+ on(@test.count.length == 5) { @test.count }
420
+ end
421
+ end
422
+
423
+ # this is designed to make sure it running after the first two
424
+ # finish. if switch isn't thread safe, the last
425
+ # call to on will raise NoMethodError
426
+ t3 = Thread.new do
427
+ res3 = switch do
428
+ on false
429
+ on nil
430
+ sleep 0.1
431
+ on true
432
+ end
433
+ end
434
+
435
+ Timeout.timeout 1 do
436
+ loop do
437
+ t = [t1.status, t2.status, t3.status]
438
+ t.delete(false)
439
+ break if t.empty?
440
+ end
441
+ end
442
+
443
+ res1.should == "pizza"
444
+ res2.should == [1,2,3,4,5]
445
+ res3.should == true
446
+ end
447
+ end
448
+ end
449
+
450
+
451
+
452
+
453
+
454
+
@@ -0,0 +1,85 @@
1
+ if ENV["REPORT"] == "1" then
2
+ require 'simplecov'
3
+ require 'ruby-prof'
4
+ require 'rspec-prof'
5
+ require 'ruby-debug'
6
+
7
+ SimpleCov.start do
8
+ add_filter "/spec.rb/"
9
+ coverage_dir "report/coverage"
10
+ end
11
+
12
+ class RSpecProf::Profiler
13
+ def initialize options
14
+ @options = default_options.merge(options)
15
+ ENV["RUBY_PROF_MEASURE_MODE"] = options[:measure_mode]
16
+ RubyProf.figure_measure_mode
17
+ STDOUT.puts "initi"
18
+ end
19
+
20
+ alias :old_default :default_options
21
+ def default_options
22
+ old = old_default
23
+ old.merge({
24
+ :directory => './report/profile',
25
+ :printer => RubyProf::GraphHtmlPrinter,
26
+ :stop_block => proc do |result|
27
+ #remove every Rspec method possible.
28
+ result.threads.each do |thread_id, methods|
29
+ begin
30
+ match = /RSpec.*?/
31
+ i = 0
32
+ while i < methods.size
33
+ mi = methods[i]
34
+ method_name = mi.full_name
35
+ if method_name =~ /RSpec.*?/
36
+ (i += 1; next) if mi.root?
37
+ methods.delete_at(i)
38
+ mi.eliminate!
39
+ else
40
+ i += 1
41
+ end
42
+ end
43
+ end
44
+ end
45
+ result
46
+ end
47
+ })
48
+ end
49
+
50
+ def stop
51
+ file = options[:file] + ".html"
52
+ result = RubyProf.stop
53
+ printer_class = options[:printer]
54
+
55
+ with_io(file) do |out|
56
+ if @options[:stop_block].respond_to? :call
57
+ result = @options[:stop_block].call(result)
58
+ end
59
+ printer = printer_class.new(result)
60
+ printer.print(out, :print_file => options[:print_file], :min_percent => options[:min_percent])
61
+ end
62
+ end
63
+ end
64
+
65
+ RSpec.configure do |config|
66
+ config.around :each do |example|
67
+ STDOUT.puts example.metadata[:description]
68
+ example.run
69
+ end
70
+ end
71
+ else
72
+ module EmptyProfile
73
+ def profile *args
74
+ yield
75
+ end
76
+ end
77
+
78
+ RSpec.configure do |config|
79
+ config.extend EmptyProfile
80
+ end
81
+ end
82
+
83
+ # Requires supporting files with custom matchers and macros, etc,
84
+ # in ./support/ and its subdirectories.
85
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: anaphoric_case
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stephen Prater
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-15 00:00:00.000000000 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: &4006280 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *4006280
26
+ - !ruby/object:Gem::Dependency
27
+ name: simplecov
28
+ requirement: &4006070 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *4006070
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec-prof
39
+ requirement: &4005860 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *4005860
48
+ - !ruby/object:Gem::Dependency
49
+ name: i18n
50
+ requirement: &4005650 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *4005650
59
+ description: ! "You have twenty or so methods, and you want to call the first one
60
+ that returns something other than nil,\n If the dog is on fire, put it out."
61
+ email:
62
+ - me@stephenprater.com
63
+ executables: []
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - .gitignore
68
+ - Gemfile
69
+ - README.md
70
+ - Rakefile
71
+ - anaphoric_case.gemspec
72
+ - lib/anaphoric_case.rb
73
+ - lib/anaphoric_case/version.rb
74
+ - spec/anaphoric_case_spec.rb
75
+ - spec/spec_helper.rb
76
+ has_rdoc: true
77
+ homepage: http://github.com/stephenprater/anaphoric_case
78
+ licenses: []
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project: anaphoric_case
97
+ rubygems_version: 1.5.2
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: Provides a simple anaphoric case statement (called "switch/on")
101
+ test_files:
102
+ - spec/anaphoric_case_spec.rb
103
+ - spec/spec_helper.rb