manveru-org 2009.02.21
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/README.md +26 -0
- data/doc/syntax.org +73 -0
- data/lib/org/markup.rb +31 -0
- data/lib/org/rule.rb +43 -0
- data/lib/org/rules.rb +108 -0
- data/lib/org/scope/org_mode.rb +78 -0
- data/lib/org/scope.rb +35 -0
- data/lib/org/state.rb +12 -0
- data/lib/org/stringscanner.rb +16 -0
- data/lib/org/to/html.rb +91 -0
- data/lib/org/to/toc.rb +51 -0
- data/lib/org/token.rb +20 -0
- data/lib/org.rb +28 -0
- data/spec/org.rb +53 -0
- metadata +75 -0
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Org
|
2
|
+
|
3
|
+
Org provides transformation of a selected subset of org-mode markup for wikis.
|
4
|
+
|
5
|
+
## About
|
6
|
+
|
7
|
+
If you fancy emacs' org-mode and would like to use its power for a wiki based on plain-text files you should check this out.
|
8
|
+
Org tries to stay compatible with org-mode, but does not support the full syntax. The most notable features you will find are table of contents, tables, headers, links and simple physical text formatting.
|
9
|
+
One feature org-mode doesn't provide (AFAIK) is code highlighting, since the preferred way is to simply link to the file containing the code, but that is a bit impractical in a wiki, so I added this feature.
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
* Headers
|
14
|
+
* Links
|
15
|
+
* Tables
|
16
|
+
* Text markup
|
17
|
+
|
18
|
+
## Dependencies
|
19
|
+
|
20
|
+
* StringScanner (ruby stdlib)
|
21
|
+
* CodeRay (optional)
|
22
|
+
* Uv (optional)
|
23
|
+
|
24
|
+
## Syntax
|
25
|
+
|
26
|
+
For a nice intro to the syntax supported by Org please check the [doc/syntax.org] file.
|
data/doc/syntax.org
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
* OrgMarkup
|
2
|
+
|
3
|
+
** Links
|
4
|
+
|
5
|
+
Internal Links follow the [[Wiki]] [[Wiki][Wiki Wiki]] style, also WikiWords work.
|
6
|
+
|
7
|
+
To recap:
|
8
|
+
|
9
|
+
[[Wiki]] is `[[Wiki]]`
|
10
|
+
[[Wiki][Wiki]] is `[[Wiki][Wiki]]`
|
11
|
+
WikiWords was `WikiWords`
|
12
|
+
|
13
|
+
You can easily plug into the handling of links and implement things like `[[flash:screencast-blog][My Screencast about Blogging]]`, but by default there will be no link formatting until I can find a nice set of defaults.
|
14
|
+
|
15
|
+
** Lists
|
16
|
+
|
17
|
+
* Lists start with a `*` after one or more spaces from the beginning of a line.
|
18
|
+
* Nested lists are maybe not working correctly yet.
|
19
|
+
|
20
|
+
** Headers
|
21
|
+
|
22
|
+
Headers are written as follows:
|
23
|
+
|
24
|
+
{{{
|
25
|
+
* h1
|
26
|
+
** h2
|
27
|
+
*** h3
|
28
|
+
**** h4
|
29
|
+
***** h5
|
30
|
+
****** h6
|
31
|
+
}}}
|
32
|
+
|
33
|
+
** Code
|
34
|
+
|
35
|
+
You can start a code block with `{{{` and end it with `}}}`, each on its own line. For code inside a line please use =`backticks`=.
|
36
|
+
|
37
|
+
{{{
|
38
|
+
This is a line of code
|
39
|
+
}}}
|
40
|
+
|
41
|
+
|
42
|
+
{{{ ruby
|
43
|
+
puts "This is a line of Ruby code"
|
44
|
+
}}}
|
45
|
+
|
46
|
+
You may also use `c`, `delphi`, `html`, `ezamar`, `nitro_xhtml`, `plaintext`, `rhtml`, or `xml`
|
47
|
+
|
48
|
+
** Text formatting
|
49
|
+
|
50
|
+
/italic/ is `/italic/`
|
51
|
+
*bold* is `*bold*`
|
52
|
+
_underline_ is `_underline_`
|
53
|
+
+strikethrough+ is `+strikethrough+`
|
54
|
+
~blockquote~ is `~blockquote~`
|
55
|
+
=code= is `=code=`
|
56
|
+
and `code` is =`code`=
|
57
|
+
last, but not least, there's also `----` the horizontal rule
|
58
|
+
|
59
|
+
----
|
60
|
+
|
61
|
+
** Tables
|
62
|
+
|
63
|
+
|--------------+-------------------------+----------------|
|
64
|
+
| Name | Telephone | Room |
|
65
|
+
|--------------+-------------------------+----------------|
|
66
|
+
| Mr. X | 777-777 | 42 |
|
67
|
+
| Mrs. Y | 888-888 | 21 |
|
68
|
+
| see? | tables | are |
|
69
|
+
| easy | enough | eh? |
|
70
|
+
|--------------+-------------------------+----------------|
|
71
|
+
| you can even | use separating elements | but they won't |
|
72
|
+
| show up | in the | endresult. |
|
73
|
+
|--------------+-------------------------+----------------|
|
data/lib/org/markup.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Org
|
2
|
+
class Markup
|
3
|
+
attr_accessor :string
|
4
|
+
|
5
|
+
def initialize(file = nil)
|
6
|
+
@string = File.read(file) if file
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply(string = @string)
|
10
|
+
parent = RootToken.new(:root, nil)
|
11
|
+
scanner = StringScanner.new(string)
|
12
|
+
state = State.new(@scope, parent, scanner)
|
13
|
+
|
14
|
+
until scanner.eos?
|
15
|
+
pos = scanner.pos
|
16
|
+
# puts "=" * 80
|
17
|
+
state.step
|
18
|
+
# puts "=" * 80
|
19
|
+
# pp state
|
20
|
+
raise("Didn't move: %p" % scanner) if pos == scanner.pos
|
21
|
+
end
|
22
|
+
|
23
|
+
return parent
|
24
|
+
end
|
25
|
+
|
26
|
+
def scope(name, options = {}, &block)
|
27
|
+
@scope = Scope.new(name, options)
|
28
|
+
yield(@scope)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/org/rule.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Org
|
2
|
+
class Rule
|
3
|
+
DEFAULT = {
|
4
|
+
:bol => false,
|
5
|
+
:start => nil,
|
6
|
+
:end => nil,
|
7
|
+
:unscan => false,
|
8
|
+
}
|
9
|
+
|
10
|
+
attr_accessor :name, :regex
|
11
|
+
|
12
|
+
def initialize(name, regex, options = {}, &block)
|
13
|
+
@name, @regex, @block = name, regex, block
|
14
|
+
@options = DEFAULT.merge(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def match(state)
|
18
|
+
scope, parent, scanner = state.scope, state.parent, state.scanner
|
19
|
+
return if @options[:bol] and not scanner.bol?
|
20
|
+
|
21
|
+
return false unless scanner.scan(@regex)
|
22
|
+
scanner.unscan if @options[:unscan]
|
23
|
+
|
24
|
+
name = @options[:tag] || @name
|
25
|
+
token = Token.new(name, scanner.captures, &@block)
|
26
|
+
return true if @options[:ignore]
|
27
|
+
|
28
|
+
if mode = @options[:start]
|
29
|
+
# puts "Start #{mode}"
|
30
|
+
state.scope = mode.is_a?(Scope) ? mode : scope.scopes[mode]
|
31
|
+
parent << token
|
32
|
+
state.parent = token
|
33
|
+
elsif mode = @options[:end]
|
34
|
+
# puts "End #{mode}"
|
35
|
+
state.parent = parent.parent
|
36
|
+
state.scope = scope.parent
|
37
|
+
else
|
38
|
+
parent << token
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/org/rules.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'org'
|
2
|
+
|
3
|
+
# rs = RuleSet.new("~/c/innate/example/app/wiki/pages/Home.owl")
|
4
|
+
rs = OrgMarkup.new("test.org")
|
5
|
+
|
6
|
+
rs.scope(:block, :indent => true) do |block|
|
7
|
+
block.rule :header, /(\*+)\s+(.*)\n/, :bol => true
|
8
|
+
block.rule :table, /\|([^|]+)/, :bol => true, :start => :table, :unscan => true
|
9
|
+
block.rule :br, /\n/
|
10
|
+
block.rule :p, /(.)/, :bol => true, :start => :inline, :unscan => true
|
11
|
+
block.rule :space, /\s/
|
12
|
+
|
13
|
+
inline_rules = lambda do |parent|
|
14
|
+
# * You can make words *bold*, /italic/, _underlined_, `=code=' and
|
15
|
+
# `~verbatim~', and, if you must, `+strikethrough+'. Text in the
|
16
|
+
# code and verbatim string is not processed for org-mode specific
|
17
|
+
# syntax, it is exported verbatim.
|
18
|
+
parent.rule :a, /\b([A-Z]\w+[A-Z]\w+)/
|
19
|
+
parent.rule :text, /([A-Za-z0-9,. ]+)/
|
20
|
+
# [[file:foo][My file foo]]
|
21
|
+
parent.rule :a, /\[\[([^:\]]+):([^\]]+)\]\[([^\]]+)\]\]/
|
22
|
+
# [[http://go.to/][Go to]]
|
23
|
+
parent.rule :a, /\[\[([^\]]+)\]\[([^\]]+)\]\]/
|
24
|
+
# [[file:foo]]
|
25
|
+
parent.rule :a, /\[\[([^:\]]+):([^\]]+)\]\]/
|
26
|
+
# [[foo]]
|
27
|
+
parent.rule :a, /\[\[([^\]]+)\]\]/
|
28
|
+
parent.rule :italic, /\/([^\/]+)\//
|
29
|
+
parent.rule :bold, /\*([^*]+)\*/, :tag => :b
|
30
|
+
parent.rule :underline, /_([^_]+)_/
|
31
|
+
parent.rule :strikethrough, /\+([^+]+)\+/
|
32
|
+
parent.rule :verbatim, /~([^~]+)~/
|
33
|
+
parent.rule :code, /\=([^=]+)\=/
|
34
|
+
end
|
35
|
+
|
36
|
+
block.scope(:inline, :indent => false) do |inline|
|
37
|
+
inline.apply(&inline_rules)
|
38
|
+
inline.rule :text, /(.)/
|
39
|
+
inline.rule :close, /\n\n+/, :end => :inline
|
40
|
+
inline.rule :br, /\n/
|
41
|
+
end
|
42
|
+
|
43
|
+
block.scope(:table, :indent => true) do |table|
|
44
|
+
# | name | telelphone | room |
|
45
|
+
# |--------+------------+------|
|
46
|
+
# | Mr. X | 777-777 | 42 |
|
47
|
+
# | Mrs. Y | 888-888 | 21 |
|
48
|
+
|
49
|
+
table.rule :tr, /\|([^|]+)/, :bol => true, :unscan => true, :start => :tr
|
50
|
+
table.rule :close, /\n/, :end => :table
|
51
|
+
|
52
|
+
table.scope(:tr, :indent => true) do |tr|
|
53
|
+
tr.rule :table_separator, /\|[+-]+\|/
|
54
|
+
tr.rule :close, /\|\n/, :end => :tr
|
55
|
+
tr.rule :close, /\n/, :end => :tr
|
56
|
+
tr.rule :td, /\|/, :start => :td
|
57
|
+
|
58
|
+
tr.scope :td do |td|
|
59
|
+
td.apply(&inline_rules)
|
60
|
+
td.rule :space, /([\t ]+)/
|
61
|
+
td.rule :text, /([^|])/
|
62
|
+
td.rule :close, /\|/, :end => :td, :unscan => true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
require 'pp'
|
69
|
+
|
70
|
+
class OrgMarkup
|
71
|
+
module ToHtml
|
72
|
+
def html_link(leader, href = nil, title = nil)
|
73
|
+
case leader
|
74
|
+
when 'rss'
|
75
|
+
link_rss(href, title)
|
76
|
+
when 'file'
|
77
|
+
link_file(href, title)
|
78
|
+
when 'http', 'https', 'ftp'
|
79
|
+
link_out("#{leader}:#{href}", title)
|
80
|
+
else
|
81
|
+
link_in(leader, href)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Respond to [[rss:href]] and [[rss:href][title]]
|
86
|
+
def link_rss(href, title)
|
87
|
+
"<rss %p %p>" % [href, title]
|
88
|
+
''
|
89
|
+
end
|
90
|
+
|
91
|
+
# Respond to [[file:href]] and [[file:href][title]]
|
92
|
+
def link_file(href, title)
|
93
|
+
"<file %p %p>" % [href, title]
|
94
|
+
''
|
95
|
+
end
|
96
|
+
|
97
|
+
def link_out(href, title)
|
98
|
+
"<out %p %p>" % [href, title]
|
99
|
+
tag(:a, title || href, :href => href)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Respond to [[name]] and [[name][title]]
|
103
|
+
def link_in(href, title)
|
104
|
+
"<wiki %p %p>" % [href, title]
|
105
|
+
tag(:a, title || href, :href => "/#{href}")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Org
|
2
|
+
OrgMode = Markup.new
|
3
|
+
|
4
|
+
OrgMode.scope(:block, :indent => true) do |block|
|
5
|
+
block.rule :header, /(\*+)\s+(.*)(\n|\z)/, :bol => true
|
6
|
+
block.rule :table, /\|([^|]+)/, :bol => true, :start => :table, :unscan => true
|
7
|
+
block.rule :ul, /[ \t]+(\*+)\s*(.*)/, :start => :ul, :unscan => true, :bol => true
|
8
|
+
block.rule :br, /\n/
|
9
|
+
block.rule :p, /(.)/, :bol => true, :start => :inline, :unscan => true
|
10
|
+
block.rule :space, /\s/
|
11
|
+
|
12
|
+
inline_rules = lambda do |parent|
|
13
|
+
# * You can make words *bold*, /italic/, _underlined_, `=code=' and
|
14
|
+
# `~verbatim~', and, if you must, `+strikethrough+'. Text in the
|
15
|
+
# code and verbatim string is not processed for org-mode specific
|
16
|
+
# syntax, it is exported verbatim.
|
17
|
+
parent.rule :a, /\b([A-Z]\w+[A-Z]\w+)/
|
18
|
+
parent.rule :text, /([A-Za-z0-9,. ]+)/
|
19
|
+
# parent.rule :text, /(\/\/)/
|
20
|
+
parent.rule :a, /\[\[([^\]]+)\]\[([^\]]+)\]\]/
|
21
|
+
parent.rule :a, /\[\[(.+?)\]\]/
|
22
|
+
parent.rule :italic, /\/([^\/ ]+)\//, :tag => :i
|
23
|
+
parent.rule :bold, /\*([^* ]+)\*/, :tag => :b
|
24
|
+
parent.rule :underline, /_([^_ ]+)_/, :tag => :u
|
25
|
+
parent.rule :strikethrough, /\+([^+ ]+)\+/, :tag => :s
|
26
|
+
parent.rule :blockquote, /~([^~ ]+)~/
|
27
|
+
parent.rule :code, /\=([^= ]+)\=/
|
28
|
+
parent.rule :code, /`([^`]+)`/
|
29
|
+
parent.rule :hr, /---+/, :bol => true
|
30
|
+
end
|
31
|
+
|
32
|
+
block.scope :ul do |ul|
|
33
|
+
ul.rule :li, /[ \t]+\*+\s*/, :start => :li, :bol => true
|
34
|
+
ul.rule :close, /\n/, :end => :ul
|
35
|
+
ul.rule :close, /(.)/, :end => :ul, :unscan => true
|
36
|
+
|
37
|
+
ul.scope :li do |li|
|
38
|
+
li.apply(&inline_rules)
|
39
|
+
li.rule :text, /(.)/
|
40
|
+
li.rule :ul, /[ \t]+\*+\s*/, :start => ul, :bol => true
|
41
|
+
li.rule :close, /\n/, :end => :li
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
block.scope(:inline, :indent => false) do |inline|
|
46
|
+
inline.apply(&inline_rules)
|
47
|
+
inline.rule :highlight, /\{\{\{[\t ]*(\S+)\n(.*?)\n\}\}\}/m
|
48
|
+
inline.rule :highlight, /\{\{\{\n(.*?)\n\}\}\}/m
|
49
|
+
inline.rule :text, /(.)/
|
50
|
+
inline.rule :close, /\n\n+/, :end => :inline
|
51
|
+
inline.rule :br, /\n/
|
52
|
+
end
|
53
|
+
|
54
|
+
block.scope(:table, :indent => true) do |table|
|
55
|
+
# | name | telelphone | room |
|
56
|
+
# |--------+------------+------|
|
57
|
+
# | Mr. X | 777-777 | 42 |
|
58
|
+
# | Mrs. Y | 888-888 | 21 |
|
59
|
+
|
60
|
+
table.rule :tr, /\|([^|]+)/, :bol => true, :unscan => true, :start => :tr
|
61
|
+
table.rule :close, /\n/, :end => :table
|
62
|
+
|
63
|
+
table.scope(:tr, :indent => true) do |tr|
|
64
|
+
tr.rule :table_separator, /\|[+-]+\|/, :ignore => true
|
65
|
+
tr.rule :close, /\|\n/, :end => :tr
|
66
|
+
tr.rule :close, /\n/, :end => :tr
|
67
|
+
tr.rule :td, /\|/, :start => :td
|
68
|
+
|
69
|
+
tr.scope :td do |td|
|
70
|
+
td.apply(&inline_rules)
|
71
|
+
td.rule :space, /([\t ]+)/
|
72
|
+
td.rule :text, /([^|])/
|
73
|
+
td.rule :close, /\|/, :end => :td, :unscan => true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/org/scope.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Org
|
2
|
+
class Scope
|
3
|
+
attr_accessor :parent, :name, :scopes
|
4
|
+
|
5
|
+
def initialize(name, options = {})
|
6
|
+
@rules = []
|
7
|
+
@name, @options = name, options
|
8
|
+
@scopes = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def scope(name, options = {}, &block)
|
12
|
+
scope = Scope.new(name, options)
|
13
|
+
scope.parent = self
|
14
|
+
yield @scopes[name] = scope
|
15
|
+
end
|
16
|
+
|
17
|
+
def rule(name, regex, options = {})
|
18
|
+
@rules << Rule.new(name, regex, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def apply
|
22
|
+
yield(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def step(state)
|
26
|
+
@rules.find do |rule|
|
27
|
+
rule.match(state)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
"<Scope #{name}>"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/org/state.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Org
|
2
|
+
class State < Struct.new(:scope, :parent, :scanner)
|
3
|
+
def step
|
4
|
+
loop do
|
5
|
+
# before = scanner.string[0...scanner.pos][-25, 25]
|
6
|
+
# after = scanner.string[scanner.pos..-1][0, 50]
|
7
|
+
# p "%40s@%40s" % [before, after]
|
8
|
+
break unless scope.step(self)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module Org
|
4
|
+
# Adding some comfort
|
5
|
+
class StringScanner < ::StringScanner
|
6
|
+
# Equivalent to Regexp#captures, returns Array of all matches
|
7
|
+
def captures
|
8
|
+
n = 0
|
9
|
+
found = []
|
10
|
+
while n += 1
|
11
|
+
return found unless element = self[n]
|
12
|
+
found << element
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/org/to/html.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
module Org
|
2
|
+
class RootToken < Token
|
3
|
+
# little optimization, avoid check for root
|
4
|
+
def to_html
|
5
|
+
@childs.map{|child| child.to_html }.join
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ToHtml
|
10
|
+
def to_html
|
11
|
+
method = "html_#{@name}"
|
12
|
+
|
13
|
+
if respond_to?(method)
|
14
|
+
send(method)
|
15
|
+
elsif @childs.empty?
|
16
|
+
Tag.new(name, values)
|
17
|
+
else
|
18
|
+
Tag.new(name, values){ @childs.map{|c| c.to_html }.join }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def html_text
|
23
|
+
Org.escape_html(values.join)
|
24
|
+
end
|
25
|
+
|
26
|
+
# unify toc_id somwhere?
|
27
|
+
def html_header
|
28
|
+
level, text = values[0].size, values[1]
|
29
|
+
id = respond_to?(:toc_id) ? toc_id : text.gsub(/\W/, '-').squeeze('-').downcase
|
30
|
+
Tag.new("h#{level}", text, :id => id)
|
31
|
+
end
|
32
|
+
|
33
|
+
def html_space
|
34
|
+
' '
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO: find a simple way of caching highlighted code from Uv,
|
38
|
+
# gives us much more possibilities in highlighting compared
|
39
|
+
# to coderay, but is also _really_ slow.
|
40
|
+
def html_highlight
|
41
|
+
language, code = *values
|
42
|
+
require 'coderay'
|
43
|
+
language = 'nitro_xhtml' if language == 'ezamar'
|
44
|
+
|
45
|
+
case language
|
46
|
+
when *%w[ruby c delphi html nitro_xhtml plaintext rhtml xml]
|
47
|
+
tokens = CodeRay.scan(code, language)
|
48
|
+
html = tokens.html(:wrap => :div)
|
49
|
+
when *%w[diff]
|
50
|
+
require 'uv'
|
51
|
+
Uv.parse(code, output = 'xhtml', syntax_name = language, line_numbers = false, render_style = 'amy', headers = false)
|
52
|
+
else
|
53
|
+
code = language if not code or code.strip.empty?
|
54
|
+
html = tag(:pre, code)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def tag(*args)
|
59
|
+
Tag.new(*args)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Extracted from Ramaze Gestalt
|
64
|
+
class Tag
|
65
|
+
def initialize(name, value, args = {}, &block)
|
66
|
+
@name, @value, @args, @block = name, value, args, block
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
@out = ''
|
71
|
+
build_tag(@name, @args, @value, &@block)
|
72
|
+
@out
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_tag(name, attr = {}, text = [])
|
76
|
+
@out << "<#{name}"
|
77
|
+
@out << attr.map{|k,v| %[ #{k}="#{Org.escape_html(v)}"] }.join
|
78
|
+
if text != [] or block_given?
|
79
|
+
@out << ">"
|
80
|
+
@out << Org.escape_html([text].join)
|
81
|
+
if block_given?
|
82
|
+
text = yield
|
83
|
+
@out << text.to_str if text != @out and text.respond_to?(:to_str)
|
84
|
+
end
|
85
|
+
@out << "</#{name}>"
|
86
|
+
else
|
87
|
+
@out << ' />'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/org/to/toc.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Org
|
2
|
+
class RootToken
|
3
|
+
def to_toc
|
4
|
+
found = @childs.map{|child| child.to_toc }.flatten.compact
|
5
|
+
|
6
|
+
out = []
|
7
|
+
nest = 0
|
8
|
+
|
9
|
+
while token = found.shift
|
10
|
+
level, text = *token.values
|
11
|
+
level = level.size
|
12
|
+
|
13
|
+
if level > nest
|
14
|
+
out << '<ol>'
|
15
|
+
elsif level < nest
|
16
|
+
out << '</ol>'
|
17
|
+
end
|
18
|
+
nest = level
|
19
|
+
|
20
|
+
out << "<li>#{token.toc_link}</li>"
|
21
|
+
end
|
22
|
+
|
23
|
+
nest.times do
|
24
|
+
out << '</ol>'
|
25
|
+
end
|
26
|
+
|
27
|
+
out
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module ToToc
|
32
|
+
TOC_ENTRIES = [:header]
|
33
|
+
|
34
|
+
def to_toc
|
35
|
+
case @name
|
36
|
+
when *TOC_ENTRIES
|
37
|
+
self
|
38
|
+
else
|
39
|
+
@childs.map{|child| child.to_toc }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def toc_link
|
44
|
+
tag(:a, values[1], :href => "##{toc_id}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def toc_id
|
48
|
+
values[1].gsub(/\W/, '-').squeeze('-').downcase
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/org/token.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Org
|
2
|
+
class Token
|
3
|
+
attr_accessor :name, :values, :options, :block, :childs, :parent
|
4
|
+
|
5
|
+
def initialize(name, values, options = {}, &block)
|
6
|
+
@name, @values, @options, @block = name, values, options, block
|
7
|
+
@childs = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<(token)
|
11
|
+
token.parent = self
|
12
|
+
@childs << token
|
13
|
+
end
|
14
|
+
|
15
|
+
def pretty_inspect
|
16
|
+
{[name, values] => childs}.pretty_inspect
|
17
|
+
end
|
18
|
+
alias inspect pretty_inspect
|
19
|
+
end
|
20
|
+
end
|
data/lib/org.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
5
|
+
|
6
|
+
module Org
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def escape_html(string)
|
10
|
+
string.to_s.gsub("&", "&").
|
11
|
+
gsub("<", "<").
|
12
|
+
gsub(">", ">").
|
13
|
+
gsub("'", "'").
|
14
|
+
gsub('"', """)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'org/version'
|
19
|
+
require 'org/stringscanner'
|
20
|
+
require 'org/markup'
|
21
|
+
require 'org/state'
|
22
|
+
require 'org/scope'
|
23
|
+
require 'org/token'
|
24
|
+
require 'org/rule'
|
25
|
+
|
26
|
+
require 'org/scope/org_mode'
|
27
|
+
require 'org/to/html'
|
28
|
+
require 'org/to/toc'
|
data/spec/org.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'lib/org'
|
2
|
+
require 'org/scope/org_mode'
|
3
|
+
require 'org/to/html'
|
4
|
+
|
5
|
+
module Org
|
6
|
+
class Token
|
7
|
+
include ToHtml
|
8
|
+
include ToToc
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'bacon'
|
13
|
+
require 'hpricot'
|
14
|
+
|
15
|
+
Bacon.extend(Bacon::TestUnitOutput)
|
16
|
+
Bacon.summary_on_exit
|
17
|
+
|
18
|
+
describe Org::Markup do
|
19
|
+
def t(string) # short for transform
|
20
|
+
Org::OrgMode.apply(string).to_html
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'markup headers' do
|
24
|
+
t("* header" ).should == '<h1>header</h1>'
|
25
|
+
t("** header" ).should == '<h2>header</h2>'
|
26
|
+
t("*** header" ).should == '<h3>header</h3>'
|
27
|
+
t("**** header" ).should == '<h4>header</h4>'
|
28
|
+
t("***** header" ).should == '<h5>header</h5>'
|
29
|
+
t("****** header").should == '<h6>header</h6>'
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'markup inline' do
|
33
|
+
t('*foo*').should == '<p><b>foo</b></p>'
|
34
|
+
t('/foo/').should == '<p><i>foo</i></p>'
|
35
|
+
t('_foo_').should == '<p><u>foo</u></p>'
|
36
|
+
t('+foo+').should == '<p><s>foo</s></p>'
|
37
|
+
t('~foo~').should == '<p><blockquote>foo</blockquote></p>'
|
38
|
+
t('=foo=').should == '<p><code>foo</code></p>'
|
39
|
+
end
|
40
|
+
|
41
|
+
should 'markup table' do
|
42
|
+
table = Hpricot(t("|name|address|\n|manveru|home|\n|gojira|tokyo|\n")).at(:table)
|
43
|
+
(table/:tr).map{|tr| (tr/:td).map{|td| td.inner_text } }.
|
44
|
+
should == [%w[name address], %w[manveru home], %w[gojira tokyo]]
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'markup link' do
|
48
|
+
t('[[home]]').should == '<p><a href="/home">home</a></p>'
|
49
|
+
t('[[home][Home]]').should == '<p><a href="/home">Home</a></p>'
|
50
|
+
t('[[http://go.to/]]').should == '<p><a href="http://go.to/">http://go.to/</a></p>'
|
51
|
+
t('[[http://go.to/][Go to]]').should == '<p><a href="http://go.to/">Go to</a></p>'
|
52
|
+
end
|
53
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: manveru-org
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2009.02.21
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael 'manveru' Fellinger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-13 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rack
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.4.0
|
24
|
+
version:
|
25
|
+
description: Simple, straight-forward, base for web-frameworks.
|
26
|
+
email: m.fellinger@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- doc/syntax.org
|
36
|
+
- lib/org.rb
|
37
|
+
- lib/org/markup.rb
|
38
|
+
- lib/org/rule.rb
|
39
|
+
- lib/org/rules.rb
|
40
|
+
- lib/org/scope.rb
|
41
|
+
- lib/org/scope/org_mode.rb
|
42
|
+
- lib/org/state.rb
|
43
|
+
- lib/org/stringscanner.rb
|
44
|
+
- lib/org/to/html.rb
|
45
|
+
- lib/org/to/toc.rb
|
46
|
+
- lib/org/token.rb
|
47
|
+
- spec/org.rb
|
48
|
+
has_rdoc: true
|
49
|
+
homepage: http://github.com/manveru/org
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.2.0
|
71
|
+
signing_key:
|
72
|
+
specification_version: 2
|
73
|
+
summary: Powerful web-framework wrapper for Rack.
|
74
|
+
test_files: []
|
75
|
+
|