Pimki 1.3.092 → 1.4.092

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. data/README +145 -131
  2. data/README-PIMKI +15 -5
  3. data/app/controllers/wiki.rb +167 -54
  4. data/app/models/author.rb +3 -3
  5. data/app/models/chunks/chunk.rb +3 -3
  6. data/app/models/chunks/engines.rb +18 -21
  7. data/app/models/chunks/include.rb +29 -29
  8. data/app/models/chunks/literal.rb +20 -20
  9. data/app/models/chunks/match.rb +19 -19
  10. data/app/models/chunks/nowiki.rb +31 -31
  11. data/app/models/chunks/nowiki_test.rb +14 -14
  12. data/app/models/chunks/test.rb +18 -18
  13. data/app/models/chunks/todo.rb +44 -23
  14. data/app/models/chunks/uri.rb +97 -97
  15. data/app/models/chunks/uri_test.rb +92 -92
  16. data/app/models/chunks/wiki.rb +4 -4
  17. data/app/models/chunks/wiki_symbols.rb +22 -22
  18. data/app/models/chunks/wiki_test.rb +36 -36
  19. data/app/models/page.rb +39 -7
  20. data/app/models/page_lock.rb +23 -23
  21. data/app/models/page_set.rb +72 -72
  22. data/app/models/page_test.rb +75 -75
  23. data/app/models/revision.rb +1 -1
  24. data/app/models/revision_test.rb +251 -251
  25. data/app/models/web.rb +19 -6
  26. data/app/models/web_test.rb +52 -52
  27. data/app/models/wiki_content.rb +131 -119
  28. data/app/models/wiki_service.rb +31 -16
  29. data/app/models/wiki_service_test.rb +15 -15
  30. data/app/models/wiki_words.rb +1 -1
  31. data/app/models/wiki_words_test.rb +12 -12
  32. data/app/views/bottom.rhtml +3 -3
  33. data/app/views/markdown_help.rhtml +15 -15
  34. data/app/views/menu.rhtml +20 -20
  35. data/app/views/navigation.rhtml +26 -26
  36. data/app/views/rdoc_help.rhtml +15 -15
  37. data/app/views/static_style_sheet.rhtml +237 -237
  38. data/app/views/style.rhtml +178 -178
  39. data/app/views/textile_help.rhtml +27 -27
  40. data/app/views/top.rhtml +7 -2
  41. data/app/views/wiki/authors.rhtml +15 -15
  42. data/app/views/wiki/bliki.rhtml +101 -101
  43. data/app/views/wiki/bliki_edit.rhtml +3 -0
  44. data/app/views/wiki/bliki_new.rhtml +3 -0
  45. data/app/views/wiki/bliki_revision.rhtml +90 -90
  46. data/app/views/wiki/edit.rhtml +12 -3
  47. data/app/views/wiki/edit_menu.rhtml +64 -47
  48. data/app/views/wiki/edit_web.rhtml +65 -18
  49. data/app/views/wiki/export.rhtml +14 -14
  50. data/app/views/wiki/feeds.rhtml +10 -10
  51. data/app/views/wiki/list.rhtml +17 -15
  52. data/app/views/wiki/locked.rhtml +13 -13
  53. data/app/views/wiki/login.rhtml +10 -10
  54. data/app/views/wiki/mind.rhtml +0 -1
  55. data/app/views/wiki/new.rhtml +8 -3
  56. data/app/views/wiki/new_system.rhtml +77 -77
  57. data/app/views/wiki/new_web.rhtml +63 -63
  58. data/app/views/wiki/page.rhtml +88 -82
  59. data/app/views/wiki/print.rhtml +15 -15
  60. data/app/views/wiki/published.rhtml +2 -1
  61. data/app/views/wiki/recently_revised.rhtml +31 -31
  62. data/app/views/wiki/revision.rhtml +1 -7
  63. data/app/views/wiki/rollback.rhtml +31 -0
  64. data/app/views/wiki/rss_feed.rhtml +21 -21
  65. data/app/views/wiki/search.rhtml +48 -48
  66. data/app/views/wiki/tex.rhtml +22 -22
  67. data/app/views/wiki/tex_web.rhtml +34 -34
  68. data/app/views/wiki/todo.rhtml +90 -67
  69. data/app/views/wiki/web_list.rhtml +12 -12
  70. data/app/views/wiki_words_help.rhtml +1 -1
  71. data/favicon.png +0 -0
  72. data/libraries/action_controller_servlet.rb +17 -2
  73. data/libraries/bluecloth.rb +1127 -1127
  74. data/libraries/diff/diff.rb +474 -474
  75. data/libraries/diff/diff_test.rb +79 -79
  76. data/libraries/erb.rb +490 -490
  77. data/libraries/madeleine/automatic.rb +418 -357
  78. data/libraries/madeleine/clock.rb +94 -94
  79. data/libraries/madeleine/files.rb +19 -0
  80. data/libraries/madeleine/zmarshal.rb +60 -0
  81. data/libraries/madeleine_service.rb +14 -15
  82. data/libraries/rdocsupport.rb +155 -155
  83. data/libraries/redcloth_for_tex.rb +869 -869
  84. data/libraries/redcloth_for_tex_test.rb +40 -40
  85. data/libraries/view_helper.rb +32 -32
  86. data/libraries/web_controller_server.rb +96 -94
  87. data/pimki.rb +47 -6
  88. metadata +18 -4
@@ -1,94 +1,94 @@
1
- #
2
- # Copyright(c) Anders Bengtsson 2003
3
- #
4
-
5
- require 'madeleine'
6
-
7
- module Madeleine
8
- module Clock
9
-
10
- # Deprecated. Use SnapshotMadeleine instead.
11
- class ClockedSnapshotMadeleine < ::Madeleine::SnapshotMadeleine
12
- end
13
-
14
- # Let your system extend this module if you need to access the
15
- # machine time. Used together with a TimeActor that keeps
16
- # the clock current.
17
- module ClockedSystem
18
-
19
- # Returns this system's Clock.
20
- def clock
21
- unless defined? @clock
22
- @clock = Clock.new
23
- end
24
- @clock
25
- end
26
- end
27
-
28
- # Sends clock ticks to update a ClockedSystem, so that time can be
29
- # dealt with in a deterministic way.
30
- class TimeActor
31
-
32
- # Create and launch a new TimeActor
33
- #
34
- # * <tt>madeleine</tt> - The SnapshotMadeleine instance to work on.
35
- # * <tt>delay</tt> - Delay between ticks in seconds (Optional).
36
- def self.launch(madeleine, delay=0.1)
37
- result = new(madeleine, delay)
38
- result
39
- end
40
-
41
- # Stops the TimeActor.
42
- def destroy
43
- @is_destroyed = true
44
- @thread.wakeup
45
- @thread.join
46
- end
47
-
48
- private_class_method :new
49
-
50
- private
51
-
52
- def initialize(madeleine, delay) #:nodoc:
53
- @madeleine = madeleine
54
- @is_destroyed = false
55
- send_tick
56
- @thread = Thread.new {
57
- until @is_destroyed
58
- sleep(delay)
59
- send_tick
60
- end
61
- }
62
- end
63
-
64
- def send_tick
65
- @madeleine.execute_command(Tick.new(Time.now))
66
- end
67
- end
68
-
69
- # Keeps track of time in a ClockedSystem.
70
- class Clock
71
- # Returns the system's time as a Ruby <tt>Time</tt>.
72
- attr_reader :time
73
-
74
- def initialize
75
- @time = Time.at(0)
76
- end
77
-
78
- def forward_to(newTime)
79
- @time = newTime
80
- end
81
- end
82
-
83
- #
84
- # Internal classes below
85
- #
86
-
87
- # Deprecated. Merged into default implementation.
88
- class TimeOptimizingLogger < ::Madeleine::Logger
89
- end
90
-
91
- end
92
- end
93
-
94
- ClockedSnapshotMadeleine = Madeleine::Clock::ClockedSnapshotMadeleine
1
+ #
2
+ # Copyright(c) Anders Bengtsson 2003
3
+ #
4
+
5
+ require 'madeleine'
6
+
7
+ module Madeleine
8
+ module Clock
9
+
10
+ # Deprecated. Use SnapshotMadeleine instead.
11
+ class ClockedSnapshotMadeleine < ::Madeleine::SnapshotMadeleine # :nodoc:
12
+ end
13
+
14
+ # Let your system extend this module if you need to access the
15
+ # machine time. Used together with a TimeActor that keeps
16
+ # the clock current.
17
+ module ClockedSystem
18
+
19
+ # Returns this system's Clock.
20
+ def clock
21
+ unless defined? @clock
22
+ @clock = Clock.new
23
+ end
24
+ @clock
25
+ end
26
+ end
27
+
28
+ # Sends clock ticks to update a ClockedSystem, so that time can be
29
+ # dealt with in a deterministic way.
30
+ class TimeActor
31
+
32
+ # Create and launch a new TimeActor
33
+ #
34
+ # * <tt>madeleine</tt> - The SnapshotMadeleine instance to work on.
35
+ # * <tt>delay</tt> - Delay between ticks in seconds (Optional).
36
+ def self.launch(madeleine, delay=0.1)
37
+ result = new(madeleine, delay)
38
+ result
39
+ end
40
+
41
+ # Stops the TimeActor.
42
+ def destroy
43
+ @is_destroyed = true
44
+ @thread.wakeup
45
+ @thread.join
46
+ end
47
+
48
+ private_class_method :new
49
+
50
+ private
51
+
52
+ def initialize(madeleine, delay) #:nodoc:
53
+ @madeleine = madeleine
54
+ @is_destroyed = false
55
+ send_tick
56
+ @thread = Thread.new {
57
+ until @is_destroyed
58
+ sleep(delay)
59
+ send_tick
60
+ end
61
+ }
62
+ end
63
+
64
+ def send_tick
65
+ @madeleine.execute_command(Tick.new(Time.now))
66
+ end
67
+ end
68
+
69
+ # Keeps track of time in a ClockedSystem.
70
+ class Clock
71
+ # Returns the system's time as a Ruby <tt>Time</tt>.
72
+ attr_reader :time
73
+
74
+ def initialize
75
+ @time = Time.at(0)
76
+ end
77
+
78
+ def forward_to(newTime)
79
+ @time = newTime
80
+ end
81
+ end
82
+
83
+ #
84
+ # Internal classes below
85
+ #
86
+
87
+ # Deprecated. Merged into default implementation.
88
+ class TimeOptimizingLogger < ::Madeleine::Logger # :nodoc:
89
+ end
90
+
91
+ end
92
+ end
93
+
94
+ ClockedSnapshotMadeleine = Madeleine::Clock::ClockedSnapshotMadeleine
@@ -0,0 +1,19 @@
1
+ #
2
+ # Wrapper for Ruby's file services, replaced during testing
3
+ # so we can run tests without touching a real filesystem.
4
+ #
5
+
6
+ class FileService
7
+
8
+ def open(*args)
9
+ super(*args)
10
+ end
11
+
12
+ def exist?(name)
13
+ File.exist?(name)
14
+ end
15
+
16
+ def dir_entries(name)
17
+ Dir.entries(name)
18
+ end
19
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # Author:: Anders Bengtsson <ndrsbngtssn@yahoo.se>
3
+ # Copyright:: Copyright (c) 2004
4
+ #
5
+
6
+ require 'zlib'
7
+
8
+ module Madeleine
9
+ #
10
+ # Snapshot marshaller for compressed snapshots.
11
+ #
12
+ # Compresses the snapshots created by another marshaller. Uses either
13
+ # Marshal (the default) or another supplied marshaller.
14
+ #
15
+ # Uses <tt>zlib</tt> to do on-the-fly compression/decompression.
16
+ #
17
+ # ZMarshal works with Ruby's own Marshal and YAML, but not with SOAP
18
+ # marshalling.
19
+ #
20
+ # Usage:
21
+ #
22
+ # require 'madeleine'
23
+ # require 'madeleine/zmarshal'
24
+ #
25
+ # marshaller = Madeleine::ZMarshal.new(YAML)
26
+ # madeleine = SnapshotMadeleine.new("my_example_storage", marshaller) {
27
+ # SomeExampleApplication.new()
28
+ # }
29
+ #
30
+ class ZMarshal
31
+
32
+ def initialize(marshaller=Marshal)
33
+ @marshaller = marshaller
34
+ end
35
+
36
+ def load(stream)
37
+ zstream = Zlib::GzipReader.new(stream)
38
+ begin
39
+ # Buffer into a string first, since GzipReader can't handle
40
+ # Marshal's 0-sized reads and SOAP can't handle streams at all.
41
+ # In a bright future we can revert to reading directly from the
42
+ # stream again.
43
+ buffer = zstream.read
44
+ return @marshaller.load(buffer)
45
+ ensure
46
+ zstream.finish
47
+ end
48
+ end
49
+
50
+ def dump(system, stream)
51
+ zstream = Zlib::GzipWriter.new(stream)
52
+ begin
53
+ @marshaller.dump(system, zstream)
54
+ ensure
55
+ zstream.finish
56
+ end
57
+ nil
58
+ end
59
+ end
60
+ end
@@ -1,5 +1,6 @@
1
- require 'madeleine/automatic'
2
1
  require 'madeleine'
2
+ require 'madeleine/automatic'
3
+ require 'madeleine/zmarshal'
3
4
  require 'singleton'
4
5
  require 'yaml'
5
6
 
@@ -17,40 +18,38 @@ class MadeleineService
17
18
  @@storage_path = storage_path
18
19
  end
19
20
 
20
- def clean_storage
21
- MadeleineServer.clean_storage(self)
22
- end
23
-
24
21
  def instance
25
22
  @system = MadeleineServer.new(self).system if @system.nil?
26
23
  @system
27
24
  end
28
25
 
29
26
  def restart
30
- clean_storage
27
+ MadeleineServer.clean_storage(self)
31
28
  @system = MadeleineServer.new(self).system
32
29
  end
33
30
  end
34
31
  end
35
32
 
36
33
  class MadeleineServer
37
- SNAPSHOT_INTERVAL = 60 * 60 * 24 # seconds * minutes * hours => Each day
34
+ SNAPSHOT_INTERVAL = 30 * 60 * 24 # Each day
38
35
  AUTOMATIC_SNAPSHOTS = true
39
36
 
40
37
  # Clears all the command_log and snapshot files located in the storage directory, so the
41
- # database is essentially dropped and recreated as blank
38
+ # database is essentially dropped and recreated as blank. Used in tests.
42
39
  def self.clean_storage(service)
43
- begin
44
- Dir.foreach(service.storage_path) do |file|
45
- File.delete(service.storage_path + File::SEPARATOR + file) if file =~ /(command_log|snapshot)$/
46
- end
47
- rescue
48
- Dir.mkdir(service.storage_path)
40
+ require 'fileutils'
41
+ if (File.directory?(service.storage_path))
42
+ FileUtils.rm_rf(Dir[service.storage_path + '/*.command_log'])
43
+ FileUtils.rm_rf(Dir[service.storage_path + '/*.snapshot'])
44
+ else
45
+ FileUtils.mkdir_p(service.storage_path)
49
46
  end
50
47
  end
51
48
 
52
49
  def initialize(service)
53
- @server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path) { service.new }
50
+ marshaller = Madeleine::ZMarshal.new()
51
+ @server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
52
+ marshaller) { service.new }
54
53
  start_snapshot_thread if AUTOMATIC_SNAPSHOTS
55
54
  end
56
55
 
@@ -1,156 +1,156 @@
1
- begin
2
- require "rdoc/markup/simple_markup"
3
- require 'rdoc/markup/simple_markup/to_html'
4
- rescue LoadError
5
- # use old version if available
6
- require 'markup/simple_markup'
7
- require 'markup/simple_markup/to_html'
8
- end
9
-
10
- module RDocSupport
11
-
12
- # A simple +rdoc+ markup class which recognizes some additional
13
- # formatting commands suitable for Wiki use.
14
- class RDocMarkup < SM::SimpleMarkup
15
- def initialize
16
- super()
17
-
18
- pre = '(?:\\s|^|\\\\)'
19
-
20
- # links of the form
21
- # [[<url> description with spaces]]
22
- add_special(/((\\)?\[\[\S+?\s+.+?\]\])/,:TIDYLINK)
23
-
24
- # and external references
25
- add_special(/((\\)?(link:|anchor:|http:|mailto:|ftp:|img:|www\.)\S+\w\/?)/,
26
- :HYPERLINK)
27
-
28
- # <br/>
29
- add_special(%r{(#{pre}<br/>)}, :BR)
30
-
31
- # and <center> ... </center>
32
- add_html("center", :CENTER)
33
- end
34
-
35
- def convert(text, handler)
36
- #$stderr.puts text.inspect
37
- res = super
38
- res.sub!(/^<p>\n/, '')
39
- res.sub!(/<\/p>$/, '')
40
- res
41
- end
42
- end
43
-
44
- # Handle special hyperlinking requirments for RDoc formatted
45
- # entries. Requires RDoc
46
-
47
- class HyperLinkHtml < SM::ToHtml
48
-
49
- # Initialize the HyperLinkHtml object.
50
- # [path] location of the node
51
- # [site] object representing the whole site (typically of class
52
- # +Site+)
53
- def initialize
54
- super()
55
- add_tag(:CENTER, "<center>", "</center>")
56
- end
57
-
58
- # handle <br/>
59
- def handle_special_BR(special)
60
- return "&lt;br/&gt" if special.text[0,1] == '\\'
61
- special.text
62
- end
63
-
64
- # We're invoked with a potential external hyperlink.
65
- # [mailto:] just gets inserted.
66
- # [http:] links are checked to see if they
67
- # reference an image. If so, that image gets inserted
68
- # using an <img> tag. Otherwise a conventional <a href>
69
- # is used.
70
- # [img:] insert a <tt><img></tt> tag
71
- # [link:] used to insert arbitrary <tt><a></tt> references
72
- # [anchor:] used to create an anchor
73
- def handle_special_HYPERLINK(special)
74
- text = special.text.strip
75
- return text[1..-1] if text[0,1] == '\\'
76
- url = special.text.strip
77
- if url =~ /([A-Za-z]+):(.*)/
78
- type = $1
79
- path = $2
80
- else
81
- type = "http"
82
- path = url
83
- url = "http://#{url}"
84
- end
85
-
86
- case type
87
- when "http"
88
- if url =~ /\.(gif|png|jpg|jpeg|bmp)$/
89
- "<img src=\"#{url}\"/>"
90
- else
91
- "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
92
- end
93
- when "img"
94
- "<img src=\"#{path}\"/>"
95
- when "link"
96
- "<a href=\"#{path}\">#{path}</a>"
97
- when "anchor"
98
- "<a name=\"#{path}\"></a>"
99
- else
100
- "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
101
- end
102
- end
103
-
104
- # Here's a hyperlink where the label is different to the URL
105
- # [[url label that may contain spaces]]
106
- #
107
-
108
- def handle_special_TIDYLINK(special)
109
- text = special.text.strip
110
- return text[1..-1] if text[0,1] == '\\'
111
- unless text =~ /\[\[(\S+?)\s+(.+?)\]\]/
112
- return text
113
- end
114
- url = $1
115
- label = $2
116
- label = RDocFormatter.new(label).to_html
117
- label = label.split.select{|x| x =~ /\S/}.
118
- map{|x| x.chomp}.join(' ')
119
-
120
- case url
121
- when /link:(\S+)/
122
- return %{<a href="#{$1}">#{label}</a>}
123
- when /img:(\S+)/
124
- return %{<img src="http://#{$1}" alt="#{label}" />}
125
- when /rubytalk:(\S+)/
126
- return %{<a href="http://ruby-talk.org/blade/#{$1}">#{label}</a>}
127
- when /rubygarden:(\S+)/
128
- return %{<a href="http://www.rubygarden.org/ruby?#{$1}">#{label}</a>}
129
- when /c2:(\S+)/
130
- return %{<a href="http://c2.com/cgi/wiki?#{$1}">#{label}</a>}
131
- when /isbn:(\S+)/
132
- return %{<a href="http://search.barnesandnoble.com/bookSearch/} +
133
- %{isbnInquiry.asp?isbn=#{$1}">#{label}</a>}
134
- end
135
-
136
- unless url =~ /\w+?:/
137
- url = "http://#{url}"
138
- end
139
-
140
- "<a href=\"#{url}\">#{label}</a>"
141
- end
142
- end
143
-
144
- class RDocFormatter
145
- def initialize(text)
146
- @text = text
147
- end
148
-
149
- def to_html
150
- markup = RDocMarkup.new
151
- h = HyperLinkHtml.new
152
- markup.convert(@text, h)
153
- end
154
- end
155
-
1
+ begin
2
+ require "rdoc/markup/simple_markup"
3
+ require 'rdoc/markup/simple_markup/to_html'
4
+ rescue LoadError
5
+ # use old version if available
6
+ require 'markup/simple_markup'
7
+ require 'markup/simple_markup/to_html'
8
+ end
9
+
10
+ module RDocSupport
11
+
12
+ # A simple +rdoc+ markup class which recognizes some additional
13
+ # formatting commands suitable for Wiki use.
14
+ class RDocMarkup < SM::SimpleMarkup
15
+ def initialize
16
+ super()
17
+
18
+ pre = '(?:\\s|^|\\\\)'
19
+
20
+ # links of the form
21
+ # [[<url> description with spaces]]
22
+ add_special(/((\\)?\[\[\S+?\s+.+?\]\])/,:TIDYLINK)
23
+
24
+ # and external references
25
+ add_special(/((\\)?(link:|anchor:|http:|mailto:|ftp:|img:|www\.)\S+\w\/?)/,
26
+ :HYPERLINK)
27
+
28
+ # <br/>
29
+ add_special(%r{(#{pre}<br/>)}, :BR)
30
+
31
+ # and <center> ... </center>
32
+ add_html("center", :CENTER)
33
+ end
34
+
35
+ def convert(text, handler)
36
+ #$stderr.puts text.inspect
37
+ res = super
38
+ res.sub!(/^<p>\n/, '')
39
+ res.sub!(/<\/p>$/, '')
40
+ res
41
+ end
42
+ end
43
+
44
+ # Handle special hyperlinking requirments for RDoc formatted
45
+ # entries. Requires RDoc
46
+
47
+ class HyperLinkHtml < SM::ToHtml
48
+
49
+ # Initialize the HyperLinkHtml object.
50
+ # [path] location of the node
51
+ # [site] object representing the whole site (typically of class
52
+ # +Site+)
53
+ def initialize
54
+ super()
55
+ add_tag(:CENTER, "<center>", "</center>")
56
+ end
57
+
58
+ # handle <br/>
59
+ def handle_special_BR(special)
60
+ return "&lt;br/&gt" if special.text[0,1] == '\\'
61
+ special.text
62
+ end
63
+
64
+ # We're invoked with a potential external hyperlink.
65
+ # [mailto:] just gets inserted.
66
+ # [http:] links are checked to see if they
67
+ # reference an image. If so, that image gets inserted
68
+ # using an <img> tag. Otherwise a conventional <a href>
69
+ # is used.
70
+ # [img:] insert a <tt><img></tt> tag
71
+ # [link:] used to insert arbitrary <tt><a></tt> references
72
+ # [anchor:] used to create an anchor
73
+ def handle_special_HYPERLINK(special)
74
+ text = special.text.strip
75
+ return text[1..-1] if text[0,1] == '\\'
76
+ url = special.text.strip
77
+ if url =~ /([A-Za-z]+):(.*)/
78
+ type = $1
79
+ path = $2
80
+ else
81
+ type = "http"
82
+ path = url
83
+ url = "http://#{url}"
84
+ end
85
+
86
+ case type
87
+ when "http"
88
+ if url =~ /\.(gif|png|jpg|jpeg|bmp)$/
89
+ "<img src=\"#{url}\"/>"
90
+ else
91
+ "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
92
+ end
93
+ when "img"
94
+ "<img src=\"#{path}\"/>"
95
+ when "link"
96
+ "<a href=\"#{path}\">#{path}</a>"
97
+ when "anchor"
98
+ "<a name=\"#{path}\"></a>"
99
+ else
100
+ "<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
101
+ end
102
+ end
103
+
104
+ # Here's a hyperlink where the label is different to the URL
105
+ # [[url label that may contain spaces]]
106
+ #
107
+
108
+ def handle_special_TIDYLINK(special)
109
+ text = special.text.strip
110
+ return text[1..-1] if text[0,1] == '\\'
111
+ unless text =~ /\[\[(\S+?)\s+(.+?)\]\]/
112
+ return text
113
+ end
114
+ url = $1
115
+ label = $2
116
+ label = RDocFormatter.new(label).to_html
117
+ label = label.split.select{|x| x =~ /\S/}.
118
+ map{|x| x.chomp}.join(' ')
119
+
120
+ case url
121
+ when /link:(\S+)/
122
+ return %{<a href="#{$1}">#{label}</a>}
123
+ when /img:(\S+)/
124
+ return %{<img src="http://#{$1}" alt="#{label}" />}
125
+ when /rubytalk:(\S+)/
126
+ return %{<a href="http://ruby-talk.org/blade/#{$1}">#{label}</a>}
127
+ when /rubygarden:(\S+)/
128
+ return %{<a href="http://www.rubygarden.org/ruby?#{$1}">#{label}</a>}
129
+ when /c2:(\S+)/
130
+ return %{<a href="http://c2.com/cgi/wiki?#{$1}">#{label}</a>}
131
+ when /isbn:(\S+)/
132
+ return %{<a href="http://search.barnesandnoble.com/bookSearch/} +
133
+ %{isbnInquiry.asp?isbn=#{$1}">#{label}</a>}
134
+ end
135
+
136
+ unless url =~ /\w+?:/
137
+ url = "http://#{url}"
138
+ end
139
+
140
+ "<a href=\"#{url}\">#{label}</a>"
141
+ end
142
+ end
143
+
144
+ class RDocFormatter
145
+ def initialize(text)
146
+ @text = text
147
+ end
148
+
149
+ def to_html
150
+ markup = RDocMarkup.new
151
+ h = HyperLinkHtml.new
152
+ markup.convert(@text, h)
153
+ end
154
+ end
155
+
156
156
  end