diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..2aa163d
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,101 @@
+= Change Log
+
+== Version 3.1.0
+
+* Included the to_xs arity patch needed for weird Rails compatibility
+ issue.
+
+* Escaping newlines in attributes now.
+
+* Allow method caching
+
+== Version 3.0.0
+
+* Ruby 1.9 compatiblity issues.
+
+== Version 2.2.0
+
+* Applied patch from Thijs van der Vossen to allow UTF-8 encoded
+ output when the encoding is UTF-8 and $KCODE is UTF8.
+
+== Version 2.1.2
+
+* Fixed bug where private methods in kernel could leak through using
+ tag!(). Thanks to Hagen Overdick for finding and diagnosing this
+ bug.
+
+== Version 2.1.1
+
+* Fixed typo in XmlMarkup class docs (ident => indent). (from Martin
+ Fowler).
+* Removed extra directory indirection from legacy CVS to SVN move.
+* Removed some extraneous tabs from source.
+* Fixed test on private methods in blankslate to differentiate between
+ targetted and untargetted private methods.
+* Removed legacy capture of @self in XmlBase (@self was used back when
+ we used instance eval).
+* Added additional tests for global functions (both direct and included).
+
+== Version 2.1.0
+
+* Fixed bug in BlankSlate where including a module into Object could
+ cause methods to leak into BlankSlate.
+* Made BlankSlate available as its own gem. Currently the builder gem
+ still directly includes the BlankSlate code.
+* Added reveal capability to BlankSlate.
+
+== Version 2.0.0
+
+* Added doc directory
+* Added unit tests for XmlEvents.
+* Added XChar module and used it in the _escape method.
+* Attributes are now quoted by default when strings. Use Symbol
+ attribute values for unquoted behavior.
+
+== Version 1.2.4
+
+* Added a cdata! command to an XML Builder (from Josh Knowles).
+
+== Version 1.2.3
+
+The attributes in the instruction will be ordered:
+version, encoding, standalone.
+
+== Version 1.2.2
+
+Another fix for BlankSlate. The Kernal/Object traps added in 1.2.1
+failed when a method was defined late more than once. Since the
+method was already marked as removed, another attempt to undefine it
+raised an error. The fix was to check the list of instance methods
+before attempting the undef operation. Thanks to Florian Gross and
+David Heinemeier Hansson for the patch.
+
+== Version 1.2.1
+
+BlankSlate now traps method definitions in Kernel and Object to avoid
+late method definitions inadvertently becoming part of the definition
+of BlankSlate as well.
+
+== Version 1.2.0
+
+Improved support for entity declarations by allowing nested
+declarations and removal of the attribute processing.
+
+Added namespace support.
+
+== Version 1.1.0
+
+Added support for comments, entity declarations and processing instructions.
+
+== Version 1.0.0
+
+Removed use of instace_eval making the use of XmlMarkup much
+less prone to error.
+
+== Version 0.1.1
+
+Bug fix.
+
+== Version 0.1.0
+
+Initial version release.
diff --git a/MIT-LICENSE b/MIT-LICENSE
index c00d4c0..7d9be51 100644
--- a/MIT-LICENSE
+++ b/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright 2011 Jim Weirich (jim@weirichhouse.org)
+Copyright (c) 2003-2012 Jim Weirich (jim.weirich@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..5d77763
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,189 @@
+# Rakefile for rake -*- ruby -*-
+
+# Copyright 2004, 2005, 2006 by Jim Weirich (jim@weirichhouse.org).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+
+require 'rake/clean'
+require 'rake/testtask'
+require 'rdoc/task'
+begin
+ require 'rubygems'
+ require 'rubygems/package_task'
+rescue Exception
+ nil
+end
+
+require './lib/builder/version'
+
+# Determine the current version of the software
+
+CLOBBER.include('pkg')
+CLEAN.include('pkg/builder-*').include('pkg/blankslate-*').exclude('pkg/*.gem')
+
+PKG_VERSION = Builder::VERSION
+
+SRC_RB = FileList['lib/**/*.rb']
+
+# The default task is run if rake is given no explicit arguments.
+
+desc "Default Task"
+task :default => :test_all
+
+# Test Tasks ---------------------------------------------------------
+
+desc "Run all tests"
+task :test_all => [:test_units]
+task :ta => [:test_all]
+
+task :tu => [:test_units]
+
+Rake::TestTask.new("test_units") do |t|
+ t.test_files = FileList['test/test*.rb']
+ t.libs << "."
+ t.verbose = false
+end
+
+# Create a task to build the RDOC documentation tree.
+
+rd = RDoc::Task.new("rdoc") { |rdoc|
+ rdoc.rdoc_dir = 'html'
+ rdoc.title = "Builder for Markup"
+ rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc'
+ rdoc.rdoc_files.include('lib/**/*.rb', '[A-Z]*', 'doc/**/*.rdoc').exclude("TAGS")
+ rdoc.template = 'doc/jamis.rb'
+}
+
+# ====================================================================
+# Create a task that will package the Rake software into distributable
+# gem files.
+
+PKG_FILES = FileList[
+ 'lib/**/*.rb',
+ 'test/**/*.rb',
+ 'scripts/**/*.rb'
+]
+PKG_FILES.exclude('test/test_cssbuilder.rb')
+PKG_FILES.exclude('lib/builder/css.rb')
+PKG_FILES.exclude('TAGS')
+
+BLANKSLATE_FILES = FileList[
+ 'lib/blankslate.rb',
+ 'test/test_blankslate.rb'
+]
+
+if ! defined?(Gem)
+ puts "Package Target requires RubyGEMs"
+else
+ spec = Gem::Specification.new do |s|
+
+ #### Basic information.
+
+ s.name = 'builder'
+ s.version = PKG_VERSION
+ s.summary = "Builders for MarkUp."
+ s.description = %{\
+Builder provides a number of builder objects that make creating structured data
+simple to do. Currently the following builder objects are supported:
+
+* XML Markup
+* XML Events
+}
+
+ s.files = PKG_FILES.to_a
+ s.require_path = 'lib'
+
+ s.test_files = PKG_FILES.select { |fn| fn =~ /^test\/test/ }
+
+ s.has_rdoc = true
+ s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
+ s.rdoc_options <<
+ '--title' << 'Builder -- Easy XML Building' <<
+ '--main' << 'README.rdoc' <<
+ '--line-numbers'
+
+ s.author = "Jim Weirich"
+ s.email = "jim.weirich@gmail.com"
+ s.homepage = "http://onestepback.org"
+ s.license = 'MIT'
+ end
+
+ blankslate_spec = Gem::Specification.new do |s|
+
+ #### Basic information.
+
+ s.name = 'blankslate'
+ s.version = PKG_VERSION
+ s.summary = "Blank Slate base class."
+ s.description = %{\
+BlankSlate provides a base class where almost all of the methods from Object and
+Kernel have been removed. This is useful when providing proxy object and other
+classes that make heavy use of method_missing.
+}
+
+ s.files = BLANKSLATE_FILES.to_a
+ s.require_path = 'lib'
+
+ s.test_files = PKG_FILES.select { |fn| fn =~ /^test\/test/ }
+
+ s.has_rdoc = true
+ s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
+ s.rdoc_options <<
+ '--title' << 'BlankSlate -- Base Class for building proxies.' <<
+ '--main' << 'README.rdoc' <<
+ '--line-numbers'
+
+ s.author = "Jim Weirich"
+ s.email = "jim.weirich@gmail.com"
+ s.homepage = "http://onestepback.org"
+ s.license = 'MIT'
+ end
+
+ namespace 'builder' do
+ Gem::PackageTask.new(spec) do |t|
+ t.need_tar = false
+ end
+ end
+
+ namespace 'blankslate' do
+ Gem::PackageTask.new(blankslate_spec) do |t|
+ t.need_tar = false
+ end
+ end
+
+ task :package => [:remove_tags, 'builder:package', 'blankslate:package']
+end
+
+task :remove_tags do
+ rm "TAGS" rescue nil
+end
+
+# RCov ---------------------------------------------------------------
+begin
+ require 'rcov/rcovtask'
+
+ Rcov::RcovTask.new do |t|
+ t.libs << "test"
+ t.rcov_opts = [
+ '-xRakefile', '--text-report'
+ ]
+ t.test_files = FileList[
+ 'test/test*.rb'
+ ]
+ t.output_dir = 'coverage'
+ t.verbose = true
+ end
+rescue LoadError
+ # No rcov available
+end
+
+desc "Install the jamis RDoc template"
+task :install_jamis_template do
+ require 'rbconfig'
+ dest_dir = File.join(Config::CONFIG['rubylibdir'], "rdoc/generators/template/html")
+ fail "Unabled to write to #{dest_dir}" unless File.writable?(dest_dir)
+ install "doc/jamis.rb", dest_dir, :verbose => true
+end
diff --git a/lib/blankslate.rb b/lib/blankslate.rb
index b6e9bf7..4cae7d5 100644
--- a/lib/blankslate.rb
+++ b/lib/blankslate.rb
@@ -1,4 +1,3 @@
-#!/usr/bin/env ruby
#--
# Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
# All rights reserved.
@@ -8,6 +7,30 @@
# above copyright notice is included.
#++
+class String
+ if instance_methods.first.is_a?(Symbol)
+ def _blankslate_as_name
+ to_sym
+ end
+ else
+ def _blankslate_as_name
+ self
+ end
+ end
+end
+
+class Symbol
+ if instance_methods.first.is_a?(Symbol)
+ def _blankslate_as_name
+ self
+ end
+ else
+ def _blankslate_as_name
+ to_s
+ end
+ end
+end
+
######################################################################
# BlankSlate provides an abstract base class with no predefined
# methods (except for \_\_send__ and \_\_id__).
@@ -16,13 +39,12 @@
#
class BlankSlate
class << self
-
+
# Hide the method named +name+ in the BlankSlate class. Don't
# hide +instance_eval+ or any method beginning with "__".
def hide(name)
- methods = instance_methods.map(&:to_sym)
- if methods.include?(name.to_sym) and
- name !~ /^(__|instance_eval)/
+ if instance_methods.include?(name._blankslate_as_name) and
+ name !~ /^(__|instance_eval$)/
@hidden_methods ||= {}
@hidden_methods[name.to_sym] = instance_method(name)
undef_method name
@@ -42,7 +64,7 @@ def reveal(name)
define_method(name, hidden_method)
end
end
-
+
instance_methods.each { |m| hide(m) }
end
@@ -107,4 +129,4 @@ def append_features(mod)
end
result
end
-end
\ No newline at end of file
+end
diff --git a/spec/blankslate_spec.rb b/spec/blankslate_spec.rb
deleted file mode 100644
index 9526445..0000000
--- a/spec/blankslate_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'spec_helper'
-
-describe BlankSlate do
- let(:blank_slate) { BlankSlate.new }
-
- def call(obj, meth, *args)
- BlankSlate.find_hidden_method(meth).bind(obj).call(*args)
- end
-
- describe "cleanliness" do
- it "should not have many methods" do
- BlankSlate.instance_methods.
- map(&:to_s).sort.
- should == ["__id__", "__send__", "instance_eval"]
- end
- end
-
- context "when methods are added to Object" do
- after(:each) {
- class Object
- undef :foo
- end
- }
-
- it "should still be blank" do
- class Object
- def foo
- end
- end
- Object.new.foo
-
- lambda {
- BlankSlate.new.foo
- }.should raise_error(NoMethodError)
- end
-
- end
-end
\ No newline at end of file
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
deleted file mode 100644
index f2b029d..0000000
--- a/spec/spec_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-
-require 'blankslate'
\ No newline at end of file
diff --git a/test/preload.rb b/test/preload.rb
new file mode 100644
index 0000000..631cd7d
--- /dev/null
+++ b/test/preload.rb
@@ -0,0 +1,37 @@
+#--
+# Portions copyright 2004 by Jim Weirich (jim@weirichhouse.org).
+# Portions copyright 2005 by Sam Ruby (rubys@intertwingly.net).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#++
+
+# We are defining method_added in Kernel and Object so that when
+# BlankSlate overrides them later, we can verify that it correctly
+# calls the older hooks.
+
+module Kernel
+ class << self
+ attr_reader :k_added_names
+ alias_method :preload_method_added, :method_added
+ def method_added(name)
+ preload_method_added(name)
+ @k_added_names ||= []
+ @k_added_names << name
+ end
+ end
+end
+
+class Object
+ class << self
+ attr_reader :o_added_names
+ alias_method :preload_method_added, :method_added
+ def method_added(name)
+ preload_method_added(name)
+ @o_added_names ||= []
+ @o_added_names << name
+ end
+ end
+end
diff --git a/test/test_blankslate.rb b/test/test_blankslate.rb
new file mode 100755
index 0000000..ea38ced
--- /dev/null
+++ b/test/test_blankslate.rb
@@ -0,0 +1,217 @@
+#!/usr/bin/env ruby
+
+#--
+# Portions copyright 2004 by Jim Weirich (jim@weirichhouse.org).
+# Portions copyright 2005 by Sam Ruby (rubys@intertwingly.net).
+# All rights reserved.
+
+# Permission is granted for use, copying, modification, distribution,
+# and distribution of modified versions of this work as long as the
+# above copyright notice is included.
+#++
+
+require 'test/unit'
+require 'test/preload'
+require 'blankslate'
+require 'stringio'
+
+# Methods to be introduced into the Object class late.
+module LateObject
+ def late_object
+ 33
+ end
+ def LateObject.included(mod)
+ # Modules defining an included method should not prevent blank
+ # slate erasure!
+ end
+end
+
+# Methods to be introduced into the Kernel module late.
+module LateKernel
+ def late_kernel
+ 44
+ end
+ def LateKernel.included(mod)
+ # Modules defining an included method should not prevent blank
+ # slate erasure!
+ end
+end
+
+# Introduce some late methods (both module and direct) into the Kernel
+# module.
+module Kernel
+ include LateKernel
+
+ def late_addition
+ 1234
+ end
+
+ def double_late_addition
+ 11
+ end
+
+ def double_late_addition
+ 22
+ end
+end
+
+
+# Introduce some late methods (both module and direct) into the Object
+# class.
+class Object
+ include LateObject
+ def another_late_addition
+ 4321
+ end
+end
+
+# Introduce some late methods by inclusion.
+module GlobalModule
+ def global_inclusion
+ 42
+ end
+end
+include GlobalModule
+
+def direct_global
+ 43
+end
+
+######################################################################
+# Test case for blank slate.
+#
+class TestBlankSlate < Test::Unit::TestCase
+ def setup
+ @bs = BlankSlate.new
+ end
+
+ def test_undefined_methods_remain_undefined
+ assert_raise(NoMethodError) { @bs.no_such_method }
+ assert_raise(NoMethodError) { @bs.nil? }
+ end
+
+
+ # NOTE: NameError is acceptable because the lack of a '.' means that
+ # Ruby can't tell if it is a method or a local variable.
+ def test_undefined_methods_remain_undefined_during_instance_eval
+ assert_raise(NoMethodError, NameError) do
+ @bs.instance_eval do nil? end
+ end
+ assert_raise(NoMethodError, NameError) do
+ @bs.instance_eval do no_such_method end
+ end
+ end
+
+ def test_private_methods_are_undefined
+ assert_raise(NoMethodError) do
+ @bs.puts "HI"
+ end
+ end
+
+ def test_targetted_private_methods_are_undefined_during_instance_eval
+ assert_raise(NoMethodError, NameError) do
+ @bs.instance_eval do self.puts "HI" end
+ end
+ end
+
+ def test_untargetted_private_methods_are_defined_during_instance_eval
+ oldstdout = $stdout
+ $stdout = StringIO.new
+ @bs.instance_eval do
+ puts "HI"
+ end
+ ensure
+ $stdout = oldstdout
+ end
+
+ def test_methods_added_late_to_kernel_remain_undefined
+ assert_equal 1234, nil.late_addition
+ assert_raise(NoMethodError) { @bs.late_addition }
+ end
+
+ def test_methods_added_late_to_object_remain_undefined
+ assert_equal 4321, nil.another_late_addition
+ assert_raise(NoMethodError) { @bs.another_late_addition }
+ end
+
+ def test_methods_added_late_to_global_remain_undefined
+ assert_equal 42, global_inclusion
+ assert_raise(NoMethodError) { @bs.global_inclusion }
+ end
+
+ def test_preload_method_added
+ assert Kernel.k_added_names.include?(:late_addition)
+ assert Object.o_added_names.include?(:another_late_addition)
+ end
+
+ def test_method_defined_late_multiple_times_remain_undefined
+ assert_equal 22, nil.double_late_addition
+ assert_raise(NoMethodError) { @bs.double_late_addition }
+ end
+
+ def test_late_included_module_in_object_is_ok
+ assert_equal 33, 1.late_object
+ assert_raise(NoMethodError) { @bs.late_object }
+ end
+
+ def test_late_included_module_in_kernel_is_ok
+ assert_raise(NoMethodError) { @bs.late_kernel }
+ end
+
+ def test_revealing_previously_hidden_methods_are_callable
+ with_to_s = Class.new(BlankSlate) do
+ reveal :to_s
+ end
+ assert_match(/^#<.*>$/, with_to_s.new.to_s)
+ end
+
+ def test_revealing_previously_hidden_methods_are_callable_with_block
+ Object.class_eval <<-EOS
+ def given_block(&block)
+ block
+ end
+ EOS
+
+ with_given_block = Class.new(BlankSlate) do
+ reveal :given_block
+ end
+ assert_not_nil with_given_block.new.given_block {}
+ end
+
+ def test_revealing_a_hidden_method_twice_is_ok
+ with_to_s = Class.new(BlankSlate) do
+ reveal :to_s
+ reveal :to_s
+ end
+ assert_match(/^#<.*>$/, with_to_s.new.to_s)
+ end
+
+ def test_revealing_unknown_hidden_method_is_an_error
+ assert_raises(RuntimeError) do
+ Class.new(BlankSlate) do
+ reveal :xyz
+ end
+ end
+ end
+
+ def test_global_includes_still_work
+ assert_nothing_raised do
+ assert_equal 42, global_inclusion
+ assert_equal 42, Object.new.global_inclusion
+ assert_equal 42, "magic number".global_inclusion
+ assert_equal 43, direct_global
+ end
+ end
+
+ def test_reveal_should_not_bind_to_an_instance
+ with_object_id = Class.new(BlankSlate) do
+ reveal(:object_id)
+ end
+
+ obj1 = with_object_id.new
+ obj2 = with_object_id.new
+
+ assert obj1.object_id != obj2.object_id,
+ "Revealed methods should not be bound to a particular instance"
+ end
+end