Pimki 1.7.092 → 1.8.092

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README-PIMKI +182 -178
  2. data/app/controllers/wiki.rb +950 -942
  3. data/app/models/chunks/category.rb +33 -33
  4. data/app/models/chunks/category_test.rb +21 -21
  5. data/app/models/chunks/chunk.rb +20 -20
  6. data/app/models/chunks/engines.rb +48 -48
  7. data/app/models/chunks/include.rb +1 -1
  8. data/app/models/chunks/match.rb +1 -1
  9. data/app/models/chunks/nowiki.rb +1 -1
  10. data/app/models/chunks/nowiki_test.rb +5 -0
  11. data/app/models/chunks/todo.rb +1 -0
  12. data/app/models/chunks/wiki.rb +130 -130
  13. data/app/models/page.rb +124 -124
  14. data/app/models/revision.rb +92 -92
  15. data/app/models/web.rb +314 -316
  16. data/app/models/wiki_content.rb +2 -2
  17. data/app/models/wiki_service.rb +170 -166
  18. data/app/models/wiki_words.rb +28 -28
  19. data/app/views/error.rhtml +37 -37
  20. data/app/views/navigation.rhtml +1 -1
  21. data/app/views/static_style_sheet.rhtml +10 -5
  22. data/app/views/top.rhtml +1 -1
  23. data/app/views/wiki/adv_search.rhtml +61 -61
  24. data/app/views/wiki/bliki.rhtml +7 -6
  25. data/app/views/wiki/bliki_edit.rhtml +26 -37
  26. data/app/views/wiki/bliki_new.rhtml +58 -64
  27. data/app/views/wiki/bliki_revision.rhtml +5 -3
  28. data/app/views/wiki/edit.rhtml +44 -44
  29. data/app/views/wiki/edit_menu.rhtml +26 -19
  30. data/app/views/wiki/edit_web.rhtml +303 -305
  31. data/app/views/wiki/glossary.rhtml +35 -27
  32. data/app/views/wiki/list.rhtml +175 -174
  33. data/app/views/wiki/list.rhtml.bak +175 -0
  34. data/app/views/wiki/mind.rhtml +70 -70
  35. data/app/views/wiki/new.rhtml +34 -32
  36. data/app/views/wiki/published.rhtml +34 -49
  37. data/app/views/wiki/revision.rhtml +88 -87
  38. data/app/views/wiki/rollback.rhtml +36 -35
  39. data/app/views/wiki/todo.rhtml +2 -2
  40. data/app/views/wiki_words_help.rhtml +8 -8
  41. data/libraries/action_controller_servlet.rb +202 -202
  42. data/libraries/madeleine_service.rb +162 -162
  43. data/pimki.rb +181 -181
  44. metadata +11 -12
  45. data/README +0 -172
  46. data/app/models/chunks/acronym.rb +0 -19
  47. data/app/views/wiki/test.rhtml +0 -25
  48. data/libraries/secure_web_controller_server.rb +0 -106
