diff --git a/Gemfile b/Gemfile index eabe9811..2a839904 100644 --- a/Gemfile +++ b/Gemfile @@ -33,7 +33,7 @@ group :test do end gem "gherkin" gem "cucumber" - gem "rspec", "~> 2.0" + gem "rspec" gem "rake" #gem "shoes-cucumber" end diff --git a/Gemfile.lock b/Gemfile.lock index 6750f754..9cfadd69 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,40 +3,40 @@ GEM specs: builder (3.0.0) columnize (0.3.6) - cucumber (1.1.0) + cucumber (1.1.4) builder (>= 2.1.2) diff-lcs (>= 1.1.2) - gherkin (~> 2.5.0) + gherkin (~> 2.7.1) json (>= 1.4.6) term-ansicolor (>= 1.0.6) diff-lcs (1.1.3) - facets (2.9.2) + facets (2.9.3) ffi (1.0.11) ffi (1.0.11-java) - gherkin (2.5.1) + gherkin (2.7.6) json (>= 1.4.6) - gherkin (2.5.1-java) + gherkin (2.7.6-java) json (>= 1.4.6) guard (1.0.0) ffi (>= 0.5.0) thor (~> 0.14.6) guard-rspec (0.6.0) guard (>= 0.10.0) - json (1.6.1) - json (1.6.1-java) + json (1.6.5) + json (1.6.5-java) linecache (0.46) rbx-require-relative (> 0.0.4) log4jruby (0.4.0) - rake (0.9.2) + rake (0.9.2.2) rbx-require-relative (0.0.5) - rspec (2.6.0) - rspec-core (~> 2.6.0) - rspec-expectations (~> 2.6.0) - rspec-mocks (~> 2.6.0) - rspec-core (2.6.4) - rspec-expectations (2.6.0) + rspec (2.8.0) + rspec-core (~> 2.8.0) + rspec-expectations (~> 2.8.0) + rspec-mocks (~> 2.8.0) + rspec-core (2.8.0) + rspec-expectations (2.8.0) diff-lcs (~> 1.1.2) - rspec-mocks (2.6.0) + rspec-mocks (2.8.0) ruby-debug (0.10.4) columnize (>= 0.1) ruby-debug-base (~> 0.10.4.0) @@ -44,7 +44,7 @@ GEM linecache (>= 0.3) ruby-debug-base (0.10.4-java) swt (0.12) - term-ansicolor (1.0.6) + term-ansicolor (1.0.7) thor (0.14.6) PLATFORMS @@ -59,6 +59,6 @@ DEPENDENCIES guard-rspec log4jruby rake - rspec (~> 2.0) + rspec ruby-debug swt diff --git a/README.rdoc b/README.rdoc index a66f1953..de158be7 100644 --- a/README.rdoc +++ b/README.rdoc @@ -2,14 +2,6 @@ A JRuby implementation of shoes -== Getting Started - - rvm install jruby - gem install bundler - bundle install - ./swing-shoooes testing/blank-window.rb - ./swt-shoooes testing/blank-window.rb - ==TODO: Shoes Element Skeletons: diff --git a/Rakefile b/Rakefile index cddd983a..5add12b9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,532 +1,23 @@ require 'rubygems' require 'rake' -#<<<<<<< HEAD -#require 'rake/clean' -## require_relative 'platform/skel' -#require 'fileutils' -#require 'find' -#require 'yaml' -#include FileUtils -# -#APP = YAML.load_file(File.join(ENV['APP'] || ".", "app.yaml")) -#APPNAME = APP['name'] -#RELEASE_ID, RELEASE_NAME = APP['version'], APP['release'] -#NAME = APP['shortname'] || APP['name'].downcase.gsub(/\W+/, '') -#SONAME = 'shoes' -# -## Like puts, but only if we've --trace'd -#def vputs(str) -# puts str if Rake.application.options.trace -#end -# -#begin -#require 'cucumber' -#require 'cucumber/rake/task' -# -#Cucumber::Rake::Task.new(:features) do |t| -# t.cucumber_opts = "--format pretty" -#end -# -#rescue LoadError -# vputs("Cukes is not loaded -- please `bundle install`") -#end -# -#begin -# -#require 'rspec/core/rake_task' -#RSpec::Core::RakeTask.new(:spec) do |t| -# t.rspec_opts = ["--color"] -#end -# -#rescue LoadError -# vputs("RSpec is not loaded -- please `bundle install`") -#end -# -#begin -# -#require 'bundler' -#Bundler::GemHelper.install_tasks -# -#rescue LoadError -# vputs("Bundler is not loaded -- please `gem install bundler && bundle install`") -#end -# -#GIT = ENV['GIT'] || "git" -#REVISION = (`#{GIT} rev-list HEAD`.split.length + 1).to_s -#VERS = ENV['VERSION'] || "0.r#{REVISION}" -#PKG = "#{NAME}-#{VERS}" -#APPARGS = APP['run'] -#FLAGS = %w[DEBUG] -# -#BIN = "*.{bundle,jar,o,so,obj,pdb,pch,res,lib,def,exp,exe,ilk}" -#CLEAN.include ["{bin,shoes}/#{BIN}", "req/**/#{BIN}", "dist", "*.app"] -# -#RUBY_SO = Config::CONFIG['RUBY_SO_NAME'] -#RUBY_V = Config::CONFIG['ruby_version'] -#RUBY_PROGRAM_VERSION = Config::CONFIG['RUBY_PROGRAM_VERSION'] -#SHOES_RUBY_ARCH = Config::CONFIG['arch'] -# -#if ENV['APP'] -# %w[dmg icons].each do |subk| -# APP[subk].keys.each do |name| -# APP[subk][name] = File.join(ENV['APP'], APP[subk][name]) -# end -# end -#end -# -#if File.exists? ".git/refs/tags/#{RELEASE_ID}/#{RELEASE_NAME}" -# abort "** Rename this release (and add to lib/shoes.rb) #{RELEASE_NAME} has already been tagged." -#end -# -## Same effect as sourcing a shell script before running rake. It's necessary to -## set these values before the make/{platform}/env.rb files are loaded. -#def osx_bootstrap_env -# ENV['DYLD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo' -# ENV['LD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo' -# ENV['CAIRO_CFLAGS'] = '-I/usr/local/Cellar/cairo/1.10.2/include/cairo' -# ENV['SHOES_DEPS_PATH'] = '/usr/local' -#end -# -# -# -#case RUBY_PLATFORM -#when /mingw/ -# require File.expand_path('rakefile_mingw') -# Builder = MakeMinGW -# NAMESPACE = :win32 -#when /darwin/ -# osx_bootstrap_env -# require File.expand_path('make/darwin/env') -# require_relative "make/darwin/homebrew" -# -# task :stub do -# ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.4' -# sh "gcc -O -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc -framework Cocoa -o stub platform/mac/stub.m -I." -# end -# NAMESPACE = :osx -#when /linux/ -# require File.expand_path('rakefile_linux') -# Builder = MakeLinux -# NAMESPACE = :linux -#else -# puts "Sorry, your platform [#{RUBY_PLATFORM}] is not supported..." -#end -# -## -------------------------- -## common platform tasks -# -#desc "Same as `rake build'" -#task :default => [:build] -# -#desc "Does a full compile, with installer" -#task :package => [:build, :installer] -# -#task :build_os => [:build_skel, "dist/#{NAME}"] -# -#task "shoes/version.h" do |t| -# File.open(t.name, 'w') do |f| -# f << %{#define SHOES_RELEASE_ID #{RELEASE_ID}\n#define SHOES_RELEASE_NAME "#{RELEASE_NAME}"\n#define SHOES_REVISION #{REVISION}\n#define SHOES_BUILD_DATE #{Time.now.strftime("%Y%m%d")}\n#define SHOES_PLATFORM "#{SHOES_RUBY_ARCH}"\n} -# end -#end -# -#task "dist/VERSION.txt" do |t| -# File.open(t.name, 'w') do |f| -# f << %{shoes #{RELEASE_NAME.downcase} (0.r#{REVISION}) [#{SHOES_RUBY_ARCH} Ruby#{RUBY_PROGRAM_VERSION}]} -# %w[DEBUG].each { |x| f << " +#{x.downcase}" if ENV[x] } -# f << "\n" -# end -#end -# -## shoes is small, if any include changes, go ahead and build from scratch. -#SRC.zip(OBJ).each do |c, o| -# file o => [c] + Dir["shoes/*.h"] -#end -# -## ------ -## skel -# -#def skel_replace(line) -# line.gsub! /\s+%DEFAULTS%/ do -# if APPARGS -# args = APPARGS.split(/\s+/) -# %{ -# char *default_argv[] = {argv[0], #{args.inspect[1..-2]}}; -# argv = default_argv; -# argc = #{args.length + 1}; -# } -# end -# end -# line -#end -# -## preprocess .skel -#task :build_skel do |t| -# Dir["bin/*.skel"].each do |src| -# name = src.gsub(/\.skel$/, '.c') -# File.open(src) do |skel| -# File.open(name, 'w') do |c| -# skel.each_line do |line| -# c << skel_replace(line) -# end -# end -# end -# end -#end -# -## -------------------------- -## tasks depending on Builder = MakeLinux|MakeDarwin|MakeMinGW -# -#desc "Does a full compile, for the OS you're running on" -#task :build => ["#{NAMESPACE}:build"] -# -## first refactor ; build calls platform namespaced build; -## for now, each of those calls the old build method. -#task :old_build => [:build_os, "dist/VERSION.txt"] do -# Builder.common_build -# Builder.copy_deps_to_dist -# Builder.copy_files_to_dist -# Builder.setup_system_resources -#end -# -#directory 'dist' -# -#task "dist/#{NAME}" => ["dist/lib#{SONAME}.#{DLEXT}", "bin/main.o"] + ADD_DLL + ["#{NAMESPACE}:make_app"] -# -#task "dist/lib#{SONAME}.#{DLEXT}" => ['shoes/version.h', 'dist'] + OBJ + ["#{NAMESPACE}:make_so"] -# -#def cc(t) -# sh "#{CC} -I. -c -o #{t.name} #{LINUX_CFLAGS} #{t.source}" -#end -# -#rule ".o" => ".m" do |t| -# cc t -#end -# -#rule ".o" => ".c" do |t| -# cc t -#end -# -#task :installer => ["#{NAMESPACE}:installer"] -# -#def rewrite before, after, reg = /\#\{(\w+)\}/, reg2 = '\1' -# File.open(after, 'w') do |a| -# File.open(before) do |b| -# b.each do |line| -# a << line.gsub(reg) do -# if reg2.include? '\1' -# reg2.gsub(%r!\\1!, Object.const_get($1)) -# else -# reg2 -# end -# end -# end -# end -# end -#end -# -#def copy_files glob, dir -# FileList[glob].each { |f| cp_r f, dir } -#end -# -#namespace :osx do -# namespace :deps do -# task :install => "homebrew:install" -# namespace :homebrew do -# desc "Install OS X dependencies using Homebrew" -# task :install => [:customize, :install_libs, :uncustomize] -# -# task :install_libs do -# brew = Homebrew.new -# brew.universal if ENV['SHOES_OSX_ARCH'] == "universal" -# brew.install_packages -# end -# -# task :customize do -# brew = Homebrew.new -# brew.universal if ENV['SHOES_OSX_ARCH'] == "universal" -# brew.add_custom_remote -# brew.add_custom_formulas -# end -# -# task :uncustomize do -# brew = Homebrew.new -# brew.universal if ENV['SHOES_OSX_ARCH'] == "universal" -# brew.remove_custom_formulas -# brew.remove_custom_remote -# end -# end -# end -# -# task :build => ["build_tasks:pre_build", :build_skel, "dist/#{NAME}", "dist/VERSION.txt", "build_tasks:build"] -# -# namespace :build_tasks do -# -# task :build => [:common_build, :copy_deps_to_dist, :change_install_names, :copy_files_to_dist, :setup_system_resources, :verify] -# -# # Make sure the installed ruby is capable of this build -# task :check_ruby_arch do -# build_arch, ruby_arch = [OSX_ARCH, Config::CONFIG['ARCH_FLAG']].map {|s| s.split.reject {|w| w.include?("arch")}} -# if build_arch.length > 1 and build_arch.sort != ruby_arch.sort -# abort("To build universal shoes, you must first install a universal ruby") -# end -# end -# -# task :pre_build => :check_ruby_arch -# -# def copy_ext_osx xdir, libdir -# Dir.chdir(xdir) do -# `ruby extconf.rb; make` -# end -# copy_files "#{xdir}/*.bundle", libdir -# end -# -# task :common_build do -# mkdir_p "dist/ruby" -# cp_r "#{EXT_RUBY}/lib/ruby/#{RUBY_V}", "dist/ruby/lib" -# unless ENV['STANDARD'] -# %w[soap wsdl xsd].each do |libn| -# rm_rf "dist/ruby/lib/#{libn}" -# end -# end -# %w[req/ftsearch/lib/* req/rake/lib/*].each do |rdir| -# FileList[rdir].each { |rlib| cp_r rlib, "dist/ruby/lib" } -# end -# %w[req/binject/ext/binject_c req/ftsearch/ext/ftsearchrt req/bloopsaphone/ext/bloops req/chipmunk/ext/chipmunk]. -# each { |xdir| copy_ext_osx xdir, "dist/ruby/lib/#{SHOES_RUBY_ARCH}" } -# -# gdir = "dist/ruby/gems/#{RUBY_V}" -# {'hpricot' => 'lib', 'json' => 'lib/json/ext', 'sqlite3' => 'lib'}.each do |gemn, xdir| -# spec = eval(File.read("req/#{gemn}/gemspec")) -# mkdir_p "#{gdir}/specifications" -# mkdir_p "#{gdir}/gems/#{spec.full_name}/lib" -# FileList["req/#{gemn}/lib/*"].each { |rlib| cp_r rlib, "#{gdir}/gems/#{spec.full_name}/lib" } -# mkdir_p "#{gdir}/gems/#{spec.full_name}/#{xdir}" -# FileList["req/#{gemn}/ext/*"].each { |elib| copy_ext_osx elib, "#{gdir}/gems/#{spec.full_name}/#{xdir}" } -# cp "req/#{gemn}/gemspec", "#{gdir}/specifications/#{spec.full_name}.gemspec" -# end -# end -# -# def dylibs_to_change lib -# `otool -L #{lib}`.split("\n").inject([]) do |dylibs, line| -# if line =~ /^\S/ or line =~ /System|@executable_path|libobjc/ -# dylibs -# else -# dylibs << line.gsub(/\s\(compatibility.*$/, '').strip -# end -# end -# end -# -# task :change_install_names do -# cd "dist" do -# ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f| -# sh "install_name_tool -id @executable_path/#{File.basename f} #{f}" -# dylibs = dylibs_to_change(f) -# dylibs.each do |dylib| -# sh "install_name_tool -change #{dylib} @executable_path/#{File.basename dylib} #{f}" -# end -# end -# end -# end -# -# task :copy_pango_modules_to_dist do -# modules_file = `brew --prefix`.chomp << '/etc/pango/pango.modules' -# modules_path = File.open(modules_file) {|f| f.grep(/^# ModulesPath = (.*)$/){$1}.first} -# mkdir_p 'dist/pango' -# cp_r modules_path, 'dist/pango' -# cp `which pango-querymodules`.chomp, 'dist/' -# end -# -# task :copy_deps_to_dist => :copy_pango_modules_to_dist do -# # Generate a list of dependencies straight from the generated files. -# # Start with dependencies of shoes-bin and pango-querymodules, and then -# # add the dependencies of those dependencies. -# dylibs = dylibs_to_change("dist/#{NAME}-bin") -# dylibs.concat dylibs_to_change("dist/pango-querymodules") -# dupes = [] -# dylibs.each do |dylib| -# dylibs_to_change(dylib).each do |d| -# if dylibs.map {|lib| File.basename(lib)}.include?(File.basename(d)) -# dupes << d -# else -# dylibs << d -# end -# end -# end -# dylibs.each {|libn| cp "#{libn}", "dist/"} -# end -# -# task :copy_files_to_dist do -# if ENV['APP'] -# if APP['clone'] -# sh APP['clone'].gsub(/^git /, "#{GIT} --git-dir=#{ENV['APP']}/.git ") -# else -# cp_r ENV['APP'], "dist/app" -# end -# if APP['ignore'] -# APP['ignore'].each do |nn| -# rm_rf "dist/app/#{nn}" -# end -# end -# end -# -# cp_r "fonts", "dist/fonts" -# cp_r "lib", "dist/lib" -# cp_r "samples", "dist/samples" -# cp_r "static", "dist/static" -# cp "README.md", "dist/README.txt" -# cp "CHANGELOG", "dist/CHANGELOG.txt" -# cp "COPYING", "dist/COPYING.txt" -# end -# -# task :setup_system_resources do -# rm_rf "#{APPNAME}.app" -# mkdir "#{APPNAME}.app" -# mkdir "#{APPNAME}.app/Contents" -# cp_r "dist", "#{APPNAME}.app/Contents/MacOS" -# mkdir "#{APPNAME}.app/Contents/Resources" -# mkdir "#{APPNAME}.app/Contents/Resources/English.lproj" -# sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/App.icns\"" -# sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/Contents/Resources/App.icns\"" -# rewrite "platform/mac/Info.plist", "#{APPNAME}.app/Contents/Info.plist" -# cp "platform/mac/version.plist", "#{APPNAME}.app/Contents/" -# rewrite "platform/mac/pangorc", "#{APPNAME}.app/Contents/MacOS/pangorc" -# cp "platform/mac/command-manual.rb", "#{APPNAME}.app/Contents/MacOS/" -# rewrite "platform/mac/shoes-launch", "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch" -# chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch" -# chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-bin" -# rewrite "platform/mac/shoes", "#{APPNAME}.app/Contents/MacOS/#{NAME}" -# chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}" -# chmod_R 0755, "#{APPNAME}.app/Contents/MacOS/pango-querymodules" -# # cp InfoPlist.strings YourApp.app/Contents/Resources/English.lproj/ -# `echo -n 'APPL????' > "#{APPNAME}.app/Contents/PkgInfo"` -# end -# end -# -# desc "Verify the build products" -# task :verify => ['verify:sanity', 'verify:lib_paths'] -# -# namespace :verify do -# def report_error message -# STDERR.puts "BUILD ERROR: " + message -# end -# -# task :sanity do -# report_error "No #{APPNAME}.app file found" unless File.exist? "#{APPNAME}.app" -# [NAME, "#{NAME}-launch", "#{NAME}-bin"].each do |f| -# report_error "No #{f} file found" unless File.exist? "#{APPNAME}.app/Contents/MacOS/#{f}" -# end -# end -# -# task :lib_paths do -# cd "#{APPNAME}.app/Contents/MacOS" do -# errors = [] -# ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f| -# dylibs = dylibs_to_change(f) -# dylibs.each do |dylib| -# errors << "Suspect library path on #{f}:\n #{dylib}\n (check with `otool -L #{File.expand_path f}`)" -# end -# end -# errors.each {|e| report_error e} -# end -# end -# end -# -# task :make_app do -# # Builder.make_app "dist/#{NAME}" -# bin = "dist/#{NAME}-bin" -# rm_f "dist/#{NAME}" -# rm_f bin -# sh "#{CC} -Ldist -o #{bin} bin/main.o #{LINUX_LIBS} -lshoes #{OSX_ARCH}" -# end -# -# task :make_so do -# name = "dist/lib#{SONAME}.#{DLEXT}" -# ldflags = LINUX_LDFLAGS.sub! /INSTALL_NAME/, "-install_name @executable_path/lib#{SONAME}.#{DLEXT}" -# sh "#{CC} -o #{name} #{OBJ.join(' ')} #{LINUX_LDFLAGS} #{LINUX_LIBS}" -# %w[libpostproc.dylib libavformat.dylib libavcodec.dylib libavutil.dylib libruby.dylib].each do |libn| -# sh "install_name_tool -change /tmp/dep/lib/#{libn} ./deps/lib/#{libn} #{name}" -# end -# end -# -# task :installer do -# dmg_ds, dmg_jpg = "platform/mac/dmg_ds_store", "static/shoes-dmg.jpg" -# if APP['dmg'] -# dmg_ds, dmg_jpg = APP['dmg']['ds_store'], APP['dmg']['background'] -# end -# -# mkdir_p "pkg" -# rm_rf "dmg" -# mkdir_p "dmg" -# cp_r "#{APPNAME}.app", "dmg" -# unless ENV['APP'] -# mv "dmg/#{APPNAME}.app/Contents/MacOS/samples", "dmg/samples" -# end -# ln_s "/Applications", "dmg/Applications" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/pango-querymodules" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-bin" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-launch" -# sh "DYLD_LIBRARY_PATH= platform/mac/pkg-dmg --target pkg/#{PKG}.dmg --source dmg --volname '#{APPNAME}' --copy #{dmg_ds}:/.DS_Store --mkdir /.background --copy #{dmg_jpg}:/.background" # --format UDRW" -# rm_rf "dmg" -# end -#end -# -#namespace :win32 do -# task :build => [:old_build] -# -# task :make_app do -# Builder.make_app "dist/#{NAME}" -# end -# -# task :make_so do -# Builder.make_so "dist/lib#{SONAME}.#{DLEXT}" -# end -# -# task :installer do -# Builder.make_installer -# end -#end -# -#namespace :linux do -# task :build => [:old_build] -# -# task :make_app do -# Builder.make_app "dist/#{NAME}" -# end -# -# task :make_so do -# Builder.make_so "dist/lib#{SONAME}.#{DLEXT}" -# end -# -# task :installer do -# Builder.make_installer -# end -#end -# -#======= -# -#begin -# require 'jeweler' -# Jeweler::Tasks.new do |gem| -# gem.name = "shoes" -# gem.summary = %Q{JRuby implementation of shoes} -# gem.description = %Q{JRuby implementation of shoes} -# gem.email = "stwerner@vt.edu" -# gem.homepage = "http://github.com/scottw/shoes" -# gem.authors = ["Scott Werner"] -# gem.add_development_dependency "rspec", ">= 1.2.9" -# gem.files.include('lib/**/*.rb') -# # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings -# end -# Jeweler::GemcutterTasks.new -#rescue LoadError -# puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler" -#end +require 'rspec' +require 'facets/hash' -require 'rspec/core/rake_task' -RSpec::Core::RakeTask.new(:spec) do |spec| - #spec.libs << 'lib' << 'spec' - spec.pattern = 'spec/**/*_spec.rb' +require 'jruby' +JRuby.runtime.instance_config.runRubyInProcess = false + +# thanks Dan Lucraft! +def jruby_run(cmd, swt = false) + opts = "-J-XstartOnFirstThread" if swt && Config::CONFIG["host_os"] =~ /darwin/ + + # see https://github.com/jruby/jruby/wiki/FAQs + # "How can I increase the heap/memory size when launching a sub-JRuby?" + sh( "jruby --debug --1.9 #{opts} -S #{cmd}" ) +end + +def rspec(files, options = "") + rspec_opts = "#{options} #{files}" + "./bin/rspec --tty #{rspec_opts}" end # run rspec in separate Jruby JVM @@ -548,18 +39,67 @@ def jruby_rspec(files, args) #return { :examples => examples_failures[1], :failures => examples_failures[2] } end -#task :spec => :check_dependencies +def spec_opts_from_args(args) + opts = args[:module] ? "-e ::#{args[:module]}" : "" +end task :default => :spec -# -#require 'rake/rdoctask' -#Rake::RDocTask.new do |rdoc| -# version = File.exist?('VERSION') ? File.read('VERSION') : "" -# -# rdoc.rdoc_dir = 'rdoc' -# rdoc.title = "shoes #{version}" -# rdoc.rdoc_files.include('README*') -# rdoc.rdoc_files.include('lib/**/*.rb') -#end -#>>>>>>> brown/master +desc "Run All Specs" +task :spec, [:module] => "spec:all" do + +end + +namespace :spec do + + + + desc "Run All Specs / All Modules" + task :default => ["spec:all"] + + desc "Run Specs on Shoes + All Frameworks + Limit the examples to specific :modules : + Animation + App + Button + Flow + + ie. $ rake spec:all[Flow] + " + task "all", [:module] do |t, args| + Rake::Task["spec:shoes"].invoke(args[:module]) + Rake::Task["spec:swing"].invoke(args[:module]) + Rake::Task["spec:swt"].invoke(args[:module]) + Rake::Task["spec:white"].invoke(args[:module]) + end + + desc "Specs for WhiteShoes Framework + Limit the examples to specific :modules : see spec:all " + task "white", [:module] do |t, args| + argh = args.to_hash + jruby_rspec("spec/white_shoes/*_spec.rb", argh) + end + + desc "Specs for Swing Framework + Limit the examples to specific :modules : see spec:all " + task "swing", [:module] do |t, args| + argh = args.to_hash + jruby_rspec("spec/swing_shoes/*_spec.rb", argh) + end + + desc "Specs for SWT Framework + Limit the examples to specific :modules : " + task "swt", [:module] do |t, args| + argh = args.to_hash + argh[:swt] = true + jruby_rspec("spec/swt_shoes/*_spec.rb", argh) + end + + desc "Specs for base Shoes libraries + Limit the examples to specific :modules : " + task "shoes", [:module] do |t, args| + argh = args.to_hash + jruby_rspec("spec/shoes/*_spec.rb", argh) + end + +end diff --git a/lib/shoes.rb b/lib/shoes.rb index e21e8447..28871854 100644 --- a/lib/shoes.rb +++ b/lib/shoes.rb @@ -20,7 +20,7 @@ def self.logger require 'shoes/app' #require 'shoes/native' #require 'shoes/element_methods' -#require 'shoes/animation' +require 'shoes/animation' #require 'shoes/runnable_block' #require 'shoes/timer_base' #require 'shoes/layout' diff --git a/lib/shoes/animation.rb b/lib/shoes/animation.rb index 741b6450..fa041ade 100644 --- a/lib/shoes/animation.rb +++ b/lib/shoes/animation.rb @@ -4,31 +4,26 @@ module Shoes class Animation < TimerBase - import javax.swing.Timer - - attr_reader :jtimer - - def initialize this, fps, &blk - ms_per_frame = 1000 / fps - - if block_given? - @runnable = RunnableBlock.new(this, blk) - @jtimer = Timer.new(ms_per_frame, @runnable ) - - #@runnable.init - @jtimer.start - end - end - - def stop - #@runnable.stop - @jtimer.stop - end - - def start - #@runnable.start - @jtimer.start + # Creates a new Animation. + # + # Arguments + # + # gui_container - The gui element that is the parent of this animation + # opts - Either an integer, representing the framerate (frames per + # second) of the animation, or a Hash of options. Right now, + # framerate is the only supported option. If no framerate + # is provided, the default is 24. + # blk - A block of code to be executed for each frame of the + # animation. + # + def initialize gui_container, *opts, &blk + @current_frame = 0 + @style = opts.last.class == Hash ? opts.pop : {} + @style[:framerate] = opts.first if opts.length == 1 + @framerate = @style[:framerate] || 24 + super gui_container, @style, &blk end + attr_reader :framerate end end diff --git a/lib/shoes/app.rb b/lib/shoes/app.rb index ba6e9e8f..4dff2e41 100644 --- a/lib/shoes/app.rb +++ b/lib/shoes/app.rb @@ -34,6 +34,7 @@ def initialize(opts={}, &blk) self.opts = opts + @app = self @style = DEFAULT_STYLE gui_init diff --git a/lib/shoes/button.rb b/lib/shoes/button.rb index 06e30cf5..ea6afb0d 100644 --- a/lib/shoes/button.rb +++ b/lib/shoes/button.rb @@ -1,17 +1,21 @@ +require 'shoes/common_methods' + module Shoes class Button + include Shoes::CommonMethods attr_accessor :gui_container, :click_event_lambda attr_accessor :gui_element - attr_accessor :text, :width, :height + attr_accessor :text def initialize(gui_container, text = 'Button', opts={}, click_event_lambda = nil) self.gui_container = gui_container self.click_event_lambda = click_event_lambda self.text = text - self.height = opts[:height] - self.width = opts[:width] - + @app = opts[:app] + @height = opts[:height] + @width = opts[:width] + gui_button_init end diff --git a/lib/shoes/common/paint.rb b/lib/shoes/common/paint.rb index 91ac5a2b..68055fe6 100644 --- a/lib/shoes/common/paint.rb +++ b/lib/shoes/common/paint.rb @@ -1,6 +1,11 @@ module Shoes module Common module Paint + DEFAULTS = { + :stroke => Shoes::COLORS[:black], + :fill => Shoes::COLORS[:black] + } + def stroke @style[:stroke] end @@ -8,6 +13,14 @@ def stroke def stroke=(color) @style[:stroke] = color end + + def fill + @style[:fill] + end + + def fill=(color) + @style[:fill] = color + end end end end diff --git a/lib/shoes/common_methods.rb b/lib/shoes/common_methods.rb index 28c9b9b0..09358e27 100644 --- a/lib/shoes/common_methods.rb +++ b/lib/shoes/common_methods.rb @@ -78,6 +78,12 @@ def toggle end + # Moves an element to a specific pixel position. The element is still in the slot, + # but will no longer be stacked or flowed with the other stuff in the slot. + def move(left, top) + @left, @top = left, top + end + # displace(left: a number, top: a number) ยป self # Displacing an element moves it. But without changing the layout around it. def displace(left, top) diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 06a85473..5b3f8532 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -24,18 +24,44 @@ module ElementMethods #end def flow(opts = {}, &blk) + opts.merge! :app => @app swt_flow = Shoes::Flow.new(self, self.gui_container, opts, blk) + #puts "flow gui_container: #{swt_flow.gui_container.inspect}" + #puts "flow gui_container.layout: #{swt_flow.gui_container.layout.inspect}" + #puts "app(?) gui_container: #{self.gui_container.inspect}" end def button(text, opts={}, &blk) + opts.merge! :app => @app button = Shoes::Button.new(self.gui_container, text, opts, blk) #@elements[button.to_s] = button #button end - def animate(fps = 10, &blk) - anim = Shoes::Animation.new(self, fps, &blk) + # Creates an animation that runs the given block of code. + # + # Signatures + # + # # Defaults to framerate of 24 frames per second + # animate do + # # animation code + # end + # + # # Uses a framerate of 10 frames per second + # animate 10 do + # # animation code + # end + # + # # Uses a framerate of 10 frames per second + # animate :framerate => 10 do + # # animation code + # end + # + def animate(opts = {}, &blk) + opts = {:framerate => opts} unless opts.is_a? Hash + opts.merge! :app => @app + animation = Shoes::Animation.new(gui_container, opts, &blk) end # similar controls as Shoes::Video (#video) @@ -88,8 +114,8 @@ def oval(*opts) end # Creates a new Shoes::Shape object - def shape(style={}, &blk) - Shoes::Shape.new(style, blk) + def shape(shape_style={}, &blk) + Shoes::Shape.new(style.merge(shape_style), blk) end # Creates a new Shoes::Color object @@ -111,6 +137,15 @@ def strokewidth(width) @style[:strokewidth] = width end + # Sets the current fill color + # + # Arguments + # + # color - a Shoes::Color + def fill(color) + @style[:fill] = color + end + # Adds style, or just returns current style if no argument # # Returns the updated style diff --git a/lib/shoes/flow.rb b/lib/shoes/flow.rb index e28cabb3..c693963a 100644 --- a/lib/shoes/flow.rb +++ b/lib/shoes/flow.rb @@ -18,6 +18,7 @@ def initialize(parent_container, parent_gui_container, opts={}, blk = nil) self.width = opts['width'] self.height = opts['height'] self.margin = opts['margin'] + @app = opts['app'] self.blk = blk @@ -29,4 +30,4 @@ def initialize(parent_container, parent_gui_container, opts={}, blk = nil) end end -end \ No newline at end of file +end diff --git a/lib/shoes/line.rb b/lib/shoes/line.rb index b1926009..bc03bddd 100644 --- a/lib/shoes/line.rb +++ b/lib/shoes/line.rb @@ -14,7 +14,7 @@ def initialize(x1, y1, x2, y2, opts = {}) @width = (x1 - x2).abs @height = (y1 - y2).abs - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) # GUI @gui_opts = @style.delete(:gui) diff --git a/lib/shoes/oval.rb b/lib/shoes/oval.rb index 143b35ed..958c9ddf 100644 --- a/lib/shoes/oval.rb +++ b/lib/shoes/oval.rb @@ -17,7 +17,7 @@ def initialize(*opts) when 3; @style[:left], @style[:top], @style[:radius] = opts else @style[:left], @style[:top], @style[:width], @style[:height] = opts end - @style = defaults.merge(@style) + @style = Shoes::Common::Paint::DEFAULTS.merge(defaults).merge(@style) @left = @style[:left] @top = @style[:top] @width = @style[:width] diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index 125e56c5..bf56b266 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -20,18 +20,10 @@ class Shape # Implementation frameworks should pass in any required arguments # through the +opts+ hash. def initialize(opts = {}, blk = nil) - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) @blk = blk - @left = @style[:left] || 0 - @top = @style[:top] || 0 - @width = @style[:width] || 0 - @height = @style[:height] || 0 - - # Initialize current point to (left, top) - @x, @y = @left, @top - # Component shapes @components = [] @@ -43,19 +35,19 @@ def initialize(opts = {}, blk = nil) end def left - @components.map(&:left).min + @left || @components.map(&:left).min || 0 end def top - @components.map(&:top).min + @top || @components.map(&:top).min || 0 end def right - @components.map { |c| c.left + c.width }.max + @right || @components.map { |c| c.left + c.width }.max || left end def bottom - @components.map { |c| c.top + c.height }.max + @bottom || @components.map { |c| c.top + c.height }.max || top end def width @@ -65,5 +57,29 @@ def width def height (top - bottom).abs end + + # Moves the shape + # + # Moves each component so bounds calculations still work. + def move(left, top) + relative_left = offset(self.left, left) + relative_top = offset(self.top, top) + @components.each do |c| + c_left = c.left + c_top = c.top + c.move(c_left + relative_left, c_top + relative_top) + end + @left, @top, @right, @bottom = left, top, nil, nil + end + + # Gives the relative offset of the new position from original position + # + # Returns a value that should be added to the current position in order to + # move to the new position. + def offset(original, new) + relative = (new - original).abs + relative = -relative if new < original + relative + end end end diff --git a/lib/shoes/timer_base.rb b/lib/shoes/timer_base.rb index 4b6aac9c..bc2d2947 100644 --- a/lib/shoes/timer_base.rb +++ b/lib/shoes/timer_base.rb @@ -1,5 +1,27 @@ module Shoes class TimerBase - # To change this template use File | Settings | File Templates. + def initialize gui_container, opts, &blk + @gui_container = gui_container + @blk = blk + @app = opts[:app] + @stopped = false + gui_init + end + + def start + @stopped = false + end + + def stop + @stopped = true + end + + def stopped? + @stopped + end + + def toggle + @stopped = !@stopped + end end -end \ No newline at end of file +end diff --git a/lib/swt_shoes.rb b/lib/swt_shoes.rb index de3a009d..32ca1a4e 100644 --- a/lib/swt_shoes.rb +++ b/lib/swt_shoes.rb @@ -10,6 +10,7 @@ def window(*a, &b) end require 'swt_shoes/element_methods' +require 'swt_shoes/animation' require 'swt_shoes/app' require 'swt_shoes/layout' #require 'swt_shoes/window' @@ -28,10 +29,6 @@ def self.app(opts={}, &blk) Shoes::App.new(opts, &blk) logger.debug "Exiting Shoes.app" end - - def self.display - Swt::Widgets::Display.getCurrent - end end end diff --git a/lib/swt_shoes/animation.rb b/lib/swt_shoes/animation.rb index c3c1bb94..c5fb19da 100644 --- a/lib/swt_shoes/animation.rb +++ b/lib/swt_shoes/animation.rb @@ -1,26 +1,45 @@ require 'shoes/timer_base' require 'shoes/runnable_block' -module Shoes - class Animation < TimerBase - - def initialize fps, &blk - ms_per_frame = 1000 / fps - - if block_given? - @runnable = RunnableBlock.new(ms_per_frame, blk) - - @runnable.init +module SwtShoes + module Animation + def gui_init + # Wrap the animation block so we can count frames. + # Note that the task re-calls itself on each run. + task = Proc.new do + @blk.call(@current_frame) + @current_frame += 1 + @app.gui_container.redraw + Swt.display.timer_exec (2000 / @framerate), task end + Swt.display.timer_exec (2000 / @framerate), task end - def stop - @runnable.stop + def run end + #def initialize fps, &blk + #ms_per_frame = 1000 / fps - def start - @runnable.start - end + #if block_given? + #@runnable = RunnableBlock.new(ms_per_frame, blk) + + #@runnable.init + #end + #end + #def stop + #@runnable.stop + #end + + #def start + #@runnable.start + #end + + end +end + +module Shoes + class Animation + include SwtShoes::Animation end end diff --git a/lib/swt_shoes/button.rb b/lib/swt_shoes/button.rb index 4c4bb51d..193599e6 100644 --- a/lib/swt_shoes/button.rb +++ b/lib/swt_shoes/button.rb @@ -12,6 +12,30 @@ def gui_button_init button.pack end + def move(left, top) + super(left, top) + unless gui_element.disposed? + # If this element is part of a layout, we need to pop it into its own + # composite layer before moving it, so the rest of of the elements in + # the layout can reflow. + if gui_container.get_layout + old_gui_container = self.gui_container + self.gui_container = Swt::Widgets::Composite.new(@app.gui_container, Swt::SWT::NO_BACKGROUND) + self.gui_element.dispose + self.gui_container.set_layout nil + self.gui_element = Swt::Widgets::Button.new(gui_container, Swt::SWT::PUSH).tap do |button| + button.set_text(self.text) + button.add_selection_listener(self.click_event_lambda) if click_event_lambda + button.pack + end + self.gui_container.set_bounds(0, 0, @app.gui_container.size.x, @app.gui_container.size.y) + self.gui_container.move_above(old_gui_container) + old_gui_container.layout + end + self.gui_element.set_location left, top + self.gui_element.redraw + end + end end end diff --git a/lib/swt_shoes/color.rb b/lib/swt_shoes/color.rb index 33f4b1a4..8fa707b1 100644 --- a/lib/swt_shoes/color.rb +++ b/lib/swt_shoes/color.rb @@ -1,7 +1,7 @@ module SwtShoes module Color def to_native - Swt::Graphics::Color.new(Shoes.display, @red, @green, @blue) + Swt::Graphics::Color.new(Swt.display, @red, @green, @blue) end end end diff --git a/lib/swt_shoes/element_methods.rb b/lib/swt_shoes/element_methods.rb index 34ca0498..acaeb8b6 100644 --- a/lib/swt_shoes/element_methods.rb +++ b/lib/swt_shoes/element_methods.rb @@ -57,23 +57,14 @@ def line(*opts) super(*opts, args) end + # FIXME: same as #line, #shape def oval(*opts) args = opts.last.class == Hash ? opts.pop : {} - args[:gui] = { - container: self.gui_container, - paint_callback: lambda do |event, shape| - #return if hidden? - gc = event.gc - gc.set_antialias Swt::SWT::ON - gc.set_line_width shape.style[:strokewidth] - gc.setForeground(shape.style[:stroke].to_native) - gc.draw_oval(shape.left, shape.top, shape.width, shape.height) - end - } + args[:gui] = {container: self.gui_container} super(*opts, args) end - # FIXME: same as #line + # FIXME: same as #line, #oval def shape(*opts) args = opts.last.class == Hash ? opts.pop : {} args[:gui] = {container: self.gui_container} diff --git a/lib/swt_shoes/flow.rb b/lib/swt_shoes/flow.rb index ddc4d8ec..21b8679c 100644 --- a/lib/swt_shoes/flow.rb +++ b/lib/swt_shoes/flow.rb @@ -5,7 +5,7 @@ module SwtShoes module Flow def gui_flow_init - self.gui_container = container = Swt::Widgets::Composite.new(self.parent_gui_container, Swt::SWT::NONE) + self.gui_container = container = Swt::Widgets::Composite.new(self.parent_gui_container, Swt::SWT::NO_BACKGROUND) # RowLayout is horizontal by default, wrapping by default layout = Swt::Layout::RowLayout.new diff --git a/lib/swt_shoes/line.rb b/lib/swt_shoes/line.rb index 80c495cc..4ac55482 100644 --- a/lib/swt_shoes/line.rb +++ b/lib/swt_shoes/line.rb @@ -1,6 +1,7 @@ module SwtShoes module Line attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback def gui_init # @gui_opts must be provided if this shape is responsible for @@ -11,6 +12,7 @@ def gui_init default_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_line(@left, @top, right, bottom) end diff --git a/lib/swt_shoes/oval.rb b/lib/swt_shoes/oval.rb index fe0bcc9c..6ab26fa3 100644 --- a/lib/swt_shoes/oval.rb +++ b/lib/swt_shoes/oval.rb @@ -1,6 +1,7 @@ module SwtShoes module Oval attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # FIXME: This (mostly) duplicates SwtShoes::Line#gui_init def gui_init @@ -12,6 +13,9 @@ def gui_init @gui_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_background self.fill.to_native + gc.fill_oval(@left, @top, @width, @height) + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_oval(@left, @top, @width, @height) end diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 0b315d36..d1aec8e7 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -8,8 +8,8 @@ module SwtShoes # @opts - options # module Shape - attr_reader :gui_container - attr_reader :gui_element + attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # The initialization hook for SwtShoes. # @@ -42,12 +42,19 @@ def gui_init # @gui_opts should be nil if @gui_opts @gui_container = @gui_opts[:container] - @gui_element = @gui_opts[:element] || Swt::Path.new(Shoes.display) + @gui_element = @gui_opts[:element] || Swt::Path.new(Swt.display) + #@transform.translate(-130, -100) @gui_paint_callback = lambda do |event| gc = event.gc + @transform = Swt::Transform.new(Swt.display) unless @transform + gc.setTransform(@transform) + gc.set_background self.fill.to_native + gc.fill_path(@gui_element) gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_path(@gui_element) + @transform.dispose end @gui_container.add_paint_listener(@gui_paint_callback) end @@ -62,11 +69,26 @@ def move_to(x, y) @x, @y = x, y @gui_element.move_to(x, y) end + + def move(left, top) + super left, top + @transform = Swt::Transform.new(Swt.display) + @transform.translate(self.left, self.top) + end end end module Shoes class Shape - include SwtShoes::Shape + # This is a hack to allow methods in this class to override methods + # defined in Shoes::Shape. It would be better fixed by a different + # architecture. The self.extend doesn't work if the module has already + # been included by the class. + #include SwtShoes::Shape + alias :old_initialize :initialize + def initialize(opts = {}, blk = nil) + self.extend SwtShoes::Shape + old_initialize opts, blk + end end end diff --git a/lib/white_shoes.rb b/lib/white_shoes.rb index 8f829d3c..4252a265 100644 --- a/lib/white_shoes.rb +++ b/lib/white_shoes.rb @@ -1,5 +1,6 @@ #require 'white_shoes/base' +require 'white_shoes/animation' require 'white_shoes/app' require 'white_shoes/flow' require 'white_shoes/button' diff --git a/lib/white_shoes/animation.rb b/lib/white_shoes/animation.rb new file mode 100644 index 00000000..949a9b71 --- /dev/null +++ b/lib/white_shoes/animation.rb @@ -0,0 +1,20 @@ +module WhiteShoes + module Animation + def gui_init + # Simulate an animation thread (note: this never stops) + Thread.new do + loop do + @blk.call(@current_frame) + @current_frame += 1 + sleep(1/@framerate) + end + end.start + end + end +end + +module Shoes + class Animation + include WhiteShoes::Animation + end +end diff --git a/samples/working-swt/simple-move.rb b/samples/working-swt/simple-move.rb new file mode 120000 index 00000000..9f8ba55a --- /dev/null +++ b/samples/working-swt/simple-move.rb @@ -0,0 +1 @@ +../simple-move.rb \ No newline at end of file diff --git a/spec/shoes/animation_spec.rb b/spec/shoes/animation_spec.rb new file mode 100644 index 00000000..2a6c2db8 --- /dev/null +++ b/spec/shoes/animation_spec.rb @@ -0,0 +1,53 @@ +require 'shoes/animation' + +describe Shoes::Animation do + let(:gui_container) { double("gui container") } + subject { Shoes::Animation.new(gui_container, 30) } + + it "defaults to started" do + subject.should_not be_stopped + end + + context "started" do + it "is not stopped" do + subject.should_not be_stopped + end + + it "stops" do + subject.stop + subject.should be_stopped + end + + it "toggles to stopped" do + subject.toggle + subject.should be_stopped + end + end + + context "stopped" do + before :each do + subject.stop + end + + it "is stopped" do + subject.should be_stopped + end + + it "starts" do + subject.start + subject.should_not be_stopped + end + + it "toggles to off" do + subject.toggle + subject.should_not be_stopped + end + end + + it "counts frames" do + counter = 0 + animation = Shoes::Animation.new(gui_container, 24) { |frame| counter += frame } + sleep(0.1) + counter.should be > 0 + end +end diff --git a/spec/shoes/button_spec.rb b/spec/shoes/button_spec.rb index 7b4b2c5c..5abbf7bd 100644 --- a/spec/shoes/button_spec.rb +++ b/spec/shoes/button_spec.rb @@ -6,16 +6,20 @@ describe Shoes::Button do - #it_should_behave_like "A Common Element" + let(:input_block) { lambda {} } + let(:input_opts) { {:width => 131, :height => 137, :margin => 143} } + subject { Shoes::Button.new("gui_container", "text", input_opts, input_block) } + + it_behaves_like "movable object" describe "initialize" do it "should set accessors" do - input_block = lambda {} - input_opts = {:width => 131, :height => 137, :margin => 143} - button = Shoes::Button.new("gui_container", "text", input_opts, input_block) + button = subject button.gui_container.should == "gui_container" button.click_event_lambda.should == input_block button.text.should == "text" + button.width.should == 131 + button.height.should == 137 end end end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 0ec1c5e1..04f7915d 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -1,4 +1,5 @@ require_relative 'spec_helper' +require "shoes/color" require 'shoes/element_methods' require 'shoes/configuration' @@ -31,6 +32,7 @@ def initialize subject.gui_container = "gui_container" blk = lambda {} opts = mock(:hash) + opts.should_receive(:merge!).and_return(opts) Shoes::Flow.should_receive(:new). with(subject, "gui_container", opts, blk) subject.flow opts, &blk @@ -51,14 +53,22 @@ def initialize end describe "shape" do - it "produces a Shoes::Shape" do - shape = ElementMethodsShoeLaces.new.shape do + let(:app) { ElementMethodsShoeLaces.new } + subject { + app.shape { move_to 400, 300 line_to 400, 200 line_to 100, 100 line_to 400, 300 - end - shape.should be_an_instance_of(Shoes::Shape) + } + } + + it { should be_an_instance_of(Shoes::Shape) } + + it "receives style from app" do + green = Shoes::COLORS.fetch :green + app.style[:stroke] = green + subject.stroke.should eq(green) end end @@ -81,9 +91,8 @@ def initialize end describe "stroke" do - require "shoes/color" # Need the colors! let(:app) { ElementMethodsShoeLaces.new } - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do app.stroke(color).class.should eq(Shoes::Color) @@ -126,6 +135,57 @@ def initialize end end + describe "fill" do + let(:app) { ElementMethodsShoeLaces.new } + let(:color) { Shoes::COLORS.fetch :tomato } + + specify "returns a color" do + app.fill(color).class.should eq(Shoes::Color) + end + + # This works differently on the app than on a normal element + specify "sets on receiver" do + app.fill color + app.style[:fill].should eq(color) + end + + specify "applies to subsequently created objects" do + app.fill color + Shoes::Oval.should_receive(:new).with do |*args| + style = args.pop + style[:fill].should eq(color) + end + app.oval(10, 10, 100, 100) + end + end + + describe "animate" do + let(:app) { ElementMethodsShoeLaces.new } + + shared_examples_for "basic" do + it { should be_an_instance_of(Shoes::Animation) } + end + + shared_examples_for "10fps" do + its(:framerate) { should eq(10) } + end + + context "defaults" do + subject { app.animate {} } + it_behaves_like "basic" + its(:framerate) { should eq(24) } + end + + context "with numeric argument" do + subject { app.animate(10) {} } + it_behaves_like "basic" + it_behaves_like "10fps" + end + + context "with hash argument" do + + end + end #it "Should return 0 for left for button_one" do # @gui.elements['button_one'].left.should be 0 #end diff --git a/spec/shoes/line_spec.rb b/spec/shoes/line_spec.rb index 6cd430b3..8e398d3a 100644 --- a/spec/shoes/line_spec.rb +++ b/spec/shoes/line_spec.rb @@ -3,6 +3,12 @@ require 'white_shoes' describe Shoes::Line do + describe "basic" do + subject { Shoes::Line.new(20, 23, 300, 430) } + it_behaves_like "object with stroke" + it_behaves_like "movable object" + end + shared_examples_for "basic line" do it { should be_kind_of(Shoes::Line) } its(:top) { should eq(15) } diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb index 04c2dfae..fe166a74 100644 --- a/spec/shoes/oval_spec.rb +++ b/spec/shoes/oval_spec.rb @@ -3,6 +3,13 @@ require 'white_shoes' describe Shoes::Oval do + describe "basic" do + subject { Shoes::Oval.new(20, 30, 100, 200) } + it_behaves_like "object with stroke" + it_behaves_like "object with fill" + it_behaves_like "movable object" + end + context "(eccentric)" do subject { Shoes::Oval.new(20, 30, 100, 200) } diff --git a/spec/shoes/shape_spec.rb b/spec/shoes/shape_spec.rb index f5940b78..0d632d3f 100644 --- a/spec/shoes/shape_spec.rb +++ b/spec/shoes/shape_spec.rb @@ -5,6 +5,7 @@ describe Shoes::Shape do it_behaves_like "object with stroke" it_behaves_like "object with style" + it_behaves_like "movable object" describe "octagon" do let(:draw) { @@ -26,5 +27,7 @@ its(:bottom) { should eq(340) } its(:width) { should eq(240) } its(:height) { should eq(240) } + + it_behaves_like "movable object" end end diff --git a/spec/shoes/shared_examples/common_methods_spec.rb b/spec/shoes/shared_examples/common_methods_spec.rb new file mode 100644 index 00000000..c71241a1 --- /dev/null +++ b/spec/shoes/shared_examples/common_methods_spec.rb @@ -0,0 +1,8 @@ +shared_examples_for "movable object" do + it "moves" do + subject.move(300, 200) + subject.left.should eq(300) + subject.top.should eq(200) + end +end + diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index 399964e8..983f6dfd 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -1,7 +1,7 @@ require 'shoes/color' shared_examples_for "object with stroke" do - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do c = subject.stroke = color @@ -13,6 +13,29 @@ subject.stroke.should eq(color) subject.style[:stroke].should eq(color) end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.stroke.should eq(Shoes::COLORS.fetch :black) + end end +shared_examples_for "object with fill" do + let(:color) { Shoes::COLORS.fetch :honeydew } + + specify "returns a color" do + c = subject.fill = color + c.class.should eq(Shoes::Color) + end + specify "sets on receiver" do + subject.fill = color + subject.fill.should eq(color) + subject.style[:fill].should eq(color) + end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.fill.should eq(Shoes::COLORS.fetch :black) + end +end diff --git a/spec/swt_shoes/animation_spec.rb b/spec/swt_shoes/animation_spec.rb new file mode 100644 index 00000000..024a8cf3 --- /dev/null +++ b/spec/swt_shoes/animation_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' +require 'swt_shoes/spec_helper' + +describe SwtShoes::Animation do + class AnimationShoeLaces + include SwtShoes::Animation + # This is painfully duplicated from Shoes::Animation + def initialize(*opts, &blk) + @style = opts.last.class == Hash ? opts.pop : {} + @style[:framerate] = opts.first if opts.length == 1 + @framerate = @style[:framerate] || 24 + @blk = blk + @current_frame = 0 + gui_init + end + end + + let(:block) { Proc.new {} } + let(:display) { Swt.display } + let(:gui_container) { double(:gui_container) } + subject { AnimationShoeLaces.new &block } + + it "injects into Shoes::Animation" do + Shoes::Animation.ancestors.should include(SwtShoes::Animation) + end + + it "triggers an Swt timer" do + display.should_receive :timer_exec + subject + end + + describe "frames" do + it "counts frames" do + pending "this feature works in an app, but not in this spec. Need some creativity." + # Using a real Shoes::Animation here + animation = Shoes::Animation.new gui_container, 30 do + "no-op" + end + sleep(1) + animation.instance_variable_get(:@current_frame).should be > 1 + end + end +end diff --git a/spec/swt_shoes/button_spec.rb b/spec/swt_shoes/button_spec.rb index 7c0923a0..525c9747 100644 --- a/spec/swt_shoes/button_spec.rb +++ b/spec/swt_shoes/button_spec.rb @@ -8,20 +8,33 @@ #it_should_behave_like "A Common Element" - class ButtonShoeLaces - include SwtShoes::Button attr_accessor :gui_container, :gui_element, :text, :height, :width, :margin, :click_event_lambda + attr_accessor :app + + # because SwtShoes::Button#move calls super :( + def move(left, top) + # no-op + end end - let(:stub_gui_parent) { Swt.display } + let(:gui_container) { double("gui container", :get_layout => true) } + let(:gui_element) { double("gui element") } + let(:app_gui_container) { double("app gui container") } + let(:app) { double("app", :gui_container => app_gui_container) } let(:shoelace) { shoelace = ButtonShoeLaces.new - debugger - shoelace.parent_gui_container = stub_gui_parent + shoelace.extend described_class + shoelace.gui_container = gui_container + shoelace.gui_element = gui_element + shoelace.app = app shoelace } + subject { shoelace } + + it_behaves_like "movable object with disposable gui element" + describe "WhiteShoes requirements" do let(:mock_element) { mock(:element, :setText => true, :pack => true )} @@ -72,4 +85,4 @@ class ButtonShoeLaces # end #end -end \ No newline at end of file +end diff --git a/spec/swt_shoes/element_methods_spec.rb b/spec/swt_shoes/element_methods_spec.rb index 006e65d8..e6ae4839 100644 --- a/spec/swt_shoes/element_methods_spec.rb +++ b/spec/swt_shoes/element_methods_spec.rb @@ -60,5 +60,4 @@ def initialize subject.should be_an_instance_of(Shoes::Shape) end end - end diff --git a/spec/swt_shoes/line_spec.rb b/spec/swt_shoes/line_spec.rb index e0a418bb..32125289 100644 --- a/spec/swt_shoes/line_spec.rb +++ b/spec/swt_shoes/line_spec.rb @@ -28,4 +28,5 @@ end it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" end diff --git a/spec/swt_shoes/oval_spec.rb b/spec/swt_shoes/oval_spec.rb new file mode 100644 index 00000000..9b840ba6 --- /dev/null +++ b/spec/swt_shoes/oval_spec.rb @@ -0,0 +1,13 @@ +describe SwtShoes::Oval do + let(:gui_container) { double("gui container") } + let(:opts) { {:gui => {:container => gui_container}} } + + subject { + Shoes::Oval.new(10, 15, 100, opts) + } + + it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" +end + diff --git a/spec/swt_shoes/shape_spec.rb b/spec/swt_shoes/shape_spec.rb index e5080ab3..65a69c71 100644 --- a/spec/swt_shoes/shape_spec.rb +++ b/spec/swt_shoes/shape_spec.rb @@ -20,13 +20,9 @@ def initialize(opts = {}, blk = nil ) let(:args_with_element) { {container: gui_container, element: gui_element} } let(:args_without_element) { {container: gui_container} } - before :each do - gui_container.should_receive(:add_paint_listener) - end - shared_examples_for "Swt::Shape" do before :each do - gui_element.stub(:move_to) + gui_container.should_receive(:add_paint_listener) end it "uses Swt and not White Shoes" do @@ -43,7 +39,6 @@ def initialize(opts = {}, blk = nil ) subject { ShapeShoeLaces.new gui: args_with_element } it_behaves_like "Swt::Shape" - end context "with gui container only" do @@ -52,10 +47,28 @@ def initialize(opts = {}, blk = nil ) it_behaves_like "Swt::Shape" describe "gui_init" do + before :each do + gui_container.should_receive(:add_paint_listener) + end + it "should not set current point on gui element" do gui_element.should_not_receive(:move_to) subject end end end + + context "basic" do + subject { + Shoes::Shape.new(gui: args_without_element) { + move_to 150, 150 + line_to 300, 300 + line_to 0, 300 + line to 150, 350 + } + } + + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" + end end diff --git a/spec/swt_shoes/shared_examples/common_methods_spec.rb b/spec/swt_shoes/shared_examples/common_methods_spec.rb new file mode 100644 index 00000000..a5044765 --- /dev/null +++ b/spec/swt_shoes/shared_examples/common_methods_spec.rb @@ -0,0 +1,13 @@ +# Requires gui_element +shared_examples_for "movable object with disposable gui element" do + before :each do + Swt::Widgets::Composite.stub(:new) { double("composite").as_null_object } + end + + it "disposes its gui element" do + pending "setup is WAAAY too complicated" + gui_element.should_receive(:disposed?) + gui_element.should_receive(:dispose) + subject.move(300, 200) + end +end diff --git a/spec/swt_shoes/shared_examples/style_spec.rb b/spec/swt_shoes/shared_examples/style_spec.rb new file mode 100644 index 00000000..45624e78 --- /dev/null +++ b/spec/swt_shoes/shared_examples/style_spec.rb @@ -0,0 +1,43 @@ +shared_examples_for "Swt object with stroke" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets stroke color" do + gc.should_receive(:set_foreground).with(subject.stroke.to_native) + subject.gui_paint_callback.call(event) + end + + specify "sets antialias" do + gc.should_receive(:set_antialias).with(Swt::SWT::ON) + subject.gui_paint_callback.call(event) + end + + specify "sets strokewidth" do + gc.should_receive(:set_line_width).with(subject.style[:strokewidth]) + subject.gui_paint_callback.call(event) + end + end +end + +shared_examples_for "Swt object with fill" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets fill color" do + gc.should_receive(:set_background).with(subject.fill.to_native) + subject.gui_paint_callback.call(event) + end + end +end diff --git a/spec/swt_shoes/spec_helper.rb b/spec/swt_shoes/spec_helper.rb index 1e91dd31..b9431cab 100644 --- a/spec/swt_shoes/spec_helper.rb +++ b/spec/swt_shoes/spec_helper.rb @@ -1,2 +1,5 @@ require "swt_shoes" Shoes.configuration.framework = 'swt_shoes' + +shared_examples = File.join(File.dirname(__FILE__), 'shared_examples', '**/*.rb') +Dir[shared_examples].each { |f| require f }