[jruby~main:f25167ae] Ant integration: Get _element working better

  • From: nicksieger@kenai.com
  • To: commits@jruby.kenai.com
  • Subject: [jruby~main:f25167ae] Ant integration: Get _element working better
  • Date: Thu, 4 Mar 2010 23:08:00 +0000

Project:    jruby
Repository: main
Revision:   f25167ae6afa7afcebdcdd8d110b320cdd8f851e
Author:     nicksieger
Date:       2010-03-04 22:57:05 UTC
Link:       

Log Message:
------------
Ant integration: Get _element working better
- Start of a test suite
-- Need more target/task examples - they can go in task_spec.rb
- Also move all Ant elements to be imported/live inside the Ant class 
namespace


Revisions:
----------
f25167ae6afa7afcebdcdd8d110b320cdd8f851e


Modified Paths:
---------------
lib/ruby/site_ruby/shared/ant/ant.rb
lib/ruby/site_ruby/shared/ant/element.rb
lib/ruby/site_ruby/shared/ant/target.rb


Added Paths:
------------
spec/java_integration/ant/ant_spec.rb
spec/java_integration/ant/project_spec.rb
spec/java_integration/ant/target_spec.rb
spec/java_integration/ant/task_spec.rb
spec/java_integration/ant_spec_helper.rb


Diffs:
------
diff --git a/lib/ruby/site_ruby/shared/ant/ant.rb 
b/lib/ruby/site_ruby/shared/ant/ant.rb
index c2c43e2..e4a4b36 100644
--- a/lib/ruby/site_ruby/shared/ant/ant.rb
+++ b/lib/ruby/site_ruby/shared/ant/ant.rb
@@ -2,52 +2,34 @@ require 'java'
 require 'ant/element'
 require 'ant/target'
 
-java_import org.apache.tools.ant.ComponentHelper
-java_import org.apache.tools.ant.DefaultLogger
-java_import org.apache.tools.ant.Location
-java_import org.apache.tools.ant.Project
-java_import org.apache.tools.ant.ProjectHelper
-java_import org.apache.tools.ant.Target
-
 class Ant
+  java_import org.apache.tools.ant.ComponentHelper
+  java_import org.apache.tools.ant.DefaultLogger
+  java_import org.apache.tools.ant.Location
+  java_import org.apache.tools.ant.Project
+  java_import org.apache.tools.ant.ProjectHelper
+
   attr_reader :project, :log, :location
   attr_accessor :current_target
 
   def initialize(options={}, &block)
     @options = options