@@ -1,163 +1,163 @@
1
- require 'madeleine'
2
- require 'madeleine/automatic'
3
- require 'madeleine/zmarshal'
4
- require 'singleton'
5
- require 'yaml'
6
-
7
- class MadeleineService
8
- include Madeleine::Automatic::Interceptor
9
-
10
- @@storage_path = self.name.downcase + "_storage"
11
- automatic_read_only :snapshot_interval_hours, :take_snapshot, :clean_old_snapshots,
12
- :restart, :request_stop
13
-
14
- class << self
15
- def storage_path
16
- @@storage_path
17
- end
18
-
19
- def storage_path=(storage_path)
20
- @@storage_path = storage_path
21
- end
22
-
23
- def instance
24
- if @system.nil?
25
- @madeleine_server = MadeleineServer.new(self)
26
- @system = @madeleine_server.system
27
- end
28
- @system
29
- end
30
-
31
- def restart
32
- MadeleineServer.delete_storage(self)
33
- @system = nil
34
- instance
35
- end
36
-
37
- def clean_old_snapshots
38
- instance
39
- @madeleine_server.clean_storage(self)
40
- end
41
-
42
- def take_snapshot
43
- instance
44
- @madeleine_server.force_snapshot
45
- end
46
-
47
- def snapshot_interval_hours
48
- instance
49
- @madeleine_server.snapshot_interval.div MadeleineServer::ONE_HOUR rescue 1
50
- end
51
-
52
- def snapshot_interval_hours= hours
53
- instance
54
- @madeleine_server.snapshot_interval = hours.to_i * MadeleineServer::ONE_HOUR rescue MadeleineServer::ONE_HOUR
55
- end
56
-
57
- def request_stop
58
- instance
59
- @madeleine_server.request_stop
60
- end
61
-
62
- end
63
- end
64
-
65
- require 'fileutils'
66
- class MadeleineServer
67
-
68
- attr_reader :storage_path
69
- attr_accessor :snapshot_interval
70
-
71
- # Clears all the command_log and snapshot files located in the storage directory, so the
72
- # database is essentially dropped and recreated as blank. Used in tests.
73
- def self.delete_storage(service)
74
- if (File.directory?(service.storage_path))
75
- FileUtils.rm_rf(Dir[service.storage_path + '/*.command_log'])
76
- FileUtils.rm_rf(Dir[service.storage_path + '/*.snapshot'])
77
- else
78
- FileUtils.mkdir_p(service.storage_path)
79
- end
80
- end
81
-
82
- def clean_storage(service)
83
- force_snapshot
84
- command_logs = Dir[service.storage_path + '/*.command_log']
85
- raise 'Error: existing command_logs after snapshot' unless command_logs.empty?
86
-
87
- snapshots = Dir[service.storage_path + '/*.snapshot']
88
- FileUtils.rm_rf(snapshots.sort[0..-2])
89
- end
90
-
91
-
92
- def initialize(service)
93
- @storage_path = service.storage_path
94
- @snapshot_interval = ONE_HOUR
95
- marshaller = Madeleine::ZMarshal.new()
96
- @server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
97
- marshaller) { service.new }
98
- start_snapshot_thread
99
- end
100
-
101
- def system
102
- @server.system
103
- end
104
-
105
- def command_log_present?
106
- not Dir[File.join(File.expand_path(storage_path), '*.command_log')].empty?
107
- end
108
-
109
- def force_snapshot
110
- begin
111
- hours_since_last_snapshot = 0
112
- @server.take_snapshot
113
- rescue => e
114
- sleep(ONE_MINUTE)
115
- retry
116
- end
117
- end
118
-
119
-
120
- ONE_MINUTE = 60
121
- ONE_HOUR = ONE_MINUTE * 60
122
- MAX_INTERVAL_HOURS = 24 * 2
123
-
124
- def start_snapshot_thread
125
- @snapshot_thread = Thread.new(@server) {
126
- hours_since_last_snapshot = 0
127
- while not @request_stop
128
- sleep(snapshot_interval)
129
- hours_since_last_snapshot += snapshot_interval.div ONE_HOUR
130
- begin
131
- # Take a snapshot if there is a command log
132
- if command_log_present? or hours_since_last_snapshot > MAX_INTERVAL_HOURS
133
- # 'Taking a Madeleine snapshot'
134
- @server.take_snapshot
135
- hours_since_last_snapshot = 0
136
- puts "[#{DateTime.now.strftime '%F %T'}] INFO Taking snapshot"
137
- else
138
- puts "[#{DateTime.now.strftime '%F %T'}] INFO Skipping snapshot (no command logs)"
139
- end
140
- rescue => e
141
- # wait for a minute (not to spoof the log with the same error)
142
- # and go back into the loop, to keep trying
143
- sleep(ONE_MINUTE)
144
- retry
145
- end
146
- end
147
- }
148
- end
149
-
150
- def request_stop
151
- begin
152
- @request_stop = true
153
- if @snapshot_thread and @snapshot_thread.alive?
154
- @snapshot_thread.wakeup
155
- @snapshot_thread.join
156
- end
157
- @server.take_snapshot if command_log_present?
158
- rescue => detail
159
- puts detail
160
- end
161
- end
162
-
1
+ require 'madeleine'
2
+ require 'madeleine/automatic'
3
+ require 'madeleine/zmarshal'
4
+ require 'singleton'
5
+ require 'yaml'
6
+
7
+ class MadeleineService
8
+ include Madeleine::Automatic::Interceptor
9
+
10
+ @@storage_path = self.name.downcase + "_storage"
11
+ automatic_read_only :snapshot_interval_hours, :take_snapshot, :clean_old_snapshots,
12
+ :restart, :request_stop
13
+
14
+ class << self
15
+ def storage_path
16
+ @@storage_path
17
+ end
18
+
19
+ def storage_path=(storage_path)
20
+ @@storage_path = storage_path
21
+ end
22
+
23
+ def instance
24
+ if @system.nil?
25
+ @madeleine_server = MadeleineServer.new(self)
26
+ @system = @madeleine_server.system
27
+ end
28
+ @system
29
+ end
30
+
31
+ def restart
32
+ MadeleineServer.delete_storage(self)
33
+ @system = nil
34
+ instance
35
+ end
36
+
37
+ def clean_old_snapshots
38
+ instance
39
+ @madeleine_server.clean_storage(self)
40
+ end
41
+
42
+ def take_snapshot
43
+ instance
44
+ @madeleine_server.force_snapshot
45
+ end
46
+
47
+ def snapshot_interval_hours
48
+ instance
49
+ @madeleine_server.snapshot_interval.div MadeleineServer::ONE_HOUR rescue 1
50
+ end
51
+
52
+ def snapshot_interval_hours= hours
53
+ instance
54
+ @madeleine_server.snapshot_interval = hours.to_i * MadeleineServer::ONE_HOUR rescue MadeleineServer::ONE_HOUR
55
+ end
56
+
57
+ def request_stop
58
+ instance
59
+ @madeleine_server.request_stop
60
+ end
61
+
62
+ end
63
+ end
64
+
65
+ require 'fileutils'
66
+ class MadeleineServer
67
+
68
+ attr_reader :storage_path
69
+ attr_accessor :snapshot_interval
70
+
71
+ # Clears all the command_log and snapshot files located in the storage directory, so the
72
+ # database is essentially dropped and recreated as blank. Used in tests.
73
+ def self.delete_storage(service)
74
+ if (File.directory?(service.storage_path))
75
+ FileUtils.rm_rf(Dir[service.storage_path + '/*.command_log'])
76
+ FileUtils.rm_rf(Dir[service.storage_path + '/*.snapshot'])
77
+ else
78
+ FileUtils.mkdir_p(service.storage_path)
79
+ end
80
+ end
81
+
82
+ def clean_storage(service)
83
+ force_snapshot
84
+ command_logs = Dir[service.storage_path + '/*.command_log']
85
+ raise 'Error: existing command_logs after snapshot' unless command_logs.empty?
86
+
87
+ snapshots = Dir[service.storage_path + '/*.snapshot']
88
+ FileUtils.rm_rf(snapshots.sort[0..-2])
89
+ end
90
+
91
+
92
+ def initialize(service)
93
+ @storage_path = service.storage_path
94
+ @snapshot_interval = ONE_HOUR
95
+ marshaller = Madeleine::ZMarshal.new()
96
+ @server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
97
+ marshaller) { service.new }
98
+ start_snapshot_thread
99
+ end
100
+
101
+ def system
102
+ @server.system
103
+ end
104
+
105
+ def command_log_present?
106
+ not Dir[File.join(File.expand_path(storage_path), '*.command_log')].empty?
107
+ end
108
+
109
+ def force_snapshot
110
+ begin
111
+ hours_since_last_snapshot = 0
112
+ @server.take_snapshot
113
+ rescue => e
114
+ sleep(ONE_MINUTE)
115
+ retry
116
+ end
117
+ end
118
+
119
+
120
+ ONE_MINUTE = 60
121
+ ONE_HOUR = ONE_MINUTE * 60
122
+ MAX_INTERVAL_HOURS = 24 * 2
123
+
124
+ def start_snapshot_thread
125
+ @snapshot_thread = Thread.new(@server) {
126
+ hours_since_last_snapshot = 0
127
+ while not @request_stop
128
+ sleep(snapshot_interval)
129
+ hours_since_last_snapshot += snapshot_interval.div ONE_HOUR
130
+ begin
131
+ # Take a snapshot if there is a command log
132
+ if command_log_present? or hours_since_last_snapshot > MAX_INTERVAL_HOURS
133
+ # 'Taking a Madeleine snapshot'
134
+ @server.take_snapshot
135
+ hours_since_last_snapshot = 0
136
+ puts "[#{DateTime.now.strftime '%F %T'}] INFO Taking snapshot"
137
+ else
138
+ puts "[#{DateTime.now.strftime '%F %T'}] INFO Skipping snapshot (no command logs)"
139
+ end
140
+ rescue => e
141
+ # wait for a minute (not to spoof the log with the same error)
142
+ # and go back into the loop, to keep trying
143
+ sleep(ONE_MINUTE)
144
+ retry
145
+ end
146
+ end
147
+ }
148
+ end
149
+
150
+ def request_stop
151
+ begin
152
+ @request_stop = true
153
+ if @snapshot_thread and @snapshot_thread.alive?
154
+ @snapshot_thread.wakeup
155
+ @snapshot_thread.join
156
+ end
157
+ @server.take_snapshot if command_log_present?
158
+ rescue => detail
159
+ puts detail
160
+ end
161
+ end
162
+
163
163
  end
