=== lib/bluecloth.rb
==================================================================
--- lib/bluecloth.rb  (revision 2103)
+++ lib/bluecloth.rb  (local)
@@ -99,9 +99,6 @@
 	# because globals make me break out in hives. Or something.
 	RenderState = Struct::new( "RenderState", :urls, :titles, :html_blocks, :log )
 
-	# Tab width for #detab! if none is specified
-	TabWidth = 4
-
 	# The tag-closing string -- set to '>' for HTML
 	EmptyElementSuffix = "/>";
 
@@ -122,6 +119,7 @@
 	###	I N S T A N C E   M E T H O D S
 	#################################################################
 
+
 	### Create a new BlueCloth string.
 	def initialize( content="", *restrictions )
 		@log = Logger::new( $deferr )
@@ -136,6 +134,7 @@
 		@filter_styles = nil
 		restrictions.flatten.each {|r| __send__("#{r}=", true) }
 		@fold_lines = true
+		@tab_width = 4
 
 		super( content )
 
@@ -156,6 +155,9 @@
 	# so this isn't used by anything.
 	attr_accessor :fold_lines
 
+	# The number of spaces to treat tabs as. Plus to use for identing/outdenting
+	# lists.
+	attr_accessor :tab_width
 
 	### Render Markdown-formatted text in this string object as HTML and return
 	### it. The parameter is for compatibility with RedCloth, and is currently
@@ -171,7 +173,8 @@
 
 		# Make a copy of the string with normalized line endings, tabs turned to
 		# spaces, and a couple of guaranteed newlines at the end
-		text = self.gsub( /\r\n?/, "\n" ).detab
+		text = self.gsub( /\r\n?/, "\n" )
+    text = detab(text)
 		text += "\n\n"
 		@log.debug "Normalized line-endings: %p" % text
 
@@ -210,21 +213,12 @@
 
 		return text
 	end
-	
 
 	### Convert tabs in +str+ to spaces.
-	def detab( tabwidth=TabWidth )
-		copy = self.dup
-		copy.detab!( tabwidth )
-		return copy
-	end
-
-
-	### Convert tabs to spaces in place and return self if any were converted.
-	def detab!( tabwidth=TabWidth )
+	def detab( str )
 		newstr = self.split( /\n/ ).collect {|line|
 			line.gsub( /(.*?)\t/ ) do
-				$1 + ' ' * (tabwidth - $1.length % tabwidth)
+				$1 + ' ' * (tab_width - $1.length % tab_width)
 			end
 		}.join("\n")
 		self.replace( newstr )
@@ -298,7 +292,7 @@
 		</\1>					# Matching end tag
 		[ ]*					# trailing spaces
 		$						# End of line or document
-	  }ix
+	}ix
 
 	# More-liberal block-matching
 	LooseBlockRegex = %r{
@@ -463,9 +457,10 @@
 	ListMarkerUl = %r{[*+-]}
 	ListMarkerAny = Regexp::union( ListMarkerOl, ListMarkerUl )
 
-	ListRegexp = %r{
+	def listRegexp
+		%r{
 		  (?:
-			^[ ]{0,#{TabWidth - 1}}		# Indent < tab width
+			^[ ]{0,#{tab_width - 1}}		# Indent < tab width
 			(#{ListMarkerAny})			# unordered or ordered ($1)
 			[ ]+						# At least one space
 		  )
@@ -480,13 +475,14 @@
 			   [ ]+)
 		  )
 	  }x
+	end
 
 	### Transform Markdown-style lists in a copy of the specified +str+ and
 	### return it.
 	def transform_lists( str, rs )
 		@log.debug " Transforming lists at %p" % (str[0,100] + '...')
 
-		str.gsub( ListRegexp ) {|list|
+		str.gsub( listRegexp ) {|list|
 			@log.debug "  Found list %p" % list
 			bullet = $1
 			list_type = (ListMarkerUl.match(bullet) ? "ul" : "ol")
@@ -538,24 +534,26 @@
 
 
 	# Pattern for matching codeblocks
-	CodeBlockRegexp = %r{
+	def codeBlockRegexp
+		%r{
 		(?:\n\n|\A)
 		(									# $1 = the code block
 		  (?:
-			(?:[ ]{#{TabWidth}} | \t)		# a tab or tab-width of spaces
+			(?:[ ]{#{tab_width}} | \t)		# a tab or tab-width of spaces
 			.*\n+
 		  )+
 		)
-		(^[ ]{0,#{TabWidth - 1}}\S|\Z)		# Lookahead for non-space at
+		(^[ ]{0,#{tab_width - 1}}\S|\Z)		# Lookahead for non-space at
 											# line-start, or end of doc
 	  }x
+	end
 
 	### Transform Markdown-style codeblocks in a copy of the specified +str+ and
 	### return it.
 	def transform_code_blocks( str, rs )
 		@log.debug " Transforming code blocks"
 
-		str.gsub( CodeBlockRegexp ) {|block|
+		str.gsub( codeBlockRegexp ) {|block|
 			codeblock = $1
 			remainder = $2
 
@@ -588,7 +586,7 @@
 			quote.gsub!( /^ *> ?/, '' ) # Trim one level of quoting 
 			quote.gsub!( /^ +$/, '' )	# Trim whitespace-only lines
 
-			indent = " " * TabWidth
+			indent = " " * tab_width
 			quoted = %{<blockquote>\n%s\n</blockquote>\n\n} %
 				apply_block_transforms( quote, rs ).
 				gsub( /^/, indent ).
@@ -1137,7 +1135,7 @@
 	### Return one level of line-leading tabs or spaces from a copy of +str+ and
 	### return it.
 	def outdent( str )
-		str.gsub( /^(\t|[ ]{1,#{TabWidth}})/, '')
+		str.gsub( /^(\t|[ ]{1,#{tab_width}})/, '')
 	end
 	
 end # class BlueCloth