-    @location = Location.new(caller.detect{|el| el !~ 
/^#{__FILE__}/}.split(/:/).first)
+    @location = Ant.location_from_caller
     @project = create_project options
     @current_target = nil
     initialize_elements
-    handle_argv unless options[:run] == false || Ant.run || 
@location.file_name != $0
-  end
-
-  def create_project(options)
-    # If we are calling into a rakefile from ant then we already have a 
project to use
-    return $project if defined?($project) && $project
-
-    output_level = options.delete(:output_level) || 2
-
-    Project.new.tap do |p|
-      p.init
-      p.add_build_listener(DefaultLogger.new.tap do |log|
-        log.output_print_stream = java.lang.System.out
-        log.error_print_stream = java.lang.System.err
-        log.emacs_mode = true
-        log.message_output_level = output_level
-        @log = log
-      end)
-      helper = ProjectHelper.getProjectHelper
-      helper.import_stack.add(Object.new)
-      p.addReference(ProjectHelper::PROJECTHELPER_REFERENCE, helper)
-      options.each_pair {|k,v| p.send("set_#{k}", v) }
-    end
+    process_arguments unless options[:run] == false || Ant.run || 
@location.file_name != $0
+    define_tasks(&block)
   end
 
   def properties
     @project.properties
   end
 
+  def define_tasks(&code)
+    code.arity == 1 ? code[self] : instance_eval(&code) if code
+  end
+
   # Add a target (two forms)
   # 1. Execute a block as a target: add_target "foo-target" { echo :message 
=> "I am cool" }
   # 2. Execute a rake task as a target: add_target 
Rake.application["default"]
@@ -58,7 +40,7 @@ class Ant
   alias target add_target
 
   def [](name)
-    if @project.targets.containsKey(name)
+    if @project.targets.containsKey(name.to_s)
       TargetWrapper.new(@project, name)
     else
       MissingWrapper.new(@project, name)
@@ -109,10 +91,14 @@ class Ant
     @elements[name + clazz.to_s] = Element.new(self, name, clazz)
   end
 
-  def _element(name, *args, &block)
-#     raise "unknown element #{name}!" unless @helper.get_definition(name)
-    element = acquire_element(name, nil)
-    element.call(@current_target, *args, &block)
+  def _element(name, args = {}, &block)
+    definition = @helper.get_definition(name)
+    clazz = definition.getTypeClass(@project) if definition
+    Element.new(self, name, clazz).call(@current_target, args, &block)
+  end
+
+  def method_missing(name, *args, &block)
+    _element(name, *args, &block)
   end
 
   def run(*targets)
@@ -123,18 +109,7 @@ class Ant
     end
   end
 
-  private
-  def generate_children(collection)
-    collection.each do |name, clazz|
-      element = acquire_element(name, clazz)
-      self.class.send(:define_method, Ant.safe_method_name(name)) do |*a, &b|
-        element.call(@current_target, *a, &b)
-      end
-    end
-  end
-
-  def handle_argv
-    argv = ARGV
+  def process_arguments(argv = ARGV, run_at_exit = true)
     properties = []
     targets = []
     argv.each {|a| a =~ /^-D/ ? properties << a[2..-1] : targets << a }
@@ -150,6 +125,39 @@ class Ant
         warn e.message
         exit 1
       end
+    end if run_at_exit
+  end
+
+  private
+  def create_project(options)
+    # If we are calling into a rakefile from ant then we already have a 
project to use
+    return $project if defined?($project) && $project
+
+    options[:basedir] ||= '.'
+    output_level = options.delete(:output_level) || 2
+
+    Project.new.tap do |p|
+      p.init
+      p.add_build_listener(DefaultLogger.new.tap do |log|
+        log.output_print_stream = Java::java.lang.System.out
+        log.error_print_stream = Java::java.lang.System.err
+        log.emacs_mode = true
+        log.message_output_level = output_level
+        @log = log
+      end)
+      helper = ProjectHelper.getProjectHelper
+      helper.import_stack.add(Java::java.io.File.new(@location.file_name))
+      p.addReference(ProjectHelper::PROJECTHELPER_REFERENCE, helper)
+      options.each_pair {|k,v| p.send("set_#{k}", v) if 
p.respond_to?("set_#{k}") }
+    end
+  end
+
+  def generate_children(collection)
+    collection.each do |name, clazz|
+      element = acquire_element(name, clazz)
+      self.class.send(:define_method, Ant.safe_method_name(name)) do |*a, &b|
+        element.call(@current_target, *a, &b)
+      end
     end
   end
 
@@ -164,15 +172,23 @@ class Ant
       end
     end
 
+    def location_from_caller
+      file, line = caller.detect{|el| el !~ 
/^#{File.dirname(__FILE__)}/}.split(/:/)
+      Location.new(file, line.to_i, 1)
+    end
+
     def ant(options={}, &code)
       if options.respond_to? :to_hash
         @ant ||= Ant.new options.to_hash
-        code.arity==1 ? code[@ant] : @ant.instance_eval(&code) if 
block_given?
+        @ant.define_tasks(&code)
         @ant
       else
         options = options.join(" ") if options.respond_to? :to_ary
         sh "ant #{options.to_s}"  # FIXME: Make this more secure if using 
array form
       end
+    rescue => e
+      warn e.message
+      warn e.backtrace.join("\n")
     end
   end
 end
diff --git a/lib/ruby/site_ruby/shared/ant/element.rb 
b/lib/ruby/site_ruby/shared/ant/element.rb
index e6a2354..ceb25ce 100644
--- a/lib/ruby/site_ruby/shared/ant/element.rb
+++ b/lib/ruby/site_ruby/shared/ant/element.rb
@@ -1,71 +1,85 @@
 require 'java'
 
-java_import org.apache.tools.ant.IntrospectionHelper
-java_import org.apache.tools.ant.RuntimeConfigurable
-java_import org.apache.tools.ant.UnknownElement
+class Ant
+  java_import org.apache.tools.ant.IntrospectionHelper
+  java_import org.apache.tools.ant.RuntimeConfigurable
+  java_import org.apache.tools.ant.UnknownElement
 
-# This is really the metadata of the element coupled with the logic for 
-# instantiating an instance of an element and evaluating it.  My intention
-# is to decouple these two pieces.  This has extra value since we can then
-# also make two types of instances for both top-level tasks and for targets
-# since we have some conditionals which would then be eliminated
-class Element
-  attr_reader :name
+  class UnknownElement
+    attr_accessor :ant
+    # undef some method names that might collide with ant task/type names
+    %w(test fail abort raise exec trap).each {|m| undef_method(m)}
+    Object.instance_methods.grep(/java/).each {|m| undef_method(m)}
 
-  def initialize(ant, name, clazz)
-    @ant, @name, @clazz = ant, name, clazz
-  end
+    def _element(name, args = {}, &block)
+      Element.new(ant, name).call(self, args, &block)
+    end
 
-  def call(parent, args={}, &code)
-    element = create parent
-    assign_attributes element, args
-    define_nested_elements element
-    code.arity==1 ? code[element] : element.instance_eval(&code) if 
block_given?
-    if parent.respond_to? :add_task # Target
-      @ant.project.log "Adding #{name} to #{parent}", 5
-      parent.add_task element
-    elsif parent.respond_to? :get_owning_target # Task
-      @ant.project.log "Adding #{name} to #{parent.component_name}", 5
-      parent.add_child element
-      parent.runtime_configurable_wrapper.add_child 
element.runtime_configurable_wrapper
-    else # Just run it now
-      @ant.project.log "Executing #{name}", 5
-      element.owning_target = Target.new.tap {|t| t.name = ""}
-      element.maybe_configure
-      element.execute
+    def method_missing(name, *args, &block)
+      _element(name, *args, &block)
     end
   end
 
-  private
-  def create(parent) # See ProjectHelper2.ElementHelper
-    UnknownElement.new(@name).tap do |e|
-      e.project = @ant.project
-      e.task_name = @name
-      e.location = @ant.location
-      e.owning_target = @ant.current_target
+  # This is really the metadata of the element coupled with the logic for
+  # instantiating an instance of an element and evaluating it.  My intention
+  # is to decouple these two pieces.  This has extra value since we can then
+  # also make two types of instances for both top-level tasks and for targets
+  # since we have some conditionals which would then be eliminated
+  class Element
+    attr_reader :name
+
+    def initialize(ant, name, clazz = nil)
+      @ant, @name, @clazz = ant, name, clazz
     end
-  end
 
-  # This also subsumes configureId to only have to traverse args once
-  def assign_attributes(instance, args)
-    @ant.project.log "instance.task_name #{instance.task_name} #{name}", 5
-    wrapper = RuntimeConfigurable.new instance, instance.task_name
-    args.each do |key, value|
-      # FIXME: Infinite recursion and only single expression expansion
-      while value =~ /\$\{([^\}]+)\}/
-        value.gsub!(/\$\{[^\}]+\}/, @ant.project.get_property($1).to_s)
+    def call(parent, args={}, &code)
+      element = create parent
+      assign_attributes element, args
+      define_nested_elements element if @clazz
+      code.arity==1 ? code[element] : element.instance_eval(&code) if 
block_given?
+      if parent.respond_to? :add_task # Target
+        @ant.project.log "Adding #{name} to #{parent}", 5
+        parent.add_task element
+      elsif parent.respond_to? :add_child # Task
+        @ant.project.log "Adding #{name} to #{parent.component_name}", 5
+        parent.add_child element
+        parent.runtime_configurable_wrapper.add_child 
element.runtime_configurable_wrapper
+      else # Just run it now
+        @ant.project.log "Executing #{name}", 5
+        element.owning_target = Target.new.tap {|t| t.name = ""}
+        element.maybe_configure
+        element.execute
+      end
+    end
+
+    private
+    def create(parent) # See ProjectHelper2.ElementHelper
+      UnknownElement.new(@name).tap do |e|
+        e.ant = @ant
+        e.project = @ant.project
+        e.task_name = @name
+        e.location = Ant.location_from_caller
+        e.owning_target = @ant.current_target
+      end
+    end
+
+    # This also subsumes configureId to only have to traverse args once
+    def assign_attributes(instance, args)
+      @ant.project.log "instance.task_name #{instance.task_name} #{name}", 5
+      wrapper = RuntimeConfigurable.new instance, instance.task_name
+      args.each do |key, value|
+        wrapper.set_attribute key, @ant.project.replace_properties(value)
       end
