<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>Blockenspiel.rdoc</filename>
    </added>
    <added>
      <filename>tests/tc_dsl_attrs.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,12 @@
+=== 0.3.0 / 2009-11-04
+
+* dsl_attr_writer and dsl_attr_accessor convenience methods are available
+  for creating DSL-friendly attributes.
+* Dynamic DSL methods can now take real block arguments, if supported by
+  the Ruby interpreter.
+* Shortened README.rdoc and renamed the longer version to Blockenspiel.rdoc.
+* Some documentation updates.
+
 === 0.2.2 / 2009-10-28
 
 * Support for gemcutter hosting in the build/release scripts.</diff>
      <filename>History.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -5,106 +5,29 @@ blocks. It is designed to be comprehensive and robust, supporting most common
 usage patterns, and working correctly in the presence of nested blocks and
 multithreading.
 
-=== What's a DSL block?
+=== Summary
 
-A DSL block is an API pattern in which a method call takes a block that can
-provide further configuration for the call. A classic example is the
-{Rails}[http://www.rubyonrails.org/] route definition:
-
- ActionController::Routing::Routes.draw do |map|
-   map.connect ':controller/:action/:id'
-   map.connect ':controller/:action/:id.:format'
- end
-
-Some libraries go one step further and eliminate the need for a block
-parameter. {RSpec}[http://rspec.info/] is a well-known example:
-
- describe Stack do
-   before(:each) do
-     @stack = Stack.new
-   end
-   describe &quot;(empty)&quot; do
-     it { @stack.should be_empty }
-     it &quot;should complain when sent #peek&quot; do
-       lambda { @stack.peek }.should raise_error(StackUnderflowError)
-     end
-   end
- end
-
-In both cases, the caller provides descriptive information in the block,
-using a domain-specific language. The second form, which eliminates the block
-parameter, often appears cleaner; however it is also sometimes less clear
-what is actually going on.
-
-=== How does one implement such a beast?
-
-Implementing the first form is fairly straightforward. You would create a
-class defining the methods (such as +connect+ in our Rails routing example
-above) that should be available within the block. When, for example, the
-&lt;tt&gt;draw&lt;/tt&gt; method is called with a block, you instantiate the class and
-yield it to the block.
-
-The second form is perhaps more mystifying. Somehow you would need to make
-the DSL methods available on the &quot;self&quot; object inside the block. There are
-several plausible ways to do this, such as using &lt;tt&gt;instance_eval&lt;/tt&gt;.
-However, there are many subtle pitfalls in such techniques, and quite a bit
-of discussion has taken place in the Ruby community regarding how--or
-whether--to safely implement such a syntax.
-
-I have included a critical survey of the debate in the document
-{ImplementingDSLblocks.txt}[link:files/ImplementingDSLblocks\_txt.html] for
-the curious. Blockenspiel takes what I consider the best of the solutions and
-implements them in a comprehensive way, shielding you from the complexity of
-the Ruby metaprogramming while offering a simple way to implement both forms
-of DSL blocks.
-
-=== So what _is_ Blockenspiel?
-
-Blockenspiel operates on the following observations:
-
-* Implementing a DSL block that takes a parameter is straightforward.
-* Safely implementing a DSL block that &lt;em&gt;doesn't&lt;/em&gt; take a parameter is tricky.
-
-With that in mind, Blockenspiel provides a set of tools that allow you to
-take an implementation of the first form of a DSL block, one that takes a
-parameter, and turn it into an implementation of the second form, one that
-doesn't take a parameter.
-
-Suppose you wanted to write a simple DSL block that takes a parameter:
+Blockenspiel is a helper library providing several different strategies for
+implementing DSL blocks. It supports both DSLs that take a block parameter
+and those that do not. For example:
 
+ # Call DSL block with parameter
  configure_me do |config|
    config.add_foo(1)
    config.add_bar(2)
  end
-
-You could write this as follows:
-
- class ConfigMethods
-   def add_foo(value)
-     # do something
-   end
-   def add_bar(value)
-     # do something
-   end
- end
  
- def configure_me
-   yield ConfigMethods.new
- end
-
-That was easy. However, now suppose you wanted to support usage _without_
-the &quot;config&quot; parameter. e.g.
-
+ # Call DSL block without parameter
  configure_me do
-   add_foo(1)
-   add_bar(2)
+   add_foo(3)
+   add_bar(4)
  end
 
-With Blockenspiel, you can do this in two quick steps.
-First, tell Blockenspiel that your +ConfigMethods+ class is a DSL.
+To support the above usage, you can do this:
 
+ # Implement DSL block methods
  class ConfigMethods
-   include Blockenspiel::DSL   # &lt;--- Add this line
+   include Blockenspiel::DSL
    def add_foo(value)
      # do something
    end
@@ -112,179 +35,28 @@ First, tell Blockenspiel that your +ConfigMethods+ class is a DSL.
      # do something
    end
  end
-
-Next, write your &lt;tt&gt;configure_me&lt;/tt&gt; method using Blockenspiel:
-
+ 
+ # Implement configure_me method
  def configure_me(&amp;block)
    Blockenspiel.invoke(block, ConfigMethods.new)
  end
 
-Now, your &lt;tt&gt;configure_me&lt;/tt&gt; method supports _both_ DSL block forms. A
-caller can opt to use the first form, with a parameter, simply by providing
-a block that takes a parameter. Or, if the caller provides a block that
-doesn't take a parameter, the second form without a parameter is used.
-
-=== How does that help me? (Or, why not just use instance_eval?)
-
-As noted earlier, some libraries that provide parameter-less DSL blocks use
-&lt;tt&gt;instance_eval&lt;/tt&gt;, and they could even support both the parameter and
-parameter-less mechanisms by checking the block arity:
-
- def configure_me(&amp;block)
-   if block.arity == 1
-     yield ConfigMethods.new
-   else
-     ConfigMethods.new.instance_eval(&amp;block)
-   end
- end
-
-That seems like a simple and effective technique that doesn't require a
-separate library, so why use Blockenspiel? Because &lt;tt&gt;instance_eval&lt;/tt&gt;
-introduces a number of surprising problems. I discuss these issues in detail
-in {ImplementingDSLblocks.txt}[link:files/ImplementingDSLblocks\_txt.html],
-but just to get your feet wet, suppose the caller wanted to call its own
-methods inside the block:
+By default, Blockenspiel uses a mixin technique (proposed by the late Why
+The Lucky Stiff) to support parameterless blocks without the complications
+introduced by &lt;tt&gt;instance_eval&lt;/tt&gt;. It supports nested blocks and
+multithreaded access, and provides a variety of tools for handling the
+typical issues you may encounter when writing DSLs.
 
- def callers_helper_method
-   # ...
- end
- 
- configure_me do
-   add_foo(1)
-   callers_helper_method  # Error! self is now an instance of ConfigMethods
-                          # so this will fail with a NameError
-   add_bar(2)
- end
-
-Blockenspiel by default does _not_ use the &lt;tt&gt;instance_eval&lt;/tt&gt; technique.
-Instead, it implements a mechanism using mixin modules, a technique first
-{proposed}[http://hackety.org/2008/10/06/mixingOurWayOutOfInstanceEval.html]
-by Why. In this technique, the &lt;tt&gt;add_foo&lt;/tt&gt; and &lt;tt&gt;add_bar&lt;/tt&gt; methods
-are temporarily mixed into the caller's +self+ object. That is, +self+ does
-not change, as it would if we used &lt;tt&gt;instance_eval&lt;/tt&gt;, so helper methods
-like &lt;tt&gt;callers_helper_method&lt;/tt&gt; still remain available as expected. But,
-the &lt;tt&gt;add_foo&lt;/tt&gt; and &lt;tt&gt;add_bar&lt;/tt&gt; methods are also made available
-temporarily for the duration of the block. When called, they are intercepted
-and redirected to your +ConfigMethods+ instance just as if you had called
-them directly via a block parameter. Blockenspiel handles the object
-redirection behind the scenes so you do not have to think about it. With
-Blockenspiel, the caller retains access to its helper methods, and even its
-own instance variables, within the block, because +self+ has not been
-modified.
-
-=== Is that it?
-
-Although the basic usage is very simple, Blockenspiel is designed to be
-_comprehensive_. It supports all the use cases that I've run into during my
-own implementation of DSL blocks. Notably:
-
-By default, Blockenspiel lets the caller choose to use a parametered block
-or a parameterless block, based on whether or not the block actually takes a
-parameter. You can also disable one or the other, to force the use of either
-a parametered or parameterless block.
-
-You can control wich methods of the class are available from parameterless
-blocks, and/or make some methods available under different names. Here are
-a few examples:
-
- class ConfigMethods
-   include Blockenspiel::DSL
-   
-   def add_foo         # automatically added to the dsl
-     # do stuff...
-   end
-   
-   def my_private_method
-     # do stuff...
-   end
-   dsl_method :my_private_method, false   # remove from the dsl
-   
-   dsl_methods false   # stop automatically adding methods to the dsl
-   
-   def another_private_method  # not added
-     # do stuff...
-   end
-   
-   dsl_methods true    # resume automatically adding methods to the dsl
-   
-   def add_bar         # this method is automatically added
-     # do stuff...
-   end
-   
-   def add_baz
-     # do stuff
-   end
-   dsl_method :add_baz_in_dsl, :add_baz  # Method named differently
-                                         # in a parameterless block
- end
-
-This is also useful, for example, when you use &lt;tt&gt;attr_writer&lt;/tt&gt;.
-Parameterless blocks do not support &lt;tt&gt;attr_writer&lt;/tt&gt; (or, by corollary,
-&lt;tt&gt;attr_accessor&lt;/tt&gt;) well because methods with names of the form
-&quot;attribute=&quot; are syntactically indistinguishable from variable assignments:
-
- configure_me do |config|
-   config.foo = 1    # works fine when the block has a parameter
- end
- 
- configure_me do
-   # foo = 1     # &lt;--- Doesn't work: looks like a variable assignment
-   set_foo(1)    # &lt;--- Renamed to this instead
- end
- 
- # This is implemented like this::
- class ConfigMethods
-   include Blockenspiel::DSL
-   attr_writer :foo
-   dsl_method :set_foo, :foo=    # Make &quot;foo=&quot; available as &quot;set_foo&quot;
- end
-
-In some cases, you might want to dynamically generate a DSL object rather
-than defining a static class. Blockenspiel provides a tool to do just that.
-Here's an example:
-
- Blockenspiel.invoke(block) do
-   add_method(:set_foo) do |value|
-     my_foo = value
-   end
-   add_method(:set_things_using_block, :receive_block =&gt; true) do |value, blk|
-     my_foo = value
-     my_bar = blk.call
-   end
- end
-
-That API is in itself a DSL block, and yes, Blockenspiel uses itself to
-implement this feature.
-
-By default Blockenspiel uses mixins, which usually exhibit fairly safe and
-non-surprising behavior. However, there are a few cases when you might
-want the &lt;tt&gt;instance_eval&lt;/tt&gt; behavior anyway. RSpec is a good example of
-such a case, since the DSL is being used to construct objects, so it makes
-sense for instance variables inside the block to belong to the object
-being constructed. Blockenspiel gives you the option of choosing
-&lt;tt&gt;instance_eval&lt;/tt&gt; in case you need it. Blockenspiel also provides a
-compromise behavior that uses a proxy to dispatch methods to the DSL object
-or the block's context.
-
-Blockenspiel also correctly handles nested blocks. e.g.
-
- configure_me do
-   set_foo(1)
-   configure_another do     # A block within another block
-     set_bar(2)
-     configure_another do   # A block within itself
-       set_bar(3)
-     end
-   end
- end
+For more detailed usage and examples, see
+{Blockenspiel.rdoc}[link:Blockenspiel\_rdoc.html].
 
-Finally, it is completely thread safe, correctly handling, for example, the
-case of multiple threads trying to mix methods into the same object
-concurrently.
+For an extended analysis of different ways to implement DSL blocks, see
+{ImplementingDSLblocks.rdoc}[link:ImplementingDSLblocks\_rdoc.html].
 
 === Requirements
 
-* Ruby 1.8.6 or later (1.8.7 recommended), Ruby 1.9.1 or later, or JRuby 1.2 or later (1.4 recommended).
+* Ruby 1.8.6 or later (1.8.7 recommended), Ruby 1.9.1 or later, or JRuby 1.2
+  or later (1.4 recommended).
 
 === Installation
 
@@ -317,6 +89,8 @@ copies or mirrors out there.
 The unmixer code is based on {Mixology}[http://rubyforge.org/projects/mixology],
 version 0.1 by Patrick Farley, anonymous z, Dan Manges, and Clint Bishop.
 The code has been stripped down and modified to support MRI 1.9 and JRuby 1.2.
+I know Mixology 0.2 is available, but I'm keeping the unmixer bundled with
+Blockenspiel for now, to reduce dependencies.
 
 === License
 </diff>
      <filename>README.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -43,7 +43,7 @@ require ::File.expand_path(&quot;#{::File.dirname(__FILE__)}/lib/blockenspiel/version
 
 
 # Configuration
-extra_rdoc_files_ = ['README.rdoc', 'History.rdoc', 'ImplementingDSLblocks.rdoc']
+extra_rdoc_files_ = ['README.rdoc', 'Blockenspiel.rdoc', 'History.rdoc', 'ImplementingDSLblocks.rdoc']
 
 
 # Default task
@@ -202,7 +202,7 @@ task :release =&gt; [:release_gem_to_gemcutter, :release_gem_to_rubyforge, :publish
 # Custom task that takes the implementing dsl blocks paper
 # and converts it from RDoc format to Markdown
 task :idslb_markdown do
-  ::File.open('ImplementingDSLblocks.txt') do |read_|
+  ::File.open('ImplementingDSLblocks.rdoc') do |read_|
     ::File.open('idslb_markdown.txt', 'w') do |write_|
       linenum_ = 0
       read_.each do |line_|</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -81,11 +81,13 @@ module Blockenspiel
   
   module DSLSetupMethods
     
+    
+    # :stopdoc:
+    
     # Called when DSLSetupMethods extends a class.
     # This sets up the current class, and adds a hook that causes
-    # any subclass of the current class to also be set up.
+    # any subclass of the current class also to be set up.
     
-    # :stopdoc:
     def self.extended(klass_)
       unless klass_.instance_variable_defined?(:@_blockenspiel_module)
         _setup_class(klass_)
@@ -95,6 +97,7 @@ module Blockenspiel
         end
       end
     end
+    
     # :startdoc:
     
     
@@ -175,12 +178,7 @@ module Blockenspiel
       end
       @_blockenspiel_methods[name_] = delegate_
       unless @_blockenspiel_module.public_method_defined?(name_)
-        @_blockenspiel_module.module_eval(&quot;
-          def #{name_}(*params_, &amp;block_)
-            val_ = ::Blockenspiel._target_dispatch(self, :#{name_}, params_, block_)
-            val_ == ::Blockenspiel::TARGET_MISMATCH ? super(*params_, &amp;block_) : val_
-          end
-        &quot;)
+        @_blockenspiel_module.module_eval(&quot;def #{name_}(*params_, &amp;block_); val_ = ::Blockenspiel._target_dispatch(self, :#{name_}, params_, block_); ::Blockenspiel::NO_VALUE.equal?(val_) ? super(*params_, &amp;block_) : val_; end\n&quot;)
       end
     end
     
@@ -229,6 +227,91 @@ module Blockenspiel
       end
     end
     
+    
+    # A DSL-friendly attr_accessor.
+    # 
+    # This creates the usual &quot;name&quot; and &quot;name=&quot; methods in the current
+    # class that can be used in the usual way. However, its implementation
+    # of the &quot;name&quot; method (the getter) also takes an optional parameter
+    # that causes it to behave as a setter. This is done because the usual
+    # setter syntax cannot be used in a parameterless block, since it is
+    # syntactically indistinguishable from a local variable assignment.
+    # The &quot;name&quot; method is exposed as a dsl_method.
+    # 
+    # For example:
+    # 
+    #  dsl_attr_accessor :foo
+    # 
+    # enables the following:
+    # 
+    #  my_block do |param|
+    #    param.foo = 1   # Usual setter syntax works
+    #    param.foo 2     # Alternate setter syntax also works
+    #    puts param.foo  # Usual getter syntax still works
+    #  end
+    #  
+    #  my_block do
+    #    # foo = 1       # Usual setter syntax does NOT work since it
+    #                    #   looks like a local variable assignment
+    #    foo 2           # Alternate setter syntax does work
+    #    puts foo        # Usual getter syntax still works
+    #  end
+    
+    def dsl_attr_accessor(*names_)
+      names_.each do |name_|
+        unless name_.kind_of?(::String) || name_.kind_of?(::Symbol)
+          raise ::TypeError, &quot;#{name_.inspect} is not a symbol&quot;
+        end
+        unless name_.to_s =~ /^[_a-zA-Z]\w+$/
+          raise ::NameError, &quot;invalid attribute name #{name_.inspect}&quot;
+        end
+        module_eval(&quot;def #{name_}(value_=::Blockenspiel::NO_VALUE); ::Blockenspiel::NO_VALUE.equal?(value_) ? @#{name_} : @#{name_} = value_; end\n&quot;)
+        alias_method(&quot;#{name_}=&quot;, name_)
+        dsl_method(name_)
+      end
+    end
+    
+    
+    # A DSL-friendly attr_writer.
+    # 
+    # This creates the usual &quot;name=&quot; method in the current class that can
+    # be used in the usual way. However, it also creates the method &quot;name&quot;,
+    # which also functions as a setter (but not a getter). This is done
+    # because the usual setter syntax cannot be used in a parameterless
+    # block, since it is syntactically indistinguishable from a local
+    # variable assignment. The &quot;name&quot; method is exposed as a dsl_method.
+    # 
+    # For example:
+    # 
+    #  dsl_attr_writer :foo
+    # 
+    # is functionally equivalent to:
+    # 
+    #  attr_writer :foo
+    #  alias_method :foo, :foo=
+    #  dsl_method :foo
+    # 
+    # which enables the following:
+    # 
+    #  my_block do |param|
+    #    param.foo = 1   # Usual setter syntax works
+    #    param.foo 2     # Alternate setter syntax also works
+    #  end
+    #  my_block do
+    #    # foo = 1       # Usual setter syntax does NOT work since it
+    #                    #   looks like a local variable assignment
+    #    foo(2)          # Alternate setter syntax does work
+    #  end
+    
+    def dsl_attr_writer(*names_)
+      names_.each do |name_|
+        attr_writer(name_)
+        alias_method(name_, &quot;#{name_}=&quot;)
+        dsl_method(name_)
+      end
+    end
+    
+    
   end
   
   
@@ -306,11 +389,7 @@ module Blockenspiel
       
       def self._add_methodinfo(name_, block_, yields_)
         (@_blockenspiel_methodinfo ||= ::Hash.new)[name_] = [block_, yields_]
-        module_eval(&quot;
-          def #{name_}(*params_, &amp;block_)
-            self.class._invoke_methodinfo(:#{name_}, params_, block_)
-          end
-        &quot;)
+        module_eval(&quot;def #{name_}(*params_, &amp;block_); self.class._invoke_methodinfo(:#{name_}, params_, block_); end\n&quot;)
       end
       
       
@@ -324,7 +403,7 @@ module Blockenspiel
         when :last
           params_.push(block_)
         end
-        info_[0].call(*params_)
+        info_[0].call(*params_, &amp;block_)
       end
       
     end
@@ -348,24 +427,60 @@ module Blockenspiel
     # === Declare a DSL method.
     # 
     # This call creates a method that can be called from the DSL block.
-    # Provide a name for the method, and a block defining the method's
-    # implementation. You may also provided a list of options as follows:
-    # 
-    # The &lt;tt&gt;:block&lt;/tt&gt; option controls how the generated method reports
-    # any block provided by the caller. If set to +false+ or not given, any
-    # caller-provided block is ignored. If set to &lt;tt&gt;:first&lt;/tt&gt;, the
-    # block is _prepended_ (as a +Proc+ object) to the parameters passed to
-    # the method's implementing block. If set to &lt;tt&gt;:last&lt;/tt&gt;, the block
-    # is _appended_. In either case, if the caller does not provide a block,
-    # a value of +nil+ is pre- or appended to the parameter list. A value of
-    # +true+ is equivalent to &lt;tt&gt;:first&lt;/tt&gt;.
-    # (This is a workaround for the fact that blocks cannot themselves take
-    # block parameters in Ruby 1.8.)
+    # Provide a name for the method, a block defining the method's
+    # implementation, and an optional hash of options.
     # 
+    # By default, a method of the same name is also made available to
+    # parameterless blocks. To change the name of the parameterless method,
+    # provide its name as the value of the &lt;tt&gt;:dsl_method&lt;/tt&gt; option.
+    # To disable this method for parameterless blocks, set the
+    # &lt;tt&gt;:dsl_method&lt;/tt&gt; option to +false+.
+    # 
+    # The &lt;tt&gt;:mixin&lt;/tt&gt; option is a deprecated alias for
+    # &lt;tt&gt;:dsl_method&lt;/tt&gt;.
+    # 
+    # === Warning about the +return+ keyword
+    # 
+    # Because you are implementing your method using a block, remember the
+    # distinction between &lt;tt&gt;Proc.new&lt;/tt&gt; and +lambda+. Invoking +return+
+    # from the former does not return from the block, but returns from the
+    # surrounding method scope. Since normal blocks passed to methods are
+    # of the former type, be very careful about using the +return+ keyword:
+    # 
+    #  add_method(:foo) do |param|
+    #    puts &quot;foo called with parameter &quot;+param.inspect
+    #    return &quot;a return value&quot;   # DOESN'T WORK LIKE YOU EXPECT!
+    #  end
+    # 
+    # To return a value from the method you are creating, set the evaluation
+    # value at the end of the block:
+    # 
+    #  add_method(:foo) do |param|
+    #    puts &quot;foo called with parameter &quot;+param.inspect
+    #    &quot;a return value&quot;    # Returns from method foo
+    #  end
+    # 
+    # If you must use the +return+ keyword, create your block as a lambda
+    # as in this example:
+    # 
+    #  code = lambda do |param|
+    #    puts &quot;foo called with parameter &quot;+param.inspect
+    #    return &quot;a return value&quot;   # Returns from method foo
+    #  end
+    #  add_method(:foo, &amp;code)
+    # 
+    # === Accepting a block argument
+    # 
+    # If you want your method to take a block, you have several options
+    # depending on your Ruby version. If you are running the standard Matz
+    # Ruby interpreter (MRI) version 1.8.7 or later (including 1.9.x), you
+    # can use the standard &quot;&amp;&quot; block argument notation to receive the block.
+    # Note that you must call the passed block using the +call+ method since
+    # Ruby doesn't support invoking such a block with +yield+.
     # For example, to create a method named &quot;foo&quot; that takes one parameter
     # and a block, do this:
     # 
-    #  add_method(:foo, :block =&gt; :first) do |block, param|
+    #  add_method(:foo) do |param, &amp;block|
     #    puts &quot;foo called with parameter &quot;+param.inspect
     #    puts &quot;the block returned &quot;+block.call.inspect
     #  end
@@ -374,18 +489,32 @@ module Blockenspiel
     # 
     #  foo(&quot;hello&quot;){ &quot;a value&quot; }
     # 
-    # By default, a method of the same name is also made available to
-    # parameterless blocks. To change the name of the parameterless method,
-    # provide its name as the value of the &lt;tt&gt;:dsl_method&lt;/tt&gt; option.
-    # To disable this method for parameterless blocks, set the
-    # &lt;tt&gt;:dsl_method&lt;/tt&gt; option to +false+.
+    # If you are using MRI 1.8.6, however, the parser does not support
+    # passing a block argument to a block. Oddly, the current version of
+    # JRuby (version 1.4.0 as of this writing) also does not support this
+    # syntax, though it claims MRI 1.8.7 compatibility. (See bug JRUBY-4180
+    # to track this issue.) If your Ruby interpreter doesn't support the
+    # standard way to create a method that takes a block, Blockenspiel
+    # provides an alternative in the form of the &lt;tt&gt;:block&lt;/tt&gt; option.
+    # This option causes blocks provided by the caller to be included in
+    # the normal parameter list to your method, instead of as a block
+    # parameter. It can be set to &lt;tt&gt;:first&lt;/tt&gt; or &lt;tt&gt;:last&lt;/tt&gt; to
+    # prepend or append, respectively, the block (as a +Proc+ object) to
+    # the parameter list. If the caller does not include a block when
+    # calling your DSL method, nil is prepended/appended. For example:
     # 
-    # For historical reasons, the &lt;tt&gt;:mixin&lt;/tt&gt; option is an alias for
-    # &lt;tt&gt;:dsl_method&lt;/tt&gt;. However, its use is deprecated.
+    #  add_method(:foo, :block =&gt; :last) do |param, block|
+    #    puts &quot;foo called with parameter &quot;+param.inspect
+    #    if block
+    #      puts &quot;the block returned &quot;+block.call.inspect
+    #    else
+    #      puts &quot;no block passed&quot;
+    #    end
+    #  end
     # 
-    # The &lt;tt&gt;:receive_block&lt;/tt&gt; option is also supported for historical
-    # reasons, but its use is deprecated. Setting &lt;tt&gt;:receive_block&lt;/tt&gt; to
-    # +true+ is equivalent to setting &lt;tt&gt;:block&lt;/tt&gt; to &lt;tt&gt;:last&lt;/tt&gt;.
+    # The &lt;tt&gt;:receive_block&lt;/tt&gt; option is a deprecated alternative.
+    # Setting &lt;tt&gt;:receive_block =&gt; true&lt;/tt&gt; is currently equivalent to
+    # setting &lt;tt&gt;:block =&gt; :last&lt;/tt&gt;.
     
     def add_method(name_, opts_={}, &amp;block_)
       receive_block_ = opts_[:receive_block] ? :last : opts_[:block]
@@ -402,7 +531,7 @@ module Blockenspiel
   
   
   # :stopdoc:
-  TARGET_MISMATCH = ::Object.new
+  NO_VALUE = ::Object.new
   # :startdoc:
   
   @_target_stacks = ::Hash.new
@@ -411,18 +540,37 @@ module Blockenspiel
   @_mutex = ::Mutex.new
   
   
-  # === Invoke a given block.
+  # === Invoke a given block
   # 
   # This is the meat of Blockenspiel. Call this function to invoke a block
   # provided by the user of your API.
   # 
+  # For example, if you want users of your API to be able to do this:
+  # 
+  #  call_dsl do
+  #    foo(1)
+  #    bar(2)
+  #  end
+  # 
+  # Then you should implement &lt;tt&gt;call_dsl&lt;/tt&gt; like this:
+  # 
+  #  def call_dsl(&amp;block)
+  #    my_dsl = create_block_implementation
+  #    Blockenspiel.invoke(block, my_dsl)
+  #    do_something_with(my_dsl)
+  #  end
+  # 
+  # In the above, &lt;tt&gt;create_block_implementation&lt;/tt&gt; is a placeholder that
+  # returns an instance of your DSL methods class. This class includes the
+  # Blockenspiel::DSL module and defines the DSL methods +foo+ and +bar+.
+  # 
   # Normally, this method will check the block's arity to see whether it
   # takes a parameter. If so, it will pass the given target to the block.
   # If the block takes no parameter, and the given target is an instance of
   # a class with DSL capability, the DSL methods are made available on the
   # caller's self object so they may be called without a block parameter.
   # 
-  # Recognized options include:
+  # === Recognized options
   # 
   # &lt;tt&gt;:parameterless&lt;/tt&gt;::
   #   If set to false, disables parameterless blocks and always attempts to
@@ -471,7 +619,7 @@ module Blockenspiel
   #    add_method(:set_foo) do |value|
   #      my_foo = value
   #    end
-  #    add_method(:set_things_from_block, :block =&gt; :last) do |value,blk|
+  #    add_method(:set_things_from_block) do |value, &amp;blk|
   #      my_foo = value
   #      my_bar = blk.call
   #    end
@@ -495,10 +643,10 @@ module Blockenspiel
   # 
   # The obvious advantage of using dynamic object generation is that you are
   # creating methods using closures, which provides the opportunity to, for
-  # example, modify closure variables such as my_foo. This is more difficult
-  # to do when you create a target class since its methods do not have access
-  # to outside data. Hence, in the above example, we hand-waved, assuming the
-  # existence of some method called &quot;set_my_foo_from&quot;.
+  # example, modify closure local variables such as my_foo. This is more
+  # difficult to do when you create a target class since its methods do not
+  # have access to outside data. Hence, in the above example, we hand-waved,
+  # assuming the existence of some method called &quot;set_my_foo_from&quot;.
   # 
   # The disadvantage is performance. If you dynamically generate a target
   # object, it involves parsing and creating a new class whenever it is
@@ -643,11 +791,11 @@ module Blockenspiel
   # This implements the mapping between DSL module methods and target object methods.
   # We look up the current target object based on the current thread.
   # Then we attempt to call the given method on that object.
-  # If we can't find an appropriate method to call, return the special value TARGET_MISMATCH.
+  # If we can't find an appropriate method to call, return the special value NO_VALUE.
   
   def self._target_dispatch(object_, name_, params_, block_)  # :nodoc:
     target_stack_ = @_target_stacks[[::Thread.current.object_id, object_.object_id]]
-    return ::Blockenspiel::TARGET_MISMATCH unless target_stack_
+    return ::Blockenspiel::NO_VALUE unless target_stack_
     target_stack_.reverse_each do |target_|
       target_class_ = target_.class
       delegate_ = target_class_._get_blockenspiel_delegate(name_)
@@ -655,7 +803,7 @@ module Blockenspiel
         return target_.send(delegate_, *params_, &amp;block_)
       end
     end
-    return ::Blockenspiel::TARGET_MISMATCH
+    return ::Blockenspiel::NO_VALUE
   end
   
   </diff>
      <filename>lib/blockenspiel/impl.rb</filename>
    </modified>
    <modified>
      <diff>@@ -37,6 +37,6 @@
 module Blockenspiel
   
   # Current gem version, as a frozen string.
-  VERSION_STRING = '0.2.2'.freeze
+  VERSION_STRING = '0.3.0'.freeze
   
 end</diff>
      <filename>lib/blockenspiel/version.rb</filename>
    </modified>
    <modified>
      <diff>@@ -74,7 +74,7 @@ module Blockenspiel
       # * Asserts that the specified target object does in fact receive the block messages.
       
       def test_basic_param
-        block_ = proc do |t_|
+        block_ = ::Proc.new do |t_|
           t_.set_value(:a, 1)
           t_.set_value_by_block(:b){ 2 }
           assert(!self.respond_to?(:set_value))
@@ -94,7 +94,7 @@ module Blockenspiel
       # * Asserts that the specified target object still receives the messages.
       
       def test_basic_mixin
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value(:a, 1)
           set_value_by_block(:b){ 2 }
         end
@@ -113,7 +113,7 @@ module Blockenspiel
       # * Asserts that receivers with blocks are handled properly.
       
       def test_basic_builder
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value(:a, 1)
           set_value_by_block(:b){ 2 }
         end</diff>
      <filename>tests/tc_basic.rb</filename>
    </modified>
    <modified>
      <diff>@@ -89,7 +89,7 @@ module Blockenspiel
         hash_ = ::Hash.new
         context_self_ = self
         @my_instance_variable_test = :hello
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value1('a', 1)
           set_value2('b'){ 2 }
           set_value3('c', 3)
@@ -116,7 +116,7 @@ module Blockenspiel
         hash_ = ::Hash.new
         context_self_ = self
         @my_instance_variable_test = :hello
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value1('a', 1)
           set_value2('b'){ 2 }
           set_value3_dslversion('c', 3)
@@ -140,13 +140,13 @@ module Blockenspiel
       
       def test_disable_parameterless
         hash_ = ::Hash.new
-        block1_ = proc do ||
+        block1_ = ::Proc.new do ||
           set_value1('a', 1)
         end
-        block2_ = proc do |target_|
+        block2_ = ::Proc.new do |target_|
           target_.set_value1('b', 2)
         end
-        block3_ = proc do
+        block3_ = ::Proc.new do
           set_value1('c', 3)
         end
         assert_raise(::Blockenspiel::BlockParameterError) do
@@ -167,13 +167,13 @@ module Blockenspiel
       
       def test_disable_parametered
         hash_ = ::Hash.new
-        block1_ = proc do ||
+        block1_ = ::Proc.new do ||
           set_value1('a', 1)
         end
-        block2_ = proc do |target_|
+        block2_ = ::Proc.new do |target_|
           target_.set_value1('b', 2)
         end
-        block3_ = proc do
+        block3_ = ::Proc.new do
           set_value1('c', 3)
         end
         ::Blockenspiel.invoke(block1_, Target1.new(hash_), :parameter =&gt; false)</diff>
      <filename>tests/tc_behaviors.rb</filename>
    </modified>
    <modified>
      <diff>@@ -203,7 +203,7 @@ module Blockenspiel
       
       def test_default_setting
         hash_ = ::Hash.new
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value1('a', 1)
           set_value2('b'){ 2 }
           assert_raise(::NoMethodError){ _set_value3('c', 3) }
@@ -223,7 +223,7 @@ module Blockenspiel
       
       def test_onoff_switching
         hash_ = ::Hash.new
-        block_ = proc do
+        block_ = ::Proc.new do
           assert_raise(::NoMethodError){ _set_value1('a', 1) }
           set_value2('b'){ 2 }
           _set_value3('c', 3)
@@ -242,7 +242,7 @@ module Blockenspiel
       
       def test_explicit_add
         hash_ = ::Hash.new
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value1('a', 1)
           assert_raise(::NoMethodError){ set_value2('b'){ 2 } }
           renamed_set_value2('c'){ 3 }
@@ -263,7 +263,7 @@ module Blockenspiel
       
       def test_explicit_removing
         hash_ = ::Hash.new
-        block_ = proc do
+        block_ = ::Proc.new do
           assert_raise(::NoMethodError){ set_value1('a', 1) }
           assert_raise(::NoMethodError){ set_value2('b'){ 2 } }
           renamed_set_value2('c'){ 3 }
@@ -282,7 +282,7 @@ module Blockenspiel
       
       def test_subclassing
         hash_ = ::Hash.new
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value1('a', 1)
           set_value2('b'){ 2 }
           assert_raise(::NoMethodError){ set_value3('c', 3) }
@@ -307,7 +307,7 @@ module Blockenspiel
       
       def test_multiple_dsl_methods
         hash_ = ::Hash.new
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value1('a', 1)
           renamed_set_value2('b'){ 2 }
           assert_raise(::NoMethodError){ set_value2('c', 3) }</diff>
      <filename>tests/tc_dsl_methods.rb</filename>
    </modified>
    <modified>
      <diff>@@ -51,7 +51,7 @@ module Blockenspiel
       # * Asserts that the simplest case works.
       
       def test_simple
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value(:a, 1)
         end
         hash_ = ::Hash.new
@@ -71,17 +71,17 @@ module Blockenspiel
       
       def test_renaming
         hash_ = ::Hash.new
-        dsl_definition_ = proc do
+        dsl_definition_ = ::Proc.new do
           add_method(:set_value, :dsl_method =&gt; :renamed_set_value) do |key_, value_|
             hash_[key_] = value_
           end
         end
-        block1_ = proc do
+        block1_ = ::Proc.new do
           renamed_set_value(:a, 1)
           assert_raise(::NoMethodError){ set_value(:b, 2) }
         end
         ::Blockenspiel.invoke(block1_, &amp;dsl_definition_)
-        block2_ = proc do |dsl_|
+        block2_ = ::Proc.new do |dsl_|
           dsl_.set_value(:c, 3)
           assert_raise(::NoMethodError){ renamed_set_value(:d, 4) }
         end
@@ -93,15 +93,53 @@ module Blockenspiel
       end
       
       
-      # Test calls with blocks.
+      # Test calls with blocks passed the usual way.
+      # This works in MRI 1.8.7 or later. However, it does NOT currently
+      # work with JRuby 1.4 because of JRUBY-4180. So we disable this test
+      # for all versions of JRuby (for now) and for MRI &lt; 1.8.7.
+      # 
+      # * Asserts that a block passed the usual way works
+      # * Asserts that we can detect when a block has not been passed
+      
+if ::RUBY_PLATFORM != 'java' &amp;&amp; ::RUBY_VERSION &gt;= '1.8.7'
+  module_eval &lt;&lt;-END
+      def test_blocks_normal
+        hash_ = ::Hash.new
+        block_ = ::Proc.new do
+          set_value1(:a){ 1 }
+          set_value2(:b){ 2 }
+          set_value2(:c)
+        end
+        ::Blockenspiel.invoke(block_) do
+          add_method(:set_value1) do |key_, &amp;bl_|
+            hash_[key_] = bl_.call
+          end
+          add_method(:set_value2) do |key_, &amp;bl_|
+            hash_[key_] = bl_ ? true : false
+          end
+        end
+        assert_equal(1, hash_[:a])
+        assert_equal(true, hash_[:b])
+        assert_equal(false, hash_[:c])
+      end
+  END
+end
+      
+      
+      # Test calls with blocks passed as non-block parameters.
       # 
       # * Asserts that a block passed &quot;first&quot; works.
       # * Asserts that a block passed &quot;last&quot; works.
-      # * Asserts that a block passed &quot;last&quot; works.
+      # * Asserts that a block passed &quot;true&quot; works.
       
       def test_blocks_first_and_last
         hash_ = ::Hash.new
-        dsl_definition_ = proc do
+        block_ = ::Proc.new do
+          set_value1(:a){ 1 }
+          set_value2(:b){ 2 }
+          set_value2(:c){ 3 }
+        end
+        ::Blockenspiel.invoke(block_) do
           add_method(:set_value1, :block =&gt; :first) do |bl_, key_|
             hash_[key_] = bl_.call
           end
@@ -112,12 +150,6 @@ module Blockenspiel
             hash_[key_] = bl_.call
           end
         end
-        block_ = proc do
-          set_value1(:a){ 1 }
-          set_value2(:b){ 2 }
-          set_value2(:c){ 3 }
-        end
-        ::Blockenspiel.invoke(block_, &amp;dsl_definition_)
         assert_equal(1, hash_[:a])
         assert_equal(2, hash_[:b])
         assert_equal(3, hash_[:c])
@@ -130,7 +162,11 @@ module Blockenspiel
       
       def test_blocks_nil
         hash_ = ::Hash.new
-        dsl_definition_ = proc do
+        block_ = ::Proc.new do
+          set_value1(:a)
+          set_value2(:b)
+        end
+        ::Blockenspiel.invoke(block_) do
           add_method(:set_value1, :block =&gt; :first) do |bl_, key_|
             assert_nil(bl_)
           end
@@ -138,11 +174,6 @@ module Blockenspiel
             assert_nil(bl_)
           end
         end
-        block_ = proc do
-          set_value1(:a)
-          set_value2(:b)
-        end
-        ::Blockenspiel.invoke(block_, &amp;dsl_definition_)
         assert_nil(hash_[:a])
         assert_nil(hash_[:b])
       end
@@ -150,21 +181,18 @@ module Blockenspiel
       
       # Test calls with blocks (legacy api)
       # 
-      # * Asserts that a block passed &quot;first&quot; works.
-      # * Asserts that a block passed &quot;last&quot; works.
-      # * Asserts that a block passed &quot;last&quot; works.
+      # * Asserts that a block with receive_block works.
       
       def test_blocks_legacy
         hash_ = ::Hash.new
-        dsl_definition_ = proc do
+        block_ = ::Proc.new do
+          set_value(:a){ 1 }
+        end
+        ::Blockenspiel.invoke(block_) do
           add_method(:set_value, :receive_block =&gt; true) do |key_, bl_|
             hash_[key_] = bl_.call
           end
         end
-        block_ = proc do
-          set_value(:a){ 1 }
-        end
-        ::Blockenspiel.invoke(block_, &amp;dsl_definition_)
         assert_equal(1, hash_[:a])
       end
       </diff>
      <filename>tests/tc_dynamic.rb</filename>
    </modified>
    <modified>
      <diff>@@ -97,7 +97,7 @@ module Blockenspiel
         @my_instance_variable_test = :hello
         assert(!self.respond_to?(:set_value))
         assert(!self.respond_to?(:set_value2))
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value('a', 1)
           set_value2('b'){ 2 }
           assert_equal(:hello, @my_instance_variable_test)
@@ -121,7 +121,7 @@ module Blockenspiel
         assert(!self.respond_to?(:set_value))
         assert(!self.respond_to?(:set_value2))
         assert(!self.respond_to?(:set_value2_inmixin))
-        block_ = proc do
+        block_ = ::Proc.new do
           set_value('a', 1)
           set_value2_inmixin('b'){ 2 }
           assert(!self.respond_to?(:set_value2))
@@ -146,11 +146,11 @@ module Blockenspiel
         assert(!self.respond_to?(:set_value))
         assert(!self.respond_to?(:set_value2))
         assert(!self.respond_to?(:set_value2_inmixin))
-        ::Blockenspiel.invoke(proc do
+        ::Blockenspiel.invoke(::Proc.new do
           set_value('a', 1)
           set_value2('b'){ 2 }
           assert(!self.respond_to?(:set_value2_inmixin))
-          ::Blockenspiel.invoke(proc do
+          ::Blockenspiel.invoke(::Proc.new do
             set_value('c', 1)
             set_value2_inmixin('d'){ 2 }
           end, Target2.new(hash_))
@@ -179,10 +179,10 @@ module Blockenspiel
         assert(!self.respond_to?(:set_value))
         assert(!self.respond_to?(:set_value2))
         assert(!self.respond_to?(:set_value2_inmixin))
-        ::Blockenspiel.invoke(proc do
+        ::Blockenspiel.invoke(::Proc.new do
           set_value('a', 1)
           set_value2_inmixin('b'){ 2 }
-          ::Blockenspiel.invoke(proc do
+          ::Blockenspiel.invoke(::Proc.new do
             set_value('c', 1)
             set_value2_inmixin('d'){ 2 }
             assert(!self.respond_to?(:set_value2))
@@ -208,12 +208,12 @@ module Blockenspiel
       
       def test_threads_same_mixin
         hash_ = ::Hash.new
-        block1_ = proc do
+        block1_ = ::Proc.new do
           set_value('a', 1)
           sleep(0.5)
           set_value2('b'){ 2 }
         end
-        block2_ = proc do
+        block2_ = ::Proc.new do
           set_value('c', 3)
           sleep(1)
           set_value2('d'){ 4 }</diff>
      <filename>tests/tc_mixins.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c4b59db41e03316b8b1d3befe3b993f185c96367</id>
    </parent>
  </parents>
  <author>
    <name>Daniel Azuma</name>
    <email>dazuma@gmail.com</email>
  </author>
  <url>http://github.com/dazuma/blockenspiel/commit/c5e6db9188db8da93c05279f66c30210b10429f6</url>
  <id>c5e6db9188db8da93c05279f66c30210b10429f6</id>
  <committed-date>2009-11-04T17:59:20-08:00</committed-date>
  <authored-date>2009-11-04T17:59:20-08:00</authored-date>
  <message>Version 0.3 changes</message>
  <tree>f50f2c7fd8d84b75d50e0d70e3b8caf1e43809da</tree>
  <committer>
    <name>Daniel Azuma</name>
    <email>dazuma@gmail.com</email>
  </committer>
</commit>
