require 'ostruct' require 'fileutils' require 'rbconfig' require_relative '../jruby_art/config' require_relative '../jruby_art/version' # processing wrapper module module Processing # Utility class to handle the different commands that the 'k9' command # offers. Able to run, watch, live, create, app, and unpack class Runner HELP_MESSAGE ||= <<-EOS Version: #{JRubyArt::VERSION} JRubyArt is a little shim between Processing and JRuby that helps you create sketches of code art. Usage: k9 [choice] sketch choice:- run: run sketch once watch: watch for changes on the file and relaunch it on the fly live: run sketch and open a pry console bound to $app create [width height][mode][flag]: create a new sketch. setup: check setup, install jruby-complete, unpack samples Common options: --nojruby: use jruby-complete in place of an installed version of jruby (Set [JRUBY: 'false'] in .k9rc to make using jruby-complete default) Examples: k9 setup unpack_samples k9 run rp_samples/samples/contributed/jwishy.rb k9 create some_new_sketch 640 480 p3d (P3D mode example) k9 create some_new_sketch 640 480 --wrap (a class wrapped default sketch) k9 watch some_new_sketch.rb Everything Else: http://wiki.github.com/monkstone/jruby_art-3.0 EOS WIN_PATTERNS = [ /bccwin/i, /cygwin/i, /djgpp/i, /ming/i, /mswin/i, /wince/i ] attr_reader :os # Start running a jruby_art sketch from the passed-in arguments def self.execute runner = new runner.parse_options(ARGV) runner.execute! end # Dispatch central. def execute! case @options.action when 'run' then run(@options.path, @options.args) when 'live' then live(@options.path, @options.args) when 'watch' then watch(@options.path, @options.args) when 'create' then create(@options.path, @options.args) when 'setup' then setup(@options.path) when /-v/ then show_version when /-h/ then show_help else show_help end end # Parse the command-line options. Keep it simple. def parse_options(args) @options = OpenStruct.new @options.emacs = !args.delete('--emacs').nil? @options.wrap = !args.delete('--wrap').nil? @options.inner = !args.delete('--inner').nil? @options.jruby = !args.delete('--jruby').nil? @options.nojruby = !args.delete('--nojruby').nil? @options.action = args[0] || nil @options.path = args[1] || File.basename(Dir.pwd + '.rb') @options.args = args[2..-1] || [] end # Create a fresh JRubyArt sketch, with the necessary # boilerplate filled out. def create(sketch, args) require_relative '../jruby_art/creators/creator' return Processing::Inner.new.create!(sketch, args) if @options.inner return Processing::ClassSketch.new.create!(sketch, args) if @options.wrap return Processing::EmacsSketch.new.create!(sketch, args) if @options.emacs Processing::BasicSketch.new.create!(sketch, args) end # Just simply run a JRubyArt sketch. def run(sketch, args) ensure_exists(sketch) spin_up('run.rb', sketch, args) end # Just simply run a JRubyArt sketch. def live(sketch, args) ensure_exists(sketch) spin_up('live.rb', sketch, args) end # Run a sketch, keeping an eye on it's file, and reloading # whenever it changes. def watch(sketch, args) ensure_exists(sketch) spin_up('watch.rb', sketch, args) end def setup(choice) proc_root = FileTest.exist?("#{ENV['HOME']}/.jruby_art/config.yml") case choice when /check/ check(proc_root, FileTest.exist?("#{K9_ROOT}/lib/ruby/jruby-complete.jar")) when /install/ install(proc_root) when /unpack_samples/ system "cd #{K9_ROOT}/vendors && rake unpack_samples" else puts 'Usage: k9 setup [check | install | unpack_samples]' end end def install(root_exist) system "cd #{K9_ROOT}/vendors && rake" return if root_exist set_processing_root warn 'PROCESSING_ROOT set optimistically, run check to confirm' end def check(root_exist, installed) show_version root = ' PROCESSING_ROOT = Not Set!!!' unless root_exist root ||= " PROCESSING_ROOT = #{Processing::RP_CONFIG['PROCESSING_ROOT']}" jruby = Processing::RP_CONFIG['JRUBY'] x_off = Processing::RP_CONFIG['X_OFF'] y_off = Processing::RP_CONFIG['Y_OFF'] puts root puts " JRUBY = #{jruby}" unless jruby.nil? puts " X_OFF = #{x_off}" unless x_off.nil? puts " Y_OFF = #{y_off}" unless y_off.nil? puts " jruby-complete installed = #{installed}" end # Display the current version of JRubyArt. def show_version puts format('JRubyArt version %s', JRubyArt::VERSION) end # Show the standard help/usage message. def show_help puts HELP_MESSAGE end private # Trade in this Ruby instance for a JRuby instance, loading in a starter # script and passing it some arguments.Unless '--nojruby' is passed, the # installed version of jruby is used instead of our vendored jarred one # (which is required for some sketches eg shaders). To use # jruby-complete by default set JRUBY: false in ~/.k9rc config # (but that will make using other gems in your sketches hard....) def spin_up(starter_script, sketch, args) runner = "#{K9_ROOT}/lib/jruby_art/runners/#{starter_script}" @options.nojruby = true if Processing::RP_CONFIG['JRUBY'] == 'false' java_args = discover_java_args(sketch) if @options.nojruby command = ['java', java_args, '-cp', jruby_complete, 'org.jruby.Main', runner, sketch, args].flatten else command = ['jruby', java_args, runner, sketch, args].flatten end begin exec(*command) # exec replaces the Ruby process with the JRuby one. rescue Java::JavaLang::ClassNotFoundException end end # If you need to pass in arguments to Java, such as the ones on this page: # http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/java.html # add them to a java_args.txt in your data directory next to your sketch. def discover_java_args(sketch) arg_file = "#{File.dirname(sketch)}/data/java_args.txt" args = [] args += dock_icon if FileTest.exist?(arg_file) args += File.read(arg_file).split(/\s+/) elsif Processing::RP_CONFIG['java_args'] args += Processing::RP_CONFIG['java_args'].split(/\s+/) end args.map! { |arg| "-J#{arg}" } unless @options.nojruby args end # NB: We really do mean to use 'and' not '&&' for flow control purposes def ensure_exists(sketch) puts "Couldn't find: #{sketch}" and exit unless FileTest.exist?(sketch) end def jruby_complete rcomplete = File.join(K9_ROOT, 'lib/ruby/jruby-complete.jar') return [rcomplete] if FileTest.exist?(rcomplete) warn "#{rcomplete} does not exist\nTry running `k9 setup install`" exit end def libraries %w(video sound).map { |library| sketchbook_library(library) }.flatten end def sketchbook_library(name) Dir["#{Processing::RP_CONFIG['sketchbook_path']}/libraries/#{name}/library/\*.jar"] end def host_os detect_os = RbConfig::CONFIG['host_os'] case detect_os when /mac|darwin/ then :mac when /linux/ then :linux when /solaris|bsd/ then :unix else WIN_PATTERNS.find { |r| detect_os =~ r } fail "unknown os: #{detect_os.inspect}" if Regexp.last_match.nil? :windows end end # Optimistically set processing root def set_processing_root require 'psych' @os ||= host_os data = {} path = File.expand_path("#{ENV['HOME']}/.jruby_art/config.yml") if os == :mac data['PROCESSING_ROOT'] = '/Applications/Processing.app/Contents/Java' else root = "#{ENV['HOME']}/processing-3.0a11" data['PROCESSING_ROOT'] = root end data['JRUBY'] = 'true' open(path, 'w:UTF-8') { |f| f.write(data.to_yaml) } end # On the Mac, we can display a fat, shiny ruby in the Dock. def dock_icon @os ||= host_os icon = [] if os == :mac icon << '-Xdock:name=JRubyArt' icon << "-Xdock:icon=#{K9_ROOT}/lib/templates/application/Contents/Resources/sketch.icns" end icon end end # class Runner end # module Processing