wunderbar 0.8.13 → 0.8.14

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.
data/demo/wiki.html DELETED
@@ -1,73 +0,0 @@
1
- <!DOCTYPE html>
2
- <html xmlns="http://www.w3.org/1999/xhtml">
3
- <head>
4
- <meta charset="utf-8"/>
5
- <title>Wunderbar Wiki</title>
6
- </head>
7
- <body>
8
- <h2>Wunderbar Wiki</h2>
9
-
10
- <p>Note: demo code requires Ruby 1.9.2 or later. Wunderbar itself works with
11
- Ruby 1.8.7 or later.</p>
12
-
13
- <p>Prereqs:</p>
14
-
15
- <ul>
16
- <li><code>gem install wunderbar rdiscount</code></li>
17
- <li><code>apt-get install git</code></li>
18
- <li><a href="http://jquery.com/">jQuery</a></li>
19
- <li><a href="http://www.showdown.im/">Showdown</a></li>
20
- </ul>
21
-
22
-
23
- <p>Create a data directory (one per wiki):</p>
24
-
25
- <ul>
26
- <li>Must be writeable by your web server</li>
27
- <li>Should not be in the Document Root</li>
28
- </ul>
29
-
30
-
31
- <p>Configure git:</p>
32
-
33
- <ul>
34
- <li>Follow <a
35
- href="http://help.github.com/set-your-user-name-email-and-github-token/]">Step
36
- 1</a>.</li>
37
- <li>Note that this needs to be done for the user that the webserver runs the
38
- script under. If you are not running <a
39
- href="http://httpd.apache.org/docs/2.0/suexec.html">suexec</a>, this is
40
- typically <code>www-data</code> on Unix or <code>www</code> on Mac OS/X.</li>
41
- </ul>
42
-
43
-
44
- <p>Configure Apache:</p>
45
-
46
- <pre><code> Options +ExecCGI +MultiViews
47
- MultiViewsMatch Any
48
- AddHandler cgi-script .cgi
49
- </code></pre>
50
-
51
- <blockquote><p>Optionally configure <a href="http://httpd.apache.org/docs/2.4/howto/auth.html">Authentication</a> for multiple users.</p></blockquote>
52
-
53
- <p>Install scripts:</p>
54
-
55
- <ul>
56
- <li>Copy <code>jquery-min.js</code> and <code>showdown.js</code> into your
57
- document root</li>
58
- </ul>
59
-
60
-
61
- <p>Install wiki (one per wiki):</p>
62
-
63
- <pre><code> ruby wiki.rb --install=/var/www/wikiname.cgi --WIKIDATA="/full/path/to/data/directory"
64
- </code></pre>
65
-
66
- <blockquote><p>Optionally tailor the setting of the $EMAIL variable in the script. The current default logic is based on a Unix like operating system (such as Linux, Mac OS/X) with users having email addresses on this machine. Replace as needed.</p></blockquote>
67
-
68
- <p>Access your wiki:</p>
69
-
70
- <pre><code> http://localhost/wikiname/
71
- </code>
72
- </body>
73
- </html>
data/demo/wiki.rb DELETED
@@ -1,214 +0,0 @@
1
- #!/usr/bin/ruby
2
- require 'wunderbar'
3
- require 'rdiscount'
4
- require 'digest/md5'
5
-
6
- Dir.chdir WIKIDATA
7
-
8
- # parse request
9
- %r{/(?<file>.\w+)((?<flag>/)(?<rev>\w*))?$} =~ $env.PATH_INFO
10
- flag ||= '?' if $env.REQUEST_URI.include? '?'
11
- file ||= 'index'
12
-
13
- W_.html do
14
- _head_ do
15
- _title file
16
- _style %{
17
- body {background-color: #{(flag=='?') ? '#E0D8D8' : '#FFF'}}
18
- .status {border: 2px solid #000; border-radius: 1em; background: #FAFAD2; padding: 0.5em}
19
- .input, .output {border: 1px solid #888; position: relative; width: 47.5%; height: 400px; overflow: auto}
20
- .input {float: left; left: 1.5%}
21
- .output {float: right; right: 1.5%; background-color: #6C6666; color: #FFF}
22
- .buttons {clear: both; text-align: center; padding-top: 0.5em}
23
- #message {position: fixed; left: 2%; color: #9400d3}
24
- h1 {text-align: center; margin: 0}
25
- form {clear: both}
26
- .buttons form {display: inline}
27
- ._stdin:before {content: '$ '}
28
- ._stdin {color: #9400D3; margin-bottom: 0}
29
- ._stdout {margin: 0}
30
- ._stderr {margin: 0; color: red}
31
- }
32
- _script src: '/showdown.js'
33
- _script src: '/jquery.min.js'
34
- end
35
-
36
- _body? do
37
-
38
- # determine markup
39
- if _.post? and @markup
40
- _header.status do
41
- _h1 'Status'
42
- if File.exist?(file) and Digest::MD5.hexdigest(File.read(file)) != @hash
43
- _p 'Write conflict'
44
- else
45
- File.open(file, 'w') {|fh| fh.write @markup}
46
- _.system 'git init' unless Dir.exist? '.git'
47
- if `git status --porcelain #{file}`.empty?
48
- _p 'Nothing changed'
49
- else
50
- _.system "git add #{file}"
51
-
52
- commit = %w(git commit)
53
- commit << '--author' << $EMAIL if defined? $EMAIL and $EMAIL
54
- commit << '--message' << @comment
55
- commit << file
56
-
57
- _.system commit
58
- end
59
- end
60
- end
61
-
62
- elsif File.exist? file
63
- # existing file
64
- if !rev or rev.empty?
65
- @markup = File.read(file)
66
- else
67
- @markup = `git show #{rev}:#{file}`
68
- flag = nil
69
- end
70
-
71
- else
72
- # new file: go directly into edit mode
73
- @markup = "#{file}\n#{'-'*file.length}\n\nEnter your text here..."
74
- flag = '?'
75
- end
76
-
77
- # produce HTML
78
- if file == '_index'
79
-
80
- # index
81
- index = Hash[`git ls-tree HEAD --name-only`.scan(/(\w+)()/)].
82
- merge Hash[*`git status --porcelain`.scan(/(..) (\w+)/).flatten.reverse]
83
- _table do
84
- _tbody do
85
- index.sort.each do |name, status|
86
- _tr do
87
- _td status
88
- _td {_a name, href: name}
89
- end
90
- end
91
- end
92
- end
93
-
94
- elsif flag == '?'
95
-
96
- # edit mode
97
- _header do
98
- _h1 "~~~ #{file} ~~~"
99
- _span 'Input', style: 'float: left; margin-left: 2em'
100
- _span 'Output', style: 'float: right; margin-right: 2em'
101
- end
102
-
103
- _form_ action: file, method: 'post' do
104
- _textarea.input @markup, name: 'markup'
105
- _input type: 'hidden', name: 'hash',
106
- value: Digest::MD5.hexdigest(@markup)
107
- _div.output do
108
- _ << RDiscount.new(@markup).to_html
109
- end
110
-
111
- _div.buttons do
112
- _span.message!
113
- _input name: 'comment', placeholder: 'commit message'
114
- _input type: 'submit', value: 'save'
115
- end
116
- end
117
-
118
- elsif flag == '/'
119
-
120
- # revision history
121
- _h2 "Revision history for #{file}"
122
- _ul do
123
- `git log --format="%H|%ai|%an|%s" #{file}`.lines.each do |line|
124
- hash, date, author, subject = line.split('|')
125
- _li! {_a date, href: hash; _ " #{subject} by #{author}"}
126
- end
127
- end
128
-
129
- else
130
-
131
- #display
132
- _ << RDiscount.new(@markup).to_html
133
- _div_.buttons do
134
- if !rev or rev.empty?
135
- _form action: "#{file}?", method: 'post' do
136
- _input type: 'submit', value: 'edit'
137
- end
138
- end
139
- _form action: "#{file}/" do
140
- _input type: 'submit', value: 'history'
141
- end
142
- end
143
- end
144
-
145
- _script %{
146
- // autosave every 10 seconds
147
- var dirty = false;
148
- setInterval(function() {
149
- if (!dirty) return;
150
- dirty = false;
151
-
152
- var params = {
153
- markup: $('textarea[name=markup]').val(),
154
- hash: $('input[name=hash]').val()
155
- };
156
-
157
- $.getJSON("#{SELF}", params, function(_) {
158
- $('input[name=hash]').val(_.hash);
159
- if (_.time) {
160
- var time = new Date(_.time).toLocaleTimeString();
161
- $('#message').text("Autosaved at " + time).show().fadeOut(5000);
162
- } else {
163
- $('.input').val(_.markup).attr('readonly', 'readonly');
164
- $('#message').css({'font-weight': 'bold'}).text(_.error).show();
165
- }
166
- });
167
- }, 10000);
168
-
169
- // regenerate output every 0.5 seconds
170
- var updated = false;
171
- setInterval(function() {
172
- if (!updated) return;
173
- updated = false;
174
- $('.output').html(converter.makeHtml($('.input').val()));
175
- }, 500);
176
-
177
- // update output pane and mark dirty whenever input changes
178
- var converter = new Showdown.converter();
179
- $('.input').bind('input', function() {
180
- updated = dirty = true;
181
- }).trigger('input');
182
-
183
- // resize based on window size
184
- var reserve = $('header').height() * 3 + $('.buttons').height();
185
- $(window).resize(function() {
186
- $('.input,.output').height($(window).height()-reserve);
187
- }).trigger('resize');
188
- }
189
- end
190
- end
191
-
192
- # process autosave requests
193
- W_.json do
194
- hash = Digest::MD5.hexdigest(@markup)
195
- if File.exist?(file) and Digest::MD5.hexdigest(File.read(file)) != @hash
196
- {error: "Write conflict", markup: File.read(file), hash: hash}
197
- else
198
- File.open(file, 'w') {|fh| fh.write @markup} unless @hash == hash
199
- {time: Time.now.to_i*1000, hash: hash}
200
- end
201
- end
202
-
203
- __END__
204
- # Customize where the wiki data is stored
205
- WIKIDATA = '/full/path/to/data/directory'
206
-
207
- # git author e-mail address override
208
- require 'etc'
209
- begin
210
- name = Etc.getpwnam($USER).gecos.split(',').first
211
- $EMAIL = "#{name} <#{$USER}@#{$env.SERVER_NAME}>"
212
- $EMAIL = nil if %w(www-data _www).include?($USER)
213
- rescue
214
- end
data/test/test_builder.rb DELETED
@@ -1,35 +0,0 @@
1
- require 'test/unit'
2
- require 'rubygems'
3
- require 'wunderbar'
4
-
5
- class BuilderTest < Test::Unit::TestCase
6
- def test_empty
7
- x = Wunderbar::XmlMarkup.new :indent => 2
8
- x.tag!(:script) { x.indented_text! '' }
9
- assert_equal %{<script>\n</script>\n}, x.target!
10
- end
11
-
12
- def test_unindented_input
13
- x = Wunderbar::XmlMarkup.new :indent => 2
14
- x.tag!(:script) { x.indented_text! "{\n x: 1\n}" }
15
- assert_equal %{<script>\n {\n x: 1\n }\n</script>\n}, x.target!
16
- end
17
-
18
- def test_indented_input
19
- x = Wunderbar::XmlMarkup.new :indent => 2
20
- x.tag!(:script) { x.indented_text! " alert('danger');" }
21
- assert_equal %{<script>\n alert('danger');\n</script>\n}, x.target!
22
- end
23
-
24
- def test_exception
25
- x = Wunderbar::XmlMarkup.new :indent => 2
26
- x.tag!(:body) do
27
- begin
28
- x.tag!(:p) { raise Exception.new('boom') }
29
- rescue Exception => e
30
- x.tag!(:pre, e)
31
- end
32
- end
33
- assert x.target!.include? '<p>' and x.target!.include? '</p>'
34
- end
35
- end
@@ -1,200 +0,0 @@
1
- require 'test/unit'
2
- require 'rubygems'
3
- require 'wunderbar'
4
-
5
- class HtmlMarkupTest < Test::Unit::TestCase
6
- def setup
7
- @original_log_level = Wunderbar.logger.level
8
- Wunderbar.log_level = :fatal
9
- end
10
-
11
- def teardown
12
- Wunderbar.logger.level = @original_log_level
13
- end
14
-
15
- def test_html
16
- x = HtmlMarkup.new
17
- x.html {}
18
- assert_equal %{<html>\n</html>\n}, x.target!
19
- end
20
-
21
- def test_void_element
22
- x = HtmlMarkup.new
23
- x.html {_br}
24
- assert_match %r{<br/>}, x.target!
25
- end
26
-
27
- def test_normal_element
28
- x = HtmlMarkup.new
29
- x.html {_textarea}
30
- assert_match %r{<textarea></textarea>}, x.target!
31
- end
32
-
33
- def test_script_lang
34
- x = HtmlMarkup.new
35
- x.html {_script}
36
- assert_match %r[<script lang="text/javascript">], x.target!
37
- end
38
-
39
- def test_style_type
40
- x = HtmlMarkup.new
41
- x.html {_style}
42
- assert_match %r[<style type="text/css">], x.target!
43
- end
44
-
45
- def test_script_plain
46
- x = HtmlMarkup.new
47
- x.html {_script! 'alert("foo");'}
48
- assert_match %r[<script>alert\("foo"\);</script>], x.target!
49
- end
50
-
51
- def test_script_indent
52
- x = HtmlMarkup.new
53
- x.html {_script "if (i<1) {}"}
54
- assert_match %r[^ if], x.target!
55
- end
56
-
57
- def test_script_html
58
- $XHTML = false
59
- x = HtmlMarkup.new
60
- x.html {_script "if (i<1) {}"}
61
- assert_match %r[<script.*>\s*if \(i<1\) \{\}\s*</script>], x.target!
62
- end
63
-
64
- def test_script_xhtml
65
- $XHTML = true
66
- x = HtmlMarkup.new
67
- x.html {_script "if (i<1) {}"}
68
- assert_match %r[<script.*>\s*if \(i&lt;1\) \{\}\s*</script>], x.target!
69
- end
70
-
71
- def test_disable_indent
72
- x = HtmlMarkup.new
73
- x.html {_div! {_ "one "; _strong "two"; _ " three"}}
74
- assert_match %r[<div>one <strong>two</strong> three</div>], x.target!
75
- end
76
-
77
- def test_spaced_embedded
78
- x = HtmlMarkup.new
79
- x.html {_div {_p 'one'; _hr_; _p 'two'}}
80
- assert_match %r[<div>\n +<p>one</p>\n\n +<hr/>\n\n +<p>two</p>\n +</div>],
81
- x.target!
82
- end
83
-
84
- def test_spaced_collapsed
85
- x = HtmlMarkup.new
86
- x.html {_div {_p_ 'one'; _hr_; _p_ 'two'}}
87
- assert_match %r[<div>\n +<p>one</p>\n\n +<hr/>\n\n +<p>two</p>\n +</div>],
88
- x.target!
89
- end
90
-
91
- def test_traceback
92
- x = HtmlMarkup.new
93
- x.html {_body? {boom}}
94
- assert_match %r[<pre.*>#&lt;NameError: .*boom],
95
- x.target!
96
- end
97
-
98
- def test_traceback_default_style
99
- x = HtmlMarkup.new
100
- x.html {_body? {boom}}
101
- assert_match %r[<pre style="background-color:#ff0.*">], x.target!
102
- end
103
-
104
- def test_traceback_style_override
105
- x = HtmlMarkup.new
106
- x.html {_body?(:traceback_style => 'color:red') {boom}}
107
- assert_match %r[<pre style="color:red"], x.target!
108
- end
109
-
110
- def test_traceback_class_override
111
- x = HtmlMarkup.new
112
- x.html {_body?(:traceback_class => 'traceback') {boom}}
113
- assert_match %r[<pre class="traceback"], x.target!
114
- end
115
-
116
- def test_meta_charset
117
- x = HtmlMarkup.new
118
- x.html {_head}
119
- assert_match %r[<head>\s*<meta charset="utf-8"/>\s*</head>], x.target!
120
- end
121
-
122
- def test_nil_attribute
123
- x = HtmlMarkup.new
124
- x.html {_div :class => nil}
125
- assert_match %r[^ <div></div>], x.target!
126
- end
127
-
128
- def test_class_attribute
129
- x = HtmlMarkup.new
130
- x.html {_div.header {_span.text 'foo'}}
131
- assert_match %r[<div class="header">.*</div>]m, x.target!
132
- end
133
-
134
- def test_id_attribute
135
- x = HtmlMarkup.new
136
- x.html {_h1.content! 'Content'}
137
- assert_match %r[^ <h1 id="content">Content</h1>], x.target!
138
- end
139
-
140
- def test_boolean_attribute_false
141
- x = HtmlMarkup.new
142
- x.html {_option :selected => false}
143
- assert_match %r[^ <option></option>], x.target!
144
- end
145
-
146
- def test_boolean_attribute_true
147
- x = HtmlMarkup.new
148
- x.html {_option :selected => true}
149
- assert_match %r[^ <option selected="selected"></option>], x.target!
150
- end
151
-
152
- def test_indented_text
153
- x = HtmlMarkup.new
154
- x.html {_div {_ 'text'}}
155
- assert_match %r[^ <div>\n text\n </div>], x.target!
156
- end
157
-
158
- def test_unindented_text
159
- x = HtmlMarkup.new
160
- x.html {_div {_! "text\n"}}
161
- assert_match %r[^ <div>\ntext\n </div>], x.target!
162
- end
163
-
164
- def test_declare
165
- x = HtmlMarkup.new
166
- x._.declare :DOCTYPE, 'html'
167
- assert_equal %{<!DOCTYPE "html">\n}, x.target!
168
- end
169
-
170
- def test_comment
171
- x = HtmlMarkup.new
172
- x._.comment 'foo'
173
- assert_equal %{<!-- foo -->\n}, x.target!
174
- end
175
-
176
- def test_svg
177
- x = HtmlMarkup.new
178
- x.html {_svg}
179
- assert_match %r[^ <svg xmlns="http://www.w3.org/2000/svg"/>], x.target!
180
- end
181
-
182
- def test_math
183
- x = HtmlMarkup.new
184
- x.html {_math}
185
- assert_match %r[^ <math xmlns="http://www.w3.org/1998/Math/MathML"/>], x.target!
186
- end
187
-
188
- begin
189
- require 'coffee-script'
190
-
191
- def test_coffeescript
192
- x = HtmlMarkup.new
193
- x.html {_coffeescript 'alert "foo"'}
194
- assert_match %r[<script\slang="text/javascript">\s+\(function\(\)\s
195
- \{\s+alert\("foo"\);\s+\}\).call\(this\);\s+</script>]x, x.target!
196
- end
197
- rescue LoadError
198
- end
199
-
200
- end
data/test/test_logger.rb DELETED
@@ -1,76 +0,0 @@
1
- require 'test/unit'
2
- require 'rubygems'
3
- require 'wunderbar'
4
- require 'logger'
5
-
6
- class TestLogger
7
- attr_accessor :messages
8
- def initialize
9
- @messages = Hash.new {|hash, key| hash[key] = Array.new}
10
- @original_logger = Wunderbar.logger
11
- logger = self
12
- Wunderbar.instance_eval {@logger = logger}
13
- end
14
-
15
- def method_missing(method, *args)
16
- if [:debug, :info, :warn, :error, :fatal].include? method
17
- @messages[method] << args.first
18
- else
19
- @original_logger.send(method, *args)
20
- end
21
- end
22
-
23
- def teardown
24
- logger = @original_logger
25
- Wunderbar.instance_eval {@logger = logger}
26
- end
27
- end
28
-
29
- class LoggerTest < Test::Unit::TestCase
30
- def setup
31
- @logger = TestLogger.new
32
- end
33
-
34
- def teardown
35
- @logger.teardown
36
- end
37
-
38
- def test_debug
39
- Wunderbar.debug 'Sneezy'
40
- assert @logger.messages[:debug].include? 'Sneezy'
41
- end
42
-
43
- def test_info
44
- Wunderbar.info 'Sleepy'
45
- assert @logger.messages[:info].include? 'Sleepy'
46
- end
47
-
48
- def test_warn
49
- Wunderbar.warn 'Dopey'
50
- assert @logger.messages[:warn].include? 'Dopey'
51
- end
52
-
53
- def test_error
54
- Wunderbar.error 'Doc'
55
- assert @logger.messages[:error].include? 'Doc'
56
- end
57
-
58
- def test_fatal
59
- Wunderbar.fatal 'Happy'
60
- assert @logger.messages[:fatal].include? 'Happy'
61
- end
62
-
63
- def test_loglevel
64
- assert Wunderbar.logger.level == Logger::WARN
65
- Wunderbar.log_level = 'debug'
66
- assert Wunderbar.logger.level == Logger::DEBUG
67
- Wunderbar.log_level = 'info'
68
- assert Wunderbar.logger.level == Logger::INFO
69
- Wunderbar.log_level = 'warn'
70
- assert Wunderbar.logger.level == Logger::WARN
71
- Wunderbar.log_level = 'error'
72
- assert Wunderbar.logger.level == Logger::ERROR
73
- Wunderbar.log_level = 'fatal'
74
- assert Wunderbar.logger.level == Logger::FATAL
75
- end
76
- end