anaphoric_case 0.0.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.
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