Skip to content

Commit

Permalink
Fixes #42 - Rails 4.2 beta has deprecated capture
Browse files Browse the repository at this point in the history
Thanks @cupakromer for this fix re-implementing `capture` now that Rails 4.2 has made it private.
  • Loading branch information
alexrothenberg committed Aug 21, 2014
1 parent 3df1f23 commit b85760a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 3 deletions.
1 change: 1 addition & 0 deletions lib/ammeter/init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'ammeter/rspec/rspec_2_compatibility' # if rspec2
end
require 'rails'
require 'ammeter/output_capturer.rb'
require 'ammeter/rspec/generator/example.rb'
require 'ammeter/rspec/generator/matchers.rb'

Expand Down
40 changes: 40 additions & 0 deletions lib/ammeter/output_capturer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module Ammeter
class OutputCapturer
# Is this thread safe!?!?

This comment has been minimized.

Copy link
@mikegee

mikegee Aug 29, 2014

No, its not. I have a script to prove it but I'm not sure it matters. Does it matter?

A thread-safe version might fork a subprocess to invoke the block. I don't have a working implementation yet, and I'm not sure its worth the overhead.

This comment has been minimized.

Copy link
@mikegee

mikegee Aug 29, 2014

The mentioned script, if you're curious:

require 'thread'
require 'stringio'
require_relative 'lib/ammeter/output_capturer'

q = Queue.new

captured = ''

t = Thread.new do
  captured << Ammeter::OutputCapturer.capture(:stdout) do
    q << :in_capture
    sleep
    puts 'expected'
    q << :leaving_capture
  end
end

q.pop
puts 'extra'
t.wakeup
q.pop

fail 'Not threadsafe!' if captured.include? 'extra'

This comment has been minimized.

Copy link
@cupakromer

cupakromer Aug 29, 2014

Contributor

Thanks for the feedback @mikegee. I'm not sure if it matters for ammeter, but rspec uses a similar technique and it does matter there. Ref rspec/rspec-expectations#642

# This won't work with sub-processes
def self.capture(io, &block)
case io
when :stdout
capture_stdout(&block)
when :stderr
capture_stderr(&block)
else
raise "Unknown IO #{io}"
end
end

def self.capture_stdout(&block)
captured_stream = StringIO.new

orginal_io, $stdout = $stdout, captured_stream

block.call

captured_stream.string
ensure
$stdout = orginal_io
end

def self.capture_stderr(&block)
captured_stream = StringIO.new

orginal_io, $stderr = $stderr, captured_stream

block.call

captured_stream.string
ensure
$stderr = orginal_io
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module GeneratorExampleGroup
extend ActiveSupport::Concern
include ::RSpec::Rails::RailsExampleGroup

DELEGATED_METHODS = [:capture, :destination_root, :current_path, :generator_class]
DELEGATED_METHODS = [:destination_root, :current_path, :generator_class]
module ClassMethods
mattr_accessor :test_unit_test_case_delegate
delegate :default_arguments, :to => :'self.test_unit_test_case_delegate'
Expand Down Expand Up @@ -44,12 +44,12 @@ def generator(given_args=self.default_arguments, config={})
end

def run_generator(given_args=self.default_arguments, config={})
capture(:stdout) { generator(given_args, config).invoke_all }
OutputCapturer.capture(:stdout) { generator(given_args, config).invoke_all }
end
end

def invoke_task name
capture(:stdout) { generator.invoke_task(generator_class.all_tasks[name.to_s]) }
OutputCapturer.capture(:stdout) { generator.invoke_task(generator_class.all_tasks[name.to_s]) }
end

included do
Expand Down

0 comments on commit b85760a

Please # to comment.