[#144186] Re: array of object insert polices — "Pe, Botp" <botp@...>

dave [mailto:dave.m@email.it] wrote:

14 messages 2005/06/01

[#144206] Implementing a Read-Only array — Gavin Kistner <gavin@...>

Right up front, let me say that I realize that I can't prevent

14 messages 2005/06/01

[#144224] Method Chaining Issues — "aartist" <aartist@...>

try this:

28 messages 2005/06/01
[#144231] Re: Method Chaining Issues — "Phrogz" <gavin@...> 2005/06/01

This is a FAQ, though no page on the RubyGarden wiki seems to address

[#144240] Re: Method Chaining Issues — Nikolai Weibull <mailing-lists.ruby-talk@...> 2005/06/01

Phrogz wrote:

[#144230] ternary operator confusion — Belorion <belorion@...>

I don't know if this is "improper" use of the ternary operator, but I

19 messages 2005/06/01
[#144233] Re: ternary operator confusion — "Phrogz" <gavin@...> 2005/06/01

true ? a.push(1) : a.push(2)

[#144257] Re: ternary operator confusion — "Marcel Molina Jr." <marcel@...> 2005/06/01

On Thu, Jun 02, 2005 at 01:40:23AM +0900, Phrogz wrote:

[#144263] Re: ternary operator confusion — Eric Mahurin <eric_mahurin@...> 2005/06/01

--- "Marcel Molina Jr." <marcel@vernix.org> wrote:

[#144453] RubyScript2Exe and GUI toolkits — Erik Veenstra <pan@...>

13 messages 2005/06/03

[#144487] Building a business case for Ruby — Joe Van Dyk <joevandyk@...>

Hi,

29 messages 2005/06/03

[#144535] ruby-dev summary 26128-26222 — Minero Aoki <aamine@...>

Hi all,

11 messages 2005/06/04

[#144579] Package, a future replacement for setup.rb and mkmf.rb — Christian Neukirchen <chneukirchen@...>

29 messages 2005/06/04

[#144672] newbie read.scan (?) question — "Bruce D'Arcus" <bdarcus.lists@...>

Hi,

16 messages 2005/06/06

[#144691] making a duck — Eric Mahurin <eric_mahurin@...>

Regarding duck-typing... Is there an easy way make a "duck"?

27 messages 2005/06/06

[#144867] ruby-wish@ruby-lang.org mailing list — dave <dave.m@...>

19 messages 2005/06/08
[#144870] Re: [PROPOSAL] ruby-wish@ruby-lang.org mailing list — "Robert Klemme" <bob.news@...> 2005/06/08

Austin Ziegler wrote:

[#144890] RubyStuff: The Ruby Shop for Ruby Programmers — James Britt <james_b@...>

Announcing the formal grand opening of Ruby Stuff: The Ruby Shop for

36 messages 2005/06/08

[#144966] python/ruby benchmark. — "\"</script>" <groleo@...>

I took a look at

78 messages 2005/06/09
[#144967] Re: python/ruby benchmark. — gabriele renzi <surrender_it@...> 2005/06/09

"</script> ha scritto:

[#144974] Re: python/ruby benchmark. — Lothar Scholz <mailinglists@...> 2005/06/09

Hello gabriele,

[#144977] Re: python/ruby benchmark. — Kent Sibilev <ksruby@...> 2005/06/09

Java is an order of magnitude faster than Ruby. The development of a

[#144980] Re: python/ruby benchmark. — Lothar Scholz <mailinglists@...> 2005/06/09

Hello Kent,

[#144983] Re: python/ruby benchmark. — "Ryan Leavengood" <mrcode@...> 2005/06/09

Lothar Scholz said:

[#145196] Re: python/ruby benchmark(don't shoot the messenger) — ptkwt@... (Phil Tomson) 2005/06/12

In article <9e7db91105061106485b68d629@mail.gmail.com>,

[#145207] Re: python/ruby benchmark(don't shoot the messenger) — Steven Jenkins <steven.jenkins@...> 2005/06/12

Phil Tomson wrote:

[#145212] Re: python/ruby benchmark(don't shoot the messenger) — Austin Ziegler <halostatue@...> 2005/06/12

On 6/12/05, Steven Jenkins <steven.jenkins@ieee.org> wrote:

[#145219] Re: python/ruby benchmark(don't shoot the messenger) — Steven Jenkins <steven.jenkins@...> 2005/06/12

Austin Ziegler wrote:

[#145223] Re: python/ruby benchmark(don't shoot the messenger) — Austin Ziegler <halostatue@...> 2005/06/12

On 6/12/05, Steven Jenkins <steven.jenkins@ieee.org> wrote:

[#145240] Re: python/ruby benchmark(don't shoot the messenger) — Steven Jenkins <steven.jenkins@...> 2005/06/12

Austin Ziegler wrote:

[#145241] Re: python/ruby benchmark(don't shoot the messenger) — Austin Ziegler <halostatue@...> 2005/06/13

On 6/12/05, Steven Jenkins <steven.jenkins@ieee.org> wrote:

[#145000] RDoc

Hi, I have a question. When I compiled ruby-1.8.2

13 messages 2005/06/09
[#145003] Re: RDoc — Eric Hodel <drbrain@...7.net> 2005/06/09

On 09 Jun 2005, at 13:55, Jesffffas Antonio Sfffe1nchez A. wrote:

[#145238] finding Hash subsets based on key value — "ee" <erik.eide@...>

Hi

17 messages 2005/06/12

[#145304] PDF::Writer 1.0 (version 1.0.1) — Austin Ziegler <halostatue@...>

= PDF::Writer

21 messages 2005/06/13
[#145411] Re: [ANN] PDF::Writer 1.0 (version 1.0.1) — Jason Foreman <threeve.org@...> 2005/06/14

No love from PDF::Writer on Mac OS X 10.4.1. I hope to get this fixed

[#145420] Re: [ANN] PDF::Writer 1.0 (version 1.0.1) — Austin Ziegler <halostatue@...> 2005/06/14

On 6/14/05, Jason Foreman <threeve.org@gmail.com> wrote:

[#145432] Re: [ANN] PDF::Writer 1.0 (version 1.0.1) — Jamis Buck <jamis@37signals.com> 2005/06/15

On Jun 14, 2005, at 5:11 PM, Austin Ziegler wrote:

[#145339] survey: what editor do you use to hack ruby? — Lowell Kirsh <lkirsh@...>

I've been having a tough time getting emacs set up properly with ruby

62 messages 2005/06/14

[#145390] Ruby and recursion (Ackermann benchmark) — ptkwt@... (Phil Tomson)

14 messages 2005/06/14

[#145586] How to make a browser in Ruby Tk — sujeet kumar <sujeetkr@...>

Hi

13 messages 2005/06/16

[#145636] Super-scalar Optimizations — "Phrogz" <gavin@...>

I was looking over the shoulder of a C++ coworker yesterday, when he

14 messages 2005/06/16

[#145677] Truth maintenance system in Ruby — "itsme213" <itsme213@...>

Anyone know of any kind of truth-maintenance system implemented in Ruby (or,

12 messages 2005/06/17

[#145720] Frameless RDoc template ('technology preview') — ES <ruby-ml@...>

Hi!

17 messages 2005/06/17

[#145779] Newbe questions... — "Chuck Brotman" <brotman@...>

In Ruby Is there a prefered (or otherwise elegant) way to do an inner &

17 messages 2005/06/18

[#145790] GC.disable not working? — Eric Mahurin <eric_mahurin@...>

From what I can tell, GC.disable doesn't work. I'm wanting to

37 messages 2005/06/18
[#145822] Re: GC.disable not working? — ts <decoux@...> 2005/06/19

>>>>> "E" == Eric Mahurin <eric_mahurin@yahoo.com> writes:

[#146024] evaluation of ruby — "Franz Hartmann" <porschefranz@...> 2005/06/21

Hello all,

[#145830] preventing instantiation — "R. Mark Volkmann" <mark@...>

What is the recommended way in Ruby to prevent other classes from creating

13 messages 2005/06/19
[#145831] Re: preventing instantiation — Gavri Fernandez <gavri.fernandez@...> 2005/06/19

On 6/19/05, R. Mark Volkmann <mark@ociweb.com> wrote:

[#145879] x==1 vs 1==x — Gavin Kistner <gavin@...>

I'm against _premature_ optimization in theory, but believe that a

19 messages 2005/06/20
[#145880] Re: x==1 vs 1==x — ts <decoux@...> 2005/06/20

>>>>> "G" == Gavin Kistner <gavin@refinery.com> writes:

[#145943] Chess Variants (II) (#36) — James Edward Gray II <james@...>

I don't want to spoil all the fun, in case anyone is still attempting

12 messages 2005/06/20

[#146038] 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — Michael Tan <mtan1232000@...>

Just new to Ruby since last week, running my same functional program on the windows XP(Pentium M1.5G), the Ruby version is 10 times slower than the Java version. The program is to find the prime numbers like 2, 3,5, 7, 11, 13... Are there setup issues? or it is normal?

47 messages 2005/06/21
[#146044] Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — "Florian Frank" <flori@...> 2005/06/21

Michael Tan wrote:

[#146047] Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — Jim Freeze <jim@...> 2005/06/21

* Florian Frank <flori@nixe.ping.de> [2005-06-22 05:40:14 +0900]:

[#146050] Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — "Ryan Leavengood" <mrcode@...> 2005/06/21

Jim Freeze said:

[#146132] Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — "Mark Thomas" <mrt@...> 2005/06/22

Florian Frank wrote:

[#146064] rubyscript2exe — Joe Van Dyk <joevandyk@...>

Hi,

14 messages 2005/06/21

[#146169] spidering a website to build a sitemap — Bill Guindon <agorilla@...>

I need to spider a site and build a sitemap for it. I've looked

17 messages 2005/06/22

[#146178] traits-0.4.0 - the coffee release — "Ara.T.Howard" <Ara.T.Howard@...>

15 messages 2005/06/22

[#146328] string to Class object — "R. Mark Volkmann" <mark@...>

How can I create a Class object from a String that contains the name of a class?

15 messages 2005/06/24

[#146380] Application-0.6.0 — Jim Freeze <jim@...>

CommandLine - Application and OptionParser

22 messages 2005/06/24

[#146391] ASP.NET vs Ruby on Rails — Stephen Kellett <snail@...>

HI Folks,

21 messages 2005/06/24
[#146457] Re: ASP.NET vs Ruby on Rails — "Dema" <demetriusnunes@...> 2005/06/25

Hi Stephen,

[#146425] speeding up Process.detach frequency — Joe Van Dyk <joevandyk@...>

Is there any way to speed up Process.detach? The ri documentation for

14 messages 2005/06/25

[#146483] I saw the beauty of Ruby Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — Michael Tan <mtan1232000@...>

22 messages 2005/06/26
[#146485] Re: I saw the beauty of Ruby Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — "Florian Frank" <flori@...> 2005/06/26

Michael Tan wrote:

[#146504] Re: I saw the beauty of Ruby Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — Brad Wilson <dotnetguy@...> 2005/06/26

For comparison, the port of your code to (less than elegant) C#.

[#146515] Re: I saw the beauty of Ruby Re: 1. Ruby result: 101 seconds , 2. Java result:9.8 seconds, 3. Perl result:62 seconds — Florian Gro<florgro@...> 2005/06/26

Brad Wilson wrote:

[#146491] What do you want to see in a Sparklines Library? — Daniel Nugent <nugend@...>

This is sort of an interest gauging/feature request poll.

17 messages 2005/06/26
[#146506] Re: What do you want to see in a Sparklines Library? — Daniel Amelang <daniel.amelang@...> 2005/06/26

See what's already been done before you get too far.

[#146517] Re: What do you want to see in a Sparklines Library? — Daniel Nugent <nugend@...> 2005/06/26

Yup, seen the stuff on RedHanded, I was planning on writing a little

[#146562] RCM - A Ruby Configuration Management System — Michael Neumann <mneumann@...>

Hi all,

22 messages 2005/06/27

[#146630] yield does not take a block — Daniel Brockman <daniel@...>

Under ruby 1.9.0 (2005-06-23) [i386-linux], irb 0.9.5(05/04/13),

48 messages 2005/06/28
[#146666] Re: yield does not take a block — Daniel Brockman <daniel@...> 2005/06/28

Yukihiro Matsumoto <matz@ruby-lang.org> writes:

[#146680] Re: yield does not take a block — Yukihiro Matsumoto <matz@...> 2005/06/28

Hi,

[#146684] Re: yield does not take a block — Eric Mahurin <eric_mahurin@...> 2005/06/28

[#146779] Re: yield does not take a block — "Adam P. Jenkins" <thorin@...> 2005/06/29

Eric Mahurin wrote:

[#146700] Anything in new Eclipse for Rubyists? — "jfry" <jeff.fry@...>

Hey there, I know that a number of folks on the list use Eclipse as

14 messages 2005/06/28

[#146773] Programmers Contest: Fit pictures on a page — hicinbothem@...

GLOSSY: The Summer Programmer Of The Month Contest is underway!

18 messages 2005/06/29

[#146815] shift vs. slice!(0) and others — Eric Mahurin <eric_mahurin@...>

I just did some benchmarking of various ways to insert/delete

12 messages 2005/06/29

MiniQuiz : Renesting Nodes (OWLScratch)

From: Gavin Kistner <gavin@...>
Date: 2005-06-23 02:53:08 UTC
List: ruby-talk #146217
return unless bored? #MiniQuiz = do my 'work' for me.

I'm writing a library (OWLScratch) for converting wiki markup into  
HTML. (The OWL part of the name is because it's derived from the  
markup used by OpenWiki, hence "OpenWiki Language"; the Scratch is  
because it's my own half-implemented flavor.)

It's not nearly ready yet, but the core concepts are working. So far,  
it tokenizes the document into a series of hierarchically-nested  
nodes. If I wanted XML, I could make up my own schema and be done.  
But I want HTML.

In OWLScratch, the following represents a nested list:

   * List item 1
   * List item 2
     * List item 2.1
     * List item 2.2
   * List item 3
     * List item 3.1
       * List item 3.1.1

Right now, that tokenizes into one node per line:
<bullet level="1">List item 1</bullet>
<bullet level="1">List item 2</bullet>
<bullet level="2">List item 2.1</bullet>
<bullet level="2">List item 2.2</bullet>
<bullet level="1">List item 3</bullet>
<bullet level="2">List item 3.1</bullet>
<bullet level="3">List item 3.1.1</bullet>

The challenge is that I need to be able to spin through the list and  
(should be possible in one pass) properly nest those as the HTML  
requires:

<ul>  <-- new node!
   <li>List item 1</li>
   <li>List item 2
     <ul> <-- new node, child of list item 2!
       <li>List item 2.1</li>
       <li>List item 2.2</li>
     </ul> <-- closed because the next item is a lower level
   <li>List item 3
     <ul> <-- holy crap, it happened again!
       <li>List item 3.1
         <ul> <-- when will the madness end?
           <li>List item 3.2</li>
         </ul>
       </li>
     </ul>
   </li>
</ul>

I know this should be not-hard, but I just played a full game of  
Ultimate Frisbee, and I thought this might appeal to someone else.  
The full library (so far, v0.0.1 or so) is attached, but I can (and  
probably will have to) extend the Tag class to support DOM-like  
properties such as previous_sibling and next_sibling. And make  
reparenting a node properly remove it from the previous parent's  
@child_nodes collection.

I'll speak more about OWLScratch in a few days, when I hope to have  
it ready for a really preliminary release.

Oh, for extra credit - think about nested list types, as seen here:  
http://openwiki.com/ow.asp?HelpOnFormatting#h9
(My lists do not (currently) allow content of a single item to be  
manually wrapped onto multiple lines.)


Attachments (1)

OWLScratch.rb (18.5 KB, text/x-ruby-script)
require 'strscan'

#todo - override html conversion per factory
#todo - pass after scanning to properly reparent lists.
#todo - but I also like the name OWLScribble...no bird-tie in, but more fun
class OWLScratch

	class TagFactory
		def self.by_type
				@by_type ||= {}
		end

		attr_reader :tag_name, :open_match, :close_match, :open_requires_bol, :close_requires_bol, :autoclose, :type, :allowed_type
		def initialize( tag_name, options={} )
			@tag_name = tag_name
			[ :open_match, :close_match,
			  :open_requires_bol, :close_requires_bol,
			  :allowed_type, :autoclose,
			  :text, :attrs, :setup, :type ].each{ |k|
				self.instance_variable_set( :"@#{k}", options[ k ] )
			}
			( self.class.by_type[ @type ] ||= [] ) << self if @type
		end
		
		def match( ss )
			return nil unless ( !@open_requires_bol || ss.bol? ) && ss.scan( @open_match )
			tag = Tag.new( @tag_name, self )
			@setup.call( tag, ss ) if @setup
			tag
		end
	end

	class Tag
		attr_accessor :tag_name, :child_nodes, :attrs, :parent_node

		def initialize( tag_name, owning_factory )
			@tag_name = tag_name
			@owning_factory = owning_factory
			@child_nodes = [ ]
			@attrs = { }
		end
		
		def type
			@owning_factory.type
		end

		def close_match
			@owning_factory.close_match
		end		
		
		def close_requires_bol?
			@owning_factory.close_requires_bol
		end

		def autoclose?
			@owning_factory.autoclose
		end
	
		def allowed_type
			@owning_factory.allowed_type
		end

		def append_child( node )
			puts "#{self.inspect}.append_child( #{node.inspect} )" if $DEBUG
			@child_nodes << node
			node.parent_node = self
			node
		end

		def << ( str )
			last_child = @child_nodes.last
			if TextNode === last_child
				last_child << str
			else
				append_child( TextNode.new( str ) )
			end
		end

		def to_html
			out = "<#{@tag_name}"
			@attrs.each{ |k,v| out << " #{k}=\"#{v.to_s.gsub( '""', '&quot;' )}\"" }
			if @child_nodes.empty?
				out << ' />'
			else
				out << '>'
				@child_nodes.each{ |node|
					out << node.to_html
				}
				out << "</#{@tag_name}>"
			end
			out << "\n" unless @owning_factory.type == :inline || @owning_factory.type == :td
			out
		end
		
		def inspect
			"<#{@tag_name}:#{@type}:#{@allowed_type}>"
		end
	end

	class TextNode
		attr_accessor :parent_node
		
		def initialize( node_value='' )
			@node_value = node_value
		end
		
		def << ( str )
			@node_value << str
		end
		
		def inspect
			"<TextNode '#{@node_value}'>"
		end
		
		def to_html
			@node_value.htmlsafe!
		end
		
	end

	TagFactory.new( :wiki_command,
		:type => :block,
		:open_match => /##(TableOfContents|DEPRECATED|BALETED|IncludePage\(\s*(.+)\s*\))##/, :open_requires_bol => true,
		:setup => lambda{ |tag, ss|
			tag.attrs[ :do ] = ss[1][ /[a-z]+/i ]
			tag.attrs[ :param ] = ss[2] if ss[2]
		},
		:autoclose => true
	)
	TagFactory.new( :heading,
		:type => :block,
		:open_match => /(={1,6}) +(.+) +\1[ \t]*\n/, :open_requires_bol => true,
		:setup => lambda{ |tag, ss|
			tag.attrs[ :level ] = ss[1].length
			tag << ss[2]
		},
		:autoclose => true
	)
	TagFactory.new( :hr,
		:type => :block,
		:open_match => /-{4,} *\n/, :open_requires_bol => true,
		:autoclose => true
	)
	TagFactory.new( :bullet,
		:type => :block,
		:open_match => /((  )+) ?\* /, :open_requires_bol => true,
		:close_match => /\n/,
		:setup => lambda{ |tag, ss| tag.attrs[ :level ] = ss[ 1 ].length / 2 },
		:allowed_type => :inline
	)
	TagFactory.new( :numberlist,
		:type => :block,
		:open_match => /((  )+) ?\d+\. /, :open_requires_bol => true,
		:close_match => /\n/,
		:setup => lambda{ |tag,ss| tag.attrs[ :level ] =  ss[1].length / 2 },
		:allowed_type => :inline
	)
	TagFactory.new( :alphalist,
		:type => :block,
		:open_match => /((  )+) ?[a-z]\. /, :open_requires_bol => true,
		:close_match => /\n/,
		:setup => lambda{ |tag,ss| tag.attrs[ :level ] =  ss[1].length / 2 },
		:allowed_type => :inline
	)
	TagFactory.new( :dl,
		:type => :block,
		:open_match => /(?=(  |\t)+; .+ : )/, :open_requires_bol => true,
		:close_match => /(?!(  |\t)+; .+ : )/, :close_requires_bol => true,
		:allowed_type => :deflist
	)
	TagFactory.new( :pre,
		:type => :block,
		:open_match => /^([ \t]*)\{\{\{\n(.+?)\n\1\}\}\}\n/m, :open_requires_bol => true,
		:close_match => /\n/,
		:setup => lambda{ |tag,ss| tag << ss[2].gsub( /^#{ss[1]}/, '' ) },
		:autoclose => true
	)
	TagFactory.new( :table,
		:type => :block,
		:open_match => /(?=\|\|)/, :open_requires_bol => true,
		:close_match => /(?=[^|])/, :close_requires_bol => true,
		:allowed_type => :table
	)
	TagFactory.new( :p,
		:type => :block,
		:open_match => /((  )+) ?: /, :open_requires_bol => true,
		:close_match => /\n/,
		:setup => lambda{ |tag,ss| tag.attrs[ :indent ] =  ss[1].length / 2 },
		:allowed_type => :inline
	)
	# The paragraph is the catch-all for blocks;
	# it must appear after all other block factories
	TagFactory.new( :p,
		:type => :block,
		:open_match => /(?=\S)/, :open_requires_bol => true,
		:close_match => /\n\n/,
		:allowed_type => :inline
	)


	TagFactory.new( :tr,
		:type => :table,
		:open_match => /(?=\|\|)/, :open_requires_bol => true,
		:close_match => /\|\|[ \t]*\n/,
		:allowed_type => :td
	)
	TagFactory.new( :td,
		:type => :td,
		:open_match => /((?:\|\|)+)\s*/,
		:close_match => /(?=\s*\|\|)/,
		:setup => lambda{ |tag,ss|
			colspan = ss[1].length / 2
			tag.attrs[ :colspan ] =  colspan unless colspan < 2
		},
		:allowed_type => :inline
	)


	TagFactory.new( :dt,
		:type => :deflist,
		:open_match => /(  |\t)+; /, :open_requires_bol => true,
		:close_match => / : /,
		:allowed_type => :inline
	)
	TagFactory.new( :dd,
		:type => :deflist,
		:open_match => /(?=.)/,
		:close_match => /\n/,
		:allowed_type => :inline
	)


	TagFactory.new( :b,
		:type => :inline,
		:open_match => /\*\*/, :close_match => /\*\*/,
		:allowed_type => :inline
	)
	TagFactory.new( :i,
		:type => :inline,
		:open_match => /\/\//, :close_match => /\/\//,
		:allowed_type => :inline
	)
	TagFactory.new( :strike,
		:type => :inline,
		:open_match => /--/, :close_match => /--/,
		:allowed_type => :inline
	)
	TagFactory.new( :sup,
		:type => :inline,
		:open_match => /\^\^/, :close_match => /\^\^/,
		:allowed_type => :inline
	)
	TagFactory.new( :sub,
		:type => :inline,
		:open_match => /__/, :close_match => /__/,
		:allowed_type => :inline
	)
	TagFactory.new( :tt,
		:type => :inline,
		:open_match => /@@([^\n]+?)@@/,
		:setup => lambda{ |tag,ss| tag << ss[1] },
		:autoclose => true
	)
	TagFactory.new( :tt,
		:type => :inline,
		:open_match => /\{\{\{([^\n]+?)\}\}\}/,
		:setup => lambda{ |tag,ss| tag << ss[1] },
		:autoclose => true
	)
	TagFactory.new( :todo,
		:type => :inline,
		:open_match => /!!([a-z].+?)!!/i,
		:setup => lambda{ |tag,ss| tag << ss[1] },
		:autoclose => true
	)
	TagFactory.new( :a,
		:type => :inline,
		:open_match => /(?:HTTP|FTP|HTTPS):\/\/\S+/,
		:setup => lambda{ |tag,ss|
			tag.attrs[ :href ] = ss[0]
			tag << ss[0]
		},
		:autoclose => true
	)
	TagFactory.new( :a,
		:type => :inline,
		:open_match => /\[((?:HTTP|FTP|HTTPS):\/\/\S+) ([^\]]+)\]/,
		:setup => lambda{ |tag,ss|
			tag.attrs[ :href ] = ss[1]
			tag << ss[2]
		},
		:autoclose => true
	)
	TagFactory.new( :wiki_link,
		:type => :inline,
		:open_match => /[A-Z]{2,}[a-z][a-zA-Z]*|[A-Z][a-z]+[A-Z][a-zA-Z]*/,
		:setup => lambda{ |tag,ss|
			tag.attrs[ :page ] = ss[0]
			tag << ss[0].dewikiword
		},
		:autoclose => true
	)
	TagFactory.new( :wiki_link,
		:type => :inline,
		:open_match => /\[\[([^\]\n]{2,}?)\]\]/,
		:setup => lambda{ |tag,ss|
			tag.attrs[ :page ] = ss[0]
			tag << ss[0]
		},
		:autoclose => true
	)
	TagFactory.new( :wiki_link,
		:type => :inline,
		:open_match => /\[([A-Z]{2,}[a-z][a-zA-Z]*|[A-Z][a-z]+[A-Z][a-zA-Z]*) ([^\]]+)\]/,
		:setup => lambda{ |tag,ss|
			tag.attrs[ :page ] = ss[1]
			tag << ss[2]
		},
		:autoclose => true
	)

	def initialize( owl_string )
		@ss = StringScanner.new( owl_string )

		@root = Tag.new( :root, TagFactory.new( :root, :type => :root, :allowed_type => :block	) )
		@current = @root

		#todo - preparse de-html of invalid tags
		while !@ss.eos?
			puts "Step with @current = #{@current.inspect} : #{(@ss.peek(20)+'...').inspect}" if $DEBUG

			# Keep popping off the current tag until we get to the root,
			# as long as the end criteria is met
			while ( @current != @root ) && (!@current.close_requires_bol? || @ss.bol?) && @ss.scan( @current.close_match )	
				@current = @current.parent_node || @root
			end
			
			# No point in continuing if closing out tags consumed the rest of the string
			break if @ss.eos?

			# Look for a tag to open
			tag = nil
			TagFactory.by_type[ @current.allowed_type ].each{ |factory|
				if tag = factory.match( @ss )
					@current.append_child( tag )
					@current = tag unless tag.autoclose?
					break
				end
			}
			next if tag #found one, start over

			# Couldn't find a valid tag at this spot
			# so we need to eat some characters
			if @ss.scan( /~([A-Z]{2,}[a-z][a-zA-Z]*|[A-Z][a-z]+[A-Z][a-zA-Z]*|\[\[([^\]\n]{2,}?)\]\]|\[(?:[A-Z]{2,}[a-z][a-zA-Z]*|[A-Z][a-z]+[A-Z][a-zA-Z]*) [^\]]+\])/ )

				# Shove negated links directly as text

				consumed = @ss[1]
			else
				# Man, it would be nice if I could do a lookahead here
				# and consume more than a few characters at a time!
				
				#Hopefully no opening or closing tags are based on letters or changes in tab/spaces;
				#if that's not true, the next line must be foregone in favor of the (slow)
				#one-char-at-a-time consumption
				consumed = @ss.scan( /[a-z \t]+|./m )

				#consumed = @ss.scan( /[a-z]+|[ \t]+|./m )
				#consumed = @ss.getch
			end
			@current << consumed if @current.allowed_type == :inline
		end

	end
	
	def to_s
		out = ''
		@root.child_nodes.each{ |el|
			out << el.to_html
		}
		out
	end

end

class String
	def htmlsafe
		self.dup.htmlsafe!
	end
	
	def htmlsafe!
		self.gsub!( /&/, '&amp;' )
		self.gsub!( /</, '&lt;' )
		self.gsub!( />/, '&gt;' )
		self
	end

	def dewikiword
		self.gsub( /([a-z])([A-Z])/, '\\1 \\2' )
	end
end

if __FILE__ == $0
	str = <<ENDTEXT

##TableOfContents##

= Welcome to the OWLScribble =
//An introduction to the markup.//

== What is OWLScribble? ==
~OWLScribble is a wiki markup language //based on// the markup used by [HTTP://www.openwiki.org/ OpenWiki]. It was designed for use with the ~SewWiki project by GavinKistner.

== Supported Markup ==
=== Basic Inline Styling ===
{{{
This text **is bold**, this //is italic//, and --this has been struck--.


This is a @@code reference@@, as is {{{this text}}}.

A double-exclamation point is a special 'todo' item. !!Add more examples!!

You can also ^^superscript^^ and __subscript__ text, like H__2__O or e^^pi*i^^.
}}}
This text **is bold**, this //is italic//, and --this has been striked--.

This is a @@code reference@@, as is {{{this text}}}.

A double-exclamation point is a special 'todo' item. !!Add more examples!!

You can also ^^superscript^^ and __subscript__ text, like H__2__O or e^^pi*i^^.

  * //Unlike ~OpenWiki, you are not allowed to underline text. Sorry, but underlining is reserved for links in hyperlinked documents.//

=== Headings ===
{{{
= Heading Level 1 =
== Heading Level 2 ==
=== Heading Level 3 ===
==== Heading Level 4 ====
===== Heading Level 5 =====
====== Heading Level 6 ======
}}}
Headings must begin at the start of the line. Markup inside headings is ignored. (So, for example, {{{== My //Sweet// Heading ==}}} will show the {{{//}}} characters in the output.)

=== Linking ===
!!Put content here!!

=== Lists === 

==== Bulleted Lists ====
{{{
         1         2         3         4
1234567890123456789012345678901234567890
  * Bulleted lists must have **two** spaces per indent level.
    * **A space** must appear after the asterisk.
      * They may be nested to an arbitrary depth.
}}}

  * Bulleted lists must have **two** spaces per indent level.
    * **A space** must appear after the asterisk.
      * They may be nested to an arbitrary depth.

==== Numbered Lists ====
{{{
         1         2         3         4
1234567890123456789012345678901234567890
  1. Numbered lists must have **two** spaces per indent level.
  1. The actual number doesn't matter
    3. But the period after the number does.
    1. As well as the space after the period.
  1. All lists types can be nested.
}}}

  1. Numbered lists must have **two** spaces per indent level.
  1. The actual number doesn't matter
    3. But the period after the number does.
    1. As well as the space after the period.
  1. All lists types can be nested.

==== Letter Lists ====
!!Put content here!!

==== Definition Lists ====
!!Put content here!!

  * !!Note no nesting!!

==== Mixing Lists ====
!!Put content here!!

=== Tables === 
|| **Age** || **Sex** || **Weight** ||
|| 32 || M || 180 ||
|| 30 || F || 150 ||
|||| average || 165 ||

== Processing Directives ==
!!Put content here!!

##IncludePage(ProcessingDirectives)##


== Miscellaneous ==
HTML entities are not needed (and do not work) inside OWLScribble; you can type {{{"this & that"}}} and it will produce the HTML {{{this &amp; that}}}, displaying as "this & that". Typing {{{&amp;}}} will actually show "&amp;".

Finally, we end with a few big paragraph blocks with no styling in them at all, for speed testing purposes:

  : Dry dog food is far better than canned! It is more economical, takes up less space, and is generally better tasting. With reconstituted dried milk (and sugar if you like) most dry food tastes not too different from dry breakfast cereal. A hundred pound sack of dry dog food contains as many calories as a ton of fresh potatoes. The dog food also contains protein, vitamins, etc., that the potatoes do not.

 	: Our understanding of the rubber bag has led us to an effective tool that accurately indicates whether too much, too little, or just the right amount of food is going in. In the last chapter you've learned how to work that tool, integrating it into your daily and monthly routine so the information it yields can guide your eating.

  : All the information in the world, however, doesn't change a thing until somebody takes action based upon it. In losing weight, "somebody" is your body. Now we'll turn to planning meals to control the calories that go in. Analysis of the trend based on daily weight measurements is the key engineering trick to weight control. Meal planning for predictable calorie intake is the central management tool which closes the circle and achieves control over weight.

  : The goal of meal planning is a predictable and reliable daily calorie intake. We can't really wear an eat watch to tell us when to stop eating, but we can accomplish the same objective with a little paperwork in advance. By planning meals then sticking to the plan, you're not only guaranteed to achieve your goal, you eliminate the uncertainty about meals and the need for on-the-fly judgements about what, when, and how much to eat that are a prime contributor to weight gain in people living stressful, chaotic lives.
 
  : Planning meals in advance may seem foreign; an act that stamps out some of the precious spontaneity that makes life enjoyable. I think you'll see the reality isn't that bad, but first consider why planning meals is worth discussing at all. Eating is important; it's one of very few things in life that isn't optional. If you don't eat, you die. If you eat too much for too long, you die. You wouldn't consider for a moment investing in a company that had no budgets, where everybody said, "We just spend whatever we feel like from day to day, and hope it will all work out in the long run." Not only would such a business be prone to bankruptcy, its managers would have no way of knowing where the money was going; there'd be no way to measure actual performance against goals to discover where problems lay. No, only a fool would risk his money on such a venture.

  : Yet by trying to "wing it" with regard to what you eat, to balance your long term calorie intake meal by meal, making every decision on the spur of the moment, you're placing something even more precious than your money, your own health, in the hands of a process you know inevitably leads to serious trouble.

  : You encounter, in business, the rare exceptions: managers who can run a small to medium sized business without a budget or a plan. They are "naturals," endowed either with a talent for assimilating vast quantities of detail and extracting the meaning within, or else with a sixth sense for emerging problems and an instinct for solving them. These rare individuals, born with a "sense for business," are the managerial equivalent of people with a built-in eat watch like Skinny Sam. They can get along without the help of the numbers and calculations the rest of us need to steer a steady course.

  : So it is with weight control. Just because some people manage without planning their meals doesn't mean it'll work for you or me. We must, like most managers in business, supplement our unreliable instincts with numbers that chart our goal and guide us there.

  : In business, a budget collapses a huge amount of de- tail, the individual transactions, into a small collection of numbers: how much money is allocated to various general purposes. In planning meals, all the multitude of foods and the infinite variety of meals are similarly reduced to a single number: calories per day. To plan meals, it's essential to know how many calories per day you're trying to eat. Where does that number come from?

  : As you gain more and more experience monitoring and controlling your weight, you'll collect enough information to know precisely how many calories your own body needs per day. Until then, you can start with guidelines for people about like you. Based on your height, frame size, and sex look up the calories burned per day in the tables on pages 36 and 37. Pick a number in the middle of the range given. For example, Dietin' Doris, five foot four in her bare feet with an average build, would start with a calorie target of 1770. (The range in the table runs from 1574 to 1967, and the average of these numbers is (1574 + 1967) 2 = 1770.)

  : This target assumes Doris' goal is maintaining her present weight. If she wants to lose or gain weight, it must be adjusted based on the daily calorie shortfall or excess she intends. To lose weight at the rate of one pound per week, Doris should eat 500 fewer calories per day than she burns. (Thus, over a week she'll end up 3500 calories shy and hence burn off 3500 calories of fat: one pound.)

  : Subtracting the calorie cutback, 500, from the number she burns gives the number she can eat per day. Her calorie target is thus 1770 500 = 1270 calories per day.
ENDTEXT
	
	#$DEBUG = true
	require 'benchmark'
	parser, out = nil
	Benchmark.bm( 10 ){ |x|
		x.report( "Node Tree" ){
			parser = OWLScratch.new( str )
		}
		x.report( "To HTML" ) {
			out = parser.to_s
		}
	}
	puts out
end

In This Thread

Prev Next