pry-em 0.1.1 → 0.2.0

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.
Files changed (2) hide show
  1. data/lib/pry-em.rb +88 -38
  2. metadata +12 -10
data/lib/pry-em.rb CHANGED
@@ -1,45 +1,84 @@
1
1
  EmCommands = Pry::CommandSet.new do
2
2
 
3
- EM_DESCRIPTION = "Wait for a deferrable for a length of time (default 3 seconds). `em 3: EM::HttpRequest.new(url).get`"
4
- EM_CONFIG = {
5
- :keep_retval => true,
6
- :interpolate => false,
7
- :listing => "em",
8
- :requires_gem => 'eventmachine'
9
- }
10
-
11
- command /\s*em\s*([0-9\.]*)\s*:(.*)/, EM_DESCRIPTION, EM_CONFIG do |timeout, source|
12
-
13
- # Boot EM before eval'ing the source as it's likely to depend on the reactor.
14
- run_em_if_necessary!
15
-
16
- # This can happen for example if you do:
17
- # em: EM::HttpRequest.new("http://www.google.com/").get.callback{ binding.pry }
18
- # There ought to be a solution, but it will involve shunting either Pry or EM
19
- # onto a new thread.
20
- if EM.reactor_thread == Thread.current
21
- raise "Could not wait for deferrable, you're in the EM thread!
22
- If you don't know what to do, try `cd ..`, or just hit ctrl-C until it dies."
23
- end
3
+ create_command /\s*em\s*([0-9\.]*)\s*:(.*)/ do
24
4
 
25
- deferrable = target.eval(source)
5
+ description "Wait for a deferrable for a length of time (default 3 seconds). `em 3: EM::HttpRequest.new(url).get`"
6
+ options(
7
+ :keep_retval => true,
8
+ :interpolate => false,
9
+ :listing => "em",
10
+ :requires_gem => 'eventmachine'
11
+ )
26
12
 
27
- # TODO: Allow the user to configure the default timeout
28
- timeout = timeout == "" ? 3 : Float(timeout)
13
+ def process(timeout, source)
14
+ # We store the retval and the em-state in globals so that we can catch exceptions
15
+ # raised in the event loop and pass them back pretending to the user that the
16
+ # exception was caused by their currently executing command.
17
+ #
18
+ # We don't want to keep turning the reactor on and off, as that would limit some
19
+ # of the things the user might want to do.
20
+ @@retval, @@em_state = [nil, :waiting]
29
21
 
30
- wait_for_deferrable(deferrable, timeout) unless deferrable.nil?
31
- end
22
+ # Boot EM before eval'ing the source as it's likely to depend on the reactor.
23
+ run_em_if_necessary!
24
+
25
+ # This can happen for example if you do:
26
+ # em: EM::HttpRequest.new("http://www.google.com/").get.callback{ binding.pry }
27
+ # There ought to be a solution, but it will involve shunting either Pry or EM
28
+ # onto a new thread.
29
+ if EM.reactor_thread == Thread.current
30
+ raise "Could not wait for deferrable, you're in the EM thread!
31
+ If you don't know what to do, try `cd ..`, or just hit ctrl-C until it dies."
32
+ end
33
+
34
+ deferrable = target.eval(source)
35
+
36
+ # TODO: Allow the user to configure the default timeout
37
+ timeout = timeout == "" ? 3 : Float(timeout)
38
+
39
+ wait_for_deferrable(deferrable, timeout) unless deferrable.nil?
40
+ end
32
41
 
33
- helpers do
34
42
  # Boot a new EventMachine reactor into another thread.
35
43
  # This allows us to continue to interact with the user on the front-end thread,
36
44
  # while they run event-machine commands in the background.
37
45
  def run_em_if_necessary!
38
46
  require 'eventmachine' unless defined?(EM)
39
- Thread.new{ EM.run } unless EM.reactor_running?
47
+ unless EM.reactor_running?
48
+ Thread.new do
49
+ EM.error_handler{ |e| handle_unexpected_error(e) }
50
+ begin
51
+ EM.run
52
+ rescue Pry::RescuableException => e
53
+ handle_unexpected_error(e)
54
+ end
55
+ end
56
+ end
40
57
  sleep 0.01 until EM.reactor_running?
