ruby-processing 1.0.8 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/CHANGELOG +6 -0
  2. data/lib/core/core.jar +0 -0
  3. data/lib/core/jruby-complete.jar +0 -0
  4. data/lib/ruby-processing.rb +5 -10
  5. data/lib/ruby-processing/app.rb +139 -98
  6. data/lib/ruby-processing/exporters/applet_exporter.rb +4 -1
  7. data/lib/ruby-processing/exporters/application_exporter.rb +5 -1
  8. data/lib/ruby-processing/exporters/base_exporter.rb +3 -2
  9. data/lib/ruby-processing/runner.rb +54 -46
  10. data/lib/ruby-processing/runners/base.rb +6 -7
  11. data/lib/ruby-processing/runners/live.rb +4 -3
  12. data/lib/ruby-processing/runners/watch.rb +33 -27
  13. data/library/control_panel/control_panel.rb +24 -23
  14. data/samples/anar/data/java_args.txt +1 -0
  15. data/samples/anar/extrusion.rb +49 -0
  16. data/samples/anar/l_system.rb +86 -0
  17. data/samples/anar/library/anar/anar.jar +0 -0
  18. data/samples/anar/many_shapes.rb +98 -0
  19. data/samples/empathy.rb +73 -0
  20. data/samples/gravity.rb +113 -0
  21. data/samples/peasy_cam/data/java_args.txt +1 -0
  22. data/samples/peasy_cam/hello_peasy.rb +29 -0
  23. data/samples/peasy_cam/hilbert_fractal.rb +40 -0
  24. data/samples/peasy_cam/library/PeasyCam/PeasyCam.jar +0 -0
  25. data/samples/peasy_cam/library/hilbert/hilbert.rb +99 -0
  26. data/samples/processing_app/3D/form/brick_tower.rb +3 -3
  27. data/samples/processing_app/basics/data/characters_strings/characters_strings.rb +5 -7
  28. data/samples/processing_app/basics/form/triangle_strip.rb +11 -11
  29. data/samples/processing_app/basics/input/keyboard.rb +2 -8
  30. data/samples/processing_app/basics/input/keyboard_2.rb +4 -4
  31. data/samples/processing_app/basics/input/keyboard_functions.rb +12 -21
  32. metadata +41 -64
@@ -40,7 +40,10 @@ module Processing
40
40
  @necessary_files = [@main_file_path]
41
41
  @necessary_files += Dir["#{RP5_ROOT}/lib/{*,**}"]
42
42
  @necessary_files += @real_requires
43
- @necessary_files << "#{@main_folder}/data" if File.exists?("#{@main_folder}/data")
43
+ NECESSARY_FOLDERS.each do |folder|
44
+ resource_path = File.join(@main_folder, folder)
45
+ @necessary_files << resource_path if File.exists?(resource_path)
46
+ end
44
47
  @necessary_files += Dir["#{RP5_ROOT}/lib/templates/applet/{*,**}"]
45
48
  @necessary_files += Dir.glob("library/{#{@libraries.join(",")}}") unless @libraries.empty?
46
49
  @necessary_files.uniq!
@@ -42,7 +42,10 @@ module Processing
42
42
  @necessary_files = [@main_file_path]
43
43
  @necessary_files += Dir["#{RP5_ROOT}/lib/{*,**}"]
44
44
  @necessary_files += @real_requires
45
- @necessary_files << "#{@main_folder}/data" if File.exists?("#{@main_folder}/data")
45
+ NECESSARY_FOLDERS.each do |folder|
46
+ resource_path = File.join(@main_folder, folder)
47
+ @necessary_files << resource_path if File.exists?(resource_path)
48
+ end
46
49
  @necessary_files.uniq!
47
50
  cp_r(@necessary_files, File.join(@dest, @prefix))
48
51
  cp_r(@libraries, File.join(@dest, @prefix, "library")) unless @libraries.empty?
@@ -66,6 +69,7 @@ module Processing
66
69
  move @dest + "/run.exe", "#{runnable}.exe"
67
70
  chmod 0755, runnable
68
71
  chmod 0755, "#{runnable}.exe"
72
+ chmod 0755, File.join(@dest, 'Contents', 'MacOS', 'JavaApplicationStub')
69
73
  end
70
74
 
71
75
  def symlink_library_into_place
@@ -10,6 +10,7 @@ module Processing
10
10
 
11
11
  DEFAULT_DIMENSIONS = {'width' => '100', 'height' => '100'}
12
12
  DEFAULT_DESCRIPTION = ''