data/pimki.rb CHANGED
@@ -1,182 +1,182 @@
1
- #!/usr/local/bin/ruby
2
-
3
- if RUBY_VERSION < "1.8.1"
4
- puts "Pimki requires Ruby 1.8.1+"
5
- exit
6
- end
7
-
8
- # Handle rubygems support & loading libraries: {{{
9
- $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "libraries")
10
- begin
11
- require 'rubygems'
12
- require_gem 'madeleine'
13
- require_gem 'BlueCloth'
14
- require_gem 'rubyzip'
15
- require 'zip/zip'
16
-
17
- rescue LoadError => detail
18
- # no rubygems, so load from the libraries directory
19
- p detail if $DEBUG
20
- puts 'Unable to load libraries through RubyGems. Loading from ./libraries directory'
21
- require 'bluecloth'
22
- require 'zip/zip'
23
- end
24
- # }}}
25
-
26
- # Handle command-line options: {{{
27
- require 'optparse'
28
-
29
- cdir = File.expand_path(File.dirname(__FILE__))
30
- %w( /libraries/ /app/models /app/controllers ).each { |dir| $:.unshift(cdir + dir) }
31
- %w( web_controller_server action_controller_servlet wiki_service wiki ).each { |lib| require lib }
32
-
33
- fork_available = true
34
- begin
35
- exit unless fork
36
- rescue NotImplementedError
37
- fork_available = false
38
- end
39
-
40
- begin
41
- pdflatex_available = system "pdflatex -version"
42
- rescue Errno::ENOENT
43
- pdflatex_available = false
44
- end
45
-
46
- graphviz_available = (`dot -V 2>&1` =~ /dot version/)
47
-
48
- OPTIONS = {
49
- :server_type => fork_available ? Daemon : SimpleServer,
50
- :port => 2500,
51
- :storage => "#{Dir.pwd}/storage",
52
- :pdflatex => pdflatex_available,
53
- :redcloth => '3',
54
- :graphviz_available => graphviz_available
55
- }
56
-
57
- ARGV.options do |opts|
58
- script_name = File.basename($0)
59
- opts.banner = "Usage: ruby #{script_name} [options]"
60
-
61
- opts.separator ""
62
-
63
- opts.on("-p", "--port=port", Integer,
64
- "Runs Instiki on the specified port.",
65
- "Default: 2500\n") { |OPTIONS[:port]| }
66
- opts.on("-s", "--simple", "--simple-server",
67
- "Forces Instiki not to run as a Daemon if fork is available.\n"
68
- ) { OPTIONS[:server_type] = SimpleServer }
69
- opts.on("-t", "--storage=storage", String,
70
- "Makes Instiki use the specified directory for storage.",
71
- "Default: [cwd]/storage/[port]\n") { |OPTIONS[:storage]| }
72
- opts.on("-r", "--redcloth VERSION", String,
73
- "Makes Instiki use the specified RedCloth version.",
74
- "You can specify major version only (2 or 3)",
75
- "Default: 2.0.11\n") { |OPTIONS[:redcloth]| }
76
-
77
-
78
- opts.separator ""
79
-
80
- opts.on("-h", "--help",
81
- "Show this help message.") { puts opts; exit }
82
-
83
- opts.parse!
84
- end
85
-
86
- Socket.do_not_reverse_lookup = true
87
- #}}}
88
-
89
- # RedCloth + Modifications: {{{
90
- begin
91
- if defined? Gem
92
- if Gem.source_index.search('redcloth').map { |s| s.version.version }.include? OPTIONS[:redcloth]
93
- require_gem 'RedCloth', "#{OPTIONS[:redcloth]}"
94
- else
95
- require_gem 'RedCloth', "~> #{OPTIONS[:redcloth]}"
96
- end
97
- end
98
-
99
- rescue LoadError, NoMethodError => detail
100
- if OPTIONS[:redcloth] < '3'
101
- require 'redcloth_2.0.11'
102
- else
103
- require 'redcloth'
104
- end
105
- end
106
-
107
- # Remove the "caps" spanning:
108
- RedCloth::GLYPHS.delete_if { |glyph| glyph[1] =~ /class=\"caps\"/ }
109
-
110
- # Fix missing hard_break in RedCloth 3.0.0/1
111
- if ['3.0.0', '3.0.1'].include? RedCloth::VERSION
112
- class RedCloth #{{{
113
- # Attempts at fixing the list blocks recognition:
114
- #BLOCKS_GROUP_RE = /(^([#*> ])(?:[^\n]|\n+|\n(?!\n|\Z))+)|((?:[^\n]+|\n+ +|\n(?![#*\n]|\Z))+)/m
115
-
116
- def to_html( *rules ) #{{{
117
- rules = @rules if rules.empty?
118
- # make our working copy
119
- text = self.dup
120
-
121
- @urlrefs = {}
122
- @shelf = []
123
- textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists,
124
- :block_textile_prefix, :inline_textile_image, :inline_textile_link,
125
- :inline_textile_code, :inline_textile_span, :inline_textile_glyphs]
126
- markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
127
- :block_markdown_bq, :block_markdown_lists,
128
- :inline_markdown_reflink, :inline_markdown_link]
129
- @rules = rules.collect do |rule|
130
- case rule
131
- when :markdown
132
- markdown_rules
133
- when :textile
134
- textile_rules
135
- else
136
- rule
137
- end
138
- end.flatten
139
-
140
- # standard clean up
141
- incoming_entities text
142
- clean_white_space text
143
-
144
- # start processor
145
- pre_list = rip_offtags text
146
- refs text
147
- blocks text
148
- inline text
149
- smooth_offtags text, pre_list
150
-
151
- retrieve text
152
- hard_break text # PIMKI: this is the missing bit!
153
-
154
- text.gsub!( /<\/?notextile>/, '' )
155
- text.gsub!( /x%x%/, '&#38;' )
156
- text.strip!
157
- text
158
- end #}}}
159
- end #}}}
160
- end #}}}
161
-
162
- # Start the application: {{{
163
- storage_dir = OPTIONS[:storage] + "/" + OPTIONS[:port].to_s
164
- require 'fileutils'
165
- FileUtils.mkdir_p(storage_dir)
166
- WikiService.storage_path = storage_dir
167
-
168
- WikiController.template_root = "#{cdir}/app/views/"
169
-
170
- on_exit = lambda {
171
- WebControllerServer::the_active_server.shutdown
172
- WikiService.request_stop
173
- }
174
-
175
- trap "INT", on_exit
176
- trap "TERM", on_exit
177
-
178
- WebControllerServer.new(OPTIONS[:port], OPTIONS[:server_type], "#{cdir}/app/controllers/")
179
-
180
- # }}}
181
-
1
+ #!/usr/local/bin/ruby
2
+
3
+ if RUBY_VERSION < "1.8.1"
4
+ puts "Pimki requires Ruby 1.8.1+"
5
+ exit
6
+ end
7
+
8
+ # Handle rubygems support & loading libraries: {{{
9
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "libraries")
10
+ begin
11
+ require 'rubygems'
12
+ require_gem 'madeleine'
13
+ require_gem 'BlueCloth'
14
+ require_gem 'rubyzip'
15
+ require 'zip/zip'
16
+
17
+ rescue LoadError => detail
18
+ # no rubygems, so load from the libraries directory
19
+ p detail if $DEBUG
20
+ puts 'Unable to load libraries through RubyGems. Loading from ./libraries directory'
21
+ require 'bluecloth'
22
+ require 'zip/zip'
23
+ end
24
+ # }}}
25
+
26
+ # Handle command-line options: {{{
27
+ require 'optparse'
28
+
29
+ cdir = File.expand_path(File.dirname(__FILE__))
30
+ %w( /libraries/ /app/models /app/controllers ).each { |dir| $:.unshift(cdir + dir) }
31
+ %w( web_controller_server action_controller_servlet wiki_service wiki ).each { |lib| require lib }
32
+
33
+ fork_available = true
34
+ begin
35
+ exit unless fork
36
+ rescue NotImplementedError
37
+ fork_available = false
38
+ end
39
+
40
+ begin
41
+ pdflatex_available = system "pdflatex -version"
42
+ rescue Errno::ENOENT
43
+ pdflatex_available = false
44
+ end
45
+
46
+ graphviz_available = (`dot -V 2>&1` =~ /dot version/)
47
+
48
+ OPTIONS = {
49
+ :server_type => fork_available ? Daemon : SimpleServer,
50
+ :port => 2500,
51
+ :storage => "#{Dir.pwd}/storage",
52
+ :pdflatex => pdflatex_available,
53
+ :redcloth => '3',
54
+ :graphviz_available => graphviz_available
55
+ }
56
+
57
+ ARGV.options do |opts|
58
+ script_name = File.basename($0)
59
+ opts.banner = "Usage: ruby #{script_name} [options]"
60
+
61
+ opts.separator ""
62
+
63
+ opts.on("-p", "--port=port", Integer,
64
+ "Runs Instiki on the specified port.",
65
+ "Default: 2500\n") { |OPTIONS[:port]| }
66
+ opts.on("-s", "--simple", "--simple-server",
67
+ "Forces Instiki not to run as a Daemon if fork is available.\n"
68
+ ) { OPTIONS[:server_type] = SimpleServer }
69
+ opts.on("-t", "--storage=storage", String,
70
+ "Makes Instiki use the specified directory for storage.",
71
+ "Default: [cwd]/storage/[port]\n") { |OPTIONS[:storage]| }
72
+ opts.on("-r", "--redcloth VERSION", String,
73
+ "Makes Instiki use the specified RedCloth version.",
74
+ "You can specify major version only (2 or 3)",
75
+ "Default: 2.0.11\n") { |OPTIONS[:redcloth]| }
76
+
77
+
78
+ opts.separator ""
79
+
80
+ opts.on("-h", "--help",
81
+ "Show this help message.") { puts opts; exit }
82
+
83
+ opts.parse!
84
+ end
85
+
86
+ Socket.do_not_reverse_lookup = true
87
+ #}}}
88
+
89
+ # RedCloth + Modifications: {{{
90
+ begin
91
+ if defined? Gem
92
+ if Gem.source_index.search('redcloth').map { |s| s.version.version }.include? OPTIONS[:redcloth]
93
+ require_gem 'RedCloth', "#{OPTIONS[:redcloth]}"
94
+ else
95
+ require_gem 'RedCloth', "~> #{OPTIONS[:redcloth]}"
96
+ end
97
+ end
98
+
99
+ rescue LoadError, NoMethodError => detail
100
+ if OPTIONS[:redcloth] < '3'
101
+ require 'redcloth_2.0.11'
102
+ else
103
+ require 'redcloth'
104
+ end
105
+ end
106
+
107
+ # Remove the "caps" spanning:
108
+ RedCloth::GLYPHS.delete_if { |glyph| glyph[1] =~ /class=\"caps\"/ }
109
+
110
+ # Fix missing hard_break in RedCloth 3.0.0/1
111
+ if ['3.0.0', '3.0.1'].include? RedCloth::VERSION
112
+ class RedCloth #{{{
113
+ # Attempts at fixing the list blocks recognition:
114
+ #BLOCKS_GROUP_RE = /(^([#*> ])(?:[^\n]|\n+|\n(?!\n|\Z))+)|((?:[^\n]+|\n+ +|\n(?![#*\n]|\Z))+)/m
115
+
116
+ def to_html( *rules ) #{{{
117
+ rules = @rules if rules.empty?
118
+ # make our working copy
119
+ text = self.dup
120
+
121
+ @urlrefs = {}
122
+ @shelf = []
123
+ textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists,
124
+ :block_textile_prefix, :inline_textile_image, :inline_textile_link,
125
+ :inline_textile_code, :inline_textile_span, :inline_textile_glyphs]
126
+ markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule,
127
+ :block_markdown_bq, :block_markdown_lists,
128
+ :inline_markdown_reflink, :inline_markdown_link]
129
+ @rules = rules.collect do |rule|
130
+ case rule
131
+ when :markdown
132
+ markdown_rules
133
+ when :textile
134
+ textile_rules
135
+ else
136
+ rule
137
+ end
138
+ end.flatten
139
+
140
+ # standard clean up
141
+ incoming_entities text
142
+ clean_white_space text
143
+
144
+ # start processor
145
+ pre_list = rip_offtags text
146
+ refs text
147
+ blocks text
148
+ inline text
149
+ smooth_offtags text, pre_list
150
+
151
+ retrieve text
152
+ hard_break text # PIMKI: this is the missing bit!
153
+
154
+ text.gsub!( /<\/?notextile>/, '' )
155
+ text.gsub!( /x%x%/, '&#38;' )
156
+ text.strip!
157
+ text
158
+ end #}}}
159
+ end #}}}
160
+ end #}}}
161
+
162
+ # Start the application: {{{
163
+ storage_dir = File.join(OPTIONS[:storage], OPTIONS[:port].to_s)
164
+ require 'fileutils'
165
+ FileUtils.mkdir_p(storage_dir)
166
+ WikiService.storage_path = storage_dir
167
+
168
+ WikiController.template_root = "#{cdir}/app/views/"
169
+
170
+ on_exit = lambda {
171
+ WebControllerServer::the_active_server.shutdown
172
+ WikiService.request_stop
173
+ }
174
+
175
+ trap "INT", on_exit
176
+ trap "TERM", on_exit
177
+
178
+ WebControllerServer.new(OPTIONS[:port], OPTIONS[:server_type], "#{cdir}/app/controllers/")
179
+
180
+ # }}}
181
+
182
182
  # jEdit :folding=explicit:collapseFolds=1: