Class: Processing::Watcher
- Inherits:
-
Object
- Object
- Processing::Watcher
- Defined in:
- lib/ruby-processing/runners/watch.rb
Overview
A sketch loader, observer, and reloader, to tighten the feedback between code and effect.
Instance Method Summary collapse
-
#initialize ⇒ Watcher
constructor
Sic a new Processing::Watcher on the sketch.
-
#record_state_of_ruby ⇒ Object
Do the best we can to take a picture of the current Ruby interpreter.
-
#recursively_remove_constants(base, constant_names) ⇒ Object
Used to clean up declared constants in code that needs to be reloaded.
-
#report_errors ⇒ Object
Convenience function to report errors when loading and running a sketch, instead of having them eaten by the thread they are loaded in.
-
#rewind_to_recorded_state ⇒ Object
Try to go back to the recorded Ruby state.
-
#start_watching ⇒ Object
Kicks off a thread to watch the sketch, reloading Ruby-Processing and restarting the sketch whenever it changes.
-
#wipe_out_current_app! ⇒ Object
Used to completely remove all traces of the current sketch, so that it can be loaded afresh.
Constructor Details
#initialize ⇒ Watcher
Sic a new Processing::Watcher on the sketch
10 11 12 13 14 15 16 |
# File 'lib/ruby-processing/runners/watch.rb', line 10 def initialize @file = SKETCH_PATH @time = Time.now # Doesn't work well enough for now. # record_state_of_ruby start_watching end |
Instance Method Details
#record_state_of_ruby ⇒ Object
Do the best we can to take a picture of the current Ruby interpreter. For now, this means top-level constants and loaded .rb files.
74 75 76 77 78 79 |
# File 'lib/ruby-processing/runners/watch.rb', line 74 def record_state_of_ruby @saved_constants = Object.send(:constants).dup @saved_load_paths = $LOAD_PATH.dup @saved_features = $LOADED_FEATURES.dup @saved_globals = Kernel.global_variables.dup end |
#recursively_remove_constants(base, constant_names) ⇒ Object
Used to clean up declared constants in code that needs to be reloaded.
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/ruby-processing/runners/watch.rb', line 103 def recursively_remove_constants(base, constant_names) constants = constant_names.map {|name| base.const_get(name) } constants.each_with_index do |c, i| java_obj = Java::JavaLang::Object constants[i] = constant_names[i] = nil if c.respond_to?(:ancestors) && c.ancestors.include?(java_obj) constants[i] = nil if !c.is_a?(Class) && !c.is_a?(Module) end constants.each {|c| recursively_remove_constants(c, c.constants) if c } constant_names.each {|name| base.send(:remove_const, name.to_sym) if name } end |
#report_errors ⇒ Object
Convenience function to report errors when loading and running a sketch, instead of having them eaten by the thread they are loaded in.
42 43 44 45 46 47 48 |
# File 'lib/ruby-processing/runners/watch.rb', line 42 def report_errors yield rescue Exception => e puts "Exception occured while running sketch #{File.basename SKETCH_PATH}:" puts e.to_s puts e.backtrace.join("\n") end |
#rewind_to_recorded_state ⇒ Object
Try to go back to the recorded Ruby state.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/ruby-processing/runners/watch.rb', line 83 def rewind_to_recorded_state new_constants = Object.send(:constants).reject {|c| @saved_constants.include?(c) } new_load_paths = $LOAD_PATH.reject {|p| @saved_load_paths.include?(p) } new_features = $LOADED_FEATURES.reject {|f| @saved_features.include?(f) } new_globals = Kernel.global_variables.reject {|g| @saved_globals.include?(g) } Processing::App.recursively_remove_constants(Object, new_constants) new_load_paths.each {|p| $LOAD_PATH.delete(p) } new_features.each {|f| $LOADED_FEATURES.delete(f) } new_globals.each do |g| begin eval("#{g} = nil") # There's no way to undef a global variable in Ruby rescue NameError => e # Some globals are read-only, and we can't set them to nil. end end end |
#start_watching ⇒ Object
Kicks off a thread to watch the sketch, reloading Ruby-Processing and restarting the sketch whenever it changes.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/ruby-processing/runners/watch.rb', line 21 def start_watching @runner = Thread.start { report_errors { Processing.load_and_run_sketch } } unless $app thread = Thread.start do loop do file_mtime = File.stat(@file).mtime if file_mtime > @time @time = file_mtime wipe_out_current_app! # Taking it out the reset until it can be made to work more reliably # rewind_to_recorded_state GC.start @runner = Thread.start { report_errors { Processing.load_and_run_sketch } } end sleep 0.33 end end thread.join end |
#wipe_out_current_app! ⇒ Object
Used to completely remove all traces of the current sketch, so that it can be loaded afresh. Go down into modules to find it, even.
52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/ruby-processing/runners/watch.rb', line 52 def wipe_out_current_app! @runner.kill if @runner.alive? app = $app return unless app app.no_loop # Wait for the animation thread to finish rendering sleep 0.075 app.close constant_names = app.class.to_s.split(/::/) app_class_name = constant_names.pop obj = constant_names.inject(Object) {|o, name| o.send(:const_get, name) } obj.send(:remove_const, app_class_name) end |