13
+ NECESSARY_FOLDERS = ['data', 'lib', 'vendor']
13
14
 
14
15
  # Returns the filepath, basename, and directory name of the sketch.
15
16
  def get_main_file(file)
@@ -42,7 +43,7 @@ module Processing
42
43
 
43
44
  # Searches the source for a title.
44
45
  def extract_title(source)
45
- match = source.match(/#{@info[:class_name]}\.new.*?:title\s=>\s["'](.+)["']/m)
46
+ match = source.match(/#{@info[:class_name]}\.new.*?:title\s=>\s["'](.+?)["']/m)
46
47
  match ? match[1] : File.basename(@file, '.rb').titleize
47
48
  end
48
49
 
@@ -89,7 +90,7 @@ module Processing
89
90
  requirements = []
90
91
  partial_paths = []
91
92
  loop do
92
- matchdata = code.match(/^.*\b(require|load)\b.*$/)
93
+ matchdata = code.match(/^.*[^::\.\w](require|load)\b.*$/)
93
94
  break unless matchdata
94
95
  line = matchdata[0].gsub('__FILE__', "'#{@main_file_path}'")
95
96
  line = line.gsub(/\b(require|load)\b/, 'partial_paths << ')
@@ -2,45 +2,45 @@ require 'ostruct'
2
2
  require 'fileutils'
3
3
 
4
4
  module Processing
5
-
5
+
6
6
  # Utility class to handle the different commands that the 'rp5' command
7
7
  # offers. Able to run, watch, live, create, app, applet, and unpack
8
8
  class Runner
9
-
9
+
10
10
  HELP_MESSAGE = <<-EOS
11
-
11
+
12
12
  Ruby-Processing is a little shim between Processing and JRuby that helps
13
13
  you create sketches of code art.
14
-
14
+
15
15
  Usage:
16
16
  rp5 [run | watch | live | create | app | applet | unpack] path/to/sketch
17
-
17
+
18
18
  Examples:
19
19
  rp5 unpack samples
20
20
  rp5 run samples/jwishy.rb
21
21
  rp5 create some_new_sketch --bare 640 480
22
22
  rp5 watch some_new_sketch.rb
23
23
  rp5 applet some_new_sketch.rb
24
-
24
+
25
25
  Everything Else:
26
- http://wiki.github.com/jashkenas/ruby-processing
27
-
26
+ http://wiki.github.com/jashkenas/ruby-processing
27
+
28
28
  EOS
29
-
29
+
30
30
  # Start running a ruby-processing sketch from the passed-in arguments
31
31
  def self.execute
32
32
  runner = new
33
33
  runner.parse_options(ARGV)
34
34
  runner.execute!
35
35
  end
36
-
36
+
37
37
  # Dispatch central.
38
38
  def execute!
39
39
  case @options.action
40
- when 'run' then run(@options.path)
41
- when 'watch' then watch(@options.path)
40
+ when 'run' then run(@options.path, @options.args)
41
+ when 'watch' then watch(@options.path, @options.args)
42
+ when 'live' then live(@options.path, @options.args)
42
43
  when 'create' then create(@options.path, @options.args, @options.bare)
43
- when 'live' then live(@options.path)
44
44
  when 'app' then app(@options.path)
45
45
  when 'applet' then applet(@options.path)
46
46
  when 'unpack' then unpack(@options.path)
@@ -50,52 +50,53 @@ module Processing
50
50
  show_help
51
51
  end
52
52
  end
53
-
53
+
54
54
  # Parse the command-line options. Keep it simple.
55
55
  def parse_options(args)
56
56
  @options = OpenStruct.new
57
57
  @options.bare = !!args.delete('--bare')
58
+ @options.jruby = !!args.delete('--jruby')
58
59
  @options.action = args[0] || nil
59
60
  @options.path = args[1] || File.basename(Dir.pwd + '.rb')
60
61
  @options.args = args[2..-1] || []
61
62
  end
62
-
63
+
63
64
  # Create a fresh Ruby-Processing sketch, with the necessary
64
65
  # boilerplate filled out.
65
66
  def create(sketch, args, bare)
66
67
  Processing::Creator.new.create!(sketch, args, bare)
67
68
  end
68
-
69
+
69
70
  # Just simply run a ruby-processing sketch.
70
- def run(sketch)
71
+ def run(sketch, args)
71
72
  ensure_exists(sketch)
72
- spin_up('run.rb', sketch)
73
+ spin_up('run.rb', sketch, args)
73
74
  end
74
-
75
+
75
76
  # Run a sketch, keeping an eye on it's file, and reloading
76
77
  # whenever it changes.
77
- def watch(sketch)
78
+ def watch(sketch, args)
78
79
  ensure_exists(sketch)
79
- spin_up('watch.rb', sketch)
80
+ spin_up('watch.rb', sketch, args)
80
81
  end
81
-
82
+
82
83
  # Run a sketch, opening its guts to IRB, letting you play with it.
83
- def live(sketch)
84
+ def live(sketch, args)
84
85
  ensure_exists(sketch)
85
- spin_up('live.rb', sketch)
86
+ spin_up('live.rb', sketch, args)
86
87
  end
87
-
88
+
88
89
  # Generate a cross-platform application of a given Ruby-Processing sketch.
89
90
  def app(sketch)
90
91
  Processing::ApplicationExporter.new.export!(sketch)
91
92
  end
92
-
93
+
93
94
  # Generate an applet and HTML page for a given sketch.
94
95
  def applet(sketch)
95
96
  Processing::AppletExporter.new.export!(sketch)
96
97
  end
97
-
98
- # Install the included samples to a given path, where you can run and
98
+
99
+ # Install the included samples to a given path, where you can run and
99
100
  # alter them to your heart's content.
100
101
  def unpack(dir)
101
102
  require 'fileutils'
@@ -103,52 +104,59 @@ module Processing
103
104
  puts usage and return unless dir.match(/\A(samples|library)\Z/)
104
105
  FileUtils.cp_r("#{RP5_ROOT}/#{dir}", "#{Dir.pwd}/#{dir}")
105
106
  end
106
-
107
+
107
108
  # Display the current version of Ruby-Processing.
108
109
  def show_version
109
- puts "Ruby-Processing version #{Processing.version}"
110
+ puts "Ruby-Processing version #{Processing::VERSION}"
110
111
  end
111
-
112
+
112
113
  # Show the standard help/usage message.
113
114
  def show_help
114
115
  puts HELP_MESSAGE
115
116
  end
116
-
117
-
117
+
118
+
118
119
  private
119
-
120
- # Trade in this Ruby instance for a JRuby instance, loading in a
120
+
121
+ # Trade in this Ruby instance for a JRuby instance, loading in a
121
122
  # starter script and passing it some arguments.
122
- def spin_up(starter_script, sketch)
123
+ # If --jruby is passed, use the installed version of jruby, instead of
124
+ # our vendored jarred one (useful for gems).
125
+ def spin_up(starter_script, sketch, args)
123
126
  runner = "#{RP5_ROOT}/lib/ruby-processing/runners/#{starter_script}"
124
127
  java_args = discover_java_args(sketch)
125
- command = "java #{java_args} -cp \"#{jruby_complete}\" #{dock_icon} org.jruby.Main \"#{runner}\" #{sketch}"
126
- exec(command)
128
+ command = @options.jruby ?
129
+ ['jruby', java_args, runner, sketch, args].flatten :
130
+ ['java', java_args, '-cp', jruby_complete, 'org.jruby.Main', runner, sketch, args].flatten
131
+ exec *command
127
132
  # exec replaces the Ruby process with the JRuby one.
128
133
  end
129
-
134
+
130
135
  # If you need to pass in arguments to Java, such as the ones on this page:
131
136
  # http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/java.html
132
137
  # then type them into a java_args.txt in your data directory next to your sketch.
133
138
  def discover_java_args(sketch)
134
139
  arg_file = "#{File.dirname(sketch)}/data/java_args.txt"
135
- File.exists?(arg_file) ? File.read(arg_file).gsub("\n", " ") : ''
140
+ args = dock_icon
141
+ args += File.read(arg_file).split(/\s+/) if File.exists?(arg_file)
142
+ args.map! {|arg| "-J#{arg}" } if @options.jruby
143
+ args
136
144
  end
137
-
145
+
138
146
  def ensure_exists(sketch)
139
147
  puts "Couldn't find: #{sketch}" and exit unless File.exists?(sketch)
140
148
  end
141
-
149
+
142
150
  def jruby_complete
143
151
  File.join(RP5_ROOT, 'lib/core/jruby-complete.jar')
144
152
  end
145
-
153
+
146
154
  # On the Mac, we can display a fat, shiny ruby in the Dock.
147
155
  def dock_icon
148
156
  mac = RUBY_PLATFORM.match(/darwin/i) || (RUBY_PLATFORM == 'java' && ENV_JAVA['os.name'].match(/mac/i))
149
- mac ? "-Xdock:name=Ruby-Processing -Xdock:icon=#{RP5_ROOT}/lib/templates/application/Contents/Resources/sketch.icns" : ""
157
+ mac ? ["-Xdock:name=Ruby-Processing", "-Xdock:icon=#{RP5_ROOT}/lib/templates/application/Contents/Resources/sketch.icns"] : []
150
158
  end
151
-
159
+
152
160
  end # class Runner
153
-
161
+
154
162
  end # module Processing
@@ -1,5 +1,6 @@
1
1
  $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../../")
2
- SKETCH_ROOT = File.dirname(ARGV[0]) unless defined? SKETCH_ROOT
2
+ SKETCH_PATH = ARGV.shift
3
+ SKETCH_ROOT = File.dirname(SKETCH_PATH) unless defined? SKETCH_ROOT
3
4
 
4
5
  require 'ruby-processing'
5
6
  require 'ruby-processing/app'
@@ -7,8 +8,6 @@ require 'ruby-processing/app'
7
8
 
8
9
  module Processing
9
10
 
10
- SKETCH_PATH = ARGV[0]
11
-
12
11
  # For use with "bare" sketches that don't want to define a class or methods
13
12
  SKETCH_TEMPLATE = <<-EOS
14
13
  class Sketch < Processing::App
@@ -31,13 +30,13 @@ module Processing
31
30
  has_methods = !!source.match(/^[^#]*(def\s+setup|def\s+draw)/)
32
31
 
33
32
  if has_sketch
34
- load Processing::SKETCH_PATH
33
+ load SKETCH_PATH
35
34
  Processing::App.sketch_class.new if !$app
36
35
  return
37
36
  else
38
37
  require 'erb'
39
38
  code = ERB.new(SKETCH_TEMPLATE).result(binding)
40
- Object.class_eval code, Processing::SKETCH_PATH, 0
39
+ Object.class_eval code, SKETCH_PATH, 0
41
40
  Processing::App.sketch_class.new if !$app
42
41
  end
43
42
  end
@@ -48,7 +47,7 @@ module Processing
48
47
  if Processing.online?
49
48
  # Fuck the following lines. Fucking Java can go sit on broken glass.
50
49
  source = ''
51
- url = java.net.URL.new(JRUBY_APPLET.get_code_base, Processing::SKETCH_PATH)
50
+ url = java.net.URL.new(JRUBY_APPLET.get_code_base, SKETCH_PATH)
52
51
  input = java.io.BufferedReader.new(java.io.InputStreamReader.new(url.open_stream))
53
52
  while line = input.read_line do
54
53
  source << (line + "\n") if line
@@ -56,7 +55,7 @@ module Processing
56
55
  input.close
57
56
  else
58
57
  # Ahhh, much better.
59
- source = File.read(Processing::SKETCH_PATH)
58
+ source = File.read(SKETCH_PATH)
60
59
  end
61
60
  source
62
61
  end
@@ -3,9 +3,10 @@
3
3
  # or will start with your sketch.
4
4
 
5
5
  require "#{File.dirname(__FILE__)}/base.rb"
6
+ Processing.load_and_run_sketch
7
+
8
+ ARGV.clear # So that IRB doesn't try to load them as files.
6
9
 
7
10
  require 'irb'
8
- ARGV[0] = nil # To keep IRB from trying to run it multiple times.
9
11
  IRB.setup(__FILE__)
10
- Processing.load_and_run_sketch
11
- IRB.start()
12
+ IRB.start
@@ -1,25 +1,25 @@
1
1
  require "#{File.dirname(__FILE__)}/base.rb"
2
2
 
3
- module Processing
4
-
5
- # A sketch loader, observer, and reloader, to tighten
3
+ module Processing
4
+
5
+ # A sketch loader, observer, and reloader, to tighten
6
6
  # the feedback between code and effect.
7
7
  class Watcher
8
-
8
+
9
9
  # Sic a new Processing::Watcher on the sketch
10
10
  def initialize
11
- @file = Processing::SKETCH_PATH
11
+ @file = SKETCH_PATH
12
12
  @time = Time.now
13
13
  # Doesn't work well enough for now.
14
14
  # record_state_of_ruby
15
- Processing.load_and_run_sketch unless $app
16
15
  start_watching
17
16
  end
18
-
19
-
17
+
18
+
20
19
  # Kicks off a thread to watch the sketch, reloading Ruby-Processing
21
20
  # and restarting the sketch whenever it changes.
22
21
  def start_watching
22
+ @runner = Thread.start { report_errors { Processing.load_and_run_sketch } } unless $app
23
23
  thread = Thread.start do
24
24
  loop do
25
25
  file_mtime = File.stat(@file).mtime
@@ -29,22 +29,28 @@ module Processing
29
29
  # Taking it out the reset until it can be made to work more reliably
30
30
  # rewind_to_recorded_state
31
31
  GC.start
32
- begin
33
- Processing.load_and_run_sketch
34
- rescue StandardError, ScriptError
35
- print "Error in your sketch: ", $!, "\n"
36
- end
32
+ @runner = Thread.start { report_errors { Processing.load_and_run_sketch } }
37
33
  end
38
34
  sleep 0.33
39
35
  end
40
36
  end
41
37
  thread.join
42
38
  end
43
-
44
-
45
- # Used to completely remove all traces of the current sketch,
39
+
40
+ # Convenience function to report errors when loading and running a sketch,
41
+ # instead of having them eaten by the thread they are loaded in.
42
+ def report_errors
43
+ yield
44
+ rescue Exception => e
45
+ puts "Exception occured while running sketch #{File.basename SKETCH_PATH}:"
46
+ puts e.to_s
47
+ puts e.backtrace.join("\n")
48
+ end
49
+
50
+ # Used to completely remove all traces of the current sketch,
46
51
  # so that it can be loaded afresh. Go down into modules to find it, even.
47
52
  def wipe_out_current_app!
53
+ @runner.kill if @runner.alive?
48
54
  app = $app
49
55
  return unless app
50
56
  app.no_loop
@@ -54,15 +60,15 @@ module Processing
54
60
  constant_names = app.class.to_s.split(/::/)
55
61
  app_class_name = constant_names.pop
56
62
  obj = constant_names.inject(Object) {|o, name| o.send(:const_get, name) }
57
- obj.send(:remove_const, app_class_name)
63
+ obj.send(:remove_const, app_class_name)
58
64
  end
59
-
65
+
60
66
  # The following methods were intended to make the watcher clean up all code
61
67
  # loaded in from the sketch, gems, etc, and have them be reloaded properly
62
68
  # when the sketch is.... but it seems that this is neither a very good idea
63
- # or a very possible one. If you can make the scheme work, please do,
69
+ # or a very possible one. If you can make the scheme work, please do,
64
70
  # otherwise the following methods will probably be removed soonish.
65
-
71
+
66
72
  # Do the best we can to take a picture of the current Ruby interpreter.
67
73
  # For now, this means top-level constants and loaded .rb files.
68
74
  def record_state_of_ruby
@@ -71,19 +77,19 @@ module Processing
71
77
  @saved_features = $LOADED_FEATURES.dup
72
78
  @saved_globals = Kernel.global_variables.dup
73
79
  end
74
-
75
-
80
+
81
+
76
82
  # Try to go back to the recorded Ruby state.
77
83
  def rewind_to_recorded_state
78
84
  new_constants = Object.send(:constants).reject {|c| @saved_constants.include?(c) }
79
85
  new_load_paths = $LOAD_PATH.reject {|p| @saved_load_paths.include?(p) }
80
86
  new_features = $LOADED_FEATURES.reject {|f| @saved_features.include?(f) }
81
87
  new_globals = Kernel.global_variables.reject {|g| @saved_globals.include?(g) }
82
-
88
+
83
89
  Processing::App.recursively_remove_constants(Object, new_constants)
84
90
  new_load_paths.each {|p| $LOAD_PATH.delete(p) }
85
91
  new_features.each {|f| $LOADED_FEATURES.delete(f) }
86
- new_globals.each do |g|
92
+ new_globals.each do |g|
87
93
  begin
88
94
  eval("#{g} = nil") # There's no way to undef a global variable in Ruby
89
95
  rescue NameError => e
@@ -91,8 +97,8 @@ module Processing
91
97
  end
92
98
  end
93
99
  end
94
-
95
-
100
+
101
+
96
102
  # Used to clean up declared constants in code that needs to be reloaded.
97
103
  def recursively_remove_constants(base, constant_names)
98
104
  constants = constant_names.map {|name| base.const_get(name) }
@@ -104,7 +110,7 @@ module Processing
104
110
  constants.each {|c| recursively_remove_constants(c, c.constants) if c }
105
111
  constant_names.each {|name| base.send(:remove_const, name.to_sym) if name }
106
112
  end
107
-
113
+
108
114
  end
109
115
  end
110
116