41
58
  end
42
59
 
60
+ # If we were the ones to start the EM reactor, we want to catch
61
+ # any exceptions that are raised therein and tell the user about
62
+ # them.
63
+ #
64
+ # If they are still waiting for an async event, assume that this
65
+ # was in relation to that.
66
+ #
67
+ # If not, just print out the error and hope they don't get too
68
+ # confused.
69
+ def handle_unexpected_error(e)
70
+ if waiting?
71
+ @@em_state = :em_error
72
+ @@retval = e
73
+ else
74
+ output.puts "Unexpected exception from EventMachine reactor"
75
+ _pry_.last_exception = e
76
+ _pry_.show_result(e)
77
+ end
78
+ rescue => e
79
+ puts e
80
+ end
81
+
43
82
  # Run a deferrable on an EM reactor in a different thread,
44
83
  # sleep until it has finished, and then return the result.
45
84
  #
@@ -50,29 +89,40 @@ EmCommands = Pry::CommandSet.new do
50
89
  #
51
90
  def wait_for_deferrable(deferrable, timeout)
52
91
 
53
- retval, finished = nil
54
-
55
- EM::Timer.new(timeout) { finished ||= :timeout }
92
+ EM::Timer.new(timeout) { @@em_state = :timeout if waiting? }
56
93
 
57
94
  [:callback, :errback].each do |method|
58
95
  begin
59
96
  deferrable.__send__ method do |*result|
60
- finished = method
61
- retval = result.size > 1 ? result : result.first
97
+ @@em_state = method
98
+ @@retval = result.size > 1 ? result : result.first
62
99
  end
63
100
  rescue NoMethodError
64
- output.warn "WARNING: is not deferrable? #{deferrable}"
101
+ output.puts "WARNING: is not deferrable? #{deferrable}"
65
102
  break
66
103
  end
67
104
  end
68
105
 
69
- sleep 0.01 until finished
106
+ sleep 0.01 until @@em_state != :waiting
107
+
108
+ raise "Timeout after #{timeout} seconds" if @@em_state == :timeout
70
109
 
71
- raise "Timeout after #{timeout} seconds" if finished == :timeout
110
+ # Use Pry's (admittedly nascent) handling for exceptions where possible.
111
+ raise @@retval if @@em_state != :callback && Exception === @@retval
72
112
 
73
113
  # TODO: This doesn't interact well with the pager.
74
- output.print "#{finished} " #=>
75
- retval
114
+ output.print "#{@@em_state} " #=>
115
+ @@retval
116
+
117
+ # If the main thread is interrupted we must ensure that the @@em_state
118
+ # is no-longer :waiting so that handle_unexpected_error can do the
119
+ # right thing.
120
+ ensure
121
+ @@em_state = :interrupted if waiting?
122
+ end
123
+
124
+ def waiting?
125
+ @@em_state == :waiting
76
126
  end
77
127
  end
78
128
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-em
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
5
- prerelease:
4
+ hash: 23
5
+ prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Conrad Irwin
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-07-24 00:00:00 -07:00
18
+ date: 2012-02-24 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -24,12 +24,14 @@ dependencies:
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - ">="
27
+ - - ">"
28
28
  - !ruby/object:Gem::Version
29
- hash: 3
29
+ hash: 43
30
30
  segments:
31
31
  - 0
32
- version: "0"
32
+ - 9
33
+ - 8
34
+ version: 0.9.8
33
35
  type: :runtime
34
36
  version_requirements: *id001
35
37
  - !ruby/object:Gem::Dependency
@@ -88,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
90
  requirements: []
89
91
 
90
92
  rubyforge_project:
91
- rubygems_version: 1.6.2
93
+ rubygems_version: 1.3.7
92
94
  signing_key:
93
95
  specification_version: 3
94
96
  summary: Provides an em! function that can be used to play with deferrable more easily.