-      wrapper.set_attribute key, value 
     end
-  end
 
-  def define_nested_elements(instance)
-    meta_class = class << instance; self; end
-    @helper = IntrospectionHelper.get_helper(@ant.project, @clazz)
-    @helper.get_nested_element_map.each do |element_name, clazz|
-      element = @ant.acquire_element(element_name, clazz)
-      meta_class.send(:define_method, Ant.safe_method_name(element_name)) do 
|*args, &block|
-        element.call(instance, *args, &block)
+    def define_nested_elements(instance)
+      meta_class = class << instance; self; end
+      @helper = IntrospectionHelper.get_helper(@ant.project, @clazz)
+      @helper.get_nested_element_map.each do |element_name, clazz|
+        element = @ant.acquire_element(element_name, clazz)
+        meta_class.send(:define_method, Ant.safe_method_name(element_name)) 
do |*args, &block|
+          element.call(instance, *args, &block)
+        end
       end
     end
   end
diff --git a/lib/ruby/site_ruby/shared/ant/target.rb 
b/lib/ruby/site_ruby/shared/ant/target.rb
index 27fbe82..456bfd3 100644
--- a/lib/ruby/site_ruby/shared/ant/target.rb
+++ b/lib/ruby/site_ruby/shared/ant/target.rb
@@ -1,9 +1,9 @@
 require 'java'
 require 'ant/ant'
 
-java_import org.apache.tools.ant.Target
-
 class Ant
+  java_import org.apache.tools.ant.Target
+
   class RakeTarget < Target
     ALREADY_DEFINED_PREFIX = "rake_"
 
diff --git a/spec/java_integration/ant/ant_spec.rb 
b/spec/java_integration/ant/ant_spec.rb
new file mode 100644
index 0000000..c68ed42
--- /dev/null
+++ b/spec/java_integration/ant/ant_spec.rb
@@ -0,0 +1,70 @@
+require File.expand_path('../../ant_spec_helper', __FILE__)
+
+describe Ant, "new", :type => :ant do
+  it "can be instantiated with a block" do
+    Ant.new do
+      self.class.should == Ant
+    end
+  end
+
+  it "can be instantiated with a block whose single argument receives the 
Ant instance" do
+    Ant.new do |ant|
+      self.class.should_not == Ant
+      ant.class.should == Ant
+    end
+  end
+
+  it "should execute top-level tasks as it encounters them" do
+    Ant.new do |ant|
+      ant.properties["foo"].should_not == "bar"
+      ant.property :name => "foo", :value => "bar"
+      ant.properties["foo"].should == "bar"
+    end
+  end
+end
+
+describe Ant, :type => :ant do
+  before :each do
+    @ant = Ant.new :basedir => "/tmp", :run => false, :output_level => 0
+  end
+
+  it "should define methods corresponding to ant tasks" do
+    @ant.methods.should include("java", "antcall", "property", "import", 
"path", "patternset")
+  end
+
+  it "should have a valid location" do
+    File.should be_exist(@ant.location.file_name)
+  end
+
+  it "should execute the default target" do
+    @ant.target("default") { property :name => "spec", :value => "example" }
+    @ant.project.default = "default"
+    @ant.execute_default
+    @ant.properties["spec"].should == "example"
+  end
+
+  it "should execute the specified target" do
+    @ant.target("a") { property :name => "a", :value => "true" }
+    @ant.target("b") { property :name => "b", :value => "true" }
+    @ant.execute_target("a")
+    @ant.properties["a"].should == "true"
+    @ant["b"].execute
+    @ant.properties["b"].should == "true"
+  end
+
+  it "should raise when a bogus target is executed" do
+    lambda { @ant["bogus"].execute }.should raise_error
+  end
+
+  it "should handle -Dkey=value arguments from the command-line" do
+    @ant.project.default = "help"
+    @ant.process_arguments(["-Dcommand.line.msg=hello", "help"], false)
+    @ant.define_tasks do
+      target :help do
+        property :name => "msg", :value => "${command.line.msg}"
+      end
+    end
+    @ant.run
+    @ant.properties["msg"].should == "hello"
+  end
+end
diff --git a/spec/java_integration/ant/project_spec.rb 
b/spec/java_integration/ant/project_spec.rb
new file mode 100644
index 0000000..d907d86
--- /dev/null
+++ b/spec/java_integration/ant/project_spec.rb
@@ -0,0 +1,24 @@
+require File.expand_path('../../ant_spec_helper', __FILE__)
+
+describe Ant, "project", :type => :ant do
+  before :each do
+    @ant = Ant.new :name => "spec project", :description => "spec 
description", :basedir => "/tmp", :run => false
+  end
+
+  it "should have the 'basedir' set" do
+    @ant.project.base_dir.path.should == "/tmp"
+  end
+
+  it "should have a project helper created" do
+    
@ant.project.get_reference(Ant::ProjectHelper::PROJECTHELPER_REFERENCE).should
 be_kind_of(Ant::ProjectHelper)
+  end
+
+  it "should have a logger set" do
+    @ant.project.build_listeners.should_not be_empty
+  end
+
+  it "should have a name and description" do
+    @ant.project.name.should == "spec project"
+    @ant.project.description.should == "spec description"
+  end
+end
diff --git a/spec/java_integration/ant/target_spec.rb 
b/spec/java_integration/ant/target_spec.rb
new file mode 100644
index 0000000..c2aa3d6
--- /dev/null
+++ b/spec/java_integration/ant/target_spec.rb
@@ -0,0 +1,24 @@
+require File.expand_path('../../ant_spec_helper', __FILE__)
+
+describe Ant, "targets", :type => :ant do
+  it "should delay executing tasks in targets until the target is executed" 
do
+    ant = Ant.new :name => "foo", :output_level => 0 do
+      target :foo do
+        property :name => "foo", :value => "bar"
+      end
+    end
+    ant.properties["foo"].should_not == "bar"
+    ant.execute_target(:foo)
+    ant.properties["foo"].should == "bar"
+  end
+
+  it "#ant should accumulate targets and tasks in the same global project" do
+    ant do
+      target :a
+    end
+    ant do
+      target :b
+    end
+    ant.project.targets.keys.to_a.should include("a", "b")
+  end
+end
diff --git a/spec/java_integration/ant/task_spec.rb 
b/spec/java_integration/ant/task_spec.rb
new file mode 100644
index 0000000..e09d65e
--- /dev/null
+++ b/spec/java_integration/ant/task_spec.rb
@@ -0,0 +1,80 @@
+require File.expand_path('../../ant_spec_helper', __FILE__)
+
+describe Ant, "tasks:", :type => :ant do
+  before :all do
+    # The single example ant project these specs will validate
+    @output = output = "ant-file#{rand}.txt"
+    @ant = Ant.new :output_level => 0 do
+      property :name => "jar", :value => "spec-test.jar"
+      property :name => "dir", :value => "build"
+      taskdef :name => "jarjar", :classname => 
"com.tonicsystems.jarjar.JarJarTask",
+        :classpath => "${basedir}/build_lib/jarjar-1.0.jar"
+
+      target :jar do
+        jar :destfile => "${jar}", :compress => "true", :index => "true" do
+          fileset :dir => "${dir}"
+        end
+      end
+
+      target :jarjar do
+        jarjar :destfile => "${jar}", :compress => "true" do
+          fileset :dir => "${dir}"
+          zipfileset :src => "./lib/jruby.jar"
+        end
+      end
+
+      macrodef :name => "greet" do
+        attribute :name => "msg"
+        sequential do
+          echo :message => "Hello @{msg}", :file => "#{output}"
+        end
+      end
+
+      target :greet do
+        greet :msg => "Ant"
+      end
+    end
+  end
+
+  after :all do
+    File.unlink(@output) if File.exist?(@output)
+  end
+
+  describe "jar" do
+    subject do
+      @ant.project.targets["jar"]
+    end
+
+    it { should have_valid_tasks }
+
+    it { should have_structure([{:_name => "jar", :destfile => 
"spec-test.jar", :compress => "true", :index => "true",
+                                 :_children => [ { :_name => "fileset", :dir 
=> "build" }] }]) }
+
+    it { should have_configured_structure([{:_type => 
"org.apache.tools.ant.taskdefs.Jar",
+                                            :_children => [{:_type => 
"org.apache.tools.ant.types.FileSet"}] }]) }
+
+  end
+
+  describe "jarjar" do
+    subject do
+      @ant.project.targets["jarjar"]
+    end
+
+    it { should have_valid_tasks }
+
+    it { should have_structure([{:_name => "jarjar", :destfile => 
"spec-test.jar", :compress => "true",
+                                 :_children => [ { :_name => "fileset", :dir 
=> "build" },
+                                                 { :_name => "zipfileset", 
:src => "./lib/jruby.jar" }] }]) }
+
+    it { should have_configured_structure([{:_type => 
"com.tonicsystems.jarjar.JarJarTask",
+                                            :_children => [{:_type => 
"org.apache.tools.ant.types.FileSet"},
+                                                           {:_type => 
"org.apache.tools.ant.types.ZipFileSet"}] }]) }
+  end
+
+  describe "macrodef" do
+    it "should be defined and invokable from a target" do
+      @ant.execute_target(:greet)
+      File.read(@output).should == "Hello Ant"
+    end
+  end
+end
diff --git a/spec/java_integration/ant_spec_helper.rb 
b/spec/java_integration/ant_spec_helper.rb
new file mode 100644
index 0000000..eace9fa
--- /dev/null
+++ b/spec/java_integration/ant_spec_helper.rb
@@ -0,0 +1,141 @@
+require File.expand_path('../spec_helper', __FILE__)
+require 'ant'
+
+class Ant
+  module Spec
+    class AntExampleGroup < ::Spec::Example::ExampleGroup
+      after :each do
+        Ant.send(:instance_variable_set, "@ant", nil)
+      end
+
+      # Validates the tasks in a target look sane. Currently just
+      # checks owning_target.
+      class ValidTasksMatcher
+        def description
+          "have valid tasks"
+        end
+
+        def matches?(target)
+          @target = target
+          result = true
+          @target.tasks.each do |t|
+            result &&= (t.owning_target == @target)
+          end
+          result
+        end
+
+        def failure_message_for_should
+          "expected #{@target.inspect} to have valid tasks"
+        end
+
+        def failure_message_for_should_not
+          "expected #{@target.inspect} to not have valid tasks"
+        end
+      end
+
+      # Allows matching task structure with a nested hash as follows.
+      #
+      # { :_name => "jar", :destfile => "spec-test.jar", :compress => 
"true", :index => "true",
+      #   :_children => [
+      #     { :_name => "fileset", :dir => "build" }
+      #   ]}
+      #
+      # would match the following:
+      #
+      # jar :destfile => "spec-test.jar", :compress => "true", :index => 
"true" do
+      #   fileset :dir => "build"
+      # end
+      #
+      class TaskStructureMatcher
+        def initialize(hash, configure = false)
+          @expected = hash
+          @configure = configure
+        end
+
+        def description
+          "have the specified #{(@configure ? 'configured' : 'element')} 
structure"
+        end
+
+        def matches?(actual)
+          @actual = actual
+          result = true
+          tasks = actual.tasks
+          if Hash === @expected && tasks.length != 1 || tasks.length != 
@expected.length
+            @message = "task list length different"
+            return false
+          end
+          @expected.each_with_index do |h,i|
+            tasks[i].maybe_configure if @configure
+            result &&= match_wrapper(h, tasks[i].wrapper)
+          end
+          result
+        end
+
+        def match_wrapper(hash, wrapper, name = nil)
+          hname = hash[:_name] ? hash[:_name] : '<?>'
+          if name
+            name = "#{name} => #{hname}"
+          else
+            name = hname
+          end
+
+          # name
+          if hash[:_name] && hash[:_name] != wrapper.element_tag
+            @message = "name different: expected #{hash[:_name].inspect} but 
was #{wrapper.element_tag.inspect}"
+            return false
+          end
+
+          # proxy class name
+          if hash[:_type] && (wrapper.proxy.nil? || hash[:_type] != 
wrapper.proxy.java_class.name)
+            @message = "type different: expected #{hash[:_type]} but was 
#{wrapper.proxy.java_class.name}"
+            return false
+          end
+
+          # attributes
+          hash.keys.select {|k| k.to_s !~ /^_/}.each do |k|
+            unless wrapper.attribute_map.containsKey(k.to_s)
+              @message = "'#{name} => #{k}' attribute missing"
+              return false
+            end
+
+            if hash[k] != wrapper.attribute_map[k.to_s]
+              @message = "'#{name} => #{k}' attribute different: expected 
#{hash[k].inspect} but was #{wrapper.attribute_map[k.to_s].inspect}"
+              return false
+            end
+          end
+
+          # children, recursively
+          children = wrapper.children.to_a
+          (hash[:_children] || []).each_with_index do |h,i|
+            return false unless match_wrapper(h, children[i], name)
+          end
+          true
+        end
+
+        def failure_message_for_should
+          require 'pp'
+          "expected #{@actual.name} to have 
structure:\n#{@expected.pretty_inspect}\n#{@message}"
+        end
+
+        def failure_message_for_should_not
+          require 'pp'
+          "expected #{@actual.name} to not have 
structure:\n#{@expected.pretty_inspect}\n#{@message}"
+        end
+      end
+
+      def have_valid_tasks
+        ValidTasksMatcher.new
+      end
+
+      def have_structure(hash)
+        TaskStructureMatcher.new(hash)
+      end
+
+      def have_configured_structure(hash)
+        TaskStructureMatcher.new(hash, true)
+      end
+
+      ::Spec::Example::ExampleGroupFactory.register(:ant, self)
+    end
+  end
+end




[jruby~main:f25167ae] Ant integration: Get _element working better

nicksieger 03/04/2010
  • Mysql
  • Glassfish
  • Jruby
  • Rails
  • Nblogo
Terms of Use; Privacy Policy;
© 2010, Oracle Corporation and/or its affiliates
(revision 20120518.3c65429)
 
 
Close
loading
Please Confirm